2019-2020-1 20199326《Linux内核原理与分析》第三周作业

第三周学习内容

庖丁解牛Linux内核分析第二章:操作系统是如何工作的
Linux内核分析实验二

学到的一些知识

  • 计算机的三大法宝:存储程序计算机,函数调用堆栈,中断

  • 堆栈是C语言程序运行时必须使用的记录函数调用路径和参数存储的空间,堆栈具体的作用有:记录函数调用框架,传递函数参数,保存返回值的地址,提供函数内部局部变量的存储空间等

  • 与堆栈相关的寄存器:ESP,EBP

  • 堆栈操作:push,pop

  • CS:EIP总是指向下一条的指令地址

    • 顺序执行:总是指向地址连续的下一条指令
    • 跳转/分支:执行这样的指令时,CS:EIP的值会根据程序需要被修改
    • call:将当前的CS:EIP的值压入栈顶,CS:EIP指向被调用函数的入口地址
    • ret:从栈顶弹出原来保存在这里的CS:EIP的值,放入CS:EIP中
  • 如果两个机器的处理器指令集不同,汇编出来的汇编代码也会有所不同

实验内容

1.虚拟一个x86的CPU硬件平台

在实验楼的环境中打开shell,输入两行代码即可启动内核:

$ cd ~/LinuxKernel/linux-3.9.4
$ qemu -kernel arch/x86/boot/bzImage

内核启动后如图:

进入mykernel查看mymain.c和myinterrupt.c,如图所示:

2.在mykernel基础上构造一个简单地操作系统内核

增加一个mypcb.h的头文件

define MAX_TASK_NUM 10 // 最大进程数

define KERNEL_STACK_SIZE 1024*8

define PRIORITY_MAX 30 //从0到30的优先级

/* CPU-specific state of this task /
struct Thread {
unsigned long ip;//point to cpu run address
unsigned long sp;//point to the thread stack's top address
//todo add other attrubte of system thread
};
//PCB Struct
typedef struct PCB{
int pid; // pcb id
volatile long state; /
-1 不运行, 0 运行, >0 停止 /
char stack[KERNEL_STACK_SIZE];// each pcb stack size is 1024
8
/* CPU-specific state of this task */
struct Thread thread;
unsigned long task_entry;//the task execute entry memory address
struct PCB *next;//pcb is a circular linked list
unsigned long priority;// task priority ////////
//todo add other attrubte of process control block
}tPCB;

//void my_schedule(int pid);
void my_schedule(void);

修改mymain.c

ifdef CONFIG_X86_LOCAL_APIC

include <asm/smp.h>

endif

include "mypcb.h"

tPCB task[MAX_TASK_NUM];
tPCB * my_current_task = NULL;
volatile int my_need_sched = 0;

void my_process(void);
unsigned long get_rand(int );

void sand_priority(void)
{
int i;
for(i=0;i<MAX_TASK_NUM;i++)
task[i].priority=get_rand(PRIORITY_MAX);
}
void __init my_start_kernel(void)
{
int pid = 0;
/* Initialize process 0/
task[pid].pid = pid;
task[pid].state = 0;/
-1 unrunnable, 0 runnable, >0 stopped /
// set task 0 execute entry address to my_process
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(pid=1;pid<MAX_TASK_NUM;pid++)
{
memcpy(&task[pid],&task[0],sizeof(tPCB));
task[pid].pid = pid;
task[pid].state = -1;
task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
task[pid].priority=get_rand(PRIORITY_MAX);//each time all tasks get a random priority
}
task[MAX_TASK_NUM-1].next=&task[0];
printk(KERN_NOTICE "\n\n\n\n\n\nsystem begin :>>>process 0 running!!!<<<\n\n");
/
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*/
);
}
void my_process(void)
{
int i = 0;
while(1)
{
i++;
if(i%10000000 == 0)
{

if(my_need_sched == 1)
{
my_need_sched = 0;
sand_priority();
my_schedule();

}
}
}
}//end of my_process

//produce a random priority to a task
unsigned long get_rand(max)
{
unsigned long a;
unsigned long umax;
umax=(unsigned long)max;
get_random_bytes(&a, sizeof(unsigned long ));
a=(a+umax)%umax;
return a;
}

修改myinterrupt.c

include "mypcb.h"

define CREATE_TRACE_POINTS

include <trace/events/timer.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
// make sure need schedule after system circle 2000 times.
if(time_count%2000 == 0 && my_need_sched != 1)
{
my_need_sched = 1;
//time_count=0;
}
time_count ++ ;
#endif
return;
}

void all_task_print(void);

tPCB * get_next(void)
{
int pid,i;
tPCB * point=NULL;
tPCB * hig_pri=NULL;//points to the the hightest task
all_task_print();
hig_pri=my_current_task;
for(i=0;i<MAX_TASK_NUM;i++)
if(task[i].priority<hig_pri->priority)
hig_pri=&task[i];
printk("higst process is:%d priority is:%d\n",hig_pri->pid,hig_pri->priority);
return hig_pri;

}//end of priority_schedule

void my_schedule(void)
{
tPCB * next;
tPCB * prev;
// if there no task running or only a task ,it shouldn't need schedule
if(my_current_task == NULL
|| my_current_task->next == NULL)
{
printk(KERN_NOTICE "time out!!!,but no more than 2 task,need not schedule\n");
return;
}
/* schedule */

next = get_next();
prev = my_current_task;
printk(KERN_NOTICE "the next task is %d priority is %u\n",next->pid,next->priority);
if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped /
{//save current scene
/
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;//switch to the next task
printk(KERN_NOTICE "switch from %d process to %d process\n>>>process %d running!!!<<<\n\n",prev->pid,next->pid,next->pid);

}
else
{
next->state = 0;
my_current_task = next;
printk(KERN_NOTICE "switch from %d process to %d process\n>>>process %d running!!!<<<\n\n\n",prev->pid,next->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;
}//end of my_schedule

void all_task_print(void)
{
int i,cnum=62;//
printk(KERN_NOTICE "\ncurrent task is:%d all task in OS are:\n",my_current_task->pid);

printk("");
for(i=0;i<cnum;i++)
printk("-");
printk("\n| process:");
for(i=0;i< MAX_TASK_NUM;i++)
printk("| %2d ",i);
printk("|\n| priority:");
for(i=0;i<MAX_TASK_NUM;i++)
printk("| %2d ",task[i].priority);

printk("|\n");
for(i=0;i<cnum;i++)
printk("-");
printk("\n");
}

重新编译,输入以下代码:

$ cd ~/LinuxKernel/linux-3.9.4
$ make
$ qemu -kernel arch/x86/boot/bzImage

结果如图所示

posted @ 2019-09-29 16:18  不摸鱼  阅读(176)  评论(0)    收藏  举报