1.
在boot/setup.s文件189~191设置PE并开始进入保护模式,然后开始执行head.s
里面的指令,即startup_32标示符处的代码,初始化各个段寄存器,并设置IDT、GDT检查有没有x87(协处理器),然后无条件跳转到137行after_page_tables标示符处,
在这里压入3个参数值,及调用init/main函数后返回地址,和main函数的地址也压入栈,
这样在设置分页(setup_paging)结束后执行ret指令时会将main地址弹出堆栈,并去
执行main函数里面的代码了。
2.
3.
大家都知道,对于父进程 fork 返回子进程号,对于子进程 fork 返回 0 ,这也是执行路径如此的原因所在。但是, fork 的返回不同值的原因又是什么,这就得看 fork 的实现了。
fork 先是调用 find_empty_process 为子进程找到一个空闲的任务号,然后调用 copy_process 复制进程, fork 返回 copy_process 的返回值 last_pid ,也就是子进程号。
从上面的实现看来, fork 的返回值不会是 0 , last_pid 从 1 开始,父进程执行 if 外面的部分,上面的逻辑正是父进程的执行逻辑。
对于子进程,先看子进程的初始状态, copy_process 中创造了子进程的上下文执行环境,这个上下文环境正是父进程 fork 系统调用时的环境,其中, p->tss.eip 正是被赋值为 fork 之后下一条指令地址,这就是子进程和父进程都返回到 fork 下一条指令处的原因。同时,需要注意的是, p->tss.eax 被赋了值 0 ,当调度到子进程开始执行时,首先加载其上下文环境, eip 被加载为 fork 之后下一条指令, eax 就被加载为 0 ,所以,对于子进程来说,和父进程唯一的区别就是返回值( eax )为 0 ,子进程执行 if 里面的部分。之所以造成这样一个函数的不同代码段被两个进程执行,是和 linux0.11 的内核创建进程实现相关的