哈工大操作系统实验二--调试分析 Linux 0.00 多任务切换

文章详细探讨了中断处理程序iret的作用,特别是如何在特权级别和堆栈之间切换。还分析了时钟中断触发的任务切换过程,涉及TSS、寄存器值的变化以及堆栈和特权级别的管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 当执行完 system_interrupt 函数,执行 153iret 时,记录栈的变化情况。

system_interrupt 程序内容如下:

iret用于在处理器状态转移期间从中断或异常处理程序返回到被中断的程序,还原被中断程序的执行环境,包括寄存器、堆栈以及特权级别的状态。

iret 指令执行以下操作:

  1. 从堆栈中弹出 EIP寄存器的值,以恢复中断或异常处理程序返回到的下一条指令的地址。

  2. 从堆栈中弹出 CS 寄存器的值,以恢复中断或异常处理程序返回到的代码段。

  3. 从堆栈中弹出标志寄存器 EFLAGS的值,以恢复标志寄存器的状态。

  4. 如果在中断或异常处理程序执行期间切换了堆栈,iret 会从堆栈中弹出新的 ESP寄存器的值,以恢复原始堆栈。

  5. 根据从堆栈中弹出的 CS 寄存器的值,恢复到适当的特权级别。这允许在不同特权级别(如内核态和用户态)之间切换

在0x17c处设置断点,然后运行程序

1)执行 153iret

CPU 正在执行的下一条指令的内存地址EIP:0x17c(即将执行iret)

代码段寄存器CS:0x8(当前执行的代码段以及执行代码的特权级别为 0 内核态)

栈顶指针ESP:0xe4e

此时stack中的值从栈顶开始是:

0x10eb(即将弹出的EIP寄存器的值)

0x000f (即将弹出的CS寄存器的值)

0x0246(即将弹出的EFLAGS寄存器的值)

0x0bd8(即将弹出的ESP寄存器的值)

2)执行 153iret

CPU 正在执行的下一条指令的内存地址EIP:0x10eb

代码段寄存器CS:0xf(当前执行的代码段以及执行代码的特权级别为 3 用户态)

栈顶指针ESP:0xbd8

2. 当进入和退出 system_interrupt 时,都发生了模式切换,请总结模式切换时,特权级是如何改变的?栈切换吗?如何进行切换的?

1)特权级

在进入和退出 system_interrupt 时发生了特权级的模式切换。

  1. 进入 system_interrupt

    • 用户态(特权级 3)切换到内核态(特权级 0),中断服务在内核态中执行。

    • 处理器将特权级从 3 切换到 0,CS的值由 0xf 变为 0x8

  2. 退出 system_interrupt

    • 内核态(特权级 0)切换回用户态(特权级 3)。

    • iret执行之后,处理器将特权级从 0 切换到 3,CS的值由 0x8 变为 0xf

2)栈

在进入和退出 system_interrupt 时同时会发生栈的切换。

  1. 进入 system_interrupt

    • 发生堆栈切换,以便在内核态中使用内核堆栈,来保护用户堆栈的完整性。

  2. 退出 system_interrupt

    • 发生堆栈切换,以返回到原特权级的堆栈,并继续用户态的执行。

3)如何切换

这种特权级的切换和堆栈切换是操作系统内核处理器硬件协同工作的结果。

  1. 保存当前上下文:在模式切换之前,当前执行的任务的上下文以及当前特权级需要被保存压入栈中

  2. 选择新特权级别:根据要切换到的特权级别,操作系统选择新的代码段描述符和堆栈描述符,切换堆栈和特权级,并将它们加载到相应的寄存器中。

    • 在进入内核态时,通常会使用内核堆栈,以避免破坏用户堆栈。

    • 在退出内核态时,特权级和堆栈状态会恢复,以确保程序的正常执行。

3. 当时钟中断发生,进入到 timer_interrupt 程序,请详细记录从任务 0 切换到任务 1 的过程。

timer_interrupt 的程序内容如下:

task0 :打印 A

task1 :打印B

在0x12c处设置断点,然后运行程序

  • 如下图所示,可以发现程序执行 task0 打印了好几个 A ,但是还没有打印过B ,即还未执行过task1

  • 单步运行到CS:EIP 0x08:0x0149处准备执行指令jmpf 0x30:0 ,即远跳转到0x30:0,将一个 TSS 选择子(0x30)装入 CS,实际上就是为了将任务切换到这个 TSS。

  • 0x30恰好是task1的TSS。

  • 跳转之前输入info tss,记录任务切换前task0 的TSS

  • 单步执行后,寄存器状态如下图CS:EIP 0xf:0x10f4,现在已经切换到任务1,由于任务1是第一次执行,直接跳转到了用户程序task1的入口处

  • 输入 info tss,查看此时的TSS,发现TSS变化为task1 的TSS,并且与寄存器中的值相同,这说明了任务切换时会根据对应任务的 TSS的各个字段修改寄存器。

4. 又过了 10ms ,从任务1切换回到任务 0 ,整个流程是怎样的? TSS 是如何变化的?各个寄存器的值是如何变化的?

在0x15c处设置断点,然后运行程序

  • 如下图所示,程序打印了B ,说明程序执行了 task1

  • 此时的TSS如下图所示,与寄存器内容相同,说明已经将 task1 的上下文保存在 task1 的TSS中

  • 然后执行 jmpf 0x20:0 ,将一个 TSS 选择子(0x20)装入 CS,即task0 的TSS,由于第一次任务切换时将寄存器现场保存到了 task0 TSS里,因此将TSS切换回来后,CS:EIP 会指向第一次任务切换的下一条地址,也就是0x8:0x150。

  • 输入info tss

5. 请详细总结任务切换的过程。

  1. 时钟中断触发:任务切换通常是由系统中的时钟中断timer_interrupt 触发的。时钟中断以固定的时间间隔(每10毫秒)发生一次,它是多任务处理的触发点。

  2. 保存当前任务上下文:当时钟中断触发时,操作系统会执行时钟中断处理程序。在处理程序执行之前,当前正在执行的 taskA 的上下文会被保存。EAX、ECX、EDX、EFLAGS、ESP、CS、EIP等寄存器的状态会保存在 taskA 的 TSS 中。

  3. 选择下一个任务:在时钟中断处理程序中,操作系统会选择下一个要执行的 taskB ,任务B的上下文信息存储在 taskB 的TSS中。

  4. 加载下一个任务上下文:时钟中断处理程序通过 taskB 的 TSS 将 taskB 的上下文信息(寄存器的值)加载到处理器中,处理器现在准备执行 taskB

  5. 切换堆栈:如果 taskAtaskB 使用不同的内核堆栈,堆栈指针寄存器ESP将从 taskA 的内核堆栈切换到 taskB 的内核堆栈,以确保 taskB 可以正常执行内核代码。

  6. 特权级别切换:如果 taskAtaskB 属于不同的特权级别,时钟中断处理程序会执行特权级别切换操作。

  7. taskB 开始执行taskB 的上下文准备就绪并加载到处理器中, taskB 开始执行。

  8. 时钟中断返回:时钟中断处理程序执行完毕后,处理器返回到 taskB 的执行点, taskB 继续执行。

在这个过程中,TSS寄存器中的值将发生变化,以反映新任务的上下文。旧任务的上下文信息已经被保存,以便在未来的任务切换中恢复。其他寄存器的值也会根据任务上下文的不同而变化,以确保任务切换的正确执行。这个过程允许多个任务在同一个系统中轮流执行,实现多任务处理。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值