You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义内核调用syscall触发INVALID OPCODE中断求助

自定义内核中syscall触发#UD异常的问题

我正在实现自定义内核,已完成syscall配置,但调用syscall指令时触发**INVALID OPCODE(Interrupt 6 #UD)**中断。注释掉syscall调用行后异常消失,不清楚原因。

环境信息:系统处于长模式,已映射可用内存,未配置Ring3,所有代码运行于Ring0,因此syscall配置中内核和用户段基址均使用0x8。


相关代码

syscall配置代码

setup_syscall:
    ; Set (0xC0000081) bits 32-47 are kernel segment base, bits 48-63 are user segment base (ON GDT)
    mov ecx, 0xC0000081
    rdmsr
    
    ; setup with kernel segment inside and outside syscall
    mov edx, 0x0808
    wrmsr

    ; (0xC0000082) The kernel's RIP SYSCALL entry for 64 bit software
    mov ecx, 0xC0000082
    mov rdx, syscall_handler
    mov eax,edx
    shr rdx,32
    wrmsr

    
    ; Set IA32_EFER.SCE (0xC0000080) and SCE (SYSCALL Enable) is its 0th bit
    mov ecx,0xC0000080 
    xor rax,rax
    rdmsr
    bts rax,1
    wrmsr

    ret

syscall调用代码

test_syscall:
    ; Enable and setup syscall 
    call setup_syscall
    ; test syscall
    syscall

    jmp $

syscall处理函数

section .text
[bits 64]

[global syscall_handler]

syscall_handler:
    jmp $   ; infinite loop
    sysret

GDT配置

ALIGN 4
GDT:
.Null:
    ; Null Descriptor - should be present.
    dq 0
.Code: equ $ - GDT
    ; 64-bit code descriptor (exec/read).
    dq (1<<43)|(1<<44)|(1<<47)|(1<<53)|(1<<41)
.Data:
    ; 64-bit code descriptor (exec/read).
    dq (1<<44)|(1<<47)|(1<<41)
.Pointer:
    dw $ - GDT - 1                    ; 16-bit Size (Limit) of GDT.
    dd GDT                            ; 32-bit Base Address of GDT. (CPU will zero extend to 64-bit)

问题分析与解决

核心问题1:IA32_EFER.SCE位设置错误

IA32_EFER寄存器的SCE位是第0位,但代码中用bts rax,1置位了第1位,这根本没启用SYSCALL/SYSRET指令支持。CPU未开启SCE时,syscall属于无效操作码,直接触发#UD。

修正:将bts rax,1改为bts rax,0。

核心问题2:IA32_STAR寄存器配置不完整

IA32_STAR(0xC0000081)的低32位(EAX)未清零,rdmsr后保留的旧值会干扰寄存器配置。同时,即使不用Ring3,寄存器格式要求用户段选择子的RPL必须为3,内核段选择子RPL必须为0。

修正:

mov ecx, 0xC0000081
rdmsr
mov edx, 0x0808          ; 位47:32=0x08(内核代码段选择子),位63:48=0x08(用户代码段选择子占位)
xor eax, eax             ; 低32位清零,避免旧值干扰
wrmsr

核心问题3:IA32_LSTAR寄存器配置错误

IA32_LSTAR(0xC0000082)是64位SYSCALL的目标RIP,原代码拆分地址的逻辑错误,会导致高32位地址设置异常。

修正:

mov ecx, 0xC0000082
mov rax, syscall_handler
mov edx, eax
shr edx, 32              ; 地址高32位存入EDX
and eax, 0xFFFFFFFF      ; 地址低32位存入EAX
wrmsr

额外注意

GDT的Data段描述符注释有误,应标注为数据段(读写);若后续需要SYSRET返回,用户段选择子对应的GDT项DPL需设为3,符合寄存器格式要求。


内容的提问来源于stack exchange,提问作者Crazynds

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 11:57:42