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

一、实验要求

1、按照https://github.com/mengning/mykernel 的说明配置mykernel 2.0,熟悉Linux内核的编译;

2、基于mykernel 2.0编写一个操作系统内核,参照https://github.com/mengning/mykernel 提供的范例代码

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

二、实验环境

ubuntu-16.04.6

三、实验步骤

1、按照https://github.com/mengning/mykernel 的说明配置mykernel 2.0

下载并编译mykernel,在终端输入以下命令即可

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

sudo apt install axel

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

xz -d linux-5.4.34.tar.xz

tar-xvf linux-5.4.34.tar

cd linux-5.4.34patch-p1 < ../mykernel-2.0_for_linux-5.4.34.patch

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

make defconfig # Default configurationis based on 'x86_64_defconfig'make-j$(nproc) # 编译的时间比较久

sudo apt install qemu # install QEMU

接下来启动mykernel

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

3d721e0b1a0f992128cd114237944867.png

从qemu窗口中您可以看到my_start_kernel在执行,同时my_timer_handler时钟中断处理程序周期性执行。

2、基于mykernel编写一个操作系统

进入mykernel目录可以看到qemu窗口输出的内容的代码mymain.c和myinterrupt.c。当前有一个CPU执行C代码的上下文环境,同时具有中断处理程序的上下文环境,我们通过Linux内核代码模拟了一个具有时钟中断和C代码执行环境的硬件平台。只要在mymain.c基础上继续写进程描述PCB和进程链表管理等代码,在myinterrupt.c的基础上完成进程切换代码,一个可运行的小OS kernel就完成了。

在下载源码后,将mypcb.h,myinterrupt.c和mymain.c这三个文件拷贝到mykernel目录下,即要覆盖之前的mykernel文件夹下mymain.c和myinterrupt.c,并新增头文件mypcb.h

1)、mypcb.h:进程控制块结构体定义

1 #define MAX_TASK_NUM 4

2 #define KERNEL_STACK_SIZE 1024*2 # unsigned long

3 /*CPU-specific state of this task*/

4 structThread {5 unsigned longip;6 unsigned longsp;7};8

9 typedef structPCB{10 intpid;11 volatile long state; /*-1 unrunnable, 0 runnable, >0 stopped*/

12 unsigned longstack[KERNEL_STACK_SIZE];13 /*CPU-specific state of this task*/

14 structThread thread;15 unsigned longtask_entry;16 struct PCB *next;17}tPCB;18

19 void my_schedule(void);

该头文件中一些变量和函数的含义:

pid:进程号

state:进程状态,在模拟系统中,所有进程控制块信息都会被创建出来,其初始化值就是-1,如        果被调度运行起来,其值就会变成0

stack:进程使用的堆栈

thread:当前正在执行的线程信息

task_entry:进程入口函数

next:指向下一个PCB,模拟系统中所有的PCB是以链表的形式组织起来的。

函数的声明 my_schedule,它的实现在my_interrupt.c中,在mymain.c中的各个进程函数会根据          一 个全局变量的状态来决定是否调用它,从而实现主动调度。

2)、mymain.c:初始化各个进程并启动0号进程;

1 void __init my_start_kernel(void)2 {3 int pid = 0;4 inti;5 /*Initialize process 0*/

6 task[pid].pid =pid;7 task[pid].state = 0;/*-1 unrunnable, 0 runnable, >0 stopped*/

8 task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;9 task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];10 task[pid].next = &task[pid];11 /*fork more process*/

12 for(i=1;i

17 task[i].thread.sp = (unsigned long)(&task[i].stack[KERNEL_STACK_SIZE-1]);18 task[i].next = task[i-1].next;19 task[i-1].next = &task[i];20 }21 /*start process 0 by task[0]*/

22 pid = 0;23 my_current_task = &task[pid];24 asm volatile(25 "movl %1,%%esp\n\t" /*set task[pid].thread.sp to esp*/

26 "pushl %1\n\t" /*push ebp*/

27 "pushl %0\n\t" /*push task[pid].thread.ip*/

28 "ret\n\t" /*pop task[pid].thread.ip to eip*/

29 :30 : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) /*input c or d mean %ecx/%edx*/

31 );32 }33

34 int i = 0;35

36 void my_process(void)37 {38 while(1)39 {40 i++;41 if(i%10000000 == 0)42 {43 printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid);44 if(my_need_sched == 1)45 {46 my_need_sched = 0;47 my_schedule();48 }49 printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);50 }51 }52 }

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<<

12 void my_schedule(void)13 {14 tPCB *next;15 tPCB *prev;16

17 if(my_current_task ==NULL18 || my_current_task->next ==NULL)19 {20 return;21 }22 printk(KERN_NOTICE ">>>my_schedule<<

24 next = my_current_task->next;25 prev =my_current_task;26 if(next->state == 0)/*-1 unrunnable, 0 runnable, >0 stopped*/

27 {28 my_current_task =next;29 printk(KERN_NOTICE ">>>switch %d to %d<<pid,next->pid);30 /*switch to next process*/

31 asm volatile(32 "pushq %%rbp\n\t" /*save rbp of prev*/

33 "movq %%rsp,%0\n\t" /*save rsp of prev*/

34 "movq %2,%%rsp\n\t" /*restore rsp of next*/

35 "movq $1f,%1\n\t" /*save rip of prev*/

36 "pushq %3\n\t"

37 "ret\n\t" /*restore rip of next*/

38 "1:\t" /*next process start here*/

39 "popq %%rbp\n\t"

40 : "=m" (prev->thread.sp),"=m" (prev->thread.ip)41 : "m" (next->thread.sp),"m" (next->thread.ip)42 );43 }44 return;45 }

3、再次编译运行:

make allnoconfig

make

qemu-kernel arch/x86/boot/bzImage

039fb20e977bbccb130ce7a98e50a41f.png

四、实验总结

通过手动实现 mykernel 操作系统的内核,我学习到了进程的创建、加载以及不同进程之间切换的相关知识。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值