使用 iret 切换到用户模式

发布于 2024-11-27 03:22:03 字数 570 浏览 1 评论 0原文

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

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

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

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

I am writing a small OS that will execute some code in user mode (privilege level 3). From that user level code, I want to call an interrupt back to the OS that prints a message. Right now I don't really care how my interrupt handler takes arguments or anything like that, I really just want an interrupt handler to inform me (the user) that the code has executed.

My question is: how do I run code in user mode? I have a function that sets up a Local Descriptor Table with a code segment and data segment (both with user mode privileges). What I dont understand is how I am supposed to load these segments into cs, ss, and ds. I successfully load the my LDT, but I do not know how to actually use it. I have heard that I should use iret, but I don't understand exactly how.

Another question that I have is how my interrupt handler should work. Let's say I install an interrupt handler for vector number 0x40, which I want to print "hello, user mode!". I know how to setup an interrupt handler, but I don't exactly understand how the context will be switched when entering a kernel interrupt handler from user mode. I know that the cs register must change, since my routine will be running from the code segment specified in my IDT entry. I also understand that the stack selector probably changes as well, but I cannot be certain of this.

Could someone please explain to me what context changes are made when an interrupt gate is called?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

删除会话 2024-12-04 03:22:03

可以使用 iret 来完成环 3,因为它的工作方式已被记录。当您收到中断时,处理器会压入:

  1. 堆栈段和指针 (ss:esp),作为 4 个字
  2. EFLAGS
  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 中的内存,则必须手动执行此操作。

Getting to ring 3 can be done using iret because the way it works has been documented. When you receive an interrupt, the processor pushes:

  1. The stack segment and pointer (ss:esp), as 4 words
  2. EFLAGS
  3. The return code segment and instruction pointer (cs:eip), as 4 words
  4. An error code, if required.

iret works by undoing steps 1-3 (The ISR is responsible for undoing step 4 if necessary). We can use this fact to get to ring 3 by pushing the required information to the stack and issuing an iret instruction. Make sure you have the proper CPL in your code and stack segments (the low two bits should be set in each). However, iret doesn't change any of the data segments, so you will need to change them manually. You use the mov instruction to do this, but you will not be able to read data outside the stack between doing this and switching rings.

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

If you want a complete, working example, see this tutorial.


When an interrupt is issued, the processor reads your IDT to get the proper code segment and instruction pointer for the ISR. It then looks at your TSS to find the new stack segment and pointer. It changes ss and esp appropriately, and then pushes the old values to the new stack. It does not change any of the data segment registers. You must do this manually if you need to access memory in your ISR.

阳光①夏 2024-12-04 03:22:03

您还可以进行 retf。远返回到特权级别较低的代码段将导致新的 ss 和 sp 从特权堆栈中弹出。

只需确保对远调用执行远返回,对中断执行 iret。它们之间的唯一区别是堆栈上是否存在标志,但明智的做法是不要将它们混淆。

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

You can also do a retf. A far return to a less privileged code segment will cause the new ss and sp to be popped off of the privileged stack.

Just make sure that you do far returns for far calls and irets for interrupts. The only difference between them is the presence of flags on the stack, but it's wise not ot mix them up.

Also, don't forget that exceptions sometimes push error codes on the stack.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文