嵌入式Linux中文站

机制分析:基于简易的时间片轮转多道程序的 linux 内核


  • 内容说明 
    本次的内容,是一次 MOOC 课程的作业。具体的,是对一版 “简易的时间片轮转多道程序的 linux 内核” 进行分析,进而了解计算机、CPU 的工作机制。

  • 作业声明 
    qianyizhou17 + 原创作品转载请注明出处 + 《Linux 内核分析》MOOC 课程 
    http://mooc.study.163.com/course/USTC-1000029000

  • 致谢 
    感谢孟宇老师提供的 MOOC 课程:Linux 内核分析!

  • 实验准备

    • 环境 
      使用的是本次 MOOC 提供的实验楼的环境,可以直接访问 Linux 的环境并使用课程老师提供的资源! 
      也可以自行搭建。
    • 步骤

      1. cd LinuxKernel/linux-3.9.4
      2. rm -rf mykernel
      3. patch -p1 < ../mykernel_for_linux3.9.4sc.patch
      4. 按照下面的源码修改 mykernel 中代码
      5. make allnoconfig
      6. make #编译内核请耐心等待
      7. qemu -kernel arch/x86/boot/bzImage
    • 源码 
      mypcb.h

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

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; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 执行效果  这里写图片描述
  • 代码分析  内核进程的入口位于 mymain.c 中的 my_start_kernel,时钟中断处理函数为 my_timer_handler。  基本流程是:
    1. my_start_kernel 完成进程堆栈的初始化,将 4 个 task 整理为一个环形的任务列表,并在 t[0] 的堆栈中开始执行 my_process
    2. my_process 中循环进行查询,当 my_timer_handler 中设置允许调度时,调用 my_schedule
    3. my_schedule 中实现任务的切换和堆栈的切换

在 my_start_kernel 中的汇编分析

//movl %1, %%esp
//  = movl task[pid].thread.sp, %esp
//           Before                                          After
             my_kernel stack                 ||              Task[pid].STACK
             |           |                   ||              |           | stack[0]
             | my_kernel |                   ||              ------------- &(stack[0])
     ebp  -> -------------                   ||              |           | 
             |   param   |                   ||              |           | 
             |   param   |                   ||              |           | 
             |           |                   ||              |           | 
     esp  -> -------------                   ||              |           | 
             |           |                   ||              |           | 
             |           |                   ||              |           | stack[8191]
             |           |                   ||     esp   -> ------------- &(stack[8191])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
//pushl %1
//  = push task[pid].thread.sp
//           Before                                          After
             Task[pid].STACK                 ||              Task[pid].STACK
             |           | stack[0]          ||              |           | stack[0]
             ------------- &(stack[0])       ||              ------------- &stack[0]
             |           |                   ||              |           | 
             |           |                   ||              |           | 
             |           |                   ||              |           | 
             |           |                   ||              |           | 
             |           |                   ||              |           | 
             |           |                   ||     esp   -> ------------- 
             |           | stack[8191]       ||              | thread.sp | stack[8191]
     esp  -> ------------- &(stack[8191])    ||              ------------- &(stack[8191])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
//pushl %0
//  = push task[pid].thread.ip
//           Before                                          After
              Task[pid].STACK                ||              Task[pid].STACK
              |           | stack[0]         ||              |           | stack[0]
              ------------- &stack[0]        ||              ------------- &stack[0]
              |           |                  ||              |           | 
              |           |                  ||              |           | 
              |           |                  ||              |           | 
              |           |                  ||     esp   -> ------------- 
              |           |                  ||              | thread.ip | stack[8190]
     esp   -> -------------                  ||              ------------- &(stack[8190])
              | thread.sp | stack[8191]      ||              | thread.sp | stack[8191]
              ------------- &(stack[8191])   ||              ------------- &(stack[8191])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
//ret
//           Before                                          After
//                                                           EIP:   task[pid].thread.sp
              Task[pid].STACK                ||              Task[pid].STACK                
              |           | stack[0]         ||              |           | stack[0]              
              ------------- &stack[0]        ||              ------------- &stack[0]             
              |           |                  ||              |           |                       
              |           |                  ||              |           |                       
              |           |                  ||              |           |                       
     esp   -> -------------                  ||              -------------                       
              | thread.ip | stack[8190]      ||              |           | stack[8190]           
              ------------- &(stack[8190])   ||     esp   -> ------------- &(stack[8190])        
              | thread.sp | stack[8191]      ||              | thread.sp | stack[8191]           
              ------------- &(stack[8191])   ||              ------------- &(stack[8191])        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
