linux操作系统分析课程总结报告

Linux系统的一般执行过程 1、Linux系统的启动过程,通常也称为引导过程(Boot process),包括一系列的步骤,各步骤如下: (1)BIOS(基本输入输出系统): 计算机上电后,首先执行的是BIOS

Linux系统的一般执行过程

1、Linux系统的启动过程,通常也称为引导过程(Boot process),包括一系列的步骤,各步骤如下:

(1)BIOS(基本输入输出系统): 计算机上电后,首先执行的是BIOS。BIOS会进行POST(Power-On Self Test,开机自检),检查硬件是否正常。然后搜索、加载并执行引导加载程序。

(2)Bootloader(引导加载程序): Bootloader的作用是加载内核。在许多Linux系统中,GRUB(GRand Unified Bootloader)是最常用的Bootloader。GRUB会被加载到内存中,并开始执行,加载Linux内核。

(3)Kernel(内核): 内核是Linux系统的核心,它将负责管理系统的硬件资源,并提供上层应用程序运行所需的环境。内核首先会进行自我解压,然后进行一系列的硬件检测与初始化。之后,它会挂载根文件系统并运行第一个进程。

(4)Init进程:Init进程是Linux系统中的第一个进程(PID为1),负责启动其他所有的进程。不同的系统可能使用不同的Init系统,如System V, Upstart, systemd等。systemd是目前许多现代Linux发行版的默认选择。

(5)Runlevel(运行级别):Init进程启动后,会根据系统的运行级别来启动其他服务。Linux系统有7个运行级别(0-6),每个级别对应一组特定的服务。例如,运行级别3通常是多用户文本模式,运行级别5通常是图形界面模式。

(6)用户空间初始化:在这个阶段,Init进程会启动一系列的后台服务和守护进程,包括网络服务、日志服务、调度服务等。如果系统配置为图形界面登录,那么还会启动界面系统,并在最后显示登录界面。

注:上述步骤(3)中的"内核自我解压"是指Linux内核镜像在被Bootloader(如GRUB)加载到内存后的一个步骤。为了节省磁盘空间和减少加载时间,Linux内核通常会被压缩存储。在内核镜像文件中,除了内核代码之外,还包含一个被称为"解压引导程序"或"引导解压缩器"的小段程序。当Bootloader加载并启动内核镜像时,首先运行的是这个解压引导程序。

解压引导程序的任务是将压缩的内核代码解压缩到内存中合适的位置,然后跳转到解压后的内核入口点开始执行内核代码。这个过程被称为"内核自我解压"。完成自我解压后,内核开始初始化操作,包括设备检测、驱动加载、内存管理单元设置等,并最终挂载根文件系统,运行Init进程。

2、Linux系统启动后,正在运行的用户态进程X切换到用户态进程Y的过程

(1)正在运行的用户态进程X。

(2)发生中断(包括异常、系统调用等),CPU完成load cs:rip(entry of a specific ISR),即跳转到中断处理程序入口。

(3)中断上下文切换,具体包括如下几点:     

•    swapgs指令保存现场,可以理解CPU通过swapgs指令给当前CPU寄存器状态做了一个快照。  

•    rsp point to kernel stack,加载当前进程内核堆栈栈顶地址到RSP寄存器。快速系统调用是由系统调用入口处的汇编代码实现用户堆栈和内核堆栈的切换。   

•    save cs:rip/ss:rsp/rflags:将当前CPU关键上下文压入进程X的内核堆栈,快速系统调用是由系统调用入口处的汇编代码实现的。

此时完成了中断上下文切换,即从进程X的用户态到进程X的内核态。

(4)中断处理过程中或中断返回前调用了schedule函数,其中完成了进程调度算法选择next进程、进程地址空间切换、以及switch_to关键的进程上下文切换等。

(5)switch_to调用了__switch_to_asm汇编代码做了关键的进程上下文切换。将当前进程X的内核堆栈切换到进程调度算法选出来的next进程(本例假定为进程Y)的内核堆栈,并完成了进程上下文所需的指令指针寄存器状态切换。之后开始运行进程Y(这里进程Y曾经通过以上步骤被切换出去,因此可以从switch_to下一行代码继续执行)。

