zoukankan      html  css  js  c++  java
  • 2019-2020-1 20199301《Linux内核原理与分析》第三周作业

    操作系统是如何工作的

    本章目标是在mykernel的基础上编写一个简单的内核

    一、学习笔记

    1.计算机的三个法宝:a.存储程序计算机;b.函数调用堆栈;c.中断

    • 存储程序计算机(所有计算机的基础性的逻辑框架);
    • 函数调用堆栈(C语言程序运行时必须使用的记录函数调用路径和参数存储的空间);
      • 堆栈具体的作用:
        • 记录函数调用框架
        • 传递函数参数
        • 保存返回值的地址
        • 提供函数内部局部变量的存储空间
      • 堆栈相关的寄存器:
        • ESP:堆栈指针
        • EBP:基址指针
      • 堆栈操作:
        • push:栈顶地址减少4个字节,并将操作数放进栈顶存储单元
        • pop:栈顶地址增加4个字节,并将栈顶存储单元的内容放入操作数
      • 其他关键寄存器:
        - CS:EIP:总是指向地址连续的下一条指令
        - 跳转/分支:执行这样的命令时,CS:EIP的值会根据程序需要被修改
        - call:将当前CS:EIP的值压入栈顶,CS:EIP指向被调用函数的入口地址
        - ret:从栈顶弹出原来保存在这里CS:EIP的值,放入CS:EIP

        - 堆栈特别关键的就是函数调用堆栈框架

    二、实验

    • LinuxKernel/linux-3.9.4/mykernel目录下可以看到qemu窗口
      • 代码
    cd LinuxKernel/linux-3.9.4
    qemu -kernel arch/x86/boot/bzImage
    

    - QEMU窗口
    

    - 查看mymain.c
    


    每循环10 000次,打印一句话。

    - 查看myinterrupt.c
    


    每执行一次,都会执行一次时钟中断。

    下面是简单的时间片轮转机制内核代码:

    mypcb.h

    #define MAX_TASK_NUM 4
    
    #define KERNEL_STACK_SIZE 1024*8
    
    /* CPU-specific state of this task */
    
    struct Thread {
    
    unsigned long	ip;
    
    unsigned long	sp;
    
    };
    
    typedef struct PCB{
    
    int pid;
    
    volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
    
    char stack[KERNEL_STACK_SIZE];
    /* CPU-specific state of this task */
    
    struct Thread thread;
    
    unsigned long	task_entry;
    
    struct PCB *next;
    
    }tPCB;
    
    void my_schedule(void);
    
    - 定义一个进程控制块pcb结构体
    - task_entry:进程入口函数
    - thread:保存eip和esp
    - state:进程状态,用于判断是否调度
    

    mymain.c

    主要功能是让程序从0号进程开始运行,只列下面这段代码是核心。

    asm volatile(
    
    //%0表示参数thread.ip,%1表示参数thread.sp。
    
    "movl %1,%%esp
    	"     /* set task[pid].thread.sp to esp 把参数thread.sp放到esp中*/
    
    "pushl %1
    	"    /* push ebp 由于当前栈是空的,esp与ebp指向相同,所以等价于push ebp*/
    
    "pushl %0
    	"     /* push task[pid].thread.ip */
    
    "ret
    	"     /* pop task[pid].thread.ip to eip */
    
    "popl %%ebp
    	"
    
    :
    
    : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)     /* input c or d mean %ecx/%edx*/
    
    ); 
    

    myinterrupt.c

    主要功能是用于时钟中断处理和进程调度算法。

    asm volatile(
    
    "pushl %%ebp
    	" /* save ebp 保存当前进程的ebp*/
    
    "movl %%esp,%0
    	" /* save esp 把当前进程的esp赋给%0(指的是thread.sp),即保存当前进程的esp*/
    
    "movl %2,%%esp
    	" /* restore esp 把%2(指下一个进程的sp)放入esp中*/
    
    "movl $1f,%1
    	" /* save eip $1f是接下来的标号“1:”的位置,把eip保存下来*/
    
    "pushl %3
    	" /*把下一个进程eip压栈*/
    
    "ret
    	" /* restore eip 下一个进程开始执行*/
    
    "1:	" /* next process start here */
    
    "popl %%ebp
    	"
    
    : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
    
    : "m" (next->thread.sp),"m" (next->thread.ip)
    
    );
    

    三、总结

    (1)进程和中断在操作系统是是非常重要的两个部分,需要熟练掌握。
    (2)EIP寄存器储存着当前执行的代码,可以通过更改EIP寄存器的值来更改当前执行的代码,从而实现进程切换。出于安全考虑,EIP寄存器的值不能被直接改变,但可以通过压栈+ret指令来间接改变。
    (3)进程在执行过程中,当时间片用完之后需要进程切换时,需要保存当前的执行上下文环境,下次被调度的时候,需要回复进程的上下文环境。

    操作系统是如何工作的?

    操作系统通过存储程序计算机机制依次执行程序的指令,堆栈为程序运行时录调用路径和参数提供空间,中断用于异常处理和进程调度。

  • 相关阅读:
    CPU飙高,OOM排查?
    反射
    Mybatits
    spring 基础问题
    java中格式化数字0和#区别
    java中File对象的mkdir和mkdirs的区别
    java截取字符串几种方式
    java工厂模式
    Java获取文件路径的几种方式
    jxl生成excel时,增加批注和冻结窗口
  • 原文地址:https://www.cnblogs.com/lsqz/p/11601160.html
Copyright © 2011-2022 走看看