Experimental section:
Run Results first
Code Analysis:
Mypcb.h
/*
* 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{
The ID of the int pid;//process is represented by a PID
volatile long state; /*-1 unrunnable, 0 runnable, >0 stopped *//process status, 1 wait, 0 run, >0 stop
Char stack[kernel_stack_size];//Stack
/* Cpu-specific State of this task */
struct thread thread;
unsigned long task_entry;//entrance
The struct PCB *next;//process is linked in the form of a linked list
}TPCB;
void My_schedule (void);
Mymian.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;//Current task pointer
volatile int my_need_sched = 0;//Whether a scheduled identity is required
void my_process (void);
void __init My_start_kernel (void)
{
int pid = 0;
int i;
/* Initialize Process 0*/
Task[pid].pid = pid;//Initialize process # No. 0
Task[pid].state = 0;/*-1 unrunnable, 0 runnable, >0 stopped *///state is running
Task[pid].task_entry = Task[pid].thread.ip = (unsigned long) my_process;//entrance is myprocess
TASK[PID].THREAD.SP = (unsigned long) &task[pid].stack[kernel_stack_size-1];//stack stack top
Task[pid].next = &task[pid];//just started it itself, so next also points to its own
/*fork more process *///create more processes
for (i=1;i<max_task_num;i++)
{
memcpy (&task[i],&task[0],sizeof (TPCB));//Copy the status of Process No. 0 to the next process
Task[i].pid = i;//Initializes the process you just created
Task[i].state =-1;
TASK[I].THREAD.SP = (unsigned long) &task[i].stack[kernel_stack_size-1];//the stack of the new process
Task[i].next = task[i-1].next;//points to the next process
Task[i-1].next = &task[i];//New process placed at the end of the list
}
/* START process 0 by task[0] *///starts execution of number No. 0
PID = 0;
My_current_task = &task[pid];
ASM volatile (//Here is the embedded assembler code
"Movl%1,%%esp\n\t"/* Set TASK[PID].THREAD.SP to ESP *///copy THREAD.SP to ESP
"PUSHL%1\n\t"/* Push EBP *///current stack is empty, esp=ebp, so the pressure stack Sep is the pressure stack ebp
"PUSHL%0\n\t"/* push Task[pid].thread.ip *///IP stack
"Ret\n\t"/* pop task[pid].thread.ip to EIP *///will IP stack, that is, the head of the myprocess, that is, the NO. 0 process officially started
"Popl%%ebp\n\t"//Bomb stack
:
: "C" (Task[pid].thread.ip), "D" (TASK[PID].THREAD.SP)/* input C or D mean%ecx/%edx*///c is%0, that is, Ip;d is%1, which is the SP.
);
}//Kernel initialization complete, process No. 0 starts execution
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)//1 is required for scheduling
{
my_need_sched = 0;
My_schedule ();
}
PRINTK (Kern_notice "This is process%d +\n", my_current_task->pid);
}
}
}
Myinterrupt
/*
* 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)//time slice switching
{
#if 1
if (time_count%1000 = = 0 && my_need_sched! = 1)
{
PRINTK (kern_notice ">>>my_timer_handler here<<<\n");
my_need_sched = 1;//Dispatch
}
Time_count + +;
#endif
Return
}
void My_schedule (void)//
{
TPCB * next;//Next process module
TPCB * prev;//The process module being executed
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 process
{
/* Switch to Next process */
ASM volatile (
"PUSHL%%ebp\n\t"/* Save EBP */
"Movl%%esp,%0\n\t"/* Save ESP *///to Memory prev->thread.sp
"Movl%2,%%esp\n\t"/* Restore ESP *///saved to memory next->thread.sp
"Movl $1f,%1\n\t"/* Save EIP *//Label 1: Position placed in memory Prev->thread.ip
"PUSHL%3\n\t"//Next->thread.ip to memory
"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//switch to a new 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
}
Summary section:
This week's highlights:
- Computer's three magic weapons: stored program computer; function call stack; interrupt mechanism
- Stack
The most primitive computer is not a stack concept, and the high-level language is the only thing that stacks up. A stack is a space for recording paths and parameters.
Function call Framework
Pass-through parameters (only for 32-bit x86)
Save return address
Provides local variable space
3. Stack Register
ESP, stack stack pointer, top pointer
EIP, stack base address pointer, base pointer
4. Stack operations
Push, press stack minus 4 bytes
Pop, Reload plus 4 bytes
5. Other Registers
An EIP, whether sequential, or jump, branches, always points to the next statement that should be executed.
Call, which pushes the value of the current EIP and changes the value of the EIP to the address value of the next instruction in the function entry.
RET, put the value of the EIP stack into the EIP.
6. Creating a function stack frame
Push%EBP
MOVL%ESP,%EBP
Removing the function stack frame
MOVL%ebp.%esp
Pop%EBP
7. Focus on understanding the MYINTERRUPUT.C process switching code. (The switchover process refers to the process executed on the next switch)
In two cases, the first is that the process that is being switched to is a process that has been executed, and the second is the process that the switch to is a new process. First, first, the current process of the EBP stack, and then the current process of the stack-top pointer to the current process PREV->THREAD.SP the list structure, and then the list of switching processes NEXT->THREAD.SP Copy to stack top pointer esp. PREV->THREAD.IP the current process in the list to the value of the entry for the function, and then the NEXT->THREAD.IP of the switch process. Then the second, the first to build the list, and then perform the above process.
Linux and Security second week summary--20135227 Huang