其他分享
首页 > 其他分享> > 基于mykernel 2.0编写一个操作系统内核

基于mykernel 2.0编写一个操作系统内核

作者:互联网

一、 实验要求

二、实验步骤

  2.1 配置mykernel 2.0

 1 wget https://raw.github.com/mengning/mykernel/master/mykernel-2.0_for_linux-5.4.34.patch
 2 sudo apt install axel
 3 axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.34.tar.xz
 4 xz -d linux-5.4.34.tar.xz
 5 tar -xvf linux-5.4.34.tar
 6 cd linux-5.4.34
 7 patch -p1 < ../mykernel-2.0_for_linux-5.4.34.patch
 8 sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev
 9 make defconfig # Default configuration is based on 'x86_64_defconfig'10 make -j$(nproc) # 编译的时间比较久哦
11 sudo apt install qemu # install QEMU
12 qemu-system-x86_64 -kernel arch/x86/boot/bzImage

    2.1.1 wget https://raw.github.com/mengning/mykernel/master/mykernel-2.0_for_linux-5.4.34.patch

            

    (这里连不上,直接使用群里的文件放到桌面) 

    2.1.2 sudo apt install axel

            

 

    2.1.3 axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.34.tar.xz

    2.1.4 xz -d linux-5.4.34.tar.xz

    2.1.5 tar -xvf linux-5.4.34.tar

    2.1.6 cd linux-5.4.34

    2.1.7 patch -p1 < ../mykernel-2.0_for_linux-5.4.34.patch

      由于mykernel-2.0_for_linux-5.4.34.patch文件,我放在桌面上。patch -p1 < /home/kyx/Desktop/mykernel-2.0_for_linux-5.4.34.patch

            

 

    2.1.8 sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev

    2.1.9 make defconfig # Default configuration is based on 'x86_64_defconfig'

    2.1.10 make -j$(nproc)

    2.1.11 sudo apt install qemu

    2.1.12 qemu-system-x86_64 -kernel arch/x86/boot/bzImage

            

  2.2 基于mykernel 2.0编写一个操作系统内核

    2.2.1 在mykernel目录下增加一个mypcb.h 头文件

            

 1 /*
 2  *  linux/mykernel/mypcb.h
 3  */
 4 
 5
 6 #define MAX_TASK_NUM        4
 7 #define KERNEL_STACK_SIZE   1024*8
 8 
 9 
10 /* CPU-specific state of this task */
11 struct Thread {
12     unsigned long       ip;
13     unsigned long       sp;
14 };
15 
16 
17 typedef struct PCB{
18     int pid;
19     volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
20     char stack[KERNEL_STACK_SIZE];
21     /* CPU-specific state of this task */
22     struct Thread thread;
23     unsigned long   task_entry;
24     struct PCB *next;
25 }tPCB;
26 
27 
28 void my_schedule(void);

    2.2.2 对mymain.c进行修改,vi mymain.c

 1 /*
 2     时间片轮转调度
 3 */
 4 
 5 #include "mypcb.h"
 6 
 7 
 8 tPCB task[MAX_TASK_NUM];
 9 tPCB * my_current_task = NULL;
10 volatile int my_need_sched = 0;
11 
12 
13 void my_process(void);
14 
15 
16 void __init my_start_kernel(void)
17 {
18     int pid = 0;
19     int i;
20     /* Initialize process 0*/
21     task[pid].pid = pid;
22     task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */
23     task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;
24     task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
25     task[pid].next = &task[pid];
26     /*fork more process */
27     for(i=1;i<MAX_TASK_NUM;i++)
28     {
29         memcpy(&task[i],&task[0],sizeof(tPCB));
30         task[i].pid = i;
31         task[i].state = -1;
32         task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-1];
33         task[i].next = task[i-1].next;
34         task[i-1].next = &task[i];
35     }
36     /* start process 0 by task[0] */
37     pid = 0;
38     my_current_task = &task[pid];
39     asm volatile(
40         "movq %1,%%rsp\n\t"  /* set task[pid].thread.sp to rsp */
41         "pushq %1\n\t"          /* push rbp */
42         "pushq %0\n\t"          /* push task[pid].thread.ip */
43         "ret\n\t"              /* pop task[pid].thread.ip to rip */
44         :
45         : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)   /* input c or d mean %ecx/%edx*/
46     );
47 }
48 
49 void my_process(void)
50 {
51     int i = 0;
52     while(1)
53     {
54         i++;
55         if(i%10000000 == 0)
56         {
57             printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid);
58             if(my_need_sched == 1)
59             {
60                 my_need_sched = 0;
61                 my_schedule();
62             }
63             printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);
64         }
65     }
66 }

    2.2.3 对myinterrupt.c中修改my_timer_handler用来记录时间片

 1 /*
 2  *  linux/mykernel/myinterrupt.c
 3  *
 4  *  Kernel internal my_timer_handler
 5  *  Change IA32 to x86-64 arch, 2020/4/26
 6  *
 7  *  Copyright (C) 2013, 2020  Mengning
 8  *
 9  */
