Syscall causing 'invalid opcode' interruption

105 views Asked by At

I'm implementing my own kernel. I have a problem when I try to use syscall instruction. I already defined the setup for syscall, but when i call syscall command the 'INVALID OPCODE' (Interrupt 6 (#UD)) interruption is called.

I don't know what is happening to cause this exception. The code that invoke the syscall is the last to execute, if i comment the last line when i call 'syscall' no exception is called.

My syscall setup:

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

My syscall invoke:

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

    jmp $

My syscall:

section .text
[bits 64]

[global syscall_handler]

syscall_handler:
    jmp $   ; infinite loop
    sysret

My 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)

Infos: Until now, my OS is in Long mode, has mapped the avaliable memory, but dont have any setup for ring 3, so all code is executed in ring 0, because of this, the base segments I use in the syscall setup is 0x8 for kernel and user.

0

There are 0 answers