2019-2020-1 20199326《Linux内核原理与分析》第三周作业

第三周学习内容

庖丁解牛Linux内核分析第二章:操作系统是如何工作的
Linux内核分析实验二

学到的一些知识

  • 计算机的三大法宝:存储程序计算机,函数调用堆栈,中断

  • 堆栈是C语言程序运行时必须使用的记录函数调用路径和参数存储的空间,堆栈具体的作用有:记录函数调用框架,传递函数参数,保存返回值的地址,提供函数内部局部变量的存储空间等

  • 与堆栈相关的寄存器:ESP,EBP

  • 堆栈操作:push,pop

  • CS:EIP总是指向下一条的指令地址

    • 顺序执行:总是指向地址连续的下一条指令
    • 跳转/分支:执行这样的指令时,CS:EIP的值会根据程序需要被修改
    • call:将当前的CS:EIP的值压入栈顶,CS:EIP指向被调用函数的入口地址
    • ret:从栈顶弹出原来保存在这里的CS:EIP的值,放入CS:EIP中
  • 如果两个机器的处理器指令集不同,汇编出来的汇编代码也会有所不同

实验内容

1.虚拟一个x86的CPU硬件平台

在实验楼的环境中打开shell,输入两行代码即可启动内核:

$ cd ~/LinuxKernel/linux-3.9.4
$ qemu -kernel arch/x86/boot/bzImage

内核启动后如图:

进入mykernel查看mymain.c和myinterrupt.c,如图所示:

2.在mykernel基础上构造一个简单地操作系统内核

增加一个mypcb.h的头文件

#define MAX_TASK_NUM 10 // 最大进程数
#define KERNEL_STACK_SIZE 1024*8
#define PRIORITY_MAX 30 //从0到30的优先级

/* CPU-specific state of this task */
struct Thread {
unsigned long	ip;//point to cpu run address
unsigned long	sp;//point to the thread stack's top address
//todo add other attrubte of system thread
};
//PCB Struct
typedef struct PCB{
int pid; // pcb id 
volatile long state;	/* -1 不运行, 0 运行, >0 停止 */
char stack[KERNEL_STACK_SIZE];// each pcb stack size is 1024*8
/* CPU-specific state of this task */
struct Thread thread;
unsigned long	task_entry;//the task execute entry memory address
struct PCB *next;//pcb is a circular linked list
unsigned long priority;// task priority ////////
//todo add other attrubte of process control block
}tPCB;

//void my_schedule(int pid);
void my_schedule(void);

修改mymain.c

#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/smp.h>
#endif
#include "mypcb.h"

tPCB task[MAX_TASK_NUM];
tPCB * my_current_task = NULL;
volatile int my_need_sched = 0;

void my_process(void);
unsigned long get_rand(int );

void sand_priority(void)
{
	int i;
	for(i=0;i<MAX_TASK_NUM;i++)
		task[i].priority=get_rand(PRIORITY_MAX);
}
void __init my_start_kernel(void)
{
int pid = 0;
/* Initialize process 0*/
task[pid].pid = pid;
task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */
// set task 0 execute entry address to my_process
task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;
task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
task[pid].next = &task[pid];
/*fork more process */
for(pid=1;pid<MAX_TASK_NUM;pid++)
{
memcpy(&task[pid],&task[0],sizeof(tPCB));
task[pid].pid = pid;
task[pid].state = -1;
task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
	task[pid].priority=get_rand(PRIORITY_MAX);//each time all tasks get a random priority
}
	task[MAX_TASK_NUM-1].next=&task[0];
printk(KERN_NOTICE "\n\n\n\n\n\nsystem begin :>>>process 0 running!!!<<<\n\n");
/* start process 0 by task[0] */
pid = 0;
my_current_task = &task[pid];
asm volatile(
 "movl %1,%%esp\n\t" /* set task[pid].thread.sp to esp */
 "pushl %1\n\t" /* push ebp */
 "pushl %0\n\t" /* push task[pid].thread.ip */
 "ret\n\t" /* pop task[pid].thread.ip to eip */
 "popl %%ebp\n\t"
 :
 : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)	/* input c or d mean %ecx/%edx*/
);
}
void my_process(void)
{
int i = 0;
while(1)
{
i++;
if(i%10000000 == 0)
{
	  
if(my_need_sched == 1)
{
my_need_sched = 0;
		sand_priority();
	   	my_schedule();  
		
	   }
}
}
}//end of my_process

