X86 使用iret切换到用户模式
我正在编写一个小操作系统,它将以用户模式(特权级别3)执行一些代码。从用户级代码中,我想调用一个中断返回到打印消息的操作系统。现在我真的不关心我的中断处理程序如何接受参数或类似的东西,我真的只希望一个中断处理程序通知我(用户)代码已经执行 我的问题是:如何在用户模式下运行代码?我有一个函数,用于设置带有代码段和数据段(都具有用户模式权限)的本地描述符表。我不明白的是如何将这些段加载到X86 使用iret切换到用户模式,x86,nasm,osdev,X86,Nasm,Osdev,我正在编写一个小操作系统,它将以用户模式(特权级别3)执行一些代码。从用户级代码中,我想调用一个中断返回到打印消息的操作系统。现在我真的不关心我的中断处理程序如何接受参数或类似的东西,我真的只希望一个中断处理程序通知我(用户)代码已经执行 我的问题是:如何在用户模式下运行代码?我有一个函数,用于设置带有代码段和数据段(都具有用户模式权限)的本地描述符表。我不明白的是如何将这些段加载到cs、ss和ds。我成功地加载了我的LDT,但我不知道如何实际使用它。我听说我应该使用iret,但我不知道具体怎么
cs
、ss
和ds
。我成功地加载了我的LDT,但我不知道如何实际使用它。我听说我应该使用iret
,但我不知道具体怎么用
我的另一个问题是我的中断处理程序应该如何工作。假设我为向量号0x40安装了一个中断处理程序,我想打印“hello,user mode!”。我知道如何设置一个中断处理程序,但我并不完全理解当从用户模式进入内核中断处理程序时,如何切换上下文。我知道cs
寄存器必须更改,因为我的例程将从IDT条目中指定的代码段运行。我也知道堆栈选择器可能也会改变,但我不能确定这一点
有人能给我解释一下,当一个中断门被调用时,上下文会发生什么变化吗 可以使用
iret
进入第3环,因为它的工作方式已经被记录在案。当您收到中断时,处理器将按下:
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以找到新的堆栈段和指针。它适当地更改
ss
和esp
,然后将旧值推送到新堆栈中。它不会更改任何数据段寄存器。如果需要访问ISR中的内存,则必须手动执行此操作。您也可以执行retf。远返回到权限较低的代码段将导致新的ss和sp从权限堆栈中弹出
只要确保对远呼叫执行远返回,对中断执行IRET。它们之间的唯一区别是堆栈上存在标志,但明智的做法是不要混淆它们
另外,不要忘记异常有时会在堆栈上推送错误代码。好的,你回答了我的问题,还有更多!我现在的理解是,我需要一个包含我的内核堆栈的TSS,等等。谢谢你的帮助。我登录只是为了升级这个!谢谢对于其他人,我也推荐osdev和英特尔ISA手册。他们真的把事情弄清楚了。你说iNet不改变数据段是什么意思?你说的是通用寄存器中的值吗?@DanHoynoski不,我指的是数据段寄存器,
ds
,es
,等等。它们没有改变,所以任何使用的都必须手动设置。