The computer has three key mechanisms: the storage program computer, the stack mechanism and the interruption mechanism.
The first chapter focuses on the computer of the storage program. Next we will focus on the stack mechanism and interrupt mechanism.
Stack Mechanism
The stack mechanism is the basic mechanism that can be implemented by advanced languages. It is the space that must be used to record the function call path and Parameter Storage when a C language program is running. Its specific functions include recording the function call framework, pass function parameters, save the return value address, and provide the storage space of local variables in the function.
Stack-related registers include:
1. ESP (Stack pointer register) and EBP (record base address pointer register of the current function call)
2. CS: EIP: always pointing to the next instruction address. During sequential execution, the next command is always directed to the address; During jump/branch execution, the value of CS: EIP will be modified according to the program's needs.
3. eax: Save the returned value. If multiple return values exist, a memory address is returned.
Stack-related operations:
Push: the stack top address is reduced by 4 bytes, And the operands are placed into the top storage unit of the stack.
Pop: Four bytes are added to the top stack address, and the content of the top storage unit of the stack is put into the operand.
Call: press the current Cs: EIP value to the top of the stack, Cs; EIP point to the entry address of the called Function
RET: from the top of the stack, the Cs: EIP value originally saved here is displayed, and the value of CS: EIP is placed.
Enter and leave: encapsulate the establishment and removal of the function call stack framework step by step.
Parameter transfer; stack pressure from left to right
Interrupt mechanism experiment virtual x86 CPU Hardware Platform Construction
This experiment is performed in the lab building environment. The experiment code is as follows:
CD linuxkernel/linux-3.9.4rm-RF mykernelpatch-P1 <../mykernel_for_linux3.9.4sc.patchmake allnoconfigmake # compile the kernel qemu-kernel ARCH/x86/boot/bzimage
After the kernel is set up, the startup effect of the kernel is as follows:
Complete a simple time slice rotation multi-channel program based on mykernel
Add a mypcb. h header file based on CD mykernel.
Mypcb. h
# 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; char stack [kernel_stack_size];/* CPU-specific state of this task */struct thread; unsigned long task_entry; struct PCB * Next;} tpcb; // The PCB struct defines void my_schedule (void );
Modify the mymain. c file as follows:
# 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]; // The PCB array tasktpcb * my_current_task = NULL; // The current task pointer volatile int my_need_sched = 0; // whether to schedule void my_process (void); void _ init my_start_kernel (void) // mykernel kernel code entry {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 other 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]; task [I]. next = task [I-1]. next; task [I-1]. next = & task [I];}/* Start Process 0 with task [0] */PID = 0; my_current_task = & task [pid]; ASM volatile ("movl % 1, % ESP \ n \ t "" pushl % 1 \ n \ t "" pushl % 0 \ n \ t "" RET \ n \ t "" 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) // determine whether scheduling is required {my_need_sched = 0; my_schedule ();} printk (kern_notice "this is process % d + \ n", my_current_task-> PID );}}}
Modify the myinterrupt. c file as follows:
/** 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 ); /* process switching */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 ;}
Check the qemu window after re-make compilation. the following result is displayed:
Problem Encountered
1. Make compilation Error
2. the kernel startup effect remains unchanged after the restart.
Solution
1. modify the code in the mykernel directory
2. With a new set of kernel code changed, the process of switching the code that was initially used was not completed.
Operating System Workflow