接下來(lái):call
do_syscall_64,進(jìn)入do_syscall_64函數(shù):
__visible void do_syscall_64(struct pt_regs *regs)
{
struct thread_info *ti = current_thread_info();
unsigned long nr = regs- >orig_ax;
enter_from_user_mode();
local_irq_enable();
if (READ_ONCE(ti- >flags) & _TIF_WORK_SYSCALL_ENTRY)
nr = syscall_trace_enter(regs);
/*
* NB: Native and x32 syscalls are dispatched from the same
* table. The only functional difference is the x32 bit in
* regs- >orig_ax, which changes the behavior of some syscalls.
*/
if (likely((nr & __SYSCALL_MASK) < NR_syscalls)) {
regs- >ax = sys_call_table[nr & __SYSCALL_MASK](
regs- >di, regs- >si, regs- >dx,
regs- >r10, regs- >r8, regs- >r9);
}
syscall_return_slowpath(regs);
}
上述函數(shù)的主邏輯很簡(jiǎn)單:
1、 通過(guò)之前保存下來(lái)的pt_regs(往內(nèi)核棧中格式化壓入的),獲取用戶(hù)傳入的系統(tǒng)調(diào)用號(hào)nr,系統(tǒng)調(diào)用號(hào)保存在了regs->orig_ax:
unsigned long nr = regs- >orig_ax;
2、 通過(guò)系統(tǒng)調(diào)用號(hào)nr,執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù),sys_call_table是函數(shù)指針數(shù)組,不同nr對(duì)應(yīng)不同系統(tǒng)調(diào)用對(duì)應(yīng)的函數(shù)。其中regx->di、regx->si、regs->dx、regs->r10、regs->r8、regs->r9分別是之前保存到內(nèi)核棧(以struct
pt_regs格式化)保存到pt_regs中的,對(duì)應(yīng)著用戶(hù)傳入該系統(tǒng)調(diào)用的參數(shù)1~6:
if (likely((nr & __SYSCALL_MASK) < NR_syscalls)) {
regs- >ax = sys_call_table[nr & __SYSCALL_MASK](
regs- >di, regs- >si, regs- >dx,
regs- >r10, regs- >r8, regs- >r9);
}
以上就完成了用戶(hù)調(diào)用系統(tǒng)調(diào)用,并從用戶(hù)棧切換到內(nèi)核棧,并執(zhí)行到系統(tǒng)調(diào)用號(hào)對(duì)應(yīng)函數(shù)的過(guò)程。 具體的系統(tǒng)調(diào)用相關(guān)細(xì)節(jié)將在以后系統(tǒng)調(diào)用相關(guān)文章中分析。
系統(tǒng)調(diào)用-分析從內(nèi)核棧切換用戶(hù)棧
上面分析到了執(zhí)行系統(tǒng)調(diào)用對(duì)應(yīng)的函數(shù),如下所示,并將返回值保存在regs->ax中了
regs- >ax = sys_call_table[nr & __SYSCALL_MASK](
regs- >di, regs- >si, regs- >dx,
regs- >r10, regs- >r8, regs- >r9);
函數(shù)執(zhí)行到do_syscall_64->syscall_return_slowpath(regs),開(kāi)始為返回用戶(hù)態(tài)做準(zhǔn)備.
并最終回到系統(tǒng)調(diào)用 內(nèi)核SYSCALL 入口:ENTRY(entry_SYSCALL_64)->return_from_SYSCALL_64,繼續(xù)完成系統(tǒng)調(diào)用返回工作,并切換用戶(hù)棧與內(nèi)核棧,使用struct pt_regs恢復(fù)用戶(hù)態(tài)寄存器值。
總之
用戶(hù)棧——>內(nèi)核棧: cpu保存用戶(hù)當(dāng)前堆棧信息保存到內(nèi)核的棧中(恢復(fù)時(shí)用到),然后將cpu指向內(nèi)核堆棧,去執(zhí)行內(nèi)核代碼。完成用用戶(hù)棧到內(nèi)核棧轉(zhuǎn)換。
內(nèi)核?!?用戶(hù)棧: 再切換到內(nèi)核堆棧前,將用戶(hù)堆棧信息壓入到內(nèi)核棧中,內(nèi)核函數(shù)執(zhí)行完回退棧幀,會(huì)將用戶(hù)的堆棧信息POP出棧,然后cpu堆棧寄存器就知道怎么回去了,返回的用戶(hù)程序中斷的地方繼續(xù)執(zhí)行。
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1378瀏覽量
40345 -
Linux
+關(guān)注
關(guān)注
87文章
11330瀏覽量
209978
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論