首页 > 系统服务 > 详细

Linux内核分析 第二周

时间:2016-03-06 20:34:50      阅读:194      评论:0      收藏:0      [点我收藏+]

Linux内核分析——完成一个简单的时间片轮转多道程序内核代码

张潇月+《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

一、实验 

打开实验楼,在老师早就建立好的环境里运行并分析一个简单的操作系统内核。

首先是进入老师搭建的平台

技术分享

然后cd mykernel 您可以看到qemu窗口输出的内容的代码mymain.c和myinterrupt.c

技术分享

技术分享

技术分享

以上是本次实验过程截图。

 

 二、分析实验代码

Mymain.c

/*

          *  linux/mykernel/mymain.c

          *

          *  Kernel internal my_start_kernel

          *

          *  Copyright (C) 2013  Mengning

          *

          */

         #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];

         tPCB * my_current_task = NULL;

         volatile int my_need_sched = 0;

        

         void my_process(void);

        

        

         void __init my_start_kernel(void)

         {

             int pid = 0;

             int i;

             /* Initialize process 0*/

             task[pid].pid = pid;

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

             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(i=1;i<MAX_TASK_NUM;i++)

             {

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

             }

             /* start process 0 by task[0] */

             pid = 0;

             my_current_task = &task[pid];

                   asm volatile(

                      "movl %1,%%esp\n\t"    /* set task[pid].thread.sp to esp */

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

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

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

                      "popl %%ebp\n\t"

                      :

                      : "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)

                 {

                     printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid);

                     if(my_need_sched == 1)

                     {

                         my_need_sched = 0;

                              my_schedule();

                          }

                          printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);

                 }    

             }

         }

 

Myinterrupt.c

/*

          *  linux/mykernel/myinterrupt.c

          *

          *  Kernel internal my_timer_handler

          *

          *  Copyright (C) 2013  Mengning

          *

          */

         #include <linux/types.h>

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

        

         /*

          * 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

             if(time_count%1000 == 0 && my_need_sched != 1)

             {

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

                 my_need_sched = 1;

             }

             time_count ++ ; 

         #endif

             return; 

         }

        

         void my_schedule(void)

         {

             tPCB * next;

             tPCB * prev;

        

             if(my_current_task == NULL

                 || my_current_task->next == NULL)

             {

                      return;

             }

             printk(KERN_NOTICE ">>>my_schedule<<<\n");

             /* schedule */

             next = my_current_task->next;

             prev = my_current_task;

             if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */

             {

                      /* switch to next process */

                      asm volatile(   

                          "pushl %%ebp\n\t"             /* save ebp */

                          "movl %%esp,%0\n\t"    /* save esp */

                          "movl %2,%%esp\n\t"     /* restore  esp */

                          "movl $1f,%1\n\t"       /* save eip */       

                          "pushl %3\n\t"

                          "ret\n\t"                      /* restore  eip */

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

                          "popl %%ebp\n\t"

                          : "=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<<<\n",prev->pid,next->pid);          

             }

             else

             {

                 next->state = 0;

                 my_current_task = next;

                 printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);

                      /* switch to new process */

                      asm volatile(   

                          "pushl %%ebp\n\t"             /* save ebp */

                          "movl %%esp,%0\n\t"    /* save esp */

                          "movl %2,%%esp\n\t"     /* restore  esp */

                          "movl %2,%%ebp\n\t"     /* restore  ebp */

                          "movl $1f,%1\n\t"       /* save eip */       

                          "pushl %3\n\t"

                          "ret\n\t"                      /* restore  eip */

                          : "=m" (prev->thread.sp),"=m" (prev->thread.ip)

                          : "m" (next->thread.sp),"m" (next->thread.ip)

                      );         

             }  

             return;    

         }

 

 

Mypcb.c

/*

          *  linux/mykernel/mypcb.h

          *

          *  Kernel internal PCB types

          *

          *  Copyright (C) 2013  Mengning

          *

          */

        

         #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);

        

 

 三、操作系统是怎么工作?

程序在经过编译链接后形成可执行程序。在加载到内存时,系统根据可执行程序初始化进程的地址空间。CPU根据ebp/eip寻址进程地址空间中的cs段的代码,取值,译码并依次执行,进行数据处理。在函数调用时,会先把参数压栈,接着执行call指令-压栈参数cs:eip并跳转到被调用函数的cs段,然后构造被调函数的堆栈,之后,同样的取值,译码并执行,进行数据处理。在被调用函数结尾,会恢复调用函数的cs段的指令。

 

Linux内核分析 第二周

原文:http://www.cnblogs.com/20135131zxy/p/5248343.html

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