1、熟悉、理解Linux内核工作方式
2、尝试编写自己的内核
3、理解多进程时间片轮转的工作方式
1 cd LinuxKernel/linux-3.9.4 2 qemu -kernel arch/x86/boot/bzImage
1 #define MAX_TASK_NUM 4 2 #define KERNEL_STACK_SIZE 1024*8 3 4 /* CPU-specific state of this task */ 5 //用于保存EIP,ESP 6 struct Thread { 7 unsigned long ip; 8 unsigned long sp; 9 }; 10 //定义进程管理相关的数据结构 11 typedef struct PCB{ 12 int pid;//进程ID 13 volatile long state; //进程状态 /* -1 unrunnable, 0 runnable, >0 stopped */ 14 char stack[KERNEL_STACK_SIZE]; //当前进程的堆栈 15 /* CPU-specific state of this task */ 16 struct Thread thread; 17 unsigned long task_entry;//进程入口 18 struct PCB *next; //构造链表 19 }tPCB; 20 //声明调度器函数 21 void my_schedule(void);
1 #include <linux/tty.h> 2 #include <linux/vmalloc.h> 3 4 5 #include "mypcb.h" 6 7 tPCB task[MAX_TASK_NUM];//进程结构数组 8 tPCB * my_current_task = NULL; //当前进程的指针 9 volatile int my_need_sched = 0;//是否需要调度 10 11 void my_process(void);
void __init my_start_kernel(void) { int pid = 0; int i; //初始化零号进程, /* Initialize process 0*/ task[pid].pid = pid; task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */ task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;//入口是my_process task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1]; task[pid].next = &task[pid]; /*fork more process */ for(i=1;i<MAX_TASK_NUM;i++) { memcpy(&task[i],&task[0],sizeof(tPCB)); task[i].pid = i; task[i].state = -1; task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-1]; task[i].next = task[i-1].next; task[i-1].next = &task[i]; } /* start process 0 by task[0] */ pid = 0; my_current_task = &task[pid]; //ret之后0号进程正式启动 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*/ ); }
1 asm volatile( 2 "movl %1,%%esp\n\t" /* 将esp指向task[0]的堆栈stack顶端。 */ 3 "pushl %1\n\t" /* 将task[0].thread.sp即堆栈顶端地址压栈,为以后的%ebp的复位使用。 */ 4 "pushl %0\n\t" /* 将task[0].thread.ip即程序入口my_process压栈。 */ 5 "ret\n\t" /*将task[0].thread.ip即程序入口my_process放到eip。 */ 6 "popl %%ebp\n\t" /*popl %%ebp:引文eip被更改,所以实际没有运行。 */ 7 : 8 : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) /* input c or d mean %ecx/%edx*/ 9 );
1 void my_process(void) 2 { 3 int i = 0; 4 while(1) 5 { 6 i++; 7 if(i%10000000 == 0) 8 { 9 printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid); 10 if(my_need_sched == 1) 11 { 12 my_need_sched = 0; 13 my_schedule(); 14 } 15 printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid); 16 } 17 } 18 }
1 #include <linux/ctype.h> 2 #include <linux/tty.h> 3 #include <linux/vmalloc.h> 4 5 #include "mypcb.h" 6 7 extern tPCB task[MAX_TASK_NUM]; 8 extern tPCB * my_current_task; 9 extern volatile int my_need_sched; 10 volatile int time_count = 0;
(1)文件头定义了一些外部变量,以及记录时间中断次数的变量time_count
1 void my_timer_handler(void) 2 { 3 #if 1 4 if(time_count%1000 == 0 && my_need_sched != 1) 5 { 6 printk(KERN_NOTICE ">>>my_timer_handler here<<<\n"); 7 my_need_sched = 1; 8 } 9 time_count ++ ; 10 #endif 11 return; 12 }
1 void my_schedule(void) 2 { 3 tPCB * next; 4 tPCB * prev; 5 //出错处理 6 if(my_current_task == NULL 7 || my_current_task->next == NULL) 8 { 9 return; 10 } 11 printk(KERN_NOTICE ">>>my_schedule<<<\n"); 12 /* schedule */ 13 next = my_current_task->next; 14 prev = my_current_task; 15 if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */ 16 { 17 /* switch to next process */ 18 asm volatile( 19 "pushl %%ebp\n\t" /* save ebp */ 20 "movl %%esp,%0\n\t" /* save esp */ 21 "movl %2,%%esp\n\t" /* restore esp */ 22 "movl $1f,%1\n\t" /* save eip */ 23 "pushl %3\n\t" 24 "ret\n\t" /* restore eip */ 25 "1:\t" /* next process start here */ 26 "popl %%ebp\n\t" 27 : "=m" (prev->thread.sp),"=m" (prev->thread.ip) 28 : "m" (next->thread.sp),"m" (next->thread.ip) 29 ); 30 my_current_task = next; 31 printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid); 32 } 33 else 34 { 35 next->state = 0; 36 my_current_task = next; 37 printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid); 38 /* switch to new process */ 39 asm volatile( 40 "pushl %%ebp\n\t" /* save ebp */ 41 "movl %%esp,%0\n\t" /* save esp */ 42 "movl %2,%%esp\n\t" /* restore esp */ 43 "movl %2,%%ebp\n\t" /* restore ebp */ 44 "movl $1f,%1\n\t" /* save eip */ 45 "pushl %3\n\t" 46 "ret\n\t" /* restore eip */ 47 : "=m" (prev->thread.sp),"=m" (prev->thread.ip) 48 : "m" (next->thread.sp),"m" (next->thread.ip) 49 ); 50 } 51 return; 52 } 53
(1)上面的函数是进程的调度函数,开始时首先进行错误处理,如果进程运行出错就返回。