Tss
TSS是CPU设计的实现多任务的方式
当使用 call/jmp + TSS段选择子的时候,CPU做了以下几件事情:
- 把当前所有寄存器(TSS结构中有的那些寄存器)的值填写到当前 tr 段寄存器指向的 TSS 中
- 把新的 TSS 段选择子指向的段描述符加载到 tr 段寄存器中
- 把新的 TSS 段中的值覆盖到当前所有寄存器(TSS结构中有的那些寄存器)中
2.6 以上内核不在使用CPU自身实现的task switch方式,而是代码里去实现。
/*
* switch_to(x,yn) should switch tasks from x to y.
*
* We fsave/fwait so that an exception goes off at the right time
* (as a call from the fsave or fwait in effect) rather than to
* the wrong process. Lazy FP saving no longer makes any sense
* with modern CPU's, and this simplifies a lot of things (SMP
* and UP become the same).
*
* NOTE! We used to use the x86 hardware context switching. The
* reason for not using it any more becomes apparent when you
* try to recover gracefully from saved state that is no longer
* valid (stale segment register values in particular). With the
* hardware task-switch, there is no way to fix up bad state in
* a reasonable manner.
*
* The fact that Intel documents the hardware task-switching to
* be slow is a fairly red herring - this code is not noticeably
* faster. However, there _is_ some room for improvement here,
* so the performance issues may eventually be a valid point.
* More important, however, is the fact that this allows us much
* more flexibility.
*
* The return value (in %eax) will be the "prev" task after
* the task-switch, and shows up in ret_from_fork in entry.S,
* for example.
*/
linux 内核知识点总结
- TSS 和 TSS 选择符, TR寄存器保存对应的TSS选择符, LDT表,和LDTR寄存器,来实现一个任务的抽象。 每个进程都会有一个单独的TSS和LDT。
- GDT 和 IDT 是全局的,只有一个。
- 段内的短跳转不涉及到任务的切换,也不涉及到堆栈的切换。
- cs代码段选择子跳转到一个新的段时,要么同一个任务内的段描述符,或者选择一个任务段描述符(或者直接是 TSS段描述符),后者涉及到TSS保存寄存器,以及加载新的TSS中的寄存器。 这个过程可以靠CPU一条指令完成,也可以靠系统程序员编写多条指令完成。 早期的是CPU一条指令完成,2.6以后内核自己编写指令完成这个过程。
- 在同一个任务内,段之间跳转时会涉及到堆栈的切换。低权限的段跳转到高权限的段(用户态向内核态转移) 需要把原来的ss:esp 先保存到新的栈。然后才保存 eflags,cs:eip 同样的权限则不需要保存 ss:esp
80x86保护模式要点
- 程序还是分段
- GDT 和 IDT 保存全局的代码段,数据段。
- TSS 和 LDT 保存每个进程的代码段,以及每个进程各个权限级别的栈空间。
- 任何时候都有一个当前任务的概念(就是TR寄存器中对应的TSS数据结构),执行GDT和IDT中的代码(即内核代码)时 也是处于某个任务上下文。
- 内核代码中有 cli, sti, 实际上就是改变的eflags中的一个标志位,是否允许外部中断。但是只对当前任务有效, 因为切换到其它任务后有自己的eflags。
- int 0x80 这种软件中断,以及1/0 这种统称为内部中断,就是在这条指令执行完,下一条指令执行前的中断周期, cpu检查到有异常发生。
2021/04/14