lab4学习

用户态和内核态(也称用户模式和内核模式): 它们是 CPU 运行的两种状态。根据 lab3 的说明,在 MOS 操作系统实验使用的仿真 R3000 CPU 中,该状态由 CP0 SR 寄存器中 KUc 位的值标志。

syscall_* 的函数是我们在用户空间中最接近的内核的也是最原子的函数,而 sys_* 的函数是内核中系统调用的具体实现部分

mysyscall中syscall后epc保存syscall的pc值,然后跳到异常处理程序执行

进程的pgdir的值是内核地址

访问TLB得到物理地址时直接用12-31位的虚拟页号,TLB缺页重填时才利用页目录号和页表号进行访存

进程的env_pgfault_handler是__asm_pgfault_handler

页写入异常流程:handle_mod---->page_fault_handler---->__asm_pgfault_handler---->__pgfault_handler(pgfault)

  • page_fault_handler: tf复制到用户异常栈中,并设置epc为env_pgfault_handler
  • handle_mod中从page_fault_handler返回后在ret_from_exception中跳到__asm_pgfault_handler
  • 上一步中已经从内核态返回用户态,在用户态进行__asm_pgfault_handler页写入异常的处理

fork的sys_env_alloc中子进程的pc被设置为epc(syscall的下一条指令,从mysyscall返回,然后从系统调用返回,返回到fork)

NESTED(except_vec3, 0, sp)
    .set noat
    .set noreorder
1:
    mfc0 k1,CP0_CAUSE
    la k0,exception_handlers
    andi k1,0x7c
    addu k0,k1
    lw k0,(k0)
    nop
    jr k0
    nop
END(except_vec3)
struct Env {
    struct Trapframe env_tf;        // Saved registers
    LIST_ENTRY(Env) env_link;       // Free list
    u_int env_id;                   // Unique environment identifier
    u_int env_parent_id;            // env_id of this env's parent
    u_int env_status;               // Status of the environment
    Pde  *env_pgdir;                // Kernel virtual address of page dir
    u_int env_cr3;
    LIST_ENTRY(Env) env_sched_link;
        u_int env_pri;
    // Lab 4 IPC
    u_int env_ipc_value;            // data value sent to us 
    u_int env_ipc_from;             // envid of the sender  
    u_int env_ipc_recving;          // env is blocked receiving
    u_int env_ipc_dstva;        // va at which to map received page
    u_int env_ipc_perm;     // perm of page mapping received

    // Lab 4 fault handling
    u_int env_pgfault_handler;      // page fault state
    u_int env_xstacktop;            // top of exception stack
struct Trapframe { //lr:need to be modified(reference to linux pt_regs) TODO
    /* Saved main processor registers. */
    unsigned long regs[32];

