当系统调用或中断出现时,Linux内核如何在用户模式和内核模式堆栈之间切换?我的意思是确切的机制 - 用户模式堆栈指针发生了什么变化,内核模式堆栈指针从哪里来?硬件会执行什么操作,软件必须执行什么操作?
当系统调用或中断出现时,Linux内核如何在用户模式和内核模式堆栈之间切换?我的意思是确切的机制 - 用户模式堆栈指针发生了什么变化,内核模式堆栈指针从哪里来?硬件会执行什么操作,软件必须执行什么操作?
以下所有单词都和x86有关。
我将描述整个系统调用路径,本答案将包含所需信息。
首先,您需要了解什么是interrupt descriptor table。这个表存储异常/中断向量的地址。系统调用是一种异常。为了引发异常,用户代码执行
int x
int 0x80
int指令是一个复杂的多步指令。以下是它的解释:
1.) 从IDT(IDT地址存储在特殊寄存器中)中提取描述符并检查CPL <= DPL。CPL是当前特权级,可以从CS寄存器中读取。DPL存储在IDT描述符中。 由此可知 - 您不能通过int指令直接从用户空间生成某些异常(例如页面故障)。如果尝试这样做,将会得到一般保护异常。
2.) 处理器切换到在TSS中定义的堆栈。 TSS已经初始化,并且已经包含了ESP和SS的值,这些值保存了内核堆栈地址。因此,现在ESP指向内核堆栈。
3.) 处理器将用户空间寄存器ss、esp、eflags、cs、eip
推送到新切换的内核堆栈中。我们需要在系统调用服务后返回,对吧?
4.) 接下来处理器从IDT描述符中设置CS和EIP。该地址定义了异常向量入口点。
5.) 现在我们处于内核中的系统调用异常向量。
关于ARM的几句话。ARM没有TSS,而是有分别针对SVC和USR模式的堆栈指针。如果您感兴趣,可以查看陷阱入口代码。
有趣的链接: MIT JOS实验室3, XV6手册。