//produce a random priority to a task
unsigned long get_rand(max)
{
	unsigned long a;
	unsigned long umax;
	umax=(unsigned long)max;
 	get_random_bytes(&a, sizeof(unsigned long ));
	a=(a+umax)%umax;
	return a;
}

修改myinterrupt.c

#include "mypcb.h"

#define CREATE_TRACE_POINTS
#include <trace/events/timer.h>

extern tPCB task[MAX_TASK_NUM];
extern tPCB * my_current_task;
extern volatile int my_need_sched;
volatile int time_count = 0;

/*
* Called by timer interrupt.
* it runs in the name of current running process,
* so it use kernel stack of current running process
*/
void my_timer_handler(void)
{
#if 1
// make sure need schedule after system circle 2000 times.
if(time_count%2000 == 0 && my_need_sched != 1)
{
my_need_sched = 1;
	//time_count=0;
}
time_count ++ ;
#endif
return;
}

void all_task_print(void);

tPCB * get_next(void)
{
	int pid,i;
	tPCB * point=NULL;
	tPCB * hig_pri=NULL;//points to the the hightest task
	all_task_print();
	hig_pri=my_current_task;
	for(i=0;i<MAX_TASK_NUM;i++)
		if(task[i].priority<hig_pri->priority)	
			hig_pri=&task[i];
	printk("higst process is:%d priority is:%d\n",hig_pri->pid,hig_pri->priority);
	return hig_pri;

}//end of priority_schedule

void my_schedule(void)
{
tPCB * next;
tPCB * prev;
// if there no task running or only a task ,it shouldn't need schedule
if(my_current_task == NULL
|| my_current_task->next == NULL)
{
	printk(KERN_NOTICE "time out!!!,but no more than 2 task,need not schedule\n");
 return;
}
/* schedule */

next = get_next();
prev = my_current_task;
printk(KERN_NOTICE "the next task is %d priority is %u\n",next->pid,next->priority);
if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */
{//save current scene
 /* switch to next process */
 asm volatile(	
 "pushl %%ebp\n\t" /* save ebp */
 "movl %%esp,%0\n\t" /* save esp */
 "movl %2,%%esp\n\t" /* restore esp */
 "movl $1f,%1\n\t" /* save eip */	
 "pushl %3\n\t"
 "ret\n\t" /* restore eip */
 "1:\t" /* next process start here */
 "popl %%ebp\n\t"
 : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
 : "m" (next->thread.sp),"m" (next->thread.ip)
 );
 my_current_task = next;//switch to the next task
printk(KERN_NOTICE "switch from %d process to %d process\n>>>process %d running!!!<<<\n\n",prev->pid,next->pid,next->pid);

  }
else
{
next->state = 0;
my_current_task = next;
printk(KERN_NOTICE "switch from %d process to %d process\n>>>process %d running!!!<<<\n\n\n",prev->pid,next->pid,next->pid);

 /* switch to new process */
 asm volatile(	
 "pushl %%ebp\n\t" /* save ebp */
 "movl %%esp,%0\n\t" /* save esp */
 "movl %2,%%esp\n\t" /* restore esp */
 "movl %2,%%ebp\n\t" /* restore ebp */
 "movl $1f,%1\n\t" /* save eip */	
 "pushl %3\n\t"
 "ret\n\t" /* restore eip */
 : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
 : "m" (next->thread.sp),"m" (next->thread.ip)
 );
}
return;	
}//end of my_schedule

void all_task_print(void)
{
	int i,cnum=62;//
	printk(KERN_NOTICE "\ncurrent task is:%d   all task in OS are:\n",my_current_task->pid);

	printk("");
	for(i=0;i<cnum;i++)
		printk("-");
	printk("\n|  process:");
	for(i=0;i< MAX_TASK_NUM;i++)
		printk("| %2d ",i);
	printk("|\n| priority:");
	for(i=0;i<MAX_TASK_NUM;i++)
		printk("| %2d ",task[i].priority);

	printk("|\n");
	for(i=0;i<cnum;i++)
		printk("-");
	printk("\n");
}

重新编译,输入以下代码:

$ cd ~/LinuxKernel/linux-3.9.4
$ make
$ qemu -kernel arch/x86/boot/bzImage

结果如图所示

posted @ 2019-09-29 16:18  不摸鱼  阅读(160)  评论(0编辑  收藏  举报