具有TSS的基于软件的上下文切换如何工作? [英] How does a software-based context-switch with TSS work?

查看:150
本文介绍了具有TSS的基于软件的上下文切换如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解TSS(任务状态段)的简单说明以及如何将其用于基于软件的上下文切换.

I would like to know a simple explanation for TSS (Task State Segment) and how it is used to do software-based context-switches.

推荐答案

首先, TSS是历史疣.一次(又称:1980年代初),英特尔公司的人坚称,硬件上下文切换而不是软件上下文切换是一个好主意.他们错了.硬件上下文切换有几个明显的缺点,而且由于从未适当实施,因此性能很差.由于所有这些原因,甚至没有理智的操作系统实现它,再加上它比分段的可移植性更差.有关详细信息,请参见 OSDevers的晦涩之处.

First of all, the TSS is a historical wart. Once in a time (a.k.a: early 1980's), people at Intel tought that hardware context-switching, instead of software context-switching, was a great idea. They were greatly wrong. Hardware context-switching has several noticeable disadvantages, and, as it was never implemented appropiately, had miserable performance. No sane OS even implemented it due to all of that, plus the fact that it's even less portable than segmentation. See the obscure corner of OSDevers for details.

现在,关于任务状态段.如果有任何OS实现了硬件上下文切换,则其目的是代表一个任务".可以将线程和进程都表示为任务",但通常,在我们使用硬件上下文切换的少数代码中,它表示一个简单的进程. TSS会保存诸如任务的通用寄存器内容,控制寄存器(CR0,CR2,CR3和CR4;没有CR1),CPU标志和指令指针等内容.

Now, with respect to the Task State Segment. If any ever OS implemented hardware context-switching, it's purpose is to represent a "task". It's possible to represent both threads and processes as "tasks", but more often than not, in the few code we have using hardware context-switching, it represents a simple process. The TSS would hold stuff such as the task's general purpose register contents, the control registers (CR0, CR2, CR3, and CR4; there's no CR1), CPU flags and instruction pointer, etc...

但是,在现实世界中,软件执行所有上下文切换,而我们只有104字节长的结构,这几乎是无用的.但是,当我们谈论英特尔时,它从未被弃用/删除,并且操作系统必须对其进行处理.

However, in the real world, where software performs all context switches, we are left with a 104-byte long structure which is (almost) useless. However, as we're talking about Intel, it was never deprecated/removed, and OSes have to deal with it.

问题实际上很简单.假设您正在典型的用户模式过程中运行典型的foo()函数.突然,您(用户)按下Windows/Meta/Super/无论如何呼叫它键,以启动您的邮件客户端.结果,从键盘向中断控制器(8259A PIC或IOAPIC)发送了一个中断请求(IRQ).然后,中断控制器安排事物以触发CPU中断. CPU进入特权级别0,将寄存器与中断号一起推送,并调用内核模式代码来处理这种情况.等待!推东西?在哪里?当然,在堆栈上!但是,为了定义堆栈"而从哪里获取堆栈指针?

The problem is actually pretty simple. Suppose you're running your typical foo() function in your typical user-mode process. Suddenly, you, the user, press the Windows/Meta/Super/however-you-call-it key in order to launch your mail client. As a result, an interrupt request (IRQ) is sent from the keyboard into the interrupt controller (either a 8259A PIC or a IOAPIC). Then, the interrupt controller arranges things in order to trigger a CPU interrupt. The CPU enters into privilege level 0, The registers are pushed, along with the interrupt number, and kernel-mode code is invoked to handle the situation. Wait! Pushing stuff? Where? On the stack, of course! But, where is the stack pointer taken from in order to define a "stack"?

如果您碰巧使用了用户模式堆栈指针,则会发生 坏事,并且可以利用巨大的安全漏洞.如果堆栈指针指向无效地址会怎样?可能会发生.毕竟,严格来说,堆栈指针只是另一个通用寄存器,众所周知,汇编程序员会以这种方式使用它,以确保内核安全.

If you happened to use the user-mode stack pointer, bad things will happen, and a giant security exploit would be available. What would happen if the stack pointer pointed into an invalid address? It could happen. After all, strictly speaking, the stack pointer is just another general purpose register, and assembly programmers are known to use it that way for hardcoreness' sake.

尝试将内容推送到那里会产生CPU异常,太好了!而且,由于双重错误(尝试处理中断时发生的异常)将再次尝试推入无效指针,因此,操作系统的最恶梦变成了事实:三次错误.您是否曾经看到计算机在没有任何事先建议的情况下突然重启?那是三重故障(或电源故障).操作系统没有任何变化可以处理三重故障,它只是重新启动了所有内容.

An attempt to push stuff there would generate a CPU exception, nice! And, as double faults (exceptions that occur while attempting to handle interrupts) would yet again attempt to push over the invalid pointer, the worst nightmare of an operating system becomes true: a triple fault. Have you ever seen your computer suddenly reboot without any prior advice? That is a triple fault (or a power failure). The OS has no change to handle a triple fault, it just reboots everything.

很好,系统已重新启动.但是,更糟的事情可能发生了.如果攻击者有意地写了一个关键内核变量(!)的地址,并以正确的顺序放置了他想要写的值,那么随着获得超级用户特权变得比以往任何时候都容易,最大的特权提升漏洞就将泛滥成灾! GDB,内核的配置(可在/proc/config.gz中找到)以及编译内核所使用的GCC版本足以完成此任务.

Great, the system has rebooted. But, something worse could have happened. Had an attacker purposefully written the address of a critical kernel variable (!), and put the values that him would like written there in the right order, let the greatest privilege elevation exploit reign as getting superuser privileges becomes easier than ever! GDB, the kernel's configuration (found in /proc/config.gz, and the GCC version the kernel was compiled with are more than enough to do this.

现在,回到TSS,碰巧前面提到的结构包含在特权级别3(用户模式)时在中断时加载的堆栈指针和堆栈段寄存器的值.内核将其设置为指向内核域中的安全堆栈.结果,系统中每个线程都有一个内核堆栈",而系统中每个逻辑CPU都有一个TSS.切换线程后,内核只需在正确的TSS中更改这两个变量.而且,每个逻辑CPU不能只有一个内核堆栈,因为内核本身(在大多数情况下)可能是被抢占的.

Now, back to the TSS, it happens that the aforementioned structure contains the values of the stack pointer and the stack segment register that are loaded upon a interrupt while in privilege level 3 (user-mode). The kernel sets this to point to a safe stack in kernel-land. As a result, there's a "kernel stack" per thread in the system, and a TSS per each logical CPU in the system. Upon thread switching, the kernel just changes these two variables in the right TSS. And no, there can't be a single kernel stack per Logical CPU, because the kernel itself may be preempted (most of the time).

我希望这能给您带来启发!

I hope this has led some light on you!

这篇关于具有TSS的基于软件的上下文切换如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