orange's学习--第六章:a第一个进程

kernel.asm操作系统内核程序调用start.c、protect.c、i8259.c设置好GDT、IDT、为了转入第一个进程,

调用main.c设置好LDT和进程表堆栈内容,执行restart();转入第一个进程。

其实很简单,在执行ret命令之前,只要把堆栈按照第三章说明的准备好eip、cs、esp、ss,

就可以跳转到指定的位置。进程表就是按照栈的结构定义的,把esp指向进程表地址就会把进程表变成栈。

准备tss应该是为了后续发生时钟中断准备的。

 

进程表结构如下:

typedef struct s_stackframe {
    u32    gs;        /* \                                    */
    u32    fs;        /* |                                    */
    u32    es;        /* |                                    */
    u32    ds;        /* |                                    */
    u32    edi;        /* |                                    */
    u32    esi;        /* | pushed by save()                   */
    u32    ebp;        /* |                                    */
    u32    kernel_esp;    /* <- 'popad' will ignore it            */
    u32    ebx;        /* |                                    */
    u32    edx;        /* |                                    */
    u32    ecx;        /* |                                    */
    u32    eax;        /* /                                    */
    u32    retaddr;    /* return addr for kernel.asm::save()   */
    u32    eip;        /* \                                    */
    u32    cs;        /* |                                    */
    u32    eflags;        /* | pushed by CPU during interrupt     */
    u32    esp;        /* |                                    */
    u32    ss;        /* /                                    */
}STACK_FRAME;


typedef struct s_proc {
    STACK_FRAME regs;          /* process registers saved in stack frame */

    u16 ldt_sel;               /* gdt selector giving ldt base and limit */
    DESCRIPTOR ldts[LDT_SIZE]; /* local descriptors for code and data */
    u32 pid;                   /* process id passed in from MM */
    char p_name[16];           /* name of the process */
}PROCESS;

; ====================================================================================
;                                   restart
; ====================================================================================
restart:
    mov    esp, [p_proc_ready]
    lldt    [esp + P_LDT_SEL] 
    lea    eax, [esp + P_STACKTOP]            
    mov    dword [tss + TSS3_S_SP0], eax 

;把本进程表的堆栈最高地址赋值给0级TSS的esp,本进程执行过程中如果发生中断,就会跳到0级堆栈位置,

内核程序在压栈的时候就会覆盖本进程的进程表内容,达到了保存本进程随时状态的功能。

    pop    gs
    pop    fs
    pop    es
    pop    ds
    popad

    add    esp, 4

    iretd

我们分析过,当进程被中断切到内核态,当前的各个寄存器应该被立即保存 (压栈)。也就是说,每个进程在运行时, tss.esp0应该是当前进程的进程表中保存寄存器值的地方,即struct  s_proc中struct  s_stackframe的最高地址处。这样,进程被挂起后才恰好保存寄存器到正确的位置。我们假设进程A在运行,那么tss.esp0的值应该是进程表A中regs的最高处,因为我们是不可能在进程A运行时来设置tss.esp0的值的,所以必须在A被恢复运行之前,即iretd执行之前做这件事。换句话说,我们应该在时钟中断处理结束之前做这件事。 
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值