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

    第一部分 学习笔记

    • 计算机的“三大法宝”:程序存储计算机、函数调用堆栈以及中断机制。
    • 堆栈的作用是:记录函数调用框架、传递函数参数、保存返回值地址、提供函数内部局部变量的存储空间。
    • 堆栈相关的寄存器:
      ESP:堆栈指针,指向堆栈栈顶
      EBP:基址指针,指向堆栈栈底
    • 堆栈操作
      push: 栈顶地址减少4个字节,将操作数放入栈顶存储单元
      **pop ** :将操作数从栈顶存储单元移出,栈顶地址增加4个字节
    • 其他关键寄存器
      CS:EIP 总是指向下一条指令地址。CS是代码段寄存器, EIP是指向下一条指令的地址。
    • C语言中内嵌汇编语言的写法
    asm volatile (
           汇编语句模版;
           输出部分;
           输入部分;
           破坏描述部分;
           );
    
    • 内嵌汇编语言的写法举例分析
    #include <stdio.h>
    
    int main()
    {
        unsigned int val1 = 1;
        unsigned int val2 = 2;
        unsigned int val3 = 0;
        pritnf("val1:%d,val2:%d,val3:%d
    ",val1,val2,val3);
        asm volatile(
            "movl $0,%%eax
    	"
            /*  将eax寄存器清零  */
            "addl %1,%%eax
    	"
            /* %1 是指下面的输入输出部分,从0开始编号,所以%1指的是val1*/
            /* 这条语句的就是就是将ecx中存储的val1的值与eax寄存器中的值相加,结果为1*/
            "addl %2,%%eax
    	"
            /* %2 是指val2存在edx寄存器中*/
            /*这条语句就是将val2与寄存器eax中的值相加,放回eax中*/
            "movl %%eax,%0
    	"
            /* val1+val2的值写入到%0中去,也就是val3*/
    
            /*输出部分 */
            :"=m"(val3)
               /* =m”代表内存变量,m就是memory,也就是直接把变量写到内存val3中*/
    
             /*输入部分 */
            :"c"(vall),"d"(val2)
                /* c代表%二次项,d![](https://img2018.cnblogs.com/blog/1800798/201909/1800798-20190928193228032-1611440033.png)
    代表%edx,就是使用这一存储器存储相应变量的值*/
        );
        pritnf("val1:%d,val2:%d,val3:%d
    ",val1,val2,val3);
    
        return 0;
    }
    
    - asm 是GCC的关键字asm的宏定义,是内嵌汇编的关键字。
    - _volatile_是GCC的关键字,告诉编译器不要优化代码,汇编指令保留原样。
    - %作为转义字符,寄存器前面会多一个转义符号
    - %加一个数字代表输入、输入和破坏描述的编号。
    

    第二部分 实验报告

    • 第一步:

    mymain.c一直在循环输出“my_start_kernel here”这句代码,而myinterrupt.c中的my_timer_hardler函数将上述函数打断,而执行自己的代码。

    • 第二步:将mykernel操作系统的代码进行扩展:
      1.添加mypcb.h头文件,用来定义进程控制块
    //mypcb.h
    #define MAX_TASK_NUM  4
    #define KERNEL_STACK_SIZE 1024*8
     
      struct Thread {
        unsigned long   ip;
        unsigned long   sp;
    };
    
    typedef struct PCB{ 
        int pid;                                        //进程的编号
        volatile long state;                            //进程的状态
        char stack[KERNEL_STACK_SIZE];               
        struct Thread thread;                          
        unsigned long   task_entry;                     //进程的起始入口地址
        struct PCB *next;                                //进程用链表连接起来
     }tPCB;
    
    void my_schedule(void);                          // 进程调度器
    

    2.修改mymain.c,作为内核代码的入口,负责初始化内核的各个组成部分

    //mymain.c
    #include <linux/types.h>#include <linux/types.h>
    #include <linux/string.h>
    #include <linux/ctype.h>
    #include <linux/tty.h>
    #include <linux/vmalloc.h>
    
    #include "mypcb.h"
    
    
    tPCB task[MAX_TASK_NUM];//定义4个进程
    tPCB * my_current_task = NULL;
    volatile int my_need_sched = 0;
    
    void my_process(void);   //每10000000 来进行进程调度,调用my_schedule
    
    void __init my_start_kernel(void)
    { 
        int pid = 0; 
        int i;
        task[pid].pid = pid;   //初始化0号进程
        task[pid].state = 0;   
        task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;//0号进程的ip和入口地址设为my_process();
        task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
        task[pid].next = &task[pid];  //next指针指向自己
        for(i=1;i<MAX_TASK_NUM;i++)  //1,2,3号进程复制0号进程
            {
                memcpy(&task[i],&task[0],sizeof(tPCB));
                task[i].pid = i;
                task[i].state = -1;
                task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-1];
                task[i].next = task[i-1].next;
                task[i-1].next = &task[i];  //所有进程成为一个循环链表
            }
        pid = 0;
        my_current_task = &task[pid];   //启动0号进程
         asm volatile(
            "movl %1,%%esp
    	" //esp指向stack数组的末尾
            "pushl %1
    	"  //将task[0].thread.sp压栈
            "pushl %0
    	"  //将task[0].thread.ip压栈
            "ret
    	"   //eip指向0进程起始地址,启动0号进程
            "popl %%ebp
    	"//释放栈空间
            : 
            : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) 
        );
    }   
    
    void my_process(void)
        {
            int i = 0;
           while(1)
        {
            i++;
            if(i%10000000 == 0)
            {
                printk(KERN_NOTICE "this is process %d -
    ",my_current_task->pid);
                if(my_need_sched == 1)
            {
                my_need_sched = 0;
                my_shcedule();
            }
                printk(KERN_NOTICE"this is process %d +
    ",my_current_task->pid);
            }
        }
    }
    

    3.修改myinterrupt.c,增加进程切换代码,模拟基于时间片轮转的多道程序。

    #include <linux/string.h>
    #include <linux/ctype.h>
    #include <linux/tty.h>
    #include <linux/vmalloc.h>
    
    #include "mypcb.h"
    
    
    extern tPCB task[MAX_TASK_NUM];
    extern *tPCB my_current_task;
    extern volatile int my_need_sched;
    volatile int time_count = 0;
    
    void my_timer_handler(void)
    {
        #if 1
        if(time_count%1000 == 0 && my_need_sched != 1)
        {
            printk(KERN_NOTICE ">>>my_timer_handler here<<<
    ");
            my_need_sched = 1;
        } 
        time_count ++ ;  
        #endif
        return;  
    }
    
    void my_schedule(void)
    {
        tPCB * next;
        tPCB * prev;
        
         if(next->state == 0)  //下一个进程可运行,执行进程切换
        {
            /* switch to next process */   
            asm volatile(
                "pushl %%ebp
    	"  
                "movl %%esp,%0
    	" /
                "movl %2,%%esp
    	" 
                "movl $1f,%1
    	"  
                "pushl %3
    	" 
                "ret
    	"  
                "1:	"  
                "popl %%ebp
    	"
                : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
                : "m" (next->thread.sp),"m" (next->thread.ip)
               ); 
            my_current_task = next; 
            printk(KERN_NOTICE ">>>switch %d to %d<<<
    ",prev->pid,next->pid);  
        else
        {
            next->state = 0;
            my_current_task = next;
            printk(KERN_NOTICE ">>>switch %d to %d<<<
    ",prev->pid,next->pid);
            /* switch to new process */
            asm volatile(
                "pushl %%ebp
    	" /* save ebp */
                "movl %%esp,%0
    	" /* save esp */
                "movl %2,%%esp
    	" /* restore  esp */
                "movl %2,%%ebp
    	" /* restore  ebp */
                "movl $1f,%1
    	"   /* save eip */
                "pushl %3
    	" 
                "ret
    	" /* restore  eip */
                : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
                : "m" (next->thread.sp),"m" (next->thread.ip)
            );  
        }
        return;
    }
    

    修改后,make 进行重新编译。

  • 相关阅读:
    CentOS7突然出现无法连接网络的情况--VM下
    设置Linux系统的LANG变量
    习题
    Linux目录路径知识
    Linux目录详细介绍
    regexp正则
    https://github.com/rwson/awesome-javascript-cn
    JavaScript资源大全中文版(Awesome最新版)
    关于 Chrome DevTools 的 25 个实用技巧
    从前端菜鸟到大神,看这一篇就够了
  • 原文地址:https://www.cnblogs.com/20199321zjy/p/11602875.html
Copyright © 2011-2022 走看看