写在开头
由于本人汇编基础基本为0,所以吐血花了将近10小时,整理了网上所有相关的知识点,彻底搞清楚了linux系统进程的问题。博客同样适用于汇编基础不好的同学,讲的非常清楚,请耐心观看,相信你也肯定大有收获
这里是个人写的完整源码哈工大操作系统课程及实验完结体会
实验目的
深入理解进程和进程切换的概念;
综合应用进程、CPU管理、PCB、LDT、内核栈、内核态等知识解决实际问题;
开始建立系统认识。
实验内容
本次实验包括如下内容:
- 编写汇编程序switch_to:
- 完成主体框架;
- 在主体框架下依次完成PCB切换、内核栈切换、LDT切换等;
- 修改fork(),由于是基于内核栈的切换,所以进程需要创建出能完成内核栈切换的样子。
- 修改PCB,即task_struct结构,增加相应的内容域,同时处理由于修改了task_struct所造成的影响。
- 用修改后的Linux 0.11仍然可以启动、可以正常使用。
总览
本实验可以分为两个主要部分:
一部分是对应switch_to五段论中的中间段——内核栈的切换,主要是对switch_to代码的修改。
(原来的switch_to是基于TSS切换和长跳转指令来切换到下一个线程);
另一部分则在更改进程切换方式的情况下,如何修改fork()使其配合新的进程切换方式。
(因为fork()需要在新建一个子线程后,切换到子线程执行,而切换方式在上一部分改变了)
本文旨在将实现的整个流程讲清楚,在switch_to的注释和内核栈视角下的五段论务必详细观看,在理解整个流程起的作用非常大。
寄存器介绍
-
eip,用来存储CPU要读取指令的地址,CPU通过EIP寄存器读取即将要执行的指令
-
ebp是基址指针寄存器;处理栈帧,即处理 ebp 寄存器
-
esp是堆栈指针寄存器;这里已经进入内核态,所示是内核栈指针
一、编写switch_to(),40%
新的switch_to()函数是系统调用函数,所以要将函数重写在汇编文件system_call.s。这个函数依次主要完成如下功能:
首先我们要明确以下几点:
- 由于是 C 语言调用汇编,所以需要首先在汇编中处理栈帧,即处理 ebp 寄存器。这个需要不错的汇编基础,可以参考这里,讲的很清晰。
- 接下来要取出表示下一个进程 PCB 的参数,并和 current 做一个比较,如果等于 current,则什么也不用做。不等于 current,就开始进程切换
- 进程切换
- 完成 PCB 的切换
- TSS 中的内核栈指针的重写
- 内核栈的切换
- LDT 的切换以及 PC 指针(即 CS:EIP)的切换
以下代码的p,pnext都是PCB的首地址,也就是sched.h里的task_struct就是PCB,如果看不明白偏移的话,可以看看task_struct是长什么样的。而且,查看task_struct可知,tss_struct在task_struct的最后一个位置。
每个进程需要有自己的 LDT,地址分离地址还是必须要有的,而进程切换必然要涉及到 LDT 的切换。
switch_to(pnext, LDT(next))
先给出一个大体框架
switch_to:
pushl %ebp !这两句作用是把c函数整个压入栈,
movl %esp,%ebp !函数的参数和局部变量都是通过ebp的值加上一个偏移量来访问
pushl %ecx !接下来会用到这三个寄存器
pushl %ebx
pushl %eax
movl 8(%ebp),%ebx !取出从右向左第二个参数pnext,放入ebx寄存器中
cmpl %ebx,current !比较pnext和current,与之前的pnext初始化为current对应
je 1f !如果相等,直接跳过切换过程
! 切换PCB
! ...
! TSS中的内核栈指针的重写
! ...
! 切换内核栈
! ...
! 切换LDT
! ...
movl $0x17,%ecx
mov %cx,%fs
! 和后面的 clts 配合来处理协处理器,由于和主题关系不大,此处不做论述
cmpl %eax,last_task_used_math
jne 1f
clts
1: popl %eax !这四个寄存器是一开始进入函数保存数据的寄存器以及通用寄存器
popl %ebx
popl %ecx
popl %ebp
ret
下面逐条解释:
1.PCB的切换
PCB 的切换可以采用下面两条指令,由上面代码可知,其中ebx是从参数中取出来的下一个进程的 PCB 指针
// PCB的切换
movl %ebx,%eax !movl的用法:把32位的EAX寄存器值传送给32位的EBX寄存器值
xchgl %eax,current !xchgl的用法:交换eax和current的值
/*ebx是下一个进程的PCB首地址,cur

本文详细介绍了基于内核栈切换的Linux进程切换原理,涉及switch_to函数的编写,包括PCB切换、内核栈、LDT和PC指针的切换。还探讨了修改fork.c以配合新的进程切换方式,以及在sched.h和sched.c中的调整。文章适合汇编基础薄弱的学习者,帮助理解进程切换的完整流程。
最低0.47元/天 解锁文章
2894

被折叠的 条评论
为什么被折叠?



