ARI*_*TOS 0 assembly system-calls protected-mode osdev interrupt-handling
我正在组装中构建一个32位操作系统.
我已经设置了IDT,我正在通过int指令处理程序interruptus .
如何启用syscall和sysenter说明以及如何处理/返回?
诚然,syscall指令在32位基于英特尔处理器的支持,所以我不能用它?sysret教学不安全是真的吗?在某处存在一个教程吗?
编辑:我的主要问题是如何启用syscall和sysenter说明!(没有重复)
有关详细信息sysenter,请参阅OSdev wiki,包括有关如何避免安全/安全问题的说明.另请参阅Intel/AMD手册.它们涉及操作系统开发人员需要的许多细节.有关链接,请参阅x86标记wiki.
各种系统调用说明概述:
int:永远可用(8086)far 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位入口点)Run Code Online (Sandbox Code Playgroud)/* ... * - 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.
也许玩具操作系统可以使用它而不用担心任何问题使它不适合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 0x80或sysenter(或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用这种方式描述:
Run Code Online (Sandbox Code Playgroud)/* * 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.
如果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模式中有任何类似的错误.
| 归档时间: |
|
| 查看次数: |
929 次 |
| 最近记录: |