How the Linux kernel analyzes how the operating system works
20122137 Sha Yu Ji
Original works reproduced please indicate the source
Linux kernel Analysis MOOC course http://mooc.study.163.com/course/USTC-1000029000
1. Content Description
The inline assembly syntax is as follows:
The specific code is as follows:
(1) Mypcb.h header file
/*
* 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;
unsigned long SP;
};
typedef struct pcb{
int pid;
volatile long state; /* -1unrunnable, 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);
(2) 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"
Tpcbtask[max_task_num];
TPCB *my_current_task = NULL;
volatile intmy_need_sched = 0;
Voidmy_process (void);
void __initmy_start_kernel (void)
{
int pid = 0;
int i;
/* Initialize Process 0*/
Task[pid].pid = pid;
Task[pid].state = 0;/*-1 unrunnable, 0runnable, >0 stopped * *
Task[pid].task_entry = task[pid].thread.ip= (unsigned long) my_process;
TASK[PID].THREAD.SP = (unsignedlong) &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 = (unsignedlong) &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"/* SETTASK[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*/
);
}
Voidmy_process (void)
{
int i = 0;
while (1)
{
i++;
if (i%10000000 = = 0)
{
PRINTK (kern_notice "This isprocess%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);
}
}
}
(3) 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 currentrunning process,
* So it use kernel stack ofcurrent 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)/* -1unrunnable, 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;
}
2. Code Analysis
Here I only do the key analysis, such as the more difficult to understand the process of initialization, switching a few pieces of assembly code.
Initialization environment settings for the first process:
ASM volatile (
"Movl%1,%%esp\n\t"/* The stack value of the process is stored in the system stack */
"PUSHL%1\n\t"/* Put the current EBP register value in the stack */
"PUSHL%0\n\t"/* Put the current process's EIP into the stack */
The "ret\n\t"/*ret command just lets the process EIP in the stack be saved in the EIP register */
"Popl%%ebp\n\t"
:
: "C" (Task[pid].thread.ip), "D" (TASK[PID].THREAD.SP)
);
Process Dispatch Code:
if (next->state = = 0)/*next->state = = 0 corresponding process the next corresponding process has been executed */
{//row process dispatch key code
ASM volatile (
"Pushl%%ebp\n\t"/* Save the current EBP to the stack */
"Movl%%esp,%0\n\t"/* Save the current process stack pointer to the current process TCB */
"Movl%2,%%esp\n\t"/* Saves the ESP value of the next process to the ESP register */
"Movl $1f,%1\n\t"/* Saves the EIP value of the current process and will be executed at 1 after the next recovery process */
"PUSHL%3\n\t"/* Save the new EIP in the stack */
"Ret\n\t"/* Save EIP to EIP Register */
"1:\t"/* Next Process Execution Location */
"Popl%%ebp\n\t"/* Restore the value of 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<<<\n", prev->pid,next->pid);
}
else/* Indicates that next the process is executed for the first time */
{
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 current process EBP */
"Movl%%esp,%0\n\t"/* Save current process ESP */
"Movl%2,%%esp\n\t"/* Reload esp*/
"Movl%2,%%ebp\n\t"/* Reload EBP */
"Movl$1f,%1\n\t"/* Save current EIP Register value */
"Pushl%3\n\t"/* Put the EIP of the upcoming process into the stack */
"Ret\n\t"/* Reload eip*/
: "=m" (PREV->THREAD.SP), "=m" (PREV->THREAD.IP)
: "M" (NEXT->THREAD.SP), "M" (NEXT->THREAD.IP)
);
}
3. Test
4. Summary
This trial experiment requires the implementation of multi-channel process, the focus is on the process of switching, process execution, when the time slices need to process switching, the current process execution environment needs to be saved, the next time the process is scheduled, the process needs to restore the execution environment.
How the Linux kernel analyzes how the operating system works