• 2019-2020-1 20199326《Linux内核原理与分析》第三周作业


    第三周学习内容

    庖丁解牛Linux内核分析第二章:操作系统是如何工作的
    Linux内核分析实验二

    学到的一些知识

    • 计算机的三大法宝:存储程序计算机,函数调用堆栈,中断

    • 堆栈是C语言程序运行时必须使用的记录函数调用路径和参数存储的空间,堆栈具体的作用有:记录函数调用框架,传递函数参数,保存返回值的地址,提供函数内部局部变量的存储空间等

    • 与堆栈相关的寄存器:ESP,EBP

    • 堆栈操作:push,pop

    • CS:EIP总是指向下一条的指令地址

      • 顺序执行:总是指向地址连续的下一条指令
      • 跳转/分支:执行这样的指令时,CS:EIP的值会根据程序需要被修改
      • call:将当前的CS:EIP的值压入栈顶,CS:EIP指向被调用函数的入口地址
      • ret:从栈顶弹出原来保存在这里的CS:EIP的值,放入CS:EIP中
    • 如果两个机器的处理器指令集不同,汇编出来的汇编代码也会有所不同

    实验内容

    1.虚拟一个x86的CPU硬件平台

    在实验楼的环境中打开shell,输入两行代码即可启动内核:

    $ cd ~/LinuxKernel/linux-3.9.4
    $ qemu -kernel arch/x86/boot/bzImage
    

    内核启动后如图:

    进入mykernel查看mymain.c和myinterrupt.c,如图所示:

    2.在mykernel基础上构造一个简单地操作系统内核

    增加一个mypcb.h的头文件

    #define MAX_TASK_NUM 10 // 最大进程数
    #define KERNEL_STACK_SIZE 1024*8
    #define PRIORITY_MAX 30 //从0到30的优先级
    
    /* CPU-specific state of this task */
    struct Thread {
    unsigned long	ip;//point to cpu run address
    unsigned long	sp;//point to the thread stack's top address
    //todo add other attrubte of system thread
    };
    //PCB Struct
    typedef struct PCB{
    int pid; // pcb id 
    volatile long state;	/* -1 不运行, 0 运行, >0 停止 */
    char stack[KERNEL_STACK_SIZE];// each pcb stack size is 1024*8
    /* CPU-specific state of this task */
    struct Thread thread;
    unsigned long	task_entry;//the task execute entry memory address
    struct PCB *next;//pcb is a circular linked list
    unsigned long priority;// task priority ////////
    //todo add other attrubte of process control block
    }tPCB;
    
    //void my_schedule(int pid);
    void my_schedule(void);
    

    修改mymain.c

    #ifdef CONFIG_X86_LOCAL_APIC
    #include <asm/smp.h>
    #endif
    #include "mypcb.h"
    
    tPCB task[MAX_TASK_NUM];
    tPCB * my_current_task = NULL;
    volatile int my_need_sched = 0;
    
    void my_process(void);
    unsigned long get_rand(int );
    
    void sand_priority(void)
    {
    	int i;
    	for(i=0;i<MAX_TASK_NUM;i++)
    		task[i].priority=get_rand(PRIORITY_MAX);
    }
    void __init my_start_kernel(void)
    {
    int pid = 0;
    /* Initialize process 0*/
    task[pid].pid = pid;
    task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */
    // set task 0 execute entry address to my_process
    task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;
    task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
    task[pid].next = &task[pid];
    /*fork more process */
    for(pid=1;pid<MAX_TASK_NUM;pid++)
    {
    memcpy(&task[pid],&task[0],sizeof(tPCB));
    task[pid].pid = pid;
    task[pid].state = -1;
    task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
    	task[pid].priority=get_rand(PRIORITY_MAX);//each time all tasks get a random priority
    }
    	task[MAX_TASK_NUM-1].next=&task[0];
    printk(KERN_NOTICE "
    
    
    
    
    
    system begin :>>>process 0 running!!!<<<
    
    ");
    /* start process 0 by task[0] */
    pid = 0;
    my_current_task = &task[pid];
    asm volatile(
     "movl %1,%%esp
    	" /* set task[pid].thread.sp to esp */
     "pushl %1
    	" /* 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*/
    );
    }
    void my_process(void)
    {
    int i = 0;
    while(1)
    {
    i++;
    if(i%10000000 == 0)
    {
    	  
    if(my_need_sched == 1)
    {
    my_need_sched = 0;
    		sand_priority();
    	   	my_schedule();  
    		
    	   }
    }
    }
    }//end of my_process
    
    //produce a random priority to a task
    unsigned long get_rand(max)
    {
    	unsigned long a;
    	unsigned long umax;
    	umax=(unsigned long)max;
     	get_random_bytes(&a, sizeof(unsigned long ));
    	a=(a+umax)%umax;
    	return a;
    }
    

    修改myinterrupt.c

    #include "mypcb.h"
    
    #define CREATE_TRACE_POINTS
    #include <trace/events/timer.h>
    
    extern tPCB task[MAX_TASK_NUM];
    extern tPCB * my_current_task;
    extern volatile int my_need_sched;
    volatile int time_count = 0;
    
    /*
    * Called by timer interrupt.
    * it runs in the name of current running process,
    * so it use kernel stack of current running process
    */
    void my_timer_handler(void)
    {
    #if 1
    // make sure need schedule after system circle 2000 times.
    if(time_count%2000 == 0 && my_need_sched != 1)
    {
    my_need_sched = 1;
    	//time_count=0;
    }
    time_count ++ ;
    #endif
    return;
    }
    
    void all_task_print(void);
    
    tPCB * get_next(void)
    {
    	int pid,i;
    	tPCB * point=NULL;
    	tPCB * hig_pri=NULL;//points to the the hightest task
    	all_task_print();
    	hig_pri=my_current_task;
    	for(i=0;i<MAX_TASK_NUM;i++)
    		if(task[i].priority<hig_pri->priority)	
    			hig_pri=&task[i];
    	printk("higst process is:%d priority is:%d
    ",hig_pri->pid,hig_pri->priority);
    	return hig_pri;
    
    }//end of priority_schedule
    
    void my_schedule(void)
    {
    tPCB * next;
    tPCB * prev;
    // if there no task running or only a task ,it shouldn't need schedule
    if(my_current_task == NULL
    || my_current_task->next == NULL)
    {
    	printk(KERN_NOTICE "time out!!!,but no more than 2 task,need not schedule
    ");
     return;
    }
    /* schedule */
    
    next = get_next();
    prev = my_current_task;
    printk(KERN_NOTICE "the next task is %d priority is %u
    ",next->pid,next->priority);
    if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */
    {//save current scene
     /* switch to next process */
     asm volatile(	
     "pushl %%ebp
    	" /* save ebp */
     "movl %%esp,%0
    	" /* save esp */
     "movl %2,%%esp
    	" /* restore esp */
     "movl $1f,%1
    	" /* save eip */	
     "pushl %3
    	"
     "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)
     );
     my_current_task = next;//switch to the next task
    printk(KERN_NOTICE "switch from %d process to %d process
    >>>process %d running!!!<<<
    
    ",prev->pid,next->pid,next->pid);
    
      }
    else
    {
    next->state = 0;
    my_current_task = next;
    printk(KERN_NOTICE "switch from %d process to %d process
    >>>process %d running!!!<<<
    
    
    ",prev->pid,next->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;	
    }//end of my_schedule
    
    void all_task_print(void)
    {
    	int i,cnum=62;//
    	printk(KERN_NOTICE "
    current task is:%d   all task in OS are:
    ",my_current_task->pid);
    
    	printk("");
    	for(i=0;i<cnum;i++)
    		printk("-");
    	printk("
    |  process:");
    	for(i=0;i< MAX_TASK_NUM;i++)
    		printk("| %2d ",i);
    	printk("|
    | priority:");
    	for(i=0;i<MAX_TASK_NUM;i++)
    		printk("| %2d ",task[i].priority);
    
    	printk("|
    ");
    	for(i=0;i<cnum;i++)
    		printk("-");
    	printk("
    ");
    }
    

    重新编译,输入以下代码:

    $ cd ~/LinuxKernel/linux-3.9.4
    $ make
    $ qemu -kernel arch/x86/boot/bzImage
    

    结果如图所示

  • 相关阅读:
    利用CSS3 中steps()制用动画
    移动WEB测试工具 Adobe Edge Inspect
    Grunt配置文件编写技巧及示范
    CSS3 box-shadow快速教程
    编写爬虫程序的神器
    node+express+jade搭建一个简单的"网站"
    node+express+ejs搭建一个简单的"页面"
    node的模块管理
    node的调试
    mongoDB的权限管理
  • 原文地址:https://www.cnblogs.com/funmary/p/11608511.html
Copyright © 2020-2023  润新知