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

操作系统的秘密

(一)计算机的三大法宝

  • 存储程序计算机;
  • 函数调用堆栈机制;
  • 中断机制。

(二)堆栈

(1)堆栈的作用

  • 记录函数调用框架;
  • 传递函数参数;
  • 保存返回值的地址;
  • 提供局部变量存储空间。

(2)堆栈操作

1804156-20190929170002230-1377498696.png

  • push:栈顶地址减少4个字节,然后将操作数亚茹栈顶存储单元;
  • pop:栈顶地址增加4个字节,然后将栈顶存储的内容放回原寄存器。

(3)相关寄存器

  • ESP:堆栈指针(stack pointer),用于指向栈顶。
  • EBP:基址指针(base pointer),用于记录当前函数调用的基址。
  • EAX:累加寄存器(Extended accumulator register),用于存储返回值。
  • CS:EIP:用于指向下一条指令地址,它的实用有几种不同情形:
    顺序执行:总是指向地址连续的下一条指令;
    跳转/分支:执行这样的指令时,CS:EIP的值会根据程序需要被修改;
    call:将当前存储的值压入栈顶,然后指向被调用函数的入口地址;
    ret:原来保存的值从栈顶弹出,回到CS:EIP中。
  • 现在谈一下个人对调用函数框架的理解
    调用者用call指令来实现函数调用,接下来生成一个新的堆栈给被调用者使用,
    这个过程涵盖两步——建立堆栈框架和清空堆栈拆除框架,它们由enter和leave
    两个指令实现。
    1804156-20190929175405136-583745805.png

(三)中断

没有中断机制之前,计算机只能一个个地执行程序(批处理),而无法实现并发工作。
现在写一个时间片轮转调度的操作系统内核(使用到函数调用堆栈和内嵌汇编):
(1)使用实验楼的虚拟机打开shell,启动内核

1804156-20190929183026950-1701406670.png

(2)运行效果如下

1804156-20190929183306534-1830860876.png

(3)查看mymain.c和myinterrupt.c

1804156-20190929183501418-2066514434.png
1804156-20190929183526453-1952557289.png
1804156-20190929183540639-1533781522.png

(4)代码分析
  • mymain.c
tPCB task[MAX_TASK_NUM];   /*数组*/
tPCB * my_current_task = NULL;
volatile int my_need_sched = 0;
void my_process(void);
void __init my_start_kernel(void)  /*初始化进程*/
{
    int pid = 0;
    int i;
    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];/*ESP指向栈顶*/
    task[pid].next = &task[pid];
    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];
    }
    pid = 0;
    my_current_task = &task[pid];
    asm volatile(
        "movl %1,%%esp\n\t"   
        "pushl %1\n\t"     /*EBP入栈*/
        "pushl %0\n\t"     /*task[pid].thread.ip入栈*/
        "ret\n\t"               
        "popl %%ebp\n\t"   /*EBP出栈*/
        : 
        : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)   
    );
}   
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);  
           /*循环10000000次之后判断是否需要调度*/
            if(my_need_sched == 1)
            {
                my_need_sched = 0;
                my_schedule();
            }
            printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);
        }     
    }
}

总结

当一个中断信号发生时,CPU把当前正在执行的EIP寄存器压栈,后把EIP指向中断程序入口保护
现场。等结束后在恢复现场,恢复EIP寄存器,继续执行下一条指令,这使多个程序能够实现并发
工作。套用到实验中就是进程的切换,进程在执行的过程中,当时间片用完需要进行进程切换时,
需要先保存当前的今晨执行的上下文环境,下次进程被调度时,需要恢复进程,以此实现多道程
序的并发执行。

转载于:https://www.cnblogs.com/20199305yizihan/p/11608531.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值