Linux Kernel section II

Source: Internet
Author: User
Tags prev volatile

Wusi

Deep understanding of the function call stack

A stack is a space that the C language program must run with a record call path and parameters

The role of the stack

    • Function call Framework
    • Passing parameters
    • Save return address
    • Provides local variable space

Stack-related registers

    • ESP, stack pointer, pointing to the top of the stack
    • EBP, base point pointer, to the bottom of the stack, used in C to record the current function call base.

Other key registers

CS (Code Snippet Register): EIP: Always point to the next instruction address

    • Sequential execution: Always points to the next instruction in consecutive addresses
    • Jump/Branch: When executing such an instruction, the value of CS:EIP will be modified according to the program needs

Parameter passing and local variables

    • Establish framework (equivalent to call command)
    • Push%EBP

MOVL%ESP,%EBP

    • Frame removal (equivalent to RET Directive)
    • MOVL%ebp,%esp

Pop%EBP

When the function returns, the frame must be removed, and the build and dismantle are one by one corresponding.

    • Passing parameters

Before the framework of a child function is established, the value of the local variable is saved in the caller's stack frame, so the value of the variable can be put into the stack before the child function framework is established.

The return value of the function is passed through the EAX register

with Linux Kernel part source code simulating storage program computer working model and clock interrupt

Mykernel Experimental Ideas

The interrupt implements multi-channel program design, and then switches back and forth between the execution streams of the program, the CPU pushes the program's EBP into the stack, and points to an interrupt handler, which is implemented by the CPU and kernel code together to save the site and restore the scene.

C How to embed assembly code in code

__asm__ (

Assembly Statement Template:

Input section:

Output section:

Destruction Description section:);

Experiment -- in the Mykernel construct a simple operating system kernel based on the

Experimental process

This experiment is to understand how the operating system works by analyzing a simple time-slice rotation multi-channel program kernel source code.

Run this kernel first, and you can see a context that provides a code to run in the kernel.

Then CD Mykernel find the MYMAIN.C and myinterrupt.c two source code, enter Https://github.com/mengning/mykernel/blob/master can find several important source code that this experiment needs. The above two code is then modified to the code found in the site, in addition to adding mypcb.h.

Return to run again and see 0, 1, 2, and 3 processes switching to each other.

Source Code Analysis

Mypcb.h

The purpose of this code is to define a Process control block (PCB).

/*

* Linux/mykernel/mypcb.h

*

* Kernel Internal PCB types

*

* Copyright (C) mengning

*

*/

#define MAX_TASK_NUM 4

#define Kernel_stack_size 1024*8

/* Cpu-specific State of this task */

struct Thread {

unsigned long ip;//for the preservation of EIP

unsigned long sp;//for ESP saving

};

typedef struct PCB{//is used to represent a process that defines a process-management-related data structure

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);//called My_schedule, which represents the scheduler

Mymain.c

/*

* LINUX/MYKERNEL/MYMAIN.C

*

* Kernel Internal My_start_kernel

*

* Copyright (C) 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;//defines a flag that is used to determine whether a dispatch is required

void my_process (void);

void __init My_start_kernel (void)

{

int PID = 0;//initialization of a process 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;

Defines the entry for process 0 as My_process

TASK[PID].THREAD.SP = (unsigned long) &task[pid].stack[KERNEL_STACK_SIZE-1];

Task[pid].next = &task[pid];

Since there is only process 0 in the system at the beginning, this line of code represents the PID of next or point to itself

/*fork More Process */

Create additional processes that can directly copy code for process No. 0 when initializing these processes

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

Each process has its own stack, putting a new process created into the tail of the process list, which completes the creation

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

);

}

/*%0 indicates that the parameter thread.ip,%1 represents the parameter thread.sp.

MOVL%1,%%esp means to put the parameters thread.sp in the ESP;

Next push% 1, also because the current stack is empty, esp=ebp, so equivalent to the push ebp;

Then push Thread.ip;ret is equivalent to pop thread.ip; last pop EBP */

void my_process (void)//defines the work of all processes, if statements represent loops 10 million times before the opportunity to determine whether a dispatch is required.

{

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) 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 the current running process,

* So it with kernel stack of current running process

*/

void My_timer_handler (void)

/* for setting the size of the time slice, set the dispatch flag when the time slice runs out.

When the clock interrupted 1000 times, and My_need_sched!=1, the my_need_sched was assigned to 1.

My_schedule is executed when the process discovers my_need_sched=1. */

{

#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//task is empty, that is, returns when an error occurs

|| My_current_task->next = = NULL)

{

Return

}

PRINTK (Kern_notice ">>>my_schedule<<<\n");

/* Schedule */

Next = my_current_task->next;//assigns the next process of the current process to next

Prev = my_current_task;//The current process is prev

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

{

/* Switch to Next process */

/* If the status of the next process is executing, use the method represented by the code in the IF statement to toggle the process */

ASM volatile (

"PUSHL%%ebp\n\t"/* Save EBP Saves the ebp*/of the current process

"Movl%%esp,%0\n\t"/* Save ESP Saves the esp*/of the current process

"Movl%2,%%esp\n\t"/* Restore ESP places the SP of the next process in ESP */

"Movl $1f,%1\n\t"/* Save Eip saved 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

/* Unlike the previous code, if the next process is a new process, this piece of code in else is used.

This process is first set to the runtime state, which is used as the currently executing process. */

{

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

}

Linux Kernel section II

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.