sys: Refactor GDT initialization, enhance syscall handling, and improve user mode entry

Finally we got usermode working again, It took awhile but we got it done. A few things we did in this commit:

- Simplified GDT entry initialization in gdt.c for kernel and user segments.
- Fixed TSS structure for task switching.
- Implemented cr2 handling in a page fault.
- Enhanced user stack setup in usermode.c to return the correct RSP.
- Improved syscall implementation in syscall.c, including new syscall numbers.
- Updated syscall entry to correctly handle context switching and argument passing.
- Refactored init.c to demonstrate file operations using syscalls.
- Added new syscalls for file operations in syscalls.h.
- Modified VFS to handle leading slashes in paths correctly.

Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
kaguya
2026-04-26 02:06:28 -04:00
parent 3b6e68bc16
commit e6e8b1209b
19 changed files with 263 additions and 266 deletions
Binary file not shown.
+13 -25
View File
@@ -50,39 +50,27 @@ void x86_64_GDT_Initialize(void) {
// null desc
memset(&gdt.entries[0], 0, sizeof(struct gdt_desc));
// Kernel code 0x08
// Kernel code
gdt.entries[1].limit = 0xFFFF;
gdt.entries[1].base_low = 0;
gdt.entries[1].base_mid = 0;
gdt.entries[1].base_hi = 0;
gdt.entries[1].access = 0b10011010;
gdt.entries[1].granularity = 0b00100000;
gdt.entries[1].access = 0x9A;
gdt.entries[1].granularity = 0x20;
// Kernel data 0x10
// Kernel data
gdt.entries[2].limit = 0xFFFF;
gdt.entries[2].base_low = 0;
gdt.entries[2].base_mid = 0;
gdt.entries[2].base_hi = 0;
gdt.entries[2].access = 0b10010010;
gdt.entries[2].granularity = 0b00100000;
gdt.entries[2].access = 0x92;
gdt.entries[2].granularity = 0x00;
// User data 0x1B
// User data
gdt.entries[3].limit = 0xFFFF;
gdt.entries[3].base_low = 0;
gdt.entries[3].base_mid = 0;
gdt.entries[3].base_hi = 0;
gdt.entries[3].access = 0b11110010;
gdt.entries[3].granularity = 0b00100000;
gdt.entries[3].access = 0xF2;
gdt.entries[3].granularity = 0x00;
// User code 0x23
// User code
gdt.entries[4].limit = 0xFFFF;
gdt.entries[4].base_low = 0;
gdt.entries[4].base_mid = 0;
gdt.entries[4].base_hi = 0;
gdt.entries[4].access = 0b11111010;
gdt.entries[4].granularity = 0b00100000;
gdt.entries[4].access = 0xFA;
gdt.entries[4].granularity = 0x20;
// TSS
// TSS 0x28
gdt.tss.length = sizeof(struct tss);
gdt.tss.flags1 = 0b10001001;
+2
View File
@@ -30,5 +30,7 @@ struct tss {
uint16_t iomap_base;
} __attribute__((packed));
extern struct tss kernel_tss;
void x86_64_GDT_Initialize(void);
void gdt_load_tss(size_t addr);
+2 -2
View File
@@ -6,13 +6,13 @@
gdt_reload:
lgdt [rip + gdt_pointer]
push 8
push 0x08
lea rax, [rip + .flush]
push rax
lretq
.flush:
mov eax, 0x10
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
+42
View File
@@ -5,6 +5,12 @@
#include "idt.h"
#define MODULE "ISR"
static inline uint64_t x86_64_read_cr2(void)
{
uint64_t value;
__asm__ volatile ("mov %%cr2, %0" : "=r"(value));
return value;
}
ISRHandler g_ISRHandlers[256];
static const char* const g_Exceptions[] = {
@@ -52,8 +58,44 @@ void x86_64_ISR_Initialize(void)
x86_64_IDT_DisableGate(0x80); // syscall gate if you want
}
void page_fault_handler(Registers* regs, uint64_t cr2)
{
// You can decode error bits here:
// bit 0: present
// bit 1: write
// bit 2: user-mode
// bit 3: reserved overwrite
// bit 4: instruction fetch
log_crit(MODULE, "KERNEL PANIC! Exception %d (%s)", regs->interrupt, g_Exceptions[regs->interrupt]);
log_crit(MODULE, " rax=%x rbx=%x rcx=%x rdx=%x rsi=%x rdi=%x",
regs->rax, regs->rbx, regs->rcx, regs->rdx, regs->rsi, regs->rdi);
log_crit(MODULE, " rsp=%x rbp=%x rip=%x rflags=%x cs=%x ss=%x",
regs->rsp, regs->rbp, regs->rip, regs->rflags, regs->cs, regs->ss);
log_crit(MODULE, " interrupt=%x errorcode=%x", regs->interrupt, regs->error);
log_crit("PAGEFAULT", "Fault at address %lx (rip=%lx, err=%x)",
cr2, regs->rip, regs->error);
log_crit(MODULE, "KERNEL PANIC!");
x86_64_Panic(); // or attempt recovery
}
void __attribute__((used)) x86_64_ISR_Handler(Registers* regs)
{
if (regs->interrupt == 14)
{
uint64_t cr2 = x86_64_read_cr2();
page_fault_handler(regs, cr2);
}
if (g_ISRHandlers[regs->interrupt])
g_ISRHandlers[regs->interrupt](regs);
else if (regs->interrupt >= 32)
+40 -22
View File
@@ -22,32 +22,41 @@ static uint64_t user_stack_phys_base = 0;
extern struct pagemap *kernel_pagemap;
static void setup_user_stack()
uintptr_t setup_user_stack(void)
{
// Allocate contiguous physical pages for the stack
user_stack_phys_base = (uint64_t)pmm_alloc(USER_STACK_PAGES);
if (!user_stack_phys_base) {
printf("Failed to allocate user stack pages!\n");
for (;;);
}
uintptr_t stack_bottom = USER_STACK_TOP - USER_STACK_SIZE;
uintptr_t virt = stack_bottom;
for (int i = 0; i < USER_STACK_PAGES; i++) {
uint64_t phys = user_stack_phys_base + i * PAGE_SIZE;
uintptr_t virt = stack_bottom + i * PAGE_SIZE;
uintptr_t phys = user_stack_phys_base + i * PAGE_SIZE;
if (!vmm_map_page(kernel_pagemap, virt, phys,
PAGE_READ | PAGE_WRITE | PAGE_USER, Size4KiB)) {
printf("Failed to map user stack at 0x%lx\n", virt);
if (!vmm_map_page(kernel_pagemap,
virt,
phys,
PAGE_READ | PAGE_WRITE | PAGE_USER,
Size4KiB))
{
printf("Failed mapping user stack page\n");
for (;;);
}
virt += PAGE_SIZE;
}
// Zero the stack
memset((void*)stack_bottom, 0, USER_STACK_SIZE);
// zero physical page through HHDM
//memset((void *)(phys + g_hhdm_offset), 0, PAGE_SIZE);
}
uintptr_t rsp = USER_STACK_TOP;
rsp &= ~0xFULL;
return rsp;
}
// usermode.c
@@ -56,20 +65,30 @@ void enter_user_mode(uint64_t rip, uint64_t rsp)
{
asm volatile(
"cli\n\t"
"mov $0x1B, %%ax\n\t" // User data segment
"mov $0x1B, %%ax\n\t"
"mov %%ax, %%ds\n\t"
"mov %%ax, %%es\n\t"
"mov %%ax, %%fs\n\t"
"mov %%ax, %%gs\n\t"
"push $0x1B\n\t" // SS (user data)
"push %1\n\t" // RSP
// SS
"pushq $0x1B\n\t"
// RSP
"pushq %1\n\t"
// RFLAGS
"pushfq\n\t"
"pop %%rax\n\t"
"or $0x200, %%rax\n\t" // Enable interrupts
"push %%rax\n\t" // RFLAGS
"push $0x23\n\t" // CS (user code)
"push %0\n\t" // RIP
"or $0x200, %%rax\n\t"
"push %%rax\n\t"
// CS
"pushq $0x23\n\t"
// RIP
"pushq %0\n\t"
"iretq\n\t"
:
: "r"(rip), "r"(rsp)
@@ -91,10 +110,9 @@ void start_userspace(void)
for(;;);
}
setup_user_stack();
uintptr_t rsp = setup_user_stack();
printf("Jumping to user entry: 0x%lx with stack top 0x%lx\n",
(uint64_t)entry, USER_STACK_TOP);
printf("Entering usermode RIP=%p RSP=%p\n", entry, (void*)rsp);
enter_user_mode((uint64_t)entry, USER_STACK_TOP);
enter_user_mode((uint64_t)entry, (rsp & ~0xFULL));
}
+9 -3
View File
@@ -3,6 +3,7 @@
#include <arch/x86_64/e9.h>
#include "mp/spinlock.h"
#include "stdio.h"
#include "mm/memory.h"
#include "string.h"
static spinlock_t s_vfs_lock = SPINLOCK_INIT;
@@ -36,8 +37,11 @@ int VFS_RegisterCharDev(const char* path,
fd_t VFS_Open_internal(const char* path)
{
const char* p = path;
if (*p == '/') p++;
for (int i = 0; i < s_num_chardevs; i++) {
if (strcmp(s_chardevs[i].path, path) == 0) {
if (strcmp(s_chardevs[i].path, p) == 0) {
for (int fd = 4; fd < VFS_MAX_FDS; fd++) {
if (!vfs_fd_table[fd].used) {
vfs_fd_table[fd].used = true;
@@ -51,7 +55,9 @@ fd_t VFS_Open_internal(const char* path)
}
}
uint32_t ino = ext2_resolve_path(path);
uint32_t ino = ext2_resolve_path(p);
if (ino == 0)
return -1;
@@ -124,7 +130,7 @@ int VFS_Read(fd_t fd, uint8_t* buf, size_t size)
size = file_size - file->offset;
// naive: read whole file then slice
uint8_t tmp[file_size];
uint8_t* tmp = kmalloc(file_size);
if (!ext2_read_file(&file->ext2.inode, tmp))
return -1;
+11 -116
View File
@@ -126,15 +126,15 @@ static uacpi_interrupt_ret handle_power_button(uacpi_handle ctx) {
return UACPI_INTERRUPT_HANDLED;
}
// The following will be our kernel's entry point.
// If renaming kmain() to something else, make sure to change the
// linker script accordingly.
void kmain(void) {
// Ensure the bootloader actually understands our base revision (see spec).
if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) {
hcf();
}
uint64_t rsp;
asm volatile("mov %%rsp, %0" : "=r"(rsp));
// Ensure we got a framebuffer.
if (framebuffer_request.response == NULL
|| framebuffer_request.response->framebuffer_count < 1) {
@@ -180,8 +180,6 @@ void kmain(void) {
}
x86_64_DisableInterrupts();
uint32_t msr_lo, msr_hi;
asm volatile("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(0x1B));
msr_lo &= ~(1 << 11);
@@ -204,7 +202,6 @@ void kmain(void) {
calibrate_tsc();
//while (1) asm volatile("hlt");
ata_init();
@@ -220,102 +217,8 @@ void kmain(void) {
hcf();
}
ext2_read_root_dir();
printf("test");
uint8_t* file_buffer = kmalloc(4096); // adjust if needed
uint32_t file_size = 0;
if (ext2_read_file_from_root("a.txt", file_buffer, &file_size)) {
printf("Read file (size %d):\n", file_size);
for (uint32_t i = 0; i < file_size; i++) {
printf("%c", file_buffer[i]); // or printf("%c", ...)
}
printf("\n");
} else {
printf("Failed to read file\n");
}
kfree(file_buffer);
uint8_t* file2_buffer = kmalloc(4096); // adjust if needed
uint32_t file2_size = 0;
if (ext2_read_file_from_root("dogcatman.txt", file2_buffer, &file2_size)) {
printf("Read file (size %d):\n", file2_size);
for (uint32_t i = 0; i < file2_size; i++) {
printf("%c", file2_buffer[i]); // or printf("%c", ...)
}
printf("\n");
} else {
printf("Failed to read file\n");
}
kfree(file2_buffer);
uint8_t* file3_buffer = kmalloc(4096); // adjust if needed
uint32_t file3_size = 0;
if (ext2_read_file_from_root("test.txt", file3_buffer, &file3_size)) {
printf("Read file (size %d):\n", file3_size);
for (uint32_t i = 0; i < file3_size; i++) {
printf("%c", file3_buffer[i]); // or printf("%c", ...)
}
printf("\n");
} else {
printf("Failed to read file\n");
}
kfree(file3_buffer);
uint8_t* file4_buffer = kmalloc(4096); // adjust if needed
uint32_t file4_size = 0;
if (ext2_read_file_from_root("qwerty.txt", file4_buffer, &file4_size)) {
printf("Read file (size %d):\n", file4_size);
for (uint32_t i = 0; i < file4_size; i++) {
printf("%c", file4_buffer[i]); // or printf("%c", ...)
}
printf("\n");
} else {
printf("Failed to read file\n");
}
kfree(file4_buffer);
const char* msg = "hello i wrote from kernel!";
ext2_write_file_from_root("qwerty.txt", (const uint8_t*)msg, strlen(msg), EXT2_WRITE_APPEND);
uint8_t* file5_buffer = kmalloc(4096); // adjust if needed
uint32_t file5_size = 0;
if (ext2_read_file_from_root("qwerty.txt", file5_buffer, &file5_size)) {
printf("Read file (size %d):\n", file5_size);
for (uint32_t i = 0; i < file5_size; i++) {
printf("%c", file5_buffer[i]); // or printf("%c", ...)
}
printf("\n");
} else {
printf("Failed to read file\n");
}
kfree(file5_buffer);
uint32_t inum = ext2_resolve_path("charlie.tga");
if (!inum) {
@@ -365,19 +268,7 @@ void kmain(void) {
//clear_screen(0xFF1E1E1E);
fd_t fd = VFS_Open("/a.txt");
if (fd < 0) {
printf("asudg");
}
uint8_t buf[128];
int n;
while ((n = VFS_Read(fd, buf, sizeof(buf))) > 0)
{
VFS_Write(VFS_FD_STDOUT, buf, n);
}
VFS_Close(fd);
printf("\nKirkOS %s\n", KIRKOS_VERSION);
x86_64_EnableInterrupts();
@@ -454,8 +345,12 @@ void kmain(void) {
input_init();
ps2_kbd_init();
//syscall_init();
//start_userspace();
gdt_load_tss((size_t)&kernel_tss);
kernel_tss.rsp0 = rsp;
syscall_init();
start_userspace();
// We're done, just hang...
hcf();
+1 -24
View File
@@ -11,7 +11,7 @@ static uint64_t free_pages = 0;
void pmm_init(struct limine_memmap_entry **memmap, size_t memmapentries) {
uint64_t highest_addr = 0;
size_t memmap_entries = memmapentries - 1;
size_t memmap_entries = memmapentries;
for (size_t i = 0; i < memmap_entries; i++) {
if (memmap[i]->type != LIMINE_MEMMAP_USABLE &&
memmap[i]->type != LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE)
@@ -22,43 +22,20 @@ void pmm_init(struct limine_memmap_entry **memmap, size_t memmapentries) {
total_page_count = highest_addr / PAGE_SIZE;
size_t bitmap_size = ALIGN_UP(total_page_count / 8, PAGE_SIZE);
printf("MEM_PHYS_OFFSET: %x\n", MEM_PHYS_OFFSET);
printf("memmap_entries: %u\n", memmap_entries);
// Find place for bitmap
for (size_t i = 0; i < memmap_entries; i++) {
printf("i: %u\n", i);
if (memmap[i]->type != LIMINE_MEMMAP_USABLE) continue;
if (memmap[i]->length >= bitmap_size) {
printf("test\n");
bitmap = (uint8_t *)(memmap[i]->base + MEM_PHYS_OFFSET);
printf("bitmap: %x\n", bitmap);
printf("bitmap_size: %x\n", bitmap_size);
memset(bitmap, 0xFF, bitmap_size);
printf("test3\n");
printf("memmap base: %x\n", memmap[i]->base);
printf("memmap length: %x\n", memmap[i]->length);
memmap[i]->base += bitmap_size;
memmap[i]->length -= bitmap_size;
printf("test4\n");
printf("memmap[7]->type: %u\n", memmap[7]->type);
printf("memmap[8]->type: %u\n", memmap[8]->type);
printf("memmap[9]->type: %u\n", memmap[9]->type);
printf("memmap[10]->type: %u\n", memmap[10]->type); //#define LIMINE_MEMMAP_USABLE 0
printf("memmap[11]->type: %u\n", memmap[11]->type); //#define LIMINE_MEMMAP_RESERVED 1
printf("memmap[12]->type: %u\n", memmap[12]->type); //#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2
printf("memmap[13]->type: %u\n", memmap[13]->type); //#define LIMINE_MEMMAP_ACPI_NVS 3
printf("memmap[14]->type: %u\n", memmap[14]->type); //#define LIMINE_MEMMAP_BAD_MEMORY 4
printf("memmap[15]->type: %u\n", memmap[15]->type); //#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5
printf("memmap[16]->type: %u\n", memmap[16]->type); //#define LIMINE_MEMMAP_EXECUTABLE_AND_MODULES 6
printf("memmap[17]->type: %u\n", memmap[17]->type); //#define LIMINE_MEMMAP_FRAMEBUFFER 7
//printf("memmap[18]->type: %u\n", memmap[18]->type); //#define LIMINE_MEMMAP_RESERVED_MAPPED 8, commented out because it triple faults for some reason
break;
}
}
printf("break");
// Mark usable pages free
for (size_t i = 0; i < memmap_entries; i++) {
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include <stdint.h>
struct cpu_local {
uint64_t self; // +0x00 (GS:0x00)
uint64_t user_rsp; // +0x08 (GS:0x08) — saved user RSP on syscall entry
uint64_t kernel_rsp; // +0x10 (GS:0x10) — kernel stack for syscall handler
};
+55 -32
View File
@@ -1,54 +1,72 @@
#include <stdint.h>
#include "stdio.h"
#include "mp/percpu.h"
#include "fs/vfs.h"
#include "syscall.h"
#define MSR_EFER 0xC0000080
#define MSR_STAR 0xC0000081
#define MSR_LSTAR 0xC0000082
#define MSR_SFMASK 0xC0000084
#define MSR_KERNEL_GSBASE 0xC0000102
#define EFER_SCE (1 << 0)
static struct cpu_local g_cpu_local;
static uint8_t g_syscall_kstack[16384] __attribute__((aligned(16)));
static inline void wrmsr(uint32_t msr, uint64_t value)
{
uint32_t lo = value & 0xFFFFFFFF;
uint32_t hi = value >> 32;
asm volatile("wrmsr"
:
: "c"(msr), "a"(lo), "d"(hi));
asm volatile("wrmsr" :: "c"(msr), "a"((uint32_t)value), "d"((uint32_t)(value >> 32)));
}
static inline uint64_t rdmsr(uint32_t msr)
{
uint32_t lo, hi;
asm volatile("rdmsr"
: "=a"(lo), "=d"(hi)
: "c"(msr));
asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
return ((uint64_t)hi << 32) | lo;
}
void syscall_handler(uint64_t rax, // syscall num
uint64_t rdi, // arg1
uint64_t rsi, // arg2
uint64_t rdx, // arg3
uint64_t r10, // arg4
uint64_t r8, // arg5
uint64_t r9) // arg6
uint64_t syscall_handler(uint64_t num,
uint64_t arg1, uint64_t arg2, uint64_t arg3,
uint64_t arg4, uint64_t arg5, uint64_t arg6)
{
switch (rax)
(void)arg4; (void)arg5; (void)arg6;
switch (num)
{
case 1: // write (int fd, const void *buf, size_t count);
int c = (char)rdi;
printf("%c", c);
break;
case SYS_READ:
{
int fd = (int)arg1;
uint8_t* buf = (uint8_t*)arg2;
size_t len = (size_t)arg3;
case 2:
// exit
break;
return (uint64_t)VFS_Read(fd, buf, len);
}
case SYS_WRITE:
{
int fd = (int)arg1;
uint8_t* buf = (uint8_t*)arg2;
size_t len = (size_t)arg3;
return (uint64_t)VFS_Write(fd, buf, len);
}
case SYS_OPEN:
{
const char* path = (const char*)arg1;
return (uint64_t)VFS_Open(path);
}
case SYS_CLOSE:
{
int fd = (int)arg1;
return (uint64_t)VFS_Close(fd);
}
default:
break;
return (uint64_t)-1;
}
}
@@ -56,21 +74,26 @@ void syscall_init(void)
{
extern void syscall_entry(void);
uint64_t kernel_cs = 0x08;
uint64_t user_cs = 0x23;
// ── per-CPU local block ─────────────────────────────────────────────
g_cpu_local.self = (uint64_t)&g_cpu_local;
g_cpu_local.kernel_rsp = (uint64_t)(g_syscall_kstack + sizeof(g_syscall_kstack));
uint64_t star =
((uint64_t)kernel_cs << 32) |
((uint64_t)user_cs << 48);
// After swapgs in syscall_entry, GS points here.
wrmsr(MSR_KERNEL_GSBASE, (uint64_t)&g_cpu_local);
// ── STAR ────────────────────────────────────────────────────────────
// Bits [47:32]: SYSCALL loads CS = 0x08 (kernel code), SS = 0x10 (kernel data)
// Bits [63:48]: SYSRET loads CS = (base+16)|3 = 0x23, SS = (base+8)|3 = 0x1B
// → base must be 0x10
uint64_t star = ((uint64_t)0x08 << 32) | ((uint64_t)0x10 << 48);
wrmsr(MSR_STAR, star);
wrmsr(MSR_LSTAR, (uint64_t)syscall_entry);
uint64_t efer = rdmsr(MSR_EFER);
efer |= (1 << 0); // SYSCALL/SYSRET enable
efer |= EFER_SCE;
wrmsr(MSR_EFER, efer);
// disable interrupts on syscall entry
// Mask IF so interrupts are off during the syscall handler
wrmsr(MSR_SFMASK, (1 << 9));
}
+7
View File
@@ -1,3 +1,10 @@
#pragma once
#define SYS_READ 0
#define SYS_WRITE 1
#define SYS_OPEN 2
#define SYS_CLOSE 3
void syscall_init(void);
+24 -17
View File
@@ -3,30 +3,37 @@
syscall_entry:
swapgs
mov %rsp, %gs:0x10 # save user rsp for per cpu
# Save user RSP, switch to kernel stack
mov %rsp, %gs:0x08 # cpu_local.user_rsp = user RSP
mov %gs:0x10, %rsp # RSP = cpu_local.kernel_rsp
push %rcx # save user rip
push %r11 # save rflags
push %rcx # save user RIP (syscall puts it in RCX)
push %r11 # save user RFLAGS
# Save original args before we clobber them
push %rdi # orig rdi (arg1)
push %rsi # orig rsi (arg2)
push %rdx # orig rdx (arg3)
# Shuffle syscall regs SysV args for syscall_handler
# On entry: rax=num rdi=a1 rsi=a2 rdx=a3 r10=a4 r8=a5 r9=a6
# We want: rdi=num rsi=a1 rdx=a2 rcx=a3 r8=a4 r9=a5
#
# Move r8/r10 FIRST before the push/pop clobbers them
mov %r8, %r9 # r9 = orig r8 (a5)
mov %r10, %r8 # r8 = orig r10 (a4)
# Handle r8/r9 before r8 gets clobbered
mov %r8, %r9 # r9 = orig r8 (6th param)
mov %r10, %r8 # r8 = orig r10 (5th param)
push %rdi # save orig rdi (a1)
push %rsi # save orig rsi (a2)
push %rdx # save orig rdx (a3)
# Pop in reverse order to place into correct SysV registers
pop %rcx # rcx = orig rdx (4th param)
pop %rdx # rdx = orig rsi (3rd param)
pop %rsi # rsi = orig rdi (2nd param)
mov %rax, %rdi # rdi = rax (1st param = syscall number)
pop %rcx # rcx = a3 (4th param)
pop %rdx # rdx = a2 (3rd param)
pop %rsi # rsi = a1 (2nd param)
mov %rax, %rdi # rdi = num (1st param)
call syscall_handler
pop %r11
pop %rcx
# Restore user context
pop %r11 # user RFLAGS
pop %rcx # user RIP
mov %gs:0x08, %rsp # restore user RSP this was the missing piece
swapgs
sysretq
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+2 -7
View File
@@ -1,12 +1,7 @@
.section .text
.global _start
.global main
_start:
mov $1, %rax
mov $'H', %rdi
syscall
mov $1, %rax
mov $'i', %rdi
syscall
call main
1: jmp 1b
+5 -1
View File
@@ -1,5 +1,10 @@
#pragma once
#define SYS_READ 0
#define SYS_WRITE 1
#define SYS_OPEN 2
#define SYS_CLOSE 3
static inline long syscall(long num, long a1, long a2, long a3)
{
long ret;
@@ -8,7 +13,6 @@ static inline long syscall(long num, long a1, long a2, long a3)
"syscall"
: "=a"(ret)
: "a"(num), "D"(a1), "S"(a2), "d"(a3)
:
);
return ret;
+28 -4
View File
@@ -1,5 +1,7 @@
#include "../include/syscalls.h"
#define STDOUT 1
unsigned strlen(const char* str)
{
unsigned len = 0;
@@ -8,15 +10,37 @@ unsigned strlen(const char* str)
++len;
++str;
}
return len;
}
void main()
{
syscall(1, 'A', 0, 0);
syscall(1, 'B', 0, 0);
syscall(1, 'C', 0, 0);
const char* path = "/qwerty.txt";
const char* msg = "Suki Suki Daisuki Kekkon Shiyo, my honey!";
char buf[128];
// ── open file ─────────────────────────────
long fd = syscall(SYS_OPEN, (long)path, 0, 0);
// ── write message ─────────────────────────
syscall(SYS_WRITE, fd, (long)msg, strlen(msg));
// ── close ────────────────────────────────
syscall(SYS_CLOSE, fd, 0, 0);
// ── reopen ───────────────────────────────
fd = syscall(SYS_OPEN, (long)path, 0, 0);
// ── read into buffer ─────────────────────
long n = syscall(SYS_READ, fd, (long)buf, sizeof(buf));
// ── close ────────────────────────────────
syscall(SYS_CLOSE, fd, 0, 0);
// ── print buffer to stdout ───────────────
syscall(SYS_WRITE, STDOUT, (long)buf, n);
// ── done ────────────────────────────────
while (1);
}