(6)中断上下文恢复,与(3)中断上下文切换相对应。注意这里是进程Y的中断处理过程中,而(3)中断上下文切换是在进程X的中断处理过程中,因为内核堆栈从进程X切换到进程Y了。

(7)为了对应起见中断上下文恢复的最后一步单独拿出来(6的最后一步即是7)iret - pop cs:rip/ss:rsp/rflags,从Y进程的内核堆栈中弹出(3)中对应的压栈内容。此时完成了中断上下文的切换,即从进程Y的内核态返回到进程Y的用户态。注意快速系统调用返回sysret与iret的处理略有不同。

(8)继续运行用户态进程Y。

注:上述进程切换过程以x86-64系统结构下Linux-5.4.34为例进行说明

课程总结

在完成了Linux操作系统分析课程之后,我从中学习了Linux操作系统的许多关键概念和核心原理。以下是课程的主要内容概要:

李春杰老师主要讲解了中断与异常、文件系统管理、进程管理这三个部分。其中,中断异常的处理可谓重中之重。

首先是中断的产生部分,中断控制器监视IRQ线,接受引发信号;将信号转换为对应的中断向量(Linux中中断向量是一个数),通过INTR引脚发送,产生中断,并维持电压等待CPU的应答。这时CPU将会得到中断向量,读IDTR寄存器都确定指向IDT表的第i项,读GDTR寄存器获得GDT的基地址,找到IDT表项中的段选择符标识的段描述符,在判断中断合法后进行下一步操作。CPU将会检查进入中断的进程当前状态,根据内核态和用户态的不同来进行操作。如果是从用户态进入的,将会开启新的内核态堆栈,保存相关寄存器的值,在这之后开始真正的处理中断。在处理程序执行完成后,会再此根据进入时的特权级进行不同的操作,来还原中断前的上下文,返回原来的特权等级。【注:李老师上课讲述的内容依据Linux2.6版本】

​不同于李春杰老师着重于对底层代码的梳理,孟宁老师是从宏观角度讲述整个Linux运行的原理。孟宁老师从目前的操作系统生态环境入手,为我们展示了操作系统的发展历程,带我们看到了不同架构、不同时代的操作系统运行的差别,通过实际的代码为我们展示了ISA寄存器、操作系统寻址方式以及一些常用的指令。引领我们形成对Linux操作系统整体上的认识。

​孟宁老师对于Linux系统中出现的函数调用情况的讲解,给我留下了极为深刻的印象。老师在黑板上清晰地画出了函数调用的过程,为我们展现了函数调用时内存堆栈框架的建立和拆除的整个流程。以在x86-64架构下使用C语言和GCC编译器为例,函数调用的寄存器以及参数的压栈顺序如下:

  1. 参数传递:在这个约定下,前六个整型或者指针类型的参数分别通过寄存器rdi、rsi、rdx、rcx、r8、r9、传递。如果参数多于六个,那么剩余的参数会被压入栈中,且按照从右到左的顺序压入。也就是说,函数声明中最右边的参数最先被压入栈。

  2. 寄存器保存:在调用函数前,如果被调用函数需要改变rbp、rbx 和 r12 - r15 这几个寄存器的值,那么被调用函数(callee)在改变之前需要先将这些寄存器的原值保存下来(通常是压入栈中),然后在函数返回前,需要将这些寄存器的值恢复到原来的值。这些寄存器在函数调用中被称为 "callee-saved" 或者 "non-volatile" 寄存器。

  3. 返回值:函数的返回值通过rax寄存器返回。

  4. 其他寄存器:对于其他的寄存器,如rax、rcx、rdx、rsi、rdi、r8-r11,它们是 "caller-saved" 或者 "volatile" 寄存器。这意味着如果调用者在调用其他函数之后还需要使用这些寄存器的值,那么它需要在调用之前保存这些寄存器的值,因为被调用的函数可能会改变这些寄存器的值。

总之,Linux操作系统分析课程为我提供了一个深入了解和探索Linux内核的机会,不仅让我对Linux内核有了更深入的理解,也提高了我的代码能力。最后,感谢两位老师的倾心教授,老师辛苦啦!

知秋君
上一篇 2024-08-02 08:12
下一篇 2024-08-02 07:48

相关推荐