Page 1 of 1

syscall: returning throws exception

Posted: Wed Mar 05, 2025 4:28 pm
by SanderR
Hello all,

I wrote a systemcall implementation and when I call the systemcall in kernel mode it works well, but when I try to return, it throws a exception (0x0E)

kernel:

Code: Select all

void initialise_syscall(){
    // https://wiki.osdev.org/SYSENTER
    uint32_t alpha;
    uint32_t beta;
    cpu_get_specific_registers(0xC0000080,&alpha,&beta);
    if(!(alpha & 1)){
        alpha |= 1;
        cpu_set_specific_registers(0xC0000080,alpha,beta);
    }
    alpha = (uint32_t)((uint64_t)&syscallentrypoint);
    beta = 0x8 | ( 0x0018 << 17 );
    cpu_set_specific_registers(0xC0000081,alpha,beta);
    cpu_get_specific_registers(0xC0000082,&alpha,&beta);
    alpha = (uint32_t)((uint64_t)&syscallentrypoint);
    cpu_set_specific_registers(0xC0000082,alpha,beta);
    cpu_get_specific_registers(0xC0000083,&alpha,&beta);
    alpha = (uint32_t)((uint64_t)&syscallentrypoint);
    cpu_set_specific_registers(0xC0000083,alpha,beta);

    syscall_exstack = (uint64_t) malloc(0x1000);
}

 void syscallprobe(){
    if(syscall_rax==1){
        if(syscall_rdi!=1){
            printk("syscall: print to something else then screen!\n");
            return;
        }
        for(uint64_t i = 0 ; i < syscall_rdx ; i++){
            printk("%c",((uint8_t*)syscall_rsi)[i]);
        }
    }else{
        printk("SYSCALL\n");
        printk("- rax %x \n",syscall_rax);
        printk("- rbx %x \n",syscall_rbx);
        printk("- rcx %x \n",syscall_rcx);
        printk("- rdx %x \n",syscall_rdx);
        printk("- rsi %x \n",syscall_rsi);
        printk("- rdi %x \n",syscall_rdi);
        printk("- rsp %x \n",syscall_rsp);
        printk("- rbp %x \n",syscall_rbp);
    }
    // printk((char*) syscall_rsi);
}

[global syscallentrypoint]
[extern syscallprobe]
[extern syscall_rax]
[extern syscall_rbx]
[extern syscall_rcx]
[extern syscall_rdx]
[extern syscall_rsi]
[extern syscall_rdi]
[extern syscall_rsp]
[extern syscall_rbp]
[extern syscall_sp]
[extern syscall_exstack]

syscallentrypoint:
    mov qword [syscall_rax],rax
    mov qword [syscall_rbx],rbx
    mov qword [syscall_rcx],rcx
    mov qword [syscall_rdx],rdx
    mov qword [syscall_rsi],rsi
    mov qword [syscall_rdi],rdi
    mov qword [syscall_rsp],rsp
    mov qword [syscall_rbp],rbp
    mov rsp,qword [syscall_exstack]
    call syscallprobe
    mov rax, qword [syscall_rax]
    mov rbx, qword [syscall_rbx]
    mov rcx, qword [syscall_rcx]
    mov rdx, qword [syscall_rdx]
    mov rsi, qword [syscall_rsi]
    mov rdi, qword [syscall_rdi]
    ; mov rsp, qword [syscall_rsp]
    ; mov rbp, qword [syscall_rbp]
    iretq
testing program:

Code: Select all

        .global _start

        .text
_start:
        # write(1, message, 13)
        mov     $1, %rax                # system call 1 is write
        mov     $1, %rdi                # file handle 1 is stdout
        lea     message(%rip), %rsi     # address of string to output
        mov     $13, %rdx               # number of bytes
        syscall

        # exit(0)
        mov     $60, %rax               # system call 60 is exit
        xor     %rdi, %rdi              # return code 0
        syscall

.section .rodata           # read-only data section
message:
        .ascii  "Hello, World\n"
Does anyone have a idea what I have done wrong?
Thanks in advantage

Re: syscall: returning throws exception

Posted: Wed Mar 05, 2025 9:54 pm
by Octocontrabass
SanderR wrote: Wed Mar 05, 2025 4:28 pm

Code: Select all

    alpha = (uint32_t)((uint64_t)&syscallentrypoint);
    beta = 0x8 | ( 0x0018 << 17 );
    cpu_set_specific_registers(0xC0000081,alpha,beta);
The lower 32 bits of STAR are unused in long mode. Also, I don't like your variable and function names...
SanderR wrote: Wed Mar 05, 2025 4:28 pm

Code: Select all

    cpu_get_specific_registers(0xC0000082,&alpha,&beta);
    alpha = (uint32_t)((uint64_t)&syscallentrypoint);
    cpu_set_specific_registers(0xC0000082,alpha,beta);
LSTAR contains a 64-bit address. You need to set all 64 bits, not just the lower 32 bits.
SanderR wrote: Wed Mar 05, 2025 4:28 pm

Code: Select all

    cpu_get_specific_registers(0xC0000083,&alpha,&beta);
    alpha = (uint32_t)((uint64_t)&syscallentrypoint);
    cpu_set_specific_registers(0xC0000083,alpha,beta);
CSTAR also contains a 64-bit address. You need to set all 64 bits. You typically want CSTAR to point to a different entry point than LSTAR, since the entry point is the only way to tell the difference between SYSCALL in 64-bit mode and SYSCALL in compatibility mode. (If you're not using compatibility mode, you don't need to set CSTAR.)

It looks like you didn't set FMASK? I hope you didn't skip it, it's pretty important.
SanderR wrote: Wed Mar 05, 2025 4:28 pm

Code: Select all

    syscall_exstack = (uint64_t) malloc(0x1000);
Which end of the stack is this variable supposed to represent?
SanderR wrote: Wed Mar 05, 2025 4:28 pm

Code: Select all

    mov qword [syscall_rax],rax
    mov qword [syscall_rbx],rbx
    mov qword [syscall_rcx],rcx
    mov qword [syscall_rdx],rdx
    mov qword [syscall_rsi],rsi
    mov qword [syscall_rdi],rdi
    mov qword [syscall_rsp],rsp
    mov qword [syscall_rbp],rbp
What about the other eight registers? Also, if you use SWAPGS, you can have per-CPU variables instead of global variables.
SanderR wrote: Wed Mar 05, 2025 4:28 pm

Code: Select all

    mov rsp,qword [syscall_exstack]
Which end of the stack is this variable supposed to represent?
SanderR wrote: Wed Mar 05, 2025 4:28 pm

Code: Select all

    iretq
IRETQ is not going to do anything useful if you haven't pushed appropriate values on the stack. Did you perhaps want to use O64 SYSRET here?