2019-2020-1 20199315 "Linux kernel principle and Analysis" in the third week of work

The second chapter, "Paodingjieniu Linux kernel analysis"

  • Function call stack
    • Stack calling path and the parameter storage recording function space C language program runs must be used, a stack of specific acts: recording function call frame, transfer function parameters, save the address of the return value, provide storage function of the internal local variables, etc. .
    • Stack relevant register
      • ESP: Stack Pointer
      • EBP: base pointer, used as the recording current in the C language function calls matrix.
      • Stack space is increasing from high address to the low address.
    • Stack operations
      • push: Address reduce stack 4 bytes (32 bits), and the operand stack into a storage unit.
      • pop: stack address increase of 4 bytes (32 bits), and the top of stack operand into memory cells.
    • Other key register
      • CS: EIP always point to the address of the next instruction
    • Procedures used to hold the return value of the EAX register. If there are multiple return values, EAX register returns a memory address.
    • Local variables in the body through the stack to store.
  • Inline assembly

asm volatile(                       /*__asm__是GCC关键字asm的宏定义,是内嵌汇编的关键字,表示这是一条内嵌汇编语句。__volatile__的宏定义,告诉编译器不要优化代码,汇编指令保留原样。*/
"movl $0,%%eax\n\t"          /* clear %eax to 0。将EAX清0 */
"addl %1,%%eax\n\t"          /* %eax+=val1。%1指下面的输出和输入的部分,此处是指val1,该句意为把val1的值放到ECX里面,然后把ECX的值与EAX寄存器求和放入EAX寄存器中。 */
"addl %2,%%eax\n\t"          /* %eax+=val2。该句意为把val2的值放到ECX里面,然后把ECX的值与EAX寄存器(val1的值)求和放入EAX寄存器中。*/
"movl %%eax,%0\n\t"         /* val2=%eax。把val1加上val2的值存储的地方放到%0,即val3。 */
: "=m" (val3)                        /* =m意思是写到内存变量里面去 */
: "c" (val1),"d" (val2)            /* c指用ECX寄存器存储val1的值 */
);
  • Clock interrupt
    • When an interrupt occurs, CPU to CS program currently being executed: EIP register and ESP registers and so on down to a place called the kernel stack, then the CS: EIP points to an entry handler interrupt, do save site work, after the execution of other programs, such as when to come back again to restore the site to restore CS: EIP register and ESP registers, etc., continue to implement the program.

The second experiment laboratory building

Download linux-3.9.4.tar.xz, and build virtual x86CPU experimental platform.


$ sudo apt-get install qemu # install QEMU
$ sudo ln -s /usr/bin/qemu-system-i386 /usr/bin/qemu
$ wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.9.4.tar.xz # download Linux Kernel 3.9.4 source code
$ wget https://raw.github.com/mengning/mykernel/master/mykernel_for_linux3.9.4sc.patch # download mykernel_for_linux3.9.4sc.patch
$ xz -d linux-3.9.4.tar.xz
$ tar -xvf linux-3.9.4.tar
# 注意路径是区分大小的
$ cd ~/LinuxKernel/linux-3.9.4
$ rm -rf mykernel
$ patch -p1 < ../mykernel_for_linux3.9.4sc.patch
$ make allnoconfig
# 编译内核请耐心等待
$ make
$ qemu -kernel arch/x86/boot/bzImage

In Linux-3.9.4 kernel source root directory cd into mykernel, and can see the code mymain.c myinterrupt.c content QEMU output window.

myinterrupt.c and mymain.c codes are as follows.

mykernel/mypcb.h:

   
/*
 *  linux/mykernel/mypcb.h
 *
 *  Kernel internal PCB types
 *
 *  Copyright (C) 2013  Mengning
 *
 */

#define MAX_TASK_NUM        4
#define KERNEL_STACK_SIZE   1024*2 # unsigned long
/* 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 */
    unsigned long 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);

mykernel/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].stack[KERNEL_STACK_SIZE-1] - 1) = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-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 */
        : 
        : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)   /* input c or d mean %ecx/%edx*/
    );
} 

int i = 0;

void my_process(void)
{    
    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);
        }     
    }
}

mykernel/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 */
    {        
        my_current_task = next; 
        printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);  
        /* 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)
        ); 
    }  
    return; 
}

Guess you like

Origin www.cnblogs.com/qianxiaoxu/p/11597458.html