1. TRAMPOLINE (蹦床):模式切换的“安全屋”
在 RISC-V 中,从用户态切换到内核态(比如执行系统调用时)是一个非常惊险的动作:你需要更换页表(切换 satp 寄存器)、更换栈指针、保存所有寄存器。
- 它的角色:它是所有进程共享的一段代码。
- 它的特殊性:它在用户页表和内核页表中的虚拟地址是完全一样的(都在 )。
- 为什么叫蹦床?:用户程序像“跳”上蹦床一样进入这段代码,在蹦床上完成页表切换等高难度动作,然后“弹”进内核。如果没有它,CPU 在切换页表的瞬间会因为找不到下一条指令而崩溃。
2. TRAPFRAME (陷阱帧):寄存器的“保险柜”
当 CPU 突然要从用户态跳进内核态时,用户程序正在运行。这时,用户程序的寄存器(如 a0 到 a7、ra、sp 等)里存满了重要数据。
- 它的角色:它是每个进程独立拥有的一页物理内存。
- 它的功能:当进入
TRAMPOLINE时,代码会立刻把当前所有的寄存器值“塞”进这个TRAPFRAME页面里。
为什么需要它?:RISC-V 的调用约定规定 a0-a7 用于传递参数 。如果在进入内核时不把这些寄存器存起来,内核运行时的操作就会把用户程序的数据覆盖掉,用户程序就再也回不去了。
3. 为什么你在 proc_pagetable 里要映射它们?
每一个进程想要运行,都必须具备这三个基本映射。proc_pagetable 的逻辑通常是这样的:
- 映射 TRAMPOLINE:让进程有能力跳进内核。
- 映射 TRAPFRAME:让进程跳进内核时有地方存寄存器数据。
- 映射 USYSCALL (你加的):让进程能直接读到 PID。
- TRAMPOLINE:位于虚拟地址最高端。它是用户态与内核态转换的代码中转站,所有进程共享同一物理页。
- TRAPFRAME:位于 TRAMPOLINE 下方一页。用于在陷阱处理(Trap)期间保护用户的寄存器现场,每个进程拥有独立的物理页。
- 撤销逻辑原则:在
proc_pagetable这种初始化函数中,必须遵循 “后入先出” 的清理原则,确保映射失败时不会在页表中留下任何残留。