switch_to_user.c
Code: Select all
#define KERNEL_CS 0x08 | 0
#define KERNEL_SS 0x10 | 0
#define USER_CS 0x18 | 3 // 0x1B
#define USER_SS 0x20 | 3 // 0x23
#define STACK_SIZE 0x4000 // 16 kb
uint64_t stack_addr;
uint64_t code_addr;
extern void user_stub();
extern void user_stub_end();
extern void switch_to_user_mode(uint64_t stack_addr, uint64_t code_addr);
uint64_t create_user_function() {
uint64_t user_addr = (uint64_t) uheap_alloc(0x1000); // Allocate a page in user space
if (!user_addr) return 0;
// printf("Created a userspace pointer at: %x\n", user_addr);
uint64_t user_stub_size = ((uint64_t)&user_stub_end - (uint64_t)&user_stub);
memcpy((void *)user_addr, (void *)&user_stub, user_stub_size); // Copy function code
// printf("memory copied from kernel function: %x into user function: %x\n", (uint64_t)&user_stub, (uint64_t) user_addr);
return user_addr; // Return the user-accessible function pointer
}
void init_user_mode(){
stack_addr = (uint64_t) uheap_alloc(STACK_SIZE);
code_addr = (uint64_t) create_user_function();
printf("Starting Switching to the user mode\n");
switch_to_user_mode(stack_addr, code_addr);
syscall(1, (uint64_t)(char *)"Successfully Switch To User_mode implemented\n", 0);
}
user_stub.asm
Code: Select all
section .text
global user_stub
global user_stub_end
user_stub:
mov rax, 1
mov rdi, msg
syscall
mov rax, 3
syscall
.hang:
hlt
jmp .hang
user_stub_end:
section .data
msg: db "Hello from userspace!", 10, 0 ; 10 is asci code of newline character \n
Code: Select all
#define MSR_EFER 0xC0000080
#define MSR_STAR 0xC0000081
#define MSR_LSTAR 0xC0000082
#define MSR_SFMASK 0xC0000084
#define EFER_SCE (1 << 0) // Enable SYSCALL/SYSRET
#define USER_CS 0x1B // User mode code selector (0x18 | 3)
#define KERNEL_CS 0x08 // Kernel mode code selector
extern void syscall_entry(); // from syscall_entry.asm
extern ring_buffer_t* keyboard_buffer; // define into keyboard.c
static inline uint64_t read_msr(uint32_t msr) {
uint32_t low, high;
asm volatile ("rdmsr" : "=a"(low), "=d"(high) : "c"(msr));
return ((uint64_t)high << 32) | low;
}
static inline void write_msr(uint32_t msr, uint64_t value) {
uint32_t low = value & 0xFFFFFFFF;
uint32_t high = value >> 32;
asm volatile ("wrmsr" :: "c"(msr), "a"(low), "d"(high));
}
void init_syscall() {
// Enable SYSCALL/SYSRET by setting SCE in IA32_EFER.
uint64_t efer = read_msr(MSR_EFER);
efer |= EFER_SCE;
write_msr(MSR_EFER, efer);
// STAR: sets up CS/SS for kernel (bits 32-47) and user (bits 48-63)
uint64_t star = ((uint64_t)USER_CS << 48) | ((uint64_t)KERNEL_CS << 32);
write_msr(MSR_STAR, star);
// LSTAR: address of our syscall entry point.
write_msr(MSR_LSTAR, (uint64_t)&syscall_entry);
// SFMASK: mask IF (and maybe other flags) when transitioning.
write_msr(MSR_SFMASK, 1 << 9);
}
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(str);
break;
}
case SYSCALL_READ: {
char* user_buf = (char*)arg1;
uint64_t size = arg2;
}
case SYSCALL_EXIT: {
printf("User requested shell exit.\n");
while (1) __asm__("hlt");
break;
}
default:
printf("Unknown syscall: %d\n", (int)syscall_num);
break;
}
}
void syscall(uint64_t num, uint64_t arg1, uint64_t arg2) {
__asm__ volatile (
"syscall"
:
: "a"(num), "D"(arg1), "S"(arg2)
: "rcx", "r11", "memory"
);
}
Code: Select all
global syscall_entry
extern syscall_handler
section .text
syscall_entry:
; Don't touch RCX or R11! They are used by sysretq.
; Save other registers if needed
push rdi
push rsi
push rdx
push rax
; 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 rax
pop rdx
pop rsi
pop rdi
; Return to user — RCX and R11 must still hold original values
sysretq
Code: Select all
init_syscall();
init_user_mode();
char *temp = "Hello\n";
syscall(1, (uint64_t)temp, 0);
Code: Select all
Starting Switching to the user mode
Hello from userspace!
Hello from userspace!
Hello from userspace!
Hello from userspace!
Hello from userspace!
Hello from userspace!
Hello from userspace!
Hello from userspace!
Hello from userspace!
....