网易云课堂 Linux内核分析期末总结

寇亚飞+ 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

课程相关博客链接

  1. 网易云课堂 Linux内核分析(一)
  2. 网易云课堂 Linux内核分析(二)
  3. 网易云课堂 Linux内核分析(三)
  4. 网易云课堂 Linux内核分析(四)
  5. 网易云课堂 Linux内核分析(五)
  6. 网易云课堂 Linux内核分析(六)
  7. 网易云课堂 Linux内核分析(七)
  8. 网易云课堂 Linux内核分析(八)

课程总结

第一周:反汇编一个C语言小程序

对寄存器的作用,以及汇编代码的基础知识有了一定得了解,C语言中程序的调用,在底层汇编是如何实现的有了一定的认识。

第二周:完成一个简单的时间片轮转多道程序内核代码

简单模拟内核代码。主要包括函数调用堆栈、函数堆栈框架、内核的初始化、中断、进程上下文切换过程的简述以及基于时间片轮转的多道程序模拟。

  • 通过mykernel小程序,对进程的启动和切换机制有了深刻的理解
  • 操作系统的三个法宝:存储程序计算机、函数调用堆栈、中断机制
  • 操作系统的两把宝剑:中断上下文、进程上下文的切换

第三周:跟踪分析Linux内核的启动过程

计算机是通过执行指令来完成一系列操作,这其中很重要的一点就是eip寄存器,它给cpu指明了下一条要执行的指令是谁。因此,x86计算机启动的第一个动作就是从硬盘固定位置读取BIOS程序位置到eip中,然后BIOS例行程序检测完硬件并完成相应的初始化之后就会寻找可引导介质,找到后把引导程序加载到指定内存区域后,就把控制权交给了引导程序。这里一般是把硬盘的第一个扇区MBR和活动分区的引导程序加载到内存(即加载BootLoader),加载完整后把控制权交给BootLoader。引导程序BootLoader开始负责操作系统初始化,然后启动操作系统。

在start_kernel中,创建了系统的第一个进程,即0号进程。
道生一(start_kernel–>cpu_idle),一生二(kernel_init和kthreadd),二生三(即前面0、1和2三个进程),三生万物(1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先)

第四周:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

关于系统调用的知识。主要包括对系统调用与用户态、内核态的理解、通过编写汇编代码了解系统调用机制。

系统调用:即便是最简单的程序,在进行输入输出等操作时也会需要调用操作系统所提供的服务,也就是系统调用。Linux下的系统调用是通过中断(int 0x80)来实现的。

传递参数:在执行int 80指令时,寄存器 eax 中存放的是系统调用的功能号,而传给系统调用的参数则必须按顺序放到寄存器 ebx,ecx,edx,esi,edi 中,当系统调用完成之后,返回值可以在寄存器 eax 中获得。Linux 采用的是 C 语言的调用模式,这就意味着所有参数必须以相反的顺序进栈,即最后一个参数先入栈,而第一个参数则最后入栈。

系统调用不但把用户从底层的硬件编程中解放出来,提高了编程的效率,也极大的提高了系统的安全性。

第五周:分析system_call中断处理过程

添加一个自己编写的系统调用,加深对系统调用在内核代码中的处理过程的理解。

系统调用通过SAVE ALL保存上下文,调用内核函数,执行RESTORE_ALL并返回用户模式。

第六周:分析Linux内核创建一个新进程的过程

关于进程的描述和创建。主要包括PCB的组织形式、进程的数据结构进程描述符、fork系统调用的关键执行过程。

创建的新进程从哪里开始执行?

新进程是从ret_from_fork处开始执行的。对于fork执行处理过程来说,父子进程共享同一段代码空间,”一次调用,两次返回“,其实对于调用fork的父进程来说,如果fork出来的子进程没有得到 调度,那么父进程从fork系统调用返回,同时分析sys_fork知道,fork返回的是子进程的id。再看fork出来的子进程,由 copy_process函数可以看出,子进程的返回地址为ret_from_fork(和父进程在同一个代码点上返回),返回值直接置为0。所以当子进 程得到调度的时候,也从fork返回,返回值为0。ret_from_fork()调用schedule_tail()函数,用存放在栈中的值再装入所有寄存器,并强迫CPU返回到用户态。这样,eax寄存器就装过两个值,一个是子进程的值0,一个是父进程的值——子进程的PID。然后在fork()、vfork()或clone()返回时,新进程将开始执行。在不同的进程中返回不同的值。

第七周:Linux内核如何装载和启动一个可执行程序

Linux 系统通过用户态 execve 函数调用内核态 sys_execve 系统调用,负责将新的程序代码和数据替换到新的进程中,打开可执行文件,载入依赖的库文件,申请新的内存空间,最后执行 start_thread 函数设置 new_ip 和 new_sp,完成新进程的代码和数据替换,然后返回并执行新的进程代码。 具体的执行流程即sys_execve -> do_execve -> do_execve_common -> exec_binprm -> search_binary_handler -> load_binary ->(对于我们这里的ELF,会跳转到)load_elf_binary (也执行了elf_format)-> start_thread

第八周:理解进程调度时机跟踪分析进程调度与进程切换的过程

操作系统中进程的调度是非常常见的一种状态,无论采用何种调度册策略,它都是从进程队列中选择了一个新进程而已。因此,掌握进程调度的时机与进程上下文的切换非常重要。

Linux系统的一般执行过程

最一般情况:正在运行的用户态进程X切换到运行用户态进程Y的过程

正在运行的用户态进程X
发生中断——save cs:eip/esp/eflags(current) to kernel stack,then load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack).
SAVE_ALL //保存现场
中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换
标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)
restore_all //恢复现场
iret - pop cs:eip/ss:esp/eflags from kernel stack
继续运行用户态进程Y
特殊情况

通过中断处理过程中的调度,用户态进程与内核进程之间互相切换,与一般情形类似;
内核进程程主动调用 schedule 函数,只有进程上下文的切换,没有中断上下文切换;
创建子进程的系统调用在子进程中的执行起点及返回用户态,如:fork;
加载一个新的可执行程序后返回到用户态的情况,如:execve;

总结

Linux是计算机专业得学生一定要掌握得一门操作系统,在全部的课程中,我对Linux内核中的核心部分有了较全面的了解。对内核的启动、系统调用的执行过程、中断、进程的创建、切换等方面有了新的认识,阅读大牛们的Linux内核源码,使我对编码有了更深入的认识。孟老师的网课,这是我上的第二门,收获颇丰,值得回味。

遗憾

Linux内核博大精深,只掌握了皮毛,源码也有很多读不懂的地方。实验可能做的也比较按部就班,对Linux的学习是一个漫长的过程吧。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值