//popl %ebp
//            Before                                          After                         
//            EIP:   task[pid].thread.sp                      EIP:   task[pid].thread.sp    
              Task[pid].STACK                 ||              Task[pid].STACK             
              |           | stack[0]          ||              |           | stack[0]          
              ------------- &stack[0]         ||              ------------- &stack[0]         
              |           |                   ||              |           |                   
              |           |                   ||              |           |                   
              |           |                   ||              |           |                   
              -------------                   ||              -------------                   
              |           | stack[8190]       ||              |           | stack[8190]       
     esp   -> ------------- &(stack[8190])    ||              ------------- &(stack[8190])    
              | thread.sp | stack[8191]       ||              |           | stack[8191]       
              ------------- &(stack[8191])    ||  esp/ebp  -> ------------- &(stack[8191])    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

will call my_process as EIP -> task[pid].thread.sp = my_process;  当 i 累加 10000000 时  打印 this is process 0 -  等待 时钟中断处理函数将 my_need_sched 设置为 1  调用 my_schedule

////////////////////////////////////////////////////////////////////////////////
/*
 * in my_schedule
 */

// 打印 >>>my_schedule<<<
// 第一次进入 my_schedule 开始分析: next ->state = -1
// 调用堆栈为 task[0]的stack
//        pid state   ip      sp
//  cur:  0   0        
//  prev: 0   0
//  next: 1   -1       
//  在汇编调用之前,task 状态修改为:
//        pid state   ip      sp
//  cur:  1   0        
//  prev: 0   0
//  next: 1   0
//
// 打印 >>>switch 0 to 1<<<
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
//push %ebp
//            Before                                          After                         
//            EIP:                                            EIP:       
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0        
//            prev: 0   0                                     prev: 0   0
//            next: 1   0                                     next: 1   0        
              Task[0].STACK                   ||              Task[0].STACK                 
              |           | stack[0]          ||              |           | stack[0]              
              ------------- &stack[0]         ||              ------------- &stack[0]             
              |           |                   ||              |           |                       
              |           |                   ||              |           |                       
              |           |                   ||              |           |                       
              -------------                   ||              -------------                       
              |           | stack[6799]       ||              |           | stack[6799]           
              ------------- &(stack[6799])    ||     esp   -> ------------- &(stack[6799])        
              |           | stack[6800]       ||              | ebp: T0_XX| stack[6800]           
     esp   -> ------------- &(stack[6800])    ||              ------------- &(stack[6800])        
              |           |                   ||              |           |                       
                    .                         ||                    .                         
     ebp   ->       .       T0_XX             ||     ebp   ->       .       T0_XX             
                    .                         ||                    .                         
              |           | stack[8191]       ||              |           | stack[8191]           
              ------------- &(stack[8191])    ||              ------------- &(stack[8191])        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
