Linux kernel 分析之十 核心執行緒

2021-07-04 00:12:01 字數 1947 閱讀 4095

眾所周知,核心中建立乙個核心執行緒是通過kernel_thread實現的。宣告如下:

int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);

我們知道,使用者態建立執行緒呼叫clone(),如果要在核心態建立執行緒,首先想到的是在核心態呼叫clone()。這是可以的。比如在init核心執行緒中就直接在核心態呼叫execve,引數為/sbin/init等等。但是還是要小心翼翼。因為系統呼叫裡會有很多引數要求是使用者態的(一般在宣告前有__user ),在呼叫一些核心函式時也會檢查引數的界限,嚴格要求引數在使用者態。一旦發現引數是在核心態,就立即返回出錯。

所以kernel_thread採用了另外一種辦法。

由於不是從使用者態進入核心的,它需要製造一種現場,好像它是通過clone系統呼叫進入核心一樣。方法是手動生成並設定乙個struct pt_regs,然後呼叫do_fork()。但是怎樣把執行緒的函式指標fn,引數arg傳進去呢?和flags不同,flags可以作為do_fork()的引數。但是fn正常情況下應該是在clone()結束後才執行的。此外,執行緒總不能長生不老吧,所以執行完fn()還要執行exit()。

所以,我們希望核心執行緒在建立後,回到核心態(普通情況下是使用者態)後,去呼叫fn(arg),最後呼叫exit()。而要去「遙控」核心執行緒在建立以後的事,只能通過設定pt_regs來實現了。

看kernel_thread的實現:

355         regs.ebx = (unsigned long) fn;

356         regs.edx = (unsigned long) arg;

這裡設定了引數fn,arg,當核心執行緒在建立以後,ebx中放的是fn,edx中放的是arg

358         regs.xds = __user_ds;

359         regs.xes = __user_ds;

360         regs.orig_eax = -1;

361         regs.eip = (unsigned long) kernel_thread_helper;

當核心執行緒在建立以後,執行的是 kernel_thread_helper函式

362         regs.xcs = __kernel_cs;

當核心執行緒在建立以後,cs暫存器的值表明當前仍然處於核心態。

363         regs.eflags = x86_eflags_if | x86_eflags_sf | x86_eflags_pf | 0x2;364 

365         /* ok, create the new process.. */

366         return do_fork(flags | clone_vm | clone_untraced, 0, ®s, 0, null, null);

看來kernel_thread_helper就是我們想要的東西了。

336 __asm__(".section .text\n"

337         ".align 4\n"

338         "kernel_thread_helper:\n\t"

339         "movl %edx,%eax\n\t"

340         "pushl %edx\n\t"

341         "call *%ebx\n\t"342         "pushl %eax\n\t"343         "call do_exit\n"

344         ".previous");

首先把edx儲存到eax(不明白為什麼這麼做,因為呼叫fn後返回值就把eax覆蓋掉了)把edx(其實就是引數arg)壓入堆疊,然後呼叫ebx(也就是fn)。最後呼叫do_exit。kernel_thread_helper是不返回的。

這裡,核心通過巧妙設定pt_regs,在沒有使用者程序的情況下,在核心態建立了執行緒。

linux kernel 啟動流程簡單分析

ping linux 核心啟動的時候,總是從start kernel 這個函式作為入口。start kernel完成了對各種資源的初始化。隨後,呼叫了rest init 完成對init程序的啟動。我們用gdb跟蹤linux kernel 核心啟動可以看到。1.我們把斷點置於start kernel ...

Linux kernel路由機制分析(下)

前面已經介紹過,ip層會在輸入和輸出兩個時候去呼叫路由部分 輸入路由過程更為複雜一些也更具代表性,所以我們下面主要分析一下ip包輸入時的路由流程。下圖描述了這個流程 當有資料到達網路裝置的時候,會產生乙個中斷,中斷處理函式會呼叫驅動層的net rx函式,net rx進而產生個軟中斷進入net rx ...

載入linux kernel 的安全機制分析

system core mkbootimg mkbootimg.c 首先,一般bootimage 的結構如下 打包的時候會計算kernel,ramdisk分割槽資料的sha值,並把其存放在boot header 注意 計算的時候不包含boot header本身 sha init ctx sha up...