Page 1 of 1

Why does syscall is causing Page fault at address 0x0?

Posted: Thu Jun 19, 2025 8:10 am
by gamingjam60
My user Program is

Code: Select all

[BITS 64]
global _start

section .text
_start:
    ;syscall(SYSCALL_PRINT, (uint64_t)msg, 0)
    mov     rax, 1                  ; SYSCALL_PRINT = 1
    lea     rdi, [rel msg]          ; First argument: pointer to message
    xor     rsi, rsi                ; Second argument (not used)
    syscall                         ; Perform syscall

    ; syscall(SYSCALL_EXIT, 0, 0)
    mov     rax, 3                  ; SYSCALL_EXIT = 3
    xor     rdi, rdi                ; First argument: exit code 0
    xor     rsi, rsi                ; Second argument (unused)
    syscall                         ; Exit syscall

.hang:
    jmp     .hang                   ; If syscall fails, loop forever

section .data
msg: db "Hello from user via syscall!", 0
Store syscall_entry by

Code: Select all

write_msr(MSR_LSTAR, (uint64_t)&syscall_entry);
and

Code: Select all

syscall_entry:
    swapgs                    ; switch GS base with KernelGSBase

    mov [gs:0x10], rsp        ; Save old kernel RSP
    mov rsp, [gs:8]           ; Load per-core kernel stack
    sub rsp, 8*8              ; make room for pushes (align if needed)

    ; Don't touch RCX or R11! They are used by sysretq.
    push rcx 
    push r11 

    ; Save other registers
    push rdi
    push rsi
    push rdx
    push rax
    push r8
    push r9

    ; Arguments to syscall_handler(syscall_num, arg1)
    mov rsi, rdi         ; user argument → RSI
    mov rdi, rax         ; syscall number → RDI

    call syscall_handler

    ; Restore registers
    pop r9
    pop r8
    pop rax
    pop rdx
    pop rsi
    pop rdi

    pop r11 
    pop rcx 

    swapgs              ; switch GS base with KernelGSBase

    ; Return to user — RCX and R11 must still hold original values
    sysretq

You can see I have stored rcx but

Code: Select all

void syscall_handler(uint64_t syscall_num, uint64_t arg1, uint64_t arg2) {

    switch(syscall_num) {
        case SYSCALL_PRINT:
            const char* str = (const char*)arg1;
            printf("%s\n", str);  
            break;

        case SYSCALL_READ:
            // Handle read syscall
            char* user_buf = (char*)arg1;
            uint64_t size = arg2;
            // Implement read logic here
            break;

        case SYSCALL_EXIT:
            printf("User requested shell exit.\n");
            break;

        default:
            printf("Unknown syscall: %d\n", (int) syscall_num);
    }
}
When I am using switch_to_user_mode(user_stack, user_entry);

Code: Select all

Hello from user via syscall!
Page fault! ( Page not present, User-mode, Instruction fetch, ) at address 0x0
Halting the system due to page fault.
successfully run first syscall_handler after jumping in address 0x0 but it should call next syscall which is mentioned in user_program. Why it is happening?

Re: Why does syscall is causing Page fault at address 0x0?

Posted: Thu Jun 19, 2025 7:21 pm
by Octocontrabass
gamingjam60 wrote: Thu Jun 19, 2025 8:10 am

Code: Select all

    sysretq
Doesn't NASM warn you about this?

Re: Why does syscall is causing Page fault at address 0x0?

Posted: Fri Jun 20, 2025 7:13 am
by gamingjam60
Octocontrabass wrote: Thu Jun 19, 2025 7:21 pm
gamingjam60 wrote: Thu Jun 19, 2025 8:10 am

Code: Select all

    sysretq
Doesn't NASM warn you about this?
No warning for sysretq.

I added following lines

Code: Select all

...
 mov r12, rcx                ; Save RCX to check it
 mov r13, rdi                ; Save RDI into r13
 mov rdi, r12                ; Move RCX value to first argument
 call print_hex              ; Or any function that prints uint64_t
 mov rdi, r13                ; restore rdi with original value
 ...
 
The output:

Code: Select all

Switching into usermode: user_entry_addr-0x401000, user_stack_addr-0x1000
0x401011Unknown syscall: 736
Page fault! ( Page not present, User-mode, Instruction fetch, ) at address 0x2EB
Halting the system due to page fault.
The above output is showing RCX=0x401011 what might seem to be right and also 2nd syscall run after 1st syscall but not third .

But without above lines the output becomes

Code: Select all

Switching into usermode: user_entry_addr-0x401000, user_stack_addr-0x1000
Hello from user via syscall!
Page fault! ( Page not present, User-mode, Instruction fetch, ) at address 0x0
Halting the system due to page fault.
The output is showing only 1st syscall is run and jump into 0x0.

What is happening in here?

Re: Why does syscall is causing Page fault at address 0x0?

Posted: Fri Jun 20, 2025 8:46 am
by iansjack
gamingjam60 wrote: Fri Jun 20, 2025 7:13 amNo warning for sysretq.
Does that mean you did get some warnings?

You won't get a warning specifying "sysretq" but you should get the warning

"warning: label alone on a line without a colon might be in error [-w+label-orphan]".

(Unless you have disabled warnings, and why would anyone do that?)