//movl %esp, %0
//  = movl %esp, prev ->thread.sp
//  = movl %esp, t[0].thread.sp
//
//            Before                                          After                         
//            EIP:                                            EIP:       
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 0   0                                     prev: 0   0               t0: &stack[6799]
//            next: 1   0               t1: &stack[8191]      next: 1   0               t1: &stack[8191]
              Task[0].STACK                   ||              Task[0].STACK                         
              |           | stack[0]          ||              |           | stack[0]                      
              ------------- &stack[0]         ||              ------------- &stack[0]                     
              |           |                   ||              |           |                               
              |           |                   ||              |           |                               
              |           |                   ||              |           |                               
              -------------                   ||              -------------                               
              |           | stack[6799]       ||              |           | stack[6799]                   
     esp   -> ------------- &(stack[6799])    ||     esp   -> ------------- &(stack[6799])                
              | ebp: T0_XX| stack[6800]       ||              | ebp: T0_XX| stack[6800]                   
              ------------- &(stack[6800])    ||              ------------- &(stack[6800])                
              |           |                   ||              |           |                               
                    .                         ||                    .                                 
     ebp   ->       .       T0_XX             ||     ebp   ->       .       T0_XX                     
                    .                         ||                    .                                 
              |           | stack[8191]       ||              |           | stack[8191]                   
              ------------- &(stack[8191])    ||              ------------- &(stack[8191])                
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
//movl %2, %esp
//  = movl next ->thread.sp, %esp
//  = movl t[1].thread.sp, %esp
//movl %2, %ebp
//  = movl next ->thread.sp, %ebp
//  = movl t[1].thread.sp, %ebp
//
//            Before                                          After                         
//            EIP:                                            EIP:       
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 0   0               t0: &stack[6799]      prev: 0   0               t0: &stack[6799]
//            next: 1   0               t1: &stack[8191]      next: 1   0               t1: &stack[8191]
              Task[0].STACK                   ||              Task[0].STACK                             Task[1].STACK                     
              |           | stack[0]          ||              |           | stack[0]                    |           | stack[0]                  
              ------------- &stack[0]         ||              ------------- &stack[0]                   ------------- &stack[0]                 
              |           |                   ||              |           |                             |           |                           
              |           |                   ||              |           |                             |           |                           
              |           |                   ||              |           |                             |           |                           
              -------------                   ||              -------------                             -------------                           
              |           | stack[6799]       ||              |           | stack[6799]                 |           | stack[6799]               
     esp   -> ------------- &(stack[6799])    ||              ------------- &(stack[6799])              ------------- &(stack[6799])            
              | ebp: T0_XX| stack[6800]       ||              | ebp: T0_XX| stack[6800]                 |           | stack[6800]               
              ------------- &(stack[6800])    ||              ------------- &(stack[6800])              ------------- &(stack[6800])            
              |           |                   ||              |           |                             |           |                           
                    .                         ||                    .                                         .                             
     ebp   ->       .       T0_XX             ||                    .       T0_XX                             .                        
                    .                         ||                    .                                         .                             
              |           | stack[8191]       ||              |           | stack[8191]                 |           | stack[8191]               
              ------------- &(stack[8191])    ||              ------------- &(stack[8191])   esp/ebp -> ------------- &(stack[8191])            
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
//movl $1f, %1
//  = movl $1f, prev ->thread.ip, 其中,$1f指向了line: 64的代码地址
//  = movl $1f, t[0].thread.ip
//
//            Before                                          After                         
//            EIP:                                            EIP:       
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 0   0    my_process t0: &stack[6799]      prev: 0   0    line:64    t0: &stack[6799]
//            next: 1   0    my_process t1: &stack[8191]      next: 1   0    my_process t1: &stack[8191]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
//push %3
//  = push next ->thread.ip
//  = push t[1].thread.ip
//
//            Before                                          After                         
//            EIP:                                            EIP:       
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 0   0    line:64    t0: &stack[6799]      prev: 0   0    line:64    t0: &stack[6799]
//            next: 1   0    my_process t1: &stack[8191]      next: 1   0    my_process t1: &stack[8191]
              Task[1].STACK                   ||              Task[1].STACK                   
              |           | stack[0]          ||              |           | stack[0]                
              ------------- &stack[0]         ||              ------------- &stack[0]               
              |           |                   ||              |           |                         
              |           |                   ||              |           |                         
              |           |                   ||              |           |                         
              -------------                   ||              -------------                         
              |           | stack[6799]       ||              |           | stack[6799]             
              ------------- &(stack[6799])    ||              ------------- &(stack[6799])          
              |           | stack[6800]       ||              |           | stack[6800]             
              ------------- &(stack[6800])    ||              ------------- &(stack[6800])          
              |           |                   ||              |           |                         
                    .                         ||                    .                           
                    .                         ||                    .                       
                    .                         ||     esp   -> -------------                     
              |           | stack[8191]       ||              | my_process| stack[8191]             
   esp/ebp -> ------------- &(stack[8191])    ||     ebp   -> ------------- &(stack[8191])          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
//ret    
//
//            Before                                          After                         
//            EIP:                                            EIP:  my_process     
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 0   0    line:64    t0: &stack[6799]      prev: 0   0    line:64    t0: &stack[6799]
//            next: 1   0    my_process t1: &stack[8191]      next: 1   0    my_process t1: &stack[8191]
              Task[1].STACK                   ||              Task[1].STACK                   
              |           | stack[0]          ||              |           | stack[0]                
              ------------- &stack[0]         ||              ------------- &stack[0]               
              |           |                   ||              |           |                         
              |           |                   ||              |           |                         
              |           |                   ||              |           |                         
              -------------                   ||              -------------                         
              |           | stack[6799]       ||              |           | stack[6799]             
              ------------- &(stack[6799])    ||              ------------- &(stack[6799])          
              |           | stack[6800]       ||              |           | stack[6800]             
              ------------- &(stack[6800])    ||              ------------- &(stack[6800])          
              |           |                   ||              |           |                         
                    .                         ||                    .                           
                    .                         ||                    .                         
     esp   -> -------------                   ||              -------------                     
              | my_process| stack[8191]       ||              |           | stack[8191]             
     ebp   -> ------------- &(stack[8191])    || esp/ebp   -> ------------- &(stack[8191])          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

