基于mykernel 2.0编写一个操作系统内核
作者:互联网
一、 实验要求
-
按照https://github.com/mengning/mykernel 的说明配置mykernel 2.0,熟悉Linux内核的编译;
-
基于mykernel 2.0编写一个操作系统内核,参照https://github.com/mengning/mykernel 提供的范例代码
-
简要分析操作系统内核核心功能及运行工作机制
二、实验步骤
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