    /* Saved special registers. */
    unsigned long cp0_status;
    unsigned long hi;
    unsigned long lo;
    unsigned long cp0_badvaddr;
    unsigned long cp0_cause;
    unsigned long cp0_epc;
    unsigned long pc;
};
汇编标志 作用 例子
.align 这条指令允许程序员指定一个大于下一个数据指令通常所需的对齐方式。该对齐方式被指定为2的幂 .align 4
var: .word 0
对齐2^4=16字节边界
.set noat/at 汇编器在执行宏展开时保留注册器$1,以保存中间值;如果代码尝试使用寄存器,将会发送警告或错误消息。当汇编程序使用$at时并不总是明显的,而且在某些情况下,程序员可能需要确保它不使用(例如在保存$1之前的异常处理程序中)。如果汇编程序需要在宏指令中使用$1,那么打开noat将使汇编程序生成一个错误消息,并允许程序员在不收到警告的情况下显式地使用它
汇编 作用
ret_from_exception 使用RESTORE_SOME恢复现场,k0设置为epc的值,恢复sp寄存器,并跳到k0开始执行指令同时rfe
RESTORE_SOME宏 SR寄存器设置为,当前SR的中断掩码加上TF的SR的其他位,同时TF的寄存器恢复到当前现场
env_pop_tf 更新ENTRY_HI,最后跳到pc执行,而不像ret_from_exception跳到epc执行
在时钟中断中,time_irq会跳到sched_yield执行,sched_yield执行env_run,env_run中调用env_pop_tf恢复现场,而不是ret_from_exception
.macro RESTORE_SOME
        .set    mips1
        mfc0    t0,CP0_STATUS #t0是当前SR
        ori t0,0x3
        xori    t0,0x3
        mtc0    t0,CP0_STATUS #关中断
        lw  v0,TF_STATUS(sp) #v0是TF的SR
        li  v1, 0xff00 
        and t0, v1 #与8-15位中断掩码and 1 其他都为0
        nor v1, $0, v1 #除8-15位全为1,8-15位为0
        and v0, v1 #TF的SR 8-15位中断掩码为0
        or  v0, t0 #当前SR的中断掩码加上TF的SR的其他位
        mtc0    v0,CP0_STATUS #TF的SR存到当前的SR寄存器
        lw  v1,TF_LO(sp) #TF的寄存器恢复到当前现场 但没有恢复sp,k0,k1寄存器
        mtlo    v1
        lw  v0,TF_HI(sp)
        lw  v1,TF_EPC(sp)
        mthi    v0
        mtc0    v1,CP0_EPC
        lw  $31,TF_REG31(sp)
        lw  $30,TF_REG30(sp)
        lw  $28,TF_REG28(sp)
        lw  $25,TF_REG25(sp)
        lw  $24,TF_REG24(sp)
        lw  $23,TF_REG23(sp)
        lw  $22,TF_REG22(sp)
        lw  $21,TF_REG21(sp)
        lw  $20,TF_REG20(sp)
        lw  $19,TF_REG19(sp)
        lw  $18,TF_REG18(sp)
        lw  $17,TF_REG17(sp)
        lw  $16,TF_REG16(sp)
        lw  $15,TF_REG15(sp)
        lw  $14,TF_REG14(sp)
        lw  $13,TF_REG13(sp)
        lw  $12,TF_REG12(sp)
        lw  $11,TF_REG11(sp)
        lw  $10,TF_REG10(sp)
        lw  $9,TF_REG9(sp)
        lw  $8,TF_REG8(sp)
        lw  $7,TF_REG7(sp)
        lw  $6,TF_REG6(sp)
        lw  $5,TF_REG5(sp)
        lw  $4,TF_REG4(sp)
        lw  $3,TF_REG3(sp)
        lw  $2,TF_REG2(sp)
        lw  $1,TF_REG1(sp)
.endm
FEXPORT(ret_from_exception)
    .set noat
    .set noreorder
    RESTORE_SOME
    .set at
    lw  k0,TF_EPC(sp)
    lw  sp,TF_REG29(sp) /* Deallocate stack */
//1:    j   1b
    nop
    jr  k0
    rfe
LEAF(env_pop_tf)
.set    mips1
        //1:    j   1b
    nop
        move        k0,a0 #a0是tf地址,a1是env的asid
        mtc0    a1,CP0_ENTRYHI #更新ENTRYHI的asid为当前进程的asid


        mfc0    t0,CP0_STATUS
        ori t0,0x3
        xori    t0,0x3
        mtc0    t0,CP0_STATUS

        lw  v1,TF_LO(k0)
        mtlo    v1
        lw  v0,TF_HI(k0)
        lw  v1,TF_EPC(k0)
        mthi    v0
        mtc0    v1,CP0_EPC
        lw  $31,TF_REG31(k0)
        lw  $30,TF_REG30(k0)
        lw  $29,TF_REG29(k0)
        lw  $28,TF_REG28(k0)
        lw  $25,TF_REG25(k0)
        lw  $24,TF_REG24(k0)
        lw  $23,TF_REG23(k0)
        lw  $22,TF_REG22(k0)
        lw  $21,TF_REG21(k0)
        lw  $20,TF_REG20(k0)
        lw  $19,TF_REG19(k0)
        lw  $18,TF_REG18(k0)
        lw  $17,TF_REG17(k0)
        lw  $16,TF_REG16(k0)
        lw  $15,TF_REG15(k0)
        lw  $14,TF_REG14(k0)
        lw  $13,TF_REG13(k0)
        lw  $12,TF_REG12(k0)
        lw  $11,TF_REG11(k0)
        lw  $10,TF_REG10(k0)
        lw  $9,TF_REG9(k0)
        lw  $8,TF_REG8(k0)
        lw  $7,TF_REG7(k0)
        lw  $6,TF_REG6(k0)
        lw  $5,TF_REG5(k0)
        lw  $4,TF_REG4(k0)
        lw  $3,TF_REG3(k0)
        lw  $2,TF_REG2(k0)
        lw  $1,TF_REG1(k0)

        lw  k1,TF_PC(k0)

        lw  k0,TF_STATUS(k0)
        nop
        mtc0    k0,CP0_STATUS



        j   k1 #跳到pc执行,而非epc
        rfe
        nop


END(env_pop_tf)
posted @ 2022-06-15 21:39  繁华丶人间  阅读(68)  评论(0编辑  收藏  举报