开始执行 EIP 指向的 my_process, 此时的 cur 指向 task[1]  当 i 累加 10000000 时  打印 this is process 1 -  等待 时钟中断处理函数将 my_need_sched 设置为 1  调用 my_schedule

////////////////////////////////////////////////////////////////////////////////
/*
 * in my_schedule
 */

// 打印 >>>my_schedule<<<
//
// 第二次进入 my_schedule,为了简化,设置仅有2个 task。 
// 调用堆栈为 task[1]的stack
//        pid state   ip      sp
//  cur:  1   0        
//  prev: 1   0
//  next: 0   0        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
//push %ebp
//            Before                                          After                         
//            EIP:                                            EIP:                 
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 1   0    my_process t1: &stack[8191]      prev: 1   0    my_process t1: &stack[8191]
//            next: 0   0    line:64    t0: &stack[6799]      next: 0   0    line:64    t0: &stack[6799]
              Task[1].STACK                   ||              Task[1].STACK                   
              |           | stack[0]          ||              |           | stack[0]                
              ------------- &stack[0]         ||              ------------- &stack[0]               
              |           |                   ||              |           |                         
              |           |                   ||              |           |                         
              |           |                   ||              |           |                         
              -------------                   ||              -------------                         
              |           | stack[6799]       ||              |           | stack[6799]             
              ------------- &(stack[6799])    ||     esp   -> ------------- &(stack[6799])          
              |           | stack[6800]       ||              | ebp: T1_XX| stack[6800]             
     esp   -> ------------- &(stack[6800])    ||              ------------- &(stack[6800])          
              |           |                   ||              |           |                         
                    .                         ||                    .                           
     ebp   ->       .       T1_XX             ||     ebp   ->       .       T1_XX  
                    .                         ||                    .               
              -------------                   ||              -------------                     
              |           |                   ||              |           |                  
              -------------                   ||              ------------- &(stack[8190])      
              |           | stack[8191]       ||              |           | stack[8191]             
              ------------- &(stack[8191])    ||              ------------- &(stack[8191])          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
//movl %esp, %0
//  = movl %esp, prev ->thread.sp
//  = movl %esp, t[1].thread.sp
//            Before                                          After                         
//            EIP:                                            EIP:                 
//            ESP:  t1: &stack[6799]                          ESP:  t1: &stack[6799]  
//            EBP:  T1_XX                                     EBP:  T1_XX             
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 1   0    my_process t1: &stack[8191]      prev: 1   0    my_process t1: &stack[6799]
//            next: 0   0    line:64    t0: &stack[6799]      next: 0   0    line:64    t0: &stack[6799]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
//movl %2, %esp
//  = movl next ->thread.sp, %esp
//  = movl t[0].thread.sp, %esp
//            Before                                          After                         
//            EIP:                                            EIP:                 
//            ESP:  t1: &stack[6799]                          ESP:  t0: &stack[6799]  
//            EBP:  T1_XX                                     EBP:  T1_XX             
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 1   0    my_process t1: &stack[6799]      prev: 1   0    my_process t1: &stack[6799]
//            next: 0   0    line:64    t0: &stack[6799]      next: 0   0    line:64    t0: &stack[6799]
              Task[1].STACK                   ||              Task[1].STACK                             Task[0].STACK                   
              |           | stack[0]          ||              |           | stack[0]                    |           | stack[0]                
              ------------- &stack[0]         ||              ------------- &stack[0]                   ------------- &stack[0]               
              |           |                   ||              |           |                             |           |                         
              |           |                   ||              |           |                             |           |                         
              |           |                   ||              |           |                             |           |                         
              -------------                   ||              -------------                             -------------                         
              |           | stack[6799]       ||              |           | stack[6799]                 |           | stack[6799]             
     esp   -> ------------- &(stack[6799])    ||              ------------- &(stack[6799])     esp   -> ------------- &(stack[6799])          
              | ebp: T1_XX| stack[6800]       ||              | ebp: T1_XX| stack[6800]                 | ebp: T0_XX| stack[6800]             
              ------------- &(stack[6800])    ||              ------------- &(stack[6800])              ------------- &(stack[6800])          
              |           |                   ||              |           |                             |           |                         
                    .                         ||                    .                                         .                           
     ebp   ->       .       T1_XX             ||     ebp   ->       .       T1_XX                             .       T0_XX          
                    .                         ||                    .                                         .                      
              -------------                   ||              -------------                             -------------          
              |           |                   ||              |           |                             |           | stack[8191]   
              ------------- &(stack[8190])    ||              ------------- &(stack[8190])              ------------- &(stack[8191])   
              |           | stack[8191]       ||              |           | stack[8191]                 |           | stack[8191]       
              ------------- &(stack[8191])    ||              ------------- &(stack[8191])              ------------- &(stack[8191])    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
