|
sysenter/sysexit 系統(tǒng)調(diào)用的機制: 在 Intel 的軟件開發(fā)者手冊第二、三卷(Vol.2B,Vol.3)中,4.8.7 節(jié)是關(guān)于 sysenter/sysexit 指令的詳細描述。手冊中說明,sysenter 指令可用于特權(quán)級 3 的用戶代碼調(diào)用特權(quán)級 0 的系統(tǒng)內(nèi)核代碼,而 SYSEXIT 指令則用于特權(quán)級 0 的系統(tǒng)代碼返回用戶空間中。sysenter 指令可以在 3,2,1 這三個特權(quán)級別調(diào)用(Linux 中只用到了特權(quán)級 3),而 SYSEXIT 指令只能從特權(quán)級 0 調(diào)用。 執(zhí)行 sysenter 指令的系統(tǒng)必須滿足兩個條件:1.目標 Ring 0 代碼段必須是平坦模式(Flat Mode)的 4GB 的可讀可執(zhí)行的非一致代碼段。2.目標 RING0 堆棧段必須是平坦模式(Flat Mode)的 4GB 的可讀可寫向上擴展的棧段。 在 Intel 的手冊中,還提到了 sysenter/sysexit 和 int n/iret 指令的一個區(qū)別,那就是 sysenter/sysexit 指令并不成對,sysenter 指令并不會把 SYSEXIT 所需的返回地址壓棧,sysexit 返回的地址并不一定是 sysenter 指令的下一個指令地址。調(diào)用 sysenter/sysexit 指令地址的跳轉(zhuǎn)是通過設(shè)置一組特殊寄存器實現(xiàn)的。這些寄存器包括: SYSENTER_CS_MSR - 用于指定要執(zhí)行的 Ring 0 代碼的代碼段選擇符,由它還能得出目標 Ring 0 所用堆棧段的段選擇符; SYSENTER_EIP_MSR - 用于指定要執(zhí)行的 Ring 0 代碼的起始地址; SYSENTER_ESP_MSR-用于指定要執(zhí)行的Ring 0代碼所使用的棧指針 這些寄存器可以通過 wrmsr 指令來設(shè)置,執(zhí)行 wrmsr 指令時,通過寄存器 edx、eax 指定設(shè)置的值,edx 指定值的高 32 位,eax 指定值的低 32 位,在設(shè)置上述寄存器時,edx 都是 0,通過寄存器 ecx 指定填充的 MSR 寄存器,sysenter_CS_MSR、sysenter_ESP_MSR、sysenter_EIP_MSR 寄存器分別對應 0x174、0x175、0x176,需要注意的是,wrmsr 指令只能在 Ring 0 執(zhí)行。 這里還要介紹一個特性,就是 Ring0、Ring3 的代碼段描述符和堆棧段描述符在全局描述符表 GDT 中是順序排列的,這樣只需知道 SYSENTER_CS_MSR 中指定的 Ring0 的代碼段描述符,就可以推算出 Ring0 的堆棧段描述符以及 Ring3 的代碼段描述符和堆棧段描述符。 在 Ring3 的代碼調(diào)用了 sysenter 指令之后,CPU 會做出如下的操作: 1.將 SYSENTER_CS_MSR 的值裝載到 cs 寄存器 2.將 SYSENTER_EIP_MSR 的值裝載到 eip 寄存器 3.將 SYSENTER_CS_MSR 的值加 8(Ring0 的堆棧段描述符)裝載到 ss 寄存器。 4.將 SYSENTER_ESP_MSR 的值裝載到 esp 寄存器 5.將特權(quán)級切換到 Ring0 6.如果 EFLAGS 寄存器的 VM 標志被置位,則清除該標志 7.開始執(zhí)行指定的 Ring0 代碼 在 Ring0 代碼執(zhí)行完畢,調(diào)用 SYSEXIT 指令退回 Ring3 時,CPU 會做出如下操作: 1.將 SYSENTER_CS_MSR 的值加 16(Ring3 的代碼段描述符)裝載到 cs 寄存器 2.將寄存器 edx 的值裝載到 eip 寄存器 3.將 SYSENTER_CS_MSR 的值加 24(Ring3 的堆棧段描述符)裝載到 ss 寄存器 4.將寄存器 ecx 的值裝載到 esp 寄存器 5.將特權(quán)級切換到 Ring3 6.繼續(xù)執(zhí)行 Ring3 的代碼 由此可知,在調(diào)用 SYSENTER 進入 Ring0 之前,一定需要通過 wrmsr 指令設(shè)置好 Ring0 代碼的相關(guān)信息,在調(diào)用 SYSEXIT 之前,還要保證寄存器edx、ecx 的正確性 |
|
|