10 #include <linux/types.h>
11 #include <linux/string.h>
12 #include <linux/ctype.h>
13 #include <linux/tty.h>
14 #include <linux/vmalloc.h>
15 
16 #include "mypcb.h"
17 
18 extern tPCB task[MAX_TASK_NUM];
19 extern tPCB * my_current_task;
20 extern volatile int my_need_sched;
21 volatile int time_count = 0;
22 
23 /*
24  * Called by timer interrupt.
25  * it runs in the name of current running process,
26  * so it use kernel stack of current running process
27  */
28 void my_timer_handler(void)
29 {
30     if(time_count%1000 == 0 && my_need_sched != 1)
31     {
32         printk(KERN_NOTICE ">>>my_timer_handler here<<<\n");
33         my_need_sched = 1;
34     } 
35     time_count ++ ;  
36     return;      
37 }
38 
39 void my_schedule(void)
40 {
41     tPCB * next;
42     tPCB * prev;
43 
44     if(my_current_task == NULL 
45         || my_current_task->next == NULL)
46     {
47         return;
48     }
49     printk(KERN_NOTICE ">>>my_schedule<<<\n");
50     /* schedule */
51     next = my_current_task->next;
52     prev = my_current_task;
53     if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */
54     {        
55         my_current_task = next; 
56         printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);  
57         /* switch to next process */
58         asm volatile(    
59             "pushq %%rbp\n\t"         /* save rbp of prev */
60             "movq %%rsp,%0\n\t"     /* save rsp of prev */
61             "movq %2,%%rsp\n\t"     /* restore  rsp of next */
62             "movq $1f,%1\n\t"       /* save rip of prev */    
63             "pushq %3\n\t" 
64             "ret\n\t"                 /* restore  rip of next */
65             "1:\t"                  /* next process start here */
66             "popq %%rbp\n\t"
67             : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
68             : "m" (next->thread.sp),"m" (next->thread.ip)
69         ); 
70     }  
71     return;    
72 }

    2.2.4 将内核重新编译, 然后运行。

