您的位置:首页 > 运维架构 > Linux

网易公开课《Linux内核分析》学习心得-mykernel实验的实践和分析

2016-03-03 00:56 537 查看

网易公开课《Linux内核分析》学习心得-mykernel实验的实践和分析

杨怡泽 原创作品转载请注明出处《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

实验

根据实验要求在实验楼中进行实验,输入命令

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


得到如下结果:



现在程序中只有一个进程不断运行,但是依然可以分析出进程的启动机制。让我们观察一下mymain.c和myinterrupt.c两个文件中的核心代码。

在mymain.c中:

void __init my_start_kernel(void)
{
int i = 0;
while(1)
{
i++;
if(i%100000 == 0)
printk(KERN_NOTICE "my_start_kernel here  %d \n",i);

}
}


这段代码是操作系统的入口,从这里开始操作系统开始执行。

myinterrupt.c中,这段代码是用来处理时钟中断的,时钟中断是由linux内核完成,这段代码的主要功能就是将时钟中断进行处理:

void my_timer_handler(void)
{
printk(KERN_NOTICE "\n>>>>>>>>>>>>>>>>>my_timer_handler here<<<<<<<<<<<<<<<<<<\n\n");
}


现在我们需要在这个的基础上构建一个简单的操作系统。在mykernel文件夹中写入mypcb.h,其主要代码如下:

typedef struct PCB{
int pid; // 表示进程的状态
volatile long state;
char stack[KERNEL_STACK_SIZE];// 表示内核的堆栈
/* CPU-specific state of this task */
struct Thread thread;
unsigned long   task_entry;// 操作系统的程序入口
struct PCB *next;//进程链表
unsigned long priority;
}tPCB;




修改mymain.c:

tPCB task[MAX_TASK_NUM]; //task数组
tPCB * my_current_task = NULL; //声明当前task指针
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;  //当前进程为0号进程
task[pid].pid = pid;
task[pid].state = 0; //状态为正在运行
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 其他进程 */
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);
}
task[MAX_TASK_NUM-1].next=&task[0];
printk(KERN_NOTICE "\n\n\n\n\n\n                system begin :>>>process 0 running!!!<<<\n\n");
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)
); //汇编代码启动0号进程,内核初始化完成
}


这段代码主要是为了启动进程,在asm volatile中初始化完成内核启动0号进程。

修改myinterrupt.c用来启动其他进程和切换进程。如果下一个进程已经执行,则切换进程通过如下代码:

asm volatile(
"pushl %%ebp\n\t" /* 保存 ebp */
"movl %%esp,%0\n\t" /* 移动esp到prev->thread.sp处 */
"movl %2,%%esp\n\t" /* 恢复esp */
"movl $1f,%1\n\t" /* 保存 eip */
"pushl %3\n\t" /*调用下一个进程 */
"ret\n\t" /* 恢复 eip */
"1:\t" /* 下一进程开始执行 */
"popl %%ebp\n\t"
: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
: "m" (next->thread.sp),"m" (next->thread.ip)
);


如果下一进程尚未执行,则需要先启动类似进程:

asm volatile(
"pushl %%ebp\n\t"
"movl %%esp,%0\n\t"
"movl %2,%%esp\n\t"
"movl %2,%%ebp\n\t"
"movl $1f,%1\n\t"
"pushl %3\n\t" //保存当前进程的入口
"ret\n\t"
: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
: "m" (next->thread.sp),"m" (next->thread.ip)
);


总结

操作系统的内核通过管理不同进程之间的运行,停止,切换和断点等来实现计算机的运转。当操作系统在运行进程的时候通过实现不同进程之间的切换,来保证每个进程都能顺利进行。当设备满足了读请求时,有一个中断就会通知内核,从而恢复以前的进程继续执行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: