OsDev系统调用/ sysret和sysenter/sysexit指令启用

ARI*_*TOS 0 assembly system-calls protected-mode osdev interrupt-handling

我正在组装中构建一个32位操作系统.
我已经设置了IDT,我正在通过int指令处理程序interruptus .

如何启用syscallsysenter说明以及如何处理/返回?
诚然,syscall指令在32位基于英特尔处理器的支持,所以我不能用它?sysret教学不安全是真的吗?在某处存在一个教程吗?

编辑:我的主要问题是如何启用syscallsysenter说明!(没有重复)

Pet*_*des 8

有关详细信息sysenter,请参阅OSdev wiki,包括有关如何避免安全/安全问题的说明.另请参阅Intel/AMD手册.它们涉及操作系统开发人员需要的许多细节.有关链接,请参阅标记wiki.


各种系统调用说明概述:

  • int:永远可用(8086)
  • 陷阱通过执行无效指令,显然是在80386上进入内核的最快方式.(但事实并非如此).
  • 呼叫门(即afar call).有关该陷阱和陷阱的详细信息,请参阅OSdev链接.
  • sysenter:( http://wiki.osdev.org/Sysenter)在x86-64存在之前由英特尔推出,不久之后(多年前)被AMD采用.适用于所有现代x86 CPU.非常简约的设计,需要用户空间合作才能使内核能够返回,因为它无法在任何地方保存EIP,ESP或EFLAGS.

    Linux支持32位和64位内核,仅用于32位进程的系统调用.IDK,如果你可以设计一个内核,它也可以用于64位系统调用.(我知道这不是问题,但它是相关的.)

    使用sysenter需要用户空间合作来提供返回地址并保存自己的ESP和EFLAGS.在Linux中,内核导出一段代码页面,该页面具有此舞蹈的用户空间.用户空间需要使用call此代码而不是sysenter直接使用,但您可以根据需要自由设计操作系统.如果你没有在其他地方找到一个例子,那么看看这个舞蹈双方的Linux代码可能会很有用.

  • syscall来自64位用户空间:随处可用,因为英特尔与AMD64的其余部分一起实施.精心设计的界面在进入内核之前屏蔽RFLAGS(带有可配置的掩码),因此您可以避免竞争窗口(如果您必须手动禁用中断cli).与swapgs内核一起使用以访问其堆栈等.

    在主流x86操作系统(如Linux)上,syscall是进行64位系统调用的唯一方法.

  • syscall来自32位用户空间:与长模式完全不同的指令syscall,仅适用于AMD CPU.内核端接口对于32位内核(传统模式)与运行32位用户空间(compat模式)的64位内核不同.

    Linux内核对它有一些有用的评论:

entry_64_compat.S32位SYSCALL条目(syscall进入64位内核的32位入口点)

 /* ...
 *  - Most programmers do not directly target AMD CPUs, and the 32-bit
 *    SYSCALL instruction does not exist on Intel CPUs.  Even on AMD
 *    CPUs, Linux disables the SYSCALL instruction on 32-bit kernels
 *    because the SYSCALL instruction in legacy/native 32-bit mode (as
 *    opposed to compat mode) is sufficiently poorly designed as to be
 *    essentially unusable.
Run Code Online (Sandbox Code Playgroud)

也许玩具操作系统可以使用它而不用担心任何问题使它不适合Linux,IDK.但除非你只是好奇,否则不要浪费你的时间.OTOH,如果你对操作系统和CPU设计感兴趣,找出ISA设计的错误可能会很有趣.

BTW,当AMD设计AMD64时,他们从amd64邮件列表上的Linux内核开发者那里获得了一些反馈,改进了64位设计syscall(可配置掩盖RFLAGS),因为他们的初始设计对Linux来说是个问题.链接到此答案中的归档邮件列表帖子.


建议:sysenter用于32位内核.它应该可以在任何地方使用,包括多年来在AMD CPU上使用.int 0x80如果您想添加第二个兼容性ABI ,那么不支持它的古老CPU可以使用ABI(或您为操作系统选择的任何数字).

Linux内核入口点得到很好的评论,写得相当可读.编写时如果在64位代码中使用32位int 0x80 Linux ABI会发生什么?,我有一个简单的时间来计算使用syscall(本机64位系统调用)int 0x80sysenter(或32位系统调用,通常来自compat模式,但int 0x80支持64 位)的入口点中发生了什么但仍然会调用32位ABI!)如果启用了各种跟踪/调试,会发生一系列复杂的事情,但其他部分相当容易理解.请参阅该答案,了解Linux的一些系统调用处理内部.

arch/x86/entry,这些是感兴趣的主要文件:

  • entry_32.S:用于从用户空间进入的32位内核代码.(传统模式)
  • entry_64_compat.S:用于从32位用户空间(compat模式 - >长模式)进入的64位内核代码.
  • entry_64.S:用于从64位用户空间(长模式 - >长模式)进入的64位内核代码.

您应该能够在sysenter舞蹈的用户空间一侧找到Linux的VDSO代码,该代码将内核传递给返回用户空间所需的值.(什么是更好的"int 0x80"或"系统调用"?).相关:什么是更好的"int 0x80"或"系统调用"?Linux系统调用的权威指南将提供有关Linux所做设计选择的一些有用信息.


sysret教学不安全是真的吗?

当返回到64位用户空间时,Intel和AMD都有非规范RIP的单独错误.例如在英特尔上,Linuxentry_64.S用这种方式描述:

/*
 * On Intel CPUs, SYSRET with non-canonical RCX/RIP will #GP
 * in kernel space.  This essentially lets the user take over
 * the kernel, since userspace controls RSP.
Run Code Online (Sandbox Code Playgroud)

如果ptrace系统调用(例如,由调试器进行)将进程的保存值更改RIP为非规范地址,则会发生这种情况.Linux检查它是否可以使用sysret,如果不使用它的iret返回路径.(sysret路径足够快,值得做额外的工作来检查它是否安全).

请注意,如果系统调用阻塞/休眠,则用户空间的整数寄存器状态的"主副本"位于其内核堆栈上,系统调用入口点将其推送到其内核堆栈.(在Linux中.其他设计是可能的!)但无论如何,这就是为什么有可能最终得到用户空间无法运行的奇怪的保存状态syscall(因为它会导致jmp非规范地址出错),或者saved_rcx != saved_RIP(64位syscall设置RCX = RIP,R11 = RFLAGS(屏蔽前),因此它会破坏RCX和R11,但允许内核恢复RIP和RFLAGS.)

我不知道32位是如何syscall工作的,抱歉我在这里找到了主题.但我怀疑你可能已经读到的有关sysret不安全的内容是谈论64位内核.

IDK,如果在32位内核sysret或64位内核sysret到compat模式中有任何类似的错误.