接下來: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ù)的主邏輯很簡單:
1、 通過之前保存下來的pt_regs(往內(nèi)核棧中格式化壓入的),獲取用戶傳入的系統(tǒng)調(diào)用號nr,系統(tǒng)調(diào)用號保存在了regs->orig_ax:
unsigned long nr = regs- >orig_ax;
2、 通過系統(tǒng)調(diào)用號nr,執(zhí)行對應(yīng)的回調(diào)函數(shù),sys_call_table是函數(shù)指針數(shù)組,不同nr對應(yīng)不同系統(tǒng)調(diào)用對應(yīng)的函數(shù)。其中regx->di、regx->si、regs->dx、regs->r10、regs->r8、regs->r9分別是之前保存到內(nèi)核棧(以struct
pt_regs格式化)保存到pt_regs中的,對應(yīng)著用戶傳入該系統(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);
}
以上就完成了用戶調(diào)用系統(tǒng)調(diào)用,并從用戶棧切換到內(nèi)核棧,并執(zhí)行到系統(tǒng)調(diào)用號對應(yīng)函數(shù)的過程。 具體的系統(tǒng)調(diào)用相關(guān)細(xì)節(jié)將在以后系統(tǒng)調(diào)用相關(guān)文章中分析。
系統(tǒng)調(diào)用-分析從內(nèi)核棧切換用戶棧
上面分析到了執(zhí)行系統(tǒng)調(diào)用對應(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),開始為返回用戶態(tài)做準(zhǔn)備.
并最終回到系統(tǒng)調(diào)用 內(nèi)核SYSCALL 入口:ENTRY(entry_SYSCALL_64)->return_from_SYSCALL_64,繼續(xù)完成系統(tǒng)調(diào)用返回工作,并切換用戶棧與內(nèi)核棧,使用struct pt_regs恢復(fù)用戶態(tài)寄存器值。
總之
用戶棧——>內(nèi)核棧: cpu保存用戶當(dāng)前堆棧信息保存到內(nèi)核的棧中(恢復(fù)時用到),然后將cpu指向內(nèi)核堆棧,去執(zhí)行內(nèi)核代碼。完成用用戶棧到內(nèi)核棧轉(zhuǎn)換。
內(nèi)核棧——>用戶棧: 再切換到內(nèi)核堆棧前,將用戶堆棧信息壓入到內(nèi)核棧中,內(nèi)核函數(shù)執(zhí)行完回退棧幀,會將用戶的堆棧信息POP出棧,然后cpu堆棧寄存器就知道怎么回去了,返回的用戶程序中斷的地方繼續(xù)執(zhí)行。
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1408瀏覽量
41072 -
Linux
+關(guān)注
關(guān)注
87文章
11456瀏覽量
212739
發(fā)布評論請先 登錄
從 Linux 內(nèi)核的角度談線程棧和進(jìn)程棧

C函數(shù)調(diào)用機(jī)制與棧幀原理詳解

操作系統(tǒng)為什么分內(nèi)核態(tài)和用戶態(tài)?這兩者如何切換?
ARMv8的函數(shù)調(diào)用棧是什么意思?調(diào)用棧的內(nèi)存管理是怎樣的
用一個實(shí)例展示一下Linux內(nèi)核棧幀的入棧和退棧過程
一文詳解Linux內(nèi)核的棧回溯與妙用

對Linux的進(jìn)程內(nèi)核棧的認(rèn)識

帶你了解嵌入式C語言函數(shù)調(diào)用棧

鴻蒙內(nèi)核源碼分析:用戶棧和內(nèi)核棧的兩次切換

嵌入式系統(tǒng)中棧的變化

Linux中的進(jìn)程棧、線程棧、內(nèi)核棧以及中斷棧

系統(tǒng)調(diào)用:用戶棧與內(nèi)核棧的切換(上)

linux中的進(jìn)程棧,線程棧,內(nèi)核棧的區(qū)別

評論