zoukankan      html  css  js  c++  java
  • Linux内核分析 第二周

    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;/* 0号进程*/

    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;/*0号进程开始执行*/

    my_current_task = &task[pid];

    asm volatile(

    "movl %1,%%esp " /*%1表示下面的参数sp*/

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

    {

    printk(KERN_NOTICE "this is process %d - ",my_current_task->pid);/*主动调度,执行一千万次才调度一次*/

    if(my_need_sched == 1)

    {

    my_need_sched = 0;

    my_schedule();

    }

    printk(KERN_NOTICE "this is process %d + ",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<<< ");

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

    /* 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 " /* 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;

    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;

    }

    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;    /*用thread来存储ip,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系统管理05-----权限及归属管理
    Linux系统安装管理04----账号管理
    Linux系统管理03-----安装与管理程序
    Zabbix 监控主机
    Zabbix 页面优化
    基于 MHA 的MySQL高可用-CentOS7(理论)
    基于 MHA 的MySQL高可用-CentOS7(实例)
    部署Jumpserver环境
    GNS3连接本地服务器报错
    zabbix 安装部署
  • 原文地址:https://www.cnblogs.com/20135131zxy/p/5248343.html
Copyright © 2011-2022 走看看