//movl $1f, %1
//  = movl $1f, prev ->thread.ip, 其中,$1f指向了line: 64的代码地址
//  = movl $1f, t[1].thread.ip
//
//            Before                                          After                         
//            EIP:                                            EIP:       
//            ESP:  t1: &stack[6799]                          ESP:  t0: &stack[6799]  
//            EBP:  T1_XX                                     EBP:  T1_XX             
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 1   0    my_process t1: &stack[6799]      prev: 1   0    line:64    t1: &stack[6799]
//            next: 0   0    line:64    t0: &stack[6799]      next: 0   0    line:64    t0: &stack[6799]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
//pushl %3
//  = pushl next ->thread.ip
//  = pushl t[0].thread.ip
//            Before                                          After                         
//            EIP:                                            EIP:       
//            ESP:  t0: &stack[6799]                          ESP:  t0: &stack[6798]  
//            EBP:  T1_XX                                     EBP:  T1_XX             
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 1   0    line:64    t1: &stack[6799]      prev: 1   0    line:64    t1: &stack[6799]
//            next: 0   0    line:64    t0: &stack[6799]      next: 0   0    line:64    t0: &stack[6799]
             Task[0].STACK                    ||              Task[0].STACK               
             |           | stack[0]           ||              |           | stack[0]           
             ------------- &stack[0]          ||              ------------- &stack[0]          
             |           |                    ||              |           |                    
             |           |                    ||              |           |                    
             |           |                    ||              |           |                    
             -------------                    ||     esp   -> -------------                    
             |           | stack[6799]        ||              | line:64   | stack[6799]        
    esp   -> ------------- &(stack[6799])     ||              ------------- &(stack[6799])     
             | ebp: T0_XX| stack[6800]        ||              | ebp: T0_XX| stack[6800]        
             ------------- &(stack[6800])     ||              ------------- &(stack[6800])     
             |           |                    ||              |           |                    
                   .                          ||                    .                      
                   .       T0_XX              ||                    .       T0_XX          
                   .                          ||                    .                      
             -------------                    ||              -------------                
             |           | stack[8191]        ||              |           | stack[8191]    
             ------------- &(stack[8191])     ||              ------------- &(stack[8191]) 
             |           | stack[8191]        ||              |           | stack[8191]    
             ------------- &(stack[8191])     ||              ------------- &(stack[8191]) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
//ret     
//
//            After                                           After                         
//            EIP:                                            EIP:  line:64
//            ESP:  t0: &stack[6798]                          ESP:  t0: &stack[6799]  
//            EBP:  T1_XX                                     EBP:  T1_XX             
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 1   0    line:64    t1: &stack[6799]      prev: 1   0    line:64    t1: &stack[6799]
//            next: 0   0    line:64    t0: &stack[6799]      next: 0   0    line:64    t0: &stack[6799]
             Task[0].STACK                    ||              Task[0].STACK                      
             |           | stack[0]           ||              |           | stack[0]           
             ------------- &stack[0]          ||              ------------- &stack[0]          
             |           |                    ||              |           |                    
             |           |                    ||              |           |                    
             |           |                    ||              |           |                    
    esp   -> -------------                    ||              -------------                    
             | line:64   | stack[6799]        ||              |           | stack[6799]        
             ------------- &(stack[6799])     ||     esp   -> ------------- &(stack[6799])     
             | ebp: T0_XX| stack[6800]        ||              | ebp: T0_XX| stack[6800]        
             ------------- &(stack[6800])     ||              ------------- &(stack[6800])     
             |           |                    ||              |           |                    
                   .                          ||                    .                          
                   .       T0_XX              ||                    .       T0_XX              
                   .                          ||                    .                          
             -------------                    ||              -------------                    
             |           | stack[8191]        ||              |           | stack[8191]        
             ------------- &(stack[8191])     ||              ------------- &(stack[8191])     
             |           | stack[8191]        ||              |           | stack[8191]        
             ------------- &(stack[8191])     ||              ------------- &(stack[8191])     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

