Linux kernel_thread 的一些注意事项

来源:互联网 发布:秀才不出门 尽知天下事 编辑:程序博客网 时间:2024/04/30 20:54

 

在x86_64平台上,很多内核函数的入口定义都在entry_64.S中。

kernel_thread定义如下:

 

 

其中的FAKE_STACK_FRAME宏,虚构了一个中断堆栈信息,意思就是:中断返回后的执行第一条指令就是child_rip。

然后就是准备参数寄存器,调用do_fork这跟传统的穿件进程与线程一样的。主线程返回时,把创建的伪中断堆栈恢复,然后继续正常执行。

 

而子进程则返回到child_rip处,跟父进程的执行路径不一样,并不恢复伪堆栈的信息。执行路径的不同主要由以下几段代码来控制:

copy_thread中的一段:

 

以及switch_to宏:

 

在创建子进程时,将thread_info中的flag TIF_FORK标志位置为1。子进程创建后,并不会立即调度执行,而是通过父进程让其调度执行后才被调度。这时在switch_to宏中就会对TIF_FORK标志位判断,是否为新创建的进程,如果是,就跳到ret_from_fork进行执行。

代码如下

 

此时跳入int_ret_from_sys_call,因为此时堆栈中CS寄存器特权级为0.

 

 

这样,子进程就会调用INTERRUPT_RETURN指令(iret)。硬件中断恢复父进程创建的伪中断堆栈,执行child_rip代码段:

 

此时rdi寄存器存放的kernel_thread传递的执行函数指针int (*fn)(void *), rsi 存放args,通过call,进入到kernel_thread所需要执行的函数。执行完do_exit。

 

整个过程就是这样子的,关键是整个过程中堆栈情况要搞清楚就行了。其中do_fork的工作,和用户空间系统调用fork陷入do_fork做的事一样的。如果是用户空间过来的,在ret_from_fork中,对比cs寄存器时,特权级为3,就会从ret_from_sys_call返回用户空间。还是很烦的。

原创粉丝点击