基于内核栈切换的进程切换

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

写在开头

由于本人汇编基础基本为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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值