1 make clean
2 make allnoconfig          
3 make
4 qemu -kernel arch/x86/boot/bzImage

           

  2.3 简要分析操作系统内核核心功能及运行工作机制

    2.3.1 首先分析一下mypcb.h文件

 1 struct Thread {
 2     unsigned long       ip;
 3     unsigned long       sp;
 4 };<br>
 5 typedef struct PCB{
 6     int pid;
 7     volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
 8     unsigned long stack[KERNEL_STACK_SIZE];
 9     struct Thread thread;
10     unsigned long   task_entry;
11     struct PCB *next;
12 }tPCB;
13 
14 结构体Thread :用于存储当前进程中正在执行的线程的ip和sp
15 结构体PCB:(模拟进程控制块)
16 pid:进程号
17 state:进程状态,-1代表阻塞态,0代表可运行态,>0代表暂停状态
18 stack:进程使用的堆栈
19 thread:当前正在执行的线程信息(thread.ip和thread.sp)
20 task_entry:存储进程入口函数地址(本实验中为my_process函数)
21 next:指向下一个PCB,系统中所有的PCB是以环形链表的形式连接起来的。

    2.3.2 mymain.c文件

 1 tPCB task[MAX_TASK_NUM];
 2 tPCB * my_current_task = NULL;
 3 volatile int my_need_sched = 0void my_process(void);
 4 
 5 void __init my_start_kernel(void)
 6 {
 7     int pid = 0;
 8     int i;
 9     /* Initialize process 0*/
10     task[pid].pid = pid;
11     task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */
12     task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;
13     task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
14     task[pid].next = &task[pid];
15     /*fork more process */
16     for(i=1;i<MAX_TASK_NUM;i++)
17     {
18         memcpy(&task[i],&task[0],sizeof(tPCB));
19         task[i].pid = i;
20         task[i].thread.sp = (unsigned long)(&task[i].stack[KERNEL_STACK_SIZE-1]);
21         task[i].next = task[i-1].next;
22         task[i-1].next = &task[i];
23     }
24     /* start process 0 by task[0] */
25     pid = 0;
26     my_current_task = &task[pid];
27     asm volatile(
28         "movq %1,%%rsp\n\t"     /* set task[pid].thread.sp to rsp */
29         "pushq %1\n\t"             /* push rbp */
30         "pushq %0\n\t"             /* push task[pid].thread.ip */
31         "ret\n\t"                 /* pop task[pid].thread.ip to rip */
32         : 
33         : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)    /* input c or d mean %ecx/%edx*/
34     );
35 } 
36 
37 int i = 0;
38 void my_process(void)
39 {    
40     while(1)
41     {
42         i++;
43         if(i%10000000 == 0)
44         {
45             printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid);
46             if(my_need_sched == 1)
47             {
48                 my_need_sched = 0;
49                 my_schedule();
50             }
51             printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);
52         }     
53     }
54 }
55 
56 my_start_kernel 是系统启动后最先调用的函数,在这个函数里完成了0号进程的初始化和启动,并创建了其它的进程PCB,以方便后面的调度。在模拟系统里,每个进程的函数代码都是一样的,即 my_process 函数,my_process 在执行的时候,会打印出当前进程的 id,从而使得我们能够看到当前哪个进程正在执行。
57 在汇编语言当中
58 %1指的是task[pid].thread.sp,%0是task[pid].thread.ip
59 “movl %1,%%esp\n\t” 将原堆栈的栈顶放到sp寄存器中
60 “pushl %1\n\t” 将ep寄存器的值存入栈
61 “pushl %0\n\t” 将当前进程ip值入栈
62 这样0号进程开始启动,程序去执行my_process()

    2.3.3 myinterrupt.c

 1 void my_timer_handler(void)
 2 {
 3     if(time_count%1000 == 0 && my_need_sched != 1)
 4     {
 5         printk(KERN_NOTICE ">>>my_timer_handler here<<<\n");
 6         my_need_sched = 1;
 7     }
 8     time_count ++ ; 
 9     return;    
10 }
11  
12 void my_schedule(void)
13 {
14     tPCB * next;
15     tPCB * prev;
16     if(my_current_task == NULL || my_current_task->next == NULL)
17     {
18         return;
19     }
20     printk(KERN_NOTICE ">>>my_schedule<<<\n");
21     /* schedule */
22     next = my_current_task->next;
23     prev = my_current_task;
24     if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */
25     {       
26         my_current_task = next;
27         printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid); 
28         /* switch to next process */
29         asm volatile(  
30             "pushq %%rbp\n\t"       /* save rbp of prev */
31             "movq %%rsp,%0\n\t"     /* save rsp of prev */
32             "movq %2,%%rsp\n\t"     /* restore  rsp of next */
33             "movq $1f,%1\n\t"       /* save rip of prev */ 
34             "pushq %3\n\t"
35             "ret\n\t"               /* restore  rip of next */
36             "1:\t"                  /* next process start here */
37             "popq %%rbp\n\t"
38             : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
39             : "m" (next->thread.sp),"m" (next->thread.ip)
40         );
41     } 
42     return;
43 }
44 mymain.c:负责完成各个进程的初始化并且启动0号进程;
45 myinterrupt.c:负责完成时钟中断的处理及进程的切换;
46 mypcb.h:负责完成进程控制块PCB结构体的定义。

 

标签:task,thread,process,pid,next,内核,mykernel,2.0,my
来源: https://www.cnblogs.com/kangyuxin/p/12865186.html