14

我正在编写一个小型操作系统,它将在用户模式(权限级别 3)下执行一些代码。从该用户级代码中,我想将中断调用回打印消息的操作系统。现在我真的不在乎我的中断处理程序如何接受参数或类似的东西,我真的只是想要一个中断处理程序来通知我(用户)代码已经执行。

我的问题是:如何在用户模式下运行代码?我有一个函数可以设置一个带有代码段和数据段的本地描述符表(都具有用户模式权限)。我不明白我应该如何将这些段加载到csssds. 我成功加载了我的 LDT,但我不知道如何实际使用它。我听说我应该使用iret,但我不明白如何。

我的另一个问题是我的中断处理程序应该如何工作。假设我为向量编号 0x40 安装了一个中断处理程序,我想打印“你好,用户模式!”。我知道如何设置中断处理程序,但我不完全了解从用户模式进入内核中断处理程序时如何切换上下文。我知道cs寄存器必须更改,因为我的例程将从 IDT 条目中指定的代码段运行。我也知道堆栈选择器也可能会发生变化,但我不能确定这一点。

有人可以向我解释一下调用中断门时会发生什么上下文变化吗?

4

2 回答 2

29

可以使用 3 号响铃,iret因为它的工作方式已记录在案。当您收到中断时,处理器会推送:

  1. 堆栈段和指针 (ss:esp),为 4 个字
  2. 标志
  3. 返回代码段和指令指针 (cs:eip),为 4 个字
  4. 错误代码(如果需要)。

iret通过撤消步骤 1-3 来工作(如果需要,ISR 负责撤消步骤 4)。我们可以利用这个事实通过将所需信息压入堆栈并发出iret指令来到达环 3。确保您的代码和堆栈段中有正确的 CPL(低两位应在每个中设置)。但是,iret不会更改任何数据段,因此您需要手动更改它们。您使用该mov指令执行此操作,但在执行此操作和切换环之间您将无法读取堆栈外的数据。

cli
mov   ax, Ring3_DS
mov   ds, eax
push  dword Ring3_SS
push  dword Ring3_ESP
pushfd
or    dword [esp], 0x200 // Set IF in EFLAGS so that interrupts will be reenabled in user mode
push  dword Ring3_CS
push  dword Ring3_EIP
iret

如果您想要一个完整的工作示例,请参阅本教程


发出中断时,处理器会读取您的 IDT 以获取 ISR 的正确代码段和指令指针。然后它会查看您的 TSS 以找到新的堆栈段和指针。它会适当地更改ssesp然后将旧值推送到新堆栈。它不会更改任何数据段寄存器。如果您需要访问 ISR 中的内存,则必须手动执行此操作。

于 2011-07-31T23:08:32.117 回答
1

你也可以做一个 retf。远返回到特权较低的代码段将导致新的 ss 和 sp 从特权堆栈中弹出。

只要确保你为远调用和中断做远返回。它们之间的唯一区别是堆栈上存在标志,但不要混淆它们是明智的。

另外,不要忘记异常有时会将错误代码推入堆栈。

于 2015-03-24T03:46:21.210 回答