此时从 line:64 行开始执行

//popl %ebp
//      此时 ebp 指向t1的stack 空间
//            Before                                          After                       
//            ESP:  t0: &stack[6799]                          ESP:  t0: &stack[6800]  
//            EBP:  T1_XX                                     EBP:  T0_XX             
//            EIP:                                            EIP:           
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  1   0
//            prev: 1   0    line:64    t1: &stack[8190]      prev: 1   0    line:64    t1: &stack[8190]
//            next: 0   0    line:64    t0: &stack[6799]      next: 0   0    line:64    t0: &stack[6799]
              Task[0].STACK                   ||              Task[0].STACK                               
              |           | stack[0]          ||              |           | stack[0]                    
              ------------- &stack[0]         ||              ------------- &stack[0]                   
              |           |                   ||              |           |                             
              |           |                   ||              |           |                             
              |           |                   ||              |           |                             
              -------------                   ||              -------------                             
              |           | stack[6799]       ||              |           | stack[6799]                 
     esp   -> ------------- &(stack[6799])    ||              ------------- &(stack[6799])              
              | ebp: T0_XX| stack[6800]       ||              |           | stack[6800]                 
              ------------- &(stack[6800])    ||     esp   -> ------------- &(stack[6800])              
              |           |                   ||              |           |                             
                    .                         ||                    .                                   
                    .       T0_XX             ||     ebp   ->       .       T0_XX                       
                    .                         ||                    .                                   
              -------------                   ||              -------------                             
              |           | stack[8191]       ||              |           | stack[8191]                 
              ------------- &(stack[8191])    ||              ------------- &(stack[8191])              
              |           | stack[8191]       ||              |           | stack[8191]                 
              ------------- &(stack[8191])    ||              ------------- &(stack[8191])              
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
//执行赋值语句
//            Before                                          After                       
//            EIP:                                            EIP:           
//            ESP:  t0: &stack[6800]                          ESP:  t0: &stack[6800]  
//            EBP:  T0_XX                                     EBP:  T0_XX             
//                  pid state   ip      sp                          pid state   ip      sp       
//            cur:  1   0                                     cur:  0   0
//            prev: 1   0    line:64    t1: &stack[8190]      prev: 1   0    line:64    t1: &stack[8190]
//            next: 0   0    line:64    t0: &stack[6799]      next: 0   0    line:64    t0: &stack[6799]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

继续执行,打印>>>switch 1 to 0<<<  退出 my_schedule  打印 this is process 0 +

循环,再次调用 my_process  当 i 累加 10000000 时  打印 this is process 0 -  等待 时钟中断处理函数将 my_need_sched 设置为1  调用 my_schedule

  • 总结
    • 内核任务所运行的堆栈,是由我们通过汇编语句自行维护的,与函数调用自动生成的堆栈有些不同:通过汇编指令使 esp/ebp运行在我们所管理的堆栈上;
    • 任务的切换,本质是在我们所创建的stack 上进行 esp、ebp 的切换;
    • 任务切换的本质:保存上一个任务的 ebp/esp/eip,并将这三个寄存器切换至自己任务的 stack。
    • 样例代码中使用 stack 缓存 ebp,而使用变量保存 esp/eip:主要在于任务切换时,可以通过task 指针直接完成,再进一步 popl 来获得 ebp。我认为ebp 通过变量保存也是可以的。
    • 感觉汇编部分的实现并不唯一,应该存在其他的方案
  • 疑问
    • mymain.c中汇编部分,ret 之后接了 popl,这样 popl 指令还能执行么?虽然感觉对任务的执行并没有太大影响……

本文永久更新链接:http://embeddedlinux.org.cn/emb-linux/kernel-driver/201703/10-6253.html



分享:

评论