• 【实现】用户态切换到内核态

    【实现】用户态切换到内核态

    CPU在用户态执行到switch_to_kernel()函数(即执行“int T_SWITCH_TOK”)时,由于当前处于用户态,而中断产生后,CPU会进入内核态,所以存在特权级转换。硬件会在内核栈中压入Error Code(可选)、EIP、CS和EFLAGS、ESP(用户态特权级的)、SS(用户态特权级的)(如下图所示),然后跳转到到IDT中记录的中断号T_SWITCH_TOK所对应的中断服务例程入口地址处继续执行。通过2.3.7小节“中断处理过程”可知,会执行到trap_disptach函数(位于trap.c):

    1. case T_SWITCH_TOK:
    2. if (tf->tf_cs != KERNEL_CS) {
    3. //发出中断时,CPU处于用户态,我们希望处理完此中断后,CPU继续在内核态运行,
    4. //所以把tf->tf_cs和tf->tf_ds都设置为内核代码段和内核数据段
    5. tf->tf_cs = KERNEL_CS;
    6. tf->tf_ds = tf->tf_es = KERNEL_DS;
    7. //设置EFLAGS,让用户态不能执行in/out指令
    8. tf->tf_eflags &= ~(3 << 12);
    9. switchu2k = (struct trapframe *)(tf->tf_esp - (sizeof(struct trapframe) - 8));
    10. //设置临时栈,指向switchu2k,这样iret返回时,CPU会从switchu2k恢复数据,
    11. //而不是从现有栈恢复数据。
    12. memmove(switchu2k, tf, sizeof(struct trapframe) - 8);
    13. *((uint32_t *)tf - 1) = (uint32_t)switchu2k;
    14. }
    15. break;

    这样在trap将会返回,在__trapret:中,根据switchk2u的内容完成对返回前的寄存器和栈的回复准备工作,最后通过iret指令,CPU返回“int T_SWITCH_TOU”的后一条指令处,以内核态模式继续执行。