网站 备案地,秀米官网登录入口,用上网做任务的网站,六安商务网站建设电话前言
今天在学习《深入理解Linux内核》的时候#xff0c;发现出现了一个新的名词TSS#xff08;Task-State Segment#xff09;#xff0c;这还是我第一次了解到原来x86提供了硬件级别的任务切换功能#xff0c;之前以为任务切换都是操作系统实现的来着#xff0c;这里也…前言
今天在学习《深入理解Linux内核》的时候发现出现了一个新的名词TSSTask-State Segment这还是我第一次了解到原来x86提供了硬件级别的任务切换功能之前以为任务切换都是操作系统实现的来着这里也记录一下我的发现。
参考资料
Intel白皮书的Volume 3A Chapter 8: Task Management
什么是TSS
TSS是一块特殊的内存区域这块内存区域用来存储硬件上下文在实现硬件级别的任务切换时起到了保存和加载上下文的作用。具体而言这块内存区域的分布如下图所示 这块内存区域里面记录了一些任务的硬件上下文例如通用寄存器的值段寄存器的值栈寄存器的值等。
从段Segment的角度看TSS
从TSS的名字可以知道它也是一个段那么也是需要使用段描述符来寻址的。事实上TSS的段描述符如下图所示 保存这个段描述符的段寄存器是TR这个寄存器和SS等寄存器类似也是拥有一个用户可见部分存放描述符和用户不可见部分存放描述符的内容。 在当前特权等级为0的情况下可以使用LTR汇编指令来把一个描述符加载到TR里面。
硬件级别的任务切换过程
任务切换可以通过jump-far和call-far来实现call和call-far的区别在于普通的call不会修改CS寄存器而call-far需要传递一个新的段描述符用来更新CS寄存器的值。 根据白皮书当使用call-far并且传入的段描述符是一个TSS段描述符那么就会进行任务切换例如下面这条指令其中0x2b描述符对应的是TSS段
call 0x2b:0x00000000当满足上述条件时CPU会先经历一系列检查然后把当前的硬件上下文如寄存器的值保存到TSS段中然后根据传入的新的TSS段描述符把新的TSS段的内容加载到各个寄存器中。
Linux的任务切换
虽然x86提供了一套硬件级别的任务切换机制但是Linux内核并没有采用这套机制。具体而言Linux采取了如下的方法摘自https://liujunming.top/2020/01/18/%E6%B5%85%E8%B0%88tss/
linux没有为每一个进程都准备一个tss段而是每一个cpu使用一个tss段tr寄存器保存该段。进程切换时只更新唯一tss段中的esp0字段esp0保存新进程的内核栈地址。linux的tss段中只使用esp0和iomap等字段不用它来保存寄存器在一个用户进程被中断进入ring0的时候tss中取出esp0然后切到esp0其它的寄存器则保存在esp0指示的内核栈上而不保存在tss中。结果linux中每一个cpu只有一个tss段tr寄存器永远指向它。符合x86处理器的使用规范但不遵循intel的建议这样的后果是开销更小了因为不必切换tr寄存器了。
总之就是Linux把上下文保存在了内核栈中而内核栈的地址保存在esp0里面。