在 Day 17 中,我們將用戶程序關進了 Ring 3 的「監獄」。今天,我們為這座監獄安裝了一扇受控的窗戶 —— 系統調用 (System Call)。透過 int 0x80 指令,用戶程序現在可以安全地請求內核執行高權限操作,例如調用 kprintf 在螢幕上輸出字符。
由於用戶態無法直接執行 I/O 指令,必須透過一種「主動觸發異常」的方式進入內核。
eax,參數放入其他寄存器(如 ebx, ecx),執行 int 0x80。eax 的值,跳轉到對應的內核函數。iret 返回 Ring 3。我們實作了第一個實用的系統調用:sys_print。
我們定義了一個函數指針數組,將調用號( 1 代表 Print)映射到真正的 kprintf 實現。
用戶不再直接寫彙編,而是透過一個包裝好的 C 函數進行調用:
// 用戶態調用代碼
static inline int syscall(int num, int arg1) {
int ret;
__asm__ __volatile__ (
"int $0x80"
: "=a"(ret) // 返回值存於 eax
: "a"(num), "b"(arg1) // 編號存於 eax, 參數存於 ebx
);
return ret;
}
// 內核端初始化函數以及中斷功能表定義
// 系統調用表
static void *syscall_table[MAX_SYSCALLS] = {
[1] = sys_print
};
void syscall_dispatch(registers_t *regs)
{
if (regs->eax >= MAX_SYSCALLS)
{
kprintf("Unknown syscall: %d\\n", regs->eax);
return;
}
void (*handler)(registers_t*) = syscall_table[regs->eax];
if (handler) {
handler(regs);
}
}
void init_syscall()
{
register_interrupt_handler(128, syscall_dispatch);
}