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)