首页 > 其他 > 详细

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

时间:2020-05-12 19:52:35      阅读:68      评论:0      收藏:0      [点我收藏+]

一、配置mykernel 2.0,熟悉Linux内核的编译

1、实验环境:VMware 15 Pro,Ubuntu 18.04.4

2、配置环境

1)在电脑上先下载好以下两个文件,之后通过共享文件夹,将它们导入虚拟机。

技术分享图片

 

 

2)在虚拟机中解压linux-5.4.34.tar.xz文件得到如下文件夹

技术分享图片

 

 

3)进入该文件夹,打开终端,输入以下命令

patch -p1 < ../mykernel-2.0_for_linux-5.4.34.patch
sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev qemu
make defconfig 
make -j$(nproc) 
qemu-system-x86_64 -kernel arch/x86/boot/bzImage

上述命令的涵义是:配置mykernel、安装依赖包、编译、使用qemu运行mykernel

4)命令执行结果如下

技术分享图片

 

5)此时,在Linux-5.3.34内核源代码根目录下进入mykernel目录,可以看到QEMU窗口输出内容的源代码mymain.cmyinterrupt.c,内容如下

/* mymain.c */

void __init my_start_kernel(void)
{
    int i = 0;
    while(1)
    {
        i++;
        if(i%100000 == 0)
            printk(KERN_NOTICE "my_start_kernel here  %d \n",i);
    }
}

 

/* myinterrupt.c */

void my_timer_handler(void)
{
    printk(KERN_NOTICE "\n>>>>>>>>>>>>>>>>>my_timer_handler here<<<<<<<<<<<<<<<<<<\n\n");
}

 

程序执行的内容是:mymain.c中的代码在不停地被CPU执行。同时程序能够触发myinterrupt.c中的代码,周期性地产生的时钟中断信号。

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

1、修改相关文件

1)在mykernel目录下添加mypcb.h文件,用于定义进程控制块,内容如下

技术分享图片

 

 

2)修改mymain.c文件,添加my_process函数,用来模拟CPU执行的进程,内容如下

 

技术分享图片

 

 

 3)修改myinterrupt.c文件,修改my_timer_handler函数用来记录时间片,增加进程切换函数my_schedule(void),内容如下

 

 

 技术分享图片

 

2、重新编译并运行

运行结果如下:

技术分享图片

 

 

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

1、mymain.c核心汇编代码分析

asm volatile(

        "movq %1,%%rsp\n\t"

        "pushq %1\n\t"

        "pushq %0\n\t"

        "ret\n\t"

        :

        : "c" (task[pid].thread.ip), "d" (task[pid].thread.sp)

);

分析:1) 将进程原堆栈的栈顶地址存入RSP寄存器,而task[pid].thread.sp初始值即为进程0的堆栈栈顶;         

           2) 将当前RBP寄存器的值压栈,因为是空栈,所以RSP与RBP相同。此时,RSP = RSP - 8;

           3) 将当前进程的RIP压栈,值为初始化的my_process(void)函数的位置,此时,RSP = RSP - 8;

           4) 将栈顶位置的task[0].thread.ip,也就是my_process(void)函数的地址放入RIP寄存器中。此时,RSP = RSP + 8;

           5) 完成进程0的启动,执行my_process(void)函数。

2、myinterrupt.c核心代码分析

asm volatile(   
            "pushq %%rbp\n\t"         
            "movq %%rsp,%0\n\t"     
            "movq %2,%%rsp\n\t"     
            "movq $1f,%1\n\t"          
            "pushq %3\n\t"
            "ret\n\t"                 
            "1:\t"                 
            "popq %%rbp\n\t"
            : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
            : "m" (next->thread.sp),"m" (next->thread.ip)
);

分析:1)将当前RBP寄存器的值压入到进程0的堆栈;

           2)RSP寄存器指向进程的栈顶地址,即保存进程0的栈顶地址;而%0、%1是指汇编代码下面输入输出部分的编号;

           3)将进程1的栈顶地址存入RSP寄存器,完成进程0和进程1的堆栈切换;

           4)保存进程0当前RIP寄存器值,这里$1f是指标号1;

           5)将进程1的指令地址入栈,这时的next->thread.ip,在第一次执行时为进程1的起点my_process(void)函数,其余的情况均为$1f;

           6)将栈中的next->thread.ip放入RIP寄存器;

           7)标号1是一个特殊的地址位置,该位置的地址是$1f;

           8)将进程1堆栈的基地址从堆栈中弹出到RBP寄存器中;

           9)开始进程1,若进程1执行的过程中发生了进程调度和进程切换,进程0被会重新调度执行。

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

原文:https://www.cnblogs.com/wzh711/p/12872860.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!