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:
Binary file not shown.
+13
-25
@@ -50,39 +50,27 @@ void x86_64_GDT_Initialize(void) {
|
|||||||
|
|
||||||
// null desc
|
// null desc
|
||||||
memset(&gdt.entries[0], 0, sizeof(struct gdt_desc));
|
memset(&gdt.entries[0], 0, sizeof(struct gdt_desc));
|
||||||
// Kernel code 0x08
|
// Kernel code
|
||||||
gdt.entries[1].limit = 0xFFFF;
|
gdt.entries[1].limit = 0xFFFF;
|
||||||
gdt.entries[1].base_low = 0;
|
gdt.entries[1].access = 0x9A;
|
||||||
gdt.entries[1].base_mid = 0;
|
gdt.entries[1].granularity = 0x20;
|
||||||
gdt.entries[1].base_hi = 0;
|
|
||||||
gdt.entries[1].access = 0b10011010;
|
|
||||||
gdt.entries[1].granularity = 0b00100000;
|
|
||||||
|
|
||||||
// Kernel data 0x10
|
// Kernel data
|
||||||
gdt.entries[2].limit = 0xFFFF;
|
gdt.entries[2].limit = 0xFFFF;
|
||||||
gdt.entries[2].base_low = 0;
|
gdt.entries[2].access = 0x92;
|
||||||
gdt.entries[2].base_mid = 0;
|
gdt.entries[2].granularity = 0x00;
|
||||||
gdt.entries[2].base_hi = 0;
|
|
||||||
gdt.entries[2].access = 0b10010010;
|
|
||||||
gdt.entries[2].granularity = 0b00100000;
|
|
||||||
|
|
||||||
// User data 0x1B
|
// User data
|
||||||
gdt.entries[3].limit = 0xFFFF;
|
gdt.entries[3].limit = 0xFFFF;
|
||||||
gdt.entries[3].base_low = 0;
|
gdt.entries[3].access = 0xF2;
|
||||||
gdt.entries[3].base_mid = 0;
|
gdt.entries[3].granularity = 0x00;
|
||||||
gdt.entries[3].base_hi = 0;
|
|
||||||
gdt.entries[3].access = 0b11110010;
|
|
||||||
gdt.entries[3].granularity = 0b00100000;
|
|
||||||
|
|
||||||
// User code 0x23
|
// User code
|
||||||
gdt.entries[4].limit = 0xFFFF;
|
gdt.entries[4].limit = 0xFFFF;
|
||||||
gdt.entries[4].base_low = 0;
|
gdt.entries[4].access = 0xFA;
|
||||||
gdt.entries[4].base_mid = 0;
|
gdt.entries[4].granularity = 0x20;
|
||||||
gdt.entries[4].base_hi = 0;
|
|
||||||
gdt.entries[4].access = 0b11111010;
|
|
||||||
gdt.entries[4].granularity = 0b00100000;
|
|
||||||
|
|
||||||
// TSS
|
// TSS 0x28
|
||||||
gdt.tss.length = sizeof(struct tss);
|
gdt.tss.length = sizeof(struct tss);
|
||||||
gdt.tss.flags1 = 0b10001001;
|
gdt.tss.flags1 = 0b10001001;
|
||||||
|
|
||||||
|
|||||||
@@ -30,5 +30,7 @@ struct tss {
|
|||||||
uint16_t iomap_base;
|
uint16_t iomap_base;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
extern struct tss kernel_tss;
|
||||||
|
|
||||||
void x86_64_GDT_Initialize(void);
|
void x86_64_GDT_Initialize(void);
|
||||||
void gdt_load_tss(size_t addr);
|
void gdt_load_tss(size_t addr);
|
||||||
@@ -6,13 +6,13 @@
|
|||||||
gdt_reload:
|
gdt_reload:
|
||||||
lgdt [rip + gdt_pointer]
|
lgdt [rip + gdt_pointer]
|
||||||
|
|
||||||
push 8
|
push 0x08
|
||||||
lea rax, [rip + .flush]
|
lea rax, [rip + .flush]
|
||||||
push rax
|
push rax
|
||||||
lretq
|
lretq
|
||||||
|
|
||||||
.flush:
|
.flush:
|
||||||
mov eax, 0x10
|
mov ax, 0x10
|
||||||
mov ds, ax
|
mov ds, ax
|
||||||
mov es, ax
|
mov es, ax
|
||||||
mov fs, ax
|
mov fs, ax
|
||||||
|
|||||||
@@ -5,6 +5,12 @@
|
|||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#define MODULE "ISR"
|
#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];
|
ISRHandler g_ISRHandlers[256];
|
||||||
static const char* const g_Exceptions[] = {
|
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
|
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)
|
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])
|
if (g_ISRHandlers[regs->interrupt])
|
||||||
g_ISRHandlers[regs->interrupt](regs);
|
g_ISRHandlers[regs->interrupt](regs);
|
||||||
else if (regs->interrupt >= 32)
|
else if (regs->interrupt >= 32)
|
||||||
|
|||||||
+40
-22
@@ -22,32 +22,41 @@ static uint64_t user_stack_phys_base = 0;
|
|||||||
|
|
||||||
extern struct pagemap *kernel_pagemap;
|
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);
|
user_stack_phys_base = (uint64_t)pmm_alloc(USER_STACK_PAGES);
|
||||||
|
|
||||||
if (!user_stack_phys_base) {
|
if (!user_stack_phys_base) {
|
||||||
printf("Failed to allocate user stack pages!\n");
|
printf("Failed to allocate user stack pages!\n");
|
||||||
for (;;);
|
for (;;);
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t stack_bottom = USER_STACK_TOP - USER_STACK_SIZE;
|
uintptr_t stack_bottom = USER_STACK_TOP - USER_STACK_SIZE;
|
||||||
uintptr_t virt = stack_bottom;
|
|
||||||
|
|
||||||
for (int i = 0; i < USER_STACK_PAGES; i++) {
|
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,
|
if (!vmm_map_page(kernel_pagemap,
|
||||||
PAGE_READ | PAGE_WRITE | PAGE_USER, Size4KiB)) {
|
virt,
|
||||||
printf("Failed to map user stack at 0x%lx\n", virt);
|
phys,
|
||||||
|
PAGE_READ | PAGE_WRITE | PAGE_USER,
|
||||||
|
Size4KiB))
|
||||||
|
{
|
||||||
|
printf("Failed mapping user stack page\n");
|
||||||
for (;;);
|
for (;;);
|
||||||
}
|
}
|
||||||
virt += PAGE_SIZE;
|
|
||||||
}
|
// zero physical page through HHDM
|
||||||
// Zero the stack
|
//memset((void *)(phys + g_hhdm_offset), 0, PAGE_SIZE);
|
||||||
memset((void*)stack_bottom, 0, USER_STACK_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uintptr_t rsp = USER_STACK_TOP;
|
||||||
|
|
||||||
|
rsp &= ~0xFULL;
|
||||||
|
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// usermode.c
|
// usermode.c
|
||||||
@@ -56,20 +65,30 @@ void enter_user_mode(uint64_t rip, uint64_t rsp)
|
|||||||
{
|
{
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"cli\n\t"
|
"cli\n\t"
|
||||||
"mov $0x1B, %%ax\n\t" // User data segment
|
"mov $0x1B, %%ax\n\t"
|
||||||
"mov %%ax, %%ds\n\t"
|
"mov %%ax, %%ds\n\t"
|
||||||
"mov %%ax, %%es\n\t"
|
"mov %%ax, %%es\n\t"
|
||||||
"mov %%ax, %%fs\n\t"
|
"mov %%ax, %%fs\n\t"
|
||||||
"mov %%ax, %%gs\n\t"
|
"mov %%ax, %%gs\n\t"
|
||||||
|
|
||||||
"push $0x1B\n\t" // SS (user data)
|
// SS
|
||||||
"push %1\n\t" // RSP
|
"pushq $0x1B\n\t"
|
||||||
|
|
||||||
|
// RSP
|
||||||
|
"pushq %1\n\t"
|
||||||
|
|
||||||
|
// RFLAGS
|
||||||
"pushfq\n\t"
|
"pushfq\n\t"
|
||||||
"pop %%rax\n\t"
|
"pop %%rax\n\t"
|
||||||
"or $0x200, %%rax\n\t" // Enable interrupts
|
"or $0x200, %%rax\n\t"
|
||||||
"push %%rax\n\t" // RFLAGS
|
"push %%rax\n\t"
|
||||||
"push $0x23\n\t" // CS (user code)
|
|
||||||
"push %0\n\t" // RIP
|
// CS
|
||||||
|
"pushq $0x23\n\t"
|
||||||
|
|
||||||
|
// RIP
|
||||||
|
"pushq %0\n\t"
|
||||||
|
|
||||||
"iretq\n\t"
|
"iretq\n\t"
|
||||||
:
|
:
|
||||||
: "r"(rip), "r"(rsp)
|
: "r"(rip), "r"(rsp)
|
||||||
@@ -91,10 +110,9 @@ void start_userspace(void)
|
|||||||
for(;;);
|
for(;;);
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_user_stack();
|
uintptr_t rsp = setup_user_stack();
|
||||||
|
|
||||||
printf("Jumping to user entry: 0x%lx with stack top 0x%lx\n",
|
printf("Entering usermode RIP=%p RSP=%p\n", entry, (void*)rsp);
|
||||||
(uint64_t)entry, USER_STACK_TOP);
|
|
||||||
|
|
||||||
enter_user_mode((uint64_t)entry, USER_STACK_TOP);
|
enter_user_mode((uint64_t)entry, (rsp & ~0xFULL));
|
||||||
}
|
}
|
||||||
+9
-3
@@ -3,6 +3,7 @@
|
|||||||
#include <arch/x86_64/e9.h>
|
#include <arch/x86_64/e9.h>
|
||||||
#include "mp/spinlock.h"
|
#include "mp/spinlock.h"
|
||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
|
#include "mm/memory.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
static spinlock_t s_vfs_lock = SPINLOCK_INIT;
|
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)
|
fd_t VFS_Open_internal(const char* path)
|
||||||
{
|
{
|
||||||
|
const char* p = path;
|
||||||
|
if (*p == '/') p++;
|
||||||
|
|
||||||
for (int i = 0; i < s_num_chardevs; i++) {
|
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++) {
|
for (int fd = 4; fd < VFS_MAX_FDS; fd++) {
|
||||||
if (!vfs_fd_table[fd].used) {
|
if (!vfs_fd_table[fd].used) {
|
||||||
vfs_fd_table[fd].used = true;
|
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)
|
if (ino == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -124,7 +130,7 @@ int VFS_Read(fd_t fd, uint8_t* buf, size_t size)
|
|||||||
size = file_size - file->offset;
|
size = file_size - file->offset;
|
||||||
|
|
||||||
// naive: read whole file then slice
|
// 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))
|
if (!ext2_read_file(&file->ext2.inode, tmp))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|||||||
+11
-116
@@ -126,15 +126,15 @@ static uacpi_interrupt_ret handle_power_button(uacpi_handle ctx) {
|
|||||||
return UACPI_INTERRUPT_HANDLED;
|
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) {
|
void kmain(void) {
|
||||||
// Ensure the bootloader actually understands our base revision (see spec).
|
|
||||||
if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) {
|
if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) {
|
||||||
hcf();
|
hcf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t rsp;
|
||||||
|
asm volatile("mov %%rsp, %0" : "=r"(rsp));
|
||||||
|
|
||||||
// Ensure we got a framebuffer.
|
// Ensure we got a framebuffer.
|
||||||
if (framebuffer_request.response == NULL
|
if (framebuffer_request.response == NULL
|
||||||
|| framebuffer_request.response->framebuffer_count < 1) {
|
|| framebuffer_request.response->framebuffer_count < 1) {
|
||||||
@@ -180,8 +180,6 @@ void kmain(void) {
|
|||||||
}
|
}
|
||||||
x86_64_DisableInterrupts();
|
x86_64_DisableInterrupts();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t msr_lo, msr_hi;
|
uint32_t msr_lo, msr_hi;
|
||||||
asm volatile("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(0x1B));
|
asm volatile("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(0x1B));
|
||||||
msr_lo &= ~(1 << 11);
|
msr_lo &= ~(1 << 11);
|
||||||
@@ -204,7 +202,6 @@ void kmain(void) {
|
|||||||
calibrate_tsc();
|
calibrate_tsc();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//while (1) asm volatile("hlt");
|
//while (1) asm volatile("hlt");
|
||||||
|
|
||||||
ata_init();
|
ata_init();
|
||||||
@@ -220,102 +217,8 @@ void kmain(void) {
|
|||||||
hcf();
|
hcf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ext2_read_root_dir();
|
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");
|
uint32_t inum = ext2_resolve_path("charlie.tga");
|
||||||
if (!inum) {
|
if (!inum) {
|
||||||
@@ -365,19 +268,7 @@ void kmain(void) {
|
|||||||
|
|
||||||
//clear_screen(0xFF1E1E1E);
|
//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);
|
printf("\nKirkOS %s\n", KIRKOS_VERSION);
|
||||||
|
|
||||||
x86_64_EnableInterrupts();
|
x86_64_EnableInterrupts();
|
||||||
@@ -454,8 +345,12 @@ void kmain(void) {
|
|||||||
input_init();
|
input_init();
|
||||||
ps2_kbd_init();
|
ps2_kbd_init();
|
||||||
|
|
||||||
//syscall_init();
|
gdt_load_tss((size_t)&kernel_tss);
|
||||||
//start_userspace();
|
kernel_tss.rsp0 = rsp;
|
||||||
|
|
||||||
|
|
||||||
|
syscall_init();
|
||||||
|
start_userspace();
|
||||||
|
|
||||||
// We're done, just hang...
|
// We're done, just hang...
|
||||||
hcf();
|
hcf();
|
||||||
|
|||||||
+1
-24
@@ -11,7 +11,7 @@ static uint64_t free_pages = 0;
|
|||||||
|
|
||||||
void pmm_init(struct limine_memmap_entry **memmap, size_t memmapentries) {
|
void pmm_init(struct limine_memmap_entry **memmap, size_t memmapentries) {
|
||||||
uint64_t highest_addr = 0;
|
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++) {
|
for (size_t i = 0; i < memmap_entries; i++) {
|
||||||
if (memmap[i]->type != LIMINE_MEMMAP_USABLE &&
|
if (memmap[i]->type != LIMINE_MEMMAP_USABLE &&
|
||||||
memmap[i]->type != LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE)
|
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;
|
total_page_count = highest_addr / PAGE_SIZE;
|
||||||
size_t bitmap_size = ALIGN_UP(total_page_count / 8, 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
|
// Find place for bitmap
|
||||||
for (size_t i = 0; i < memmap_entries; i++) {
|
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]->type != LIMINE_MEMMAP_USABLE) continue;
|
||||||
if (memmap[i]->length >= bitmap_size) {
|
if (memmap[i]->length >= bitmap_size) {
|
||||||
printf("test\n");
|
|
||||||
bitmap = (uint8_t *)(memmap[i]->base + MEM_PHYS_OFFSET);
|
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);
|
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]->base += bitmap_size;
|
||||||
memmap[i]->length -= 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
printf("break");
|
|
||||||
|
|
||||||
// Mark usable pages free
|
// Mark usable pages free
|
||||||
for (size_t i = 0; i < memmap_entries; i++) {
|
for (size_t i = 0; i < memmap_entries; i++) {
|
||||||
|
|||||||
@@ -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
@@ -1,54 +1,72 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
|
#include "mp/percpu.h"
|
||||||
#include "fs/vfs.h"
|
#include "fs/vfs.h"
|
||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
#define MSR_EFER 0xC0000080
|
#define MSR_EFER 0xC0000080
|
||||||
#define MSR_STAR 0xC0000081
|
#define MSR_STAR 0xC0000081
|
||||||
#define MSR_LSTAR 0xC0000082
|
#define MSR_LSTAR 0xC0000082
|
||||||
#define MSR_SFMASK 0xC0000084
|
#define MSR_SFMASK 0xC0000084
|
||||||
|
#define MSR_KERNEL_GSBASE 0xC0000102
|
||||||
|
|
||||||
#define EFER_SCE (1 << 0)
|
#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)
|
static inline void wrmsr(uint32_t msr, uint64_t value)
|
||||||
{
|
{
|
||||||
uint32_t lo = value & 0xFFFFFFFF;
|
asm volatile("wrmsr" :: "c"(msr), "a"((uint32_t)value), "d"((uint32_t)(value >> 32)));
|
||||||
uint32_t hi = value >> 32;
|
|
||||||
|
|
||||||
asm volatile("wrmsr"
|
|
||||||
:
|
|
||||||
: "c"(msr), "a"(lo), "d"(hi));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t rdmsr(uint32_t msr)
|
static inline uint64_t rdmsr(uint32_t msr)
|
||||||
{
|
{
|
||||||
uint32_t lo, hi;
|
uint32_t lo, hi;
|
||||||
asm volatile("rdmsr"
|
asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
|
||||||
: "=a"(lo), "=d"(hi)
|
|
||||||
: "c"(msr));
|
|
||||||
return ((uint64_t)hi << 32) | lo;
|
return ((uint64_t)hi << 32) | lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void syscall_handler(uint64_t rax, // syscall num
|
uint64_t syscall_handler(uint64_t num,
|
||||||
uint64_t rdi, // arg1
|
uint64_t arg1, uint64_t arg2, uint64_t arg3,
|
||||||
uint64_t rsi, // arg2
|
uint64_t arg4, uint64_t arg5, uint64_t arg6)
|
||||||
uint64_t rdx, // arg3
|
|
||||||
uint64_t r10, // arg4
|
|
||||||
uint64_t r8, // arg5
|
|
||||||
uint64_t r9) // arg6
|
|
||||||
{
|
{
|
||||||
switch (rax)
|
(void)arg4; (void)arg5; (void)arg6;
|
||||||
|
switch (num)
|
||||||
{
|
{
|
||||||
case 1: // write (int fd, const void *buf, size_t count);
|
case SYS_READ:
|
||||||
int c = (char)rdi;
|
{
|
||||||
printf("%c", c);
|
int fd = (int)arg1;
|
||||||
break;
|
uint8_t* buf = (uint8_t*)arg2;
|
||||||
|
size_t len = (size_t)arg3;
|
||||||
|
|
||||||
case 2:
|
return (uint64_t)VFS_Read(fd, buf, len);
|
||||||
// exit
|
}
|
||||||
break;
|
|
||||||
|
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:
|
default:
|
||||||
break;
|
return (uint64_t)-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,21 +74,26 @@ void syscall_init(void)
|
|||||||
{
|
{
|
||||||
extern void syscall_entry(void);
|
extern void syscall_entry(void);
|
||||||
|
|
||||||
uint64_t kernel_cs = 0x08;
|
// ── per-CPU local block ─────────────────────────────────────────────
|
||||||
uint64_t user_cs = 0x23;
|
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 =
|
// After swapgs in syscall_entry, GS points here.
|
||||||
((uint64_t)kernel_cs << 32) |
|
wrmsr(MSR_KERNEL_GSBASE, (uint64_t)&g_cpu_local);
|
||||||
((uint64_t)user_cs << 48);
|
|
||||||
|
|
||||||
|
// ── 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_STAR, star);
|
||||||
|
|
||||||
wrmsr(MSR_LSTAR, (uint64_t)syscall_entry);
|
wrmsr(MSR_LSTAR, (uint64_t)syscall_entry);
|
||||||
|
|
||||||
uint64_t efer = rdmsr(MSR_EFER);
|
uint64_t efer = rdmsr(MSR_EFER);
|
||||||
efer |= (1 << 0); // SYSCALL/SYSRET enable
|
efer |= EFER_SCE;
|
||||||
wrmsr(MSR_EFER, efer);
|
wrmsr(MSR_EFER, efer);
|
||||||
|
|
||||||
// disable interrupts on syscall entry
|
// Mask IF so interrupts are off during the syscall handler
|
||||||
wrmsr(MSR_SFMASK, (1 << 9));
|
wrmsr(MSR_SFMASK, (1 << 9));
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#define SYS_READ 0
|
||||||
|
#define SYS_WRITE 1
|
||||||
|
#define SYS_OPEN 2
|
||||||
|
#define SYS_CLOSE 3
|
||||||
|
|
||||||
|
|
||||||
void syscall_init(void);
|
void syscall_init(void);
|
||||||
+24
-17
@@ -3,30 +3,37 @@
|
|||||||
syscall_entry:
|
syscall_entry:
|
||||||
swapgs
|
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 %rcx # save user RIP (syscall puts it in RCX)
|
||||||
push %r11 # save rflags
|
push %r11 # save user RFLAGS
|
||||||
|
|
||||||
# Save original args before we clobber them
|
# ── Shuffle syscall regs → SysV args for syscall_handler ──────────
|
||||||
push %rdi # orig rdi (arg1)
|
# On entry: rax=num rdi=a1 rsi=a2 rdx=a3 r10=a4 r8=a5 r9=a6
|
||||||
push %rsi # orig rsi (arg2)
|
# We want: rdi=num rsi=a1 rdx=a2 rcx=a3 r8=a4 r9=a5
|
||||||
push %rdx # orig rdx (arg3)
|
#
|
||||||
|
# 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
|
push %rdi # save orig rdi (a1)
|
||||||
mov %r8, %r9 # r9 = orig r8 (6th param)
|
push %rsi # save orig rsi (a2)
|
||||||
mov %r10, %r8 # r8 = orig r10 (5th param)
|
push %rdx # save orig rdx (a3)
|
||||||
|
|
||||||
# Pop in reverse order to place into correct SysV registers
|
pop %rcx # rcx = a3 (4th param)
|
||||||
pop %rcx # rcx = orig rdx (4th param)
|
pop %rdx # rdx = a2 (3rd param)
|
||||||
pop %rdx # rdx = orig rsi (3rd param)
|
pop %rsi # rsi = a1 (2nd param)
|
||||||
pop %rsi # rsi = orig rdi (2nd param)
|
mov %rax, %rdi # rdi = num (1st param)
|
||||||
mov %rax, %rdi # rdi = rax (1st param = syscall number)
|
|
||||||
|
|
||||||
call syscall_handler
|
call syscall_handler
|
||||||
|
|
||||||
pop %r11
|
# ── Restore user context ───────────────────────────────────────────
|
||||||
pop %rcx
|
pop %r11 # user RFLAGS
|
||||||
|
pop %rcx # user RIP
|
||||||
|
|
||||||
|
mov %gs:0x08, %rsp # restore user RSP ← this was the missing piece
|
||||||
|
|
||||||
swapgs
|
swapgs
|
||||||
sysretq
|
sysretq
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
-7
@@ -1,12 +1,7 @@
|
|||||||
.section .text
|
.section .text
|
||||||
.global _start
|
.global _start
|
||||||
|
.global main
|
||||||
_start:
|
_start:
|
||||||
mov $1, %rax
|
call main
|
||||||
mov $'H', %rdi
|
|
||||||
syscall
|
|
||||||
|
|
||||||
mov $1, %rax
|
|
||||||
mov $'i', %rdi
|
|
||||||
syscall
|
|
||||||
|
|
||||||
1: jmp 1b
|
1: jmp 1b
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
#pragma once
|
#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)
|
static inline long syscall(long num, long a1, long a2, long a3)
|
||||||
{
|
{
|
||||||
long ret;
|
long ret;
|
||||||
@@ -8,7 +13,6 @@ static inline long syscall(long num, long a1, long a2, long a3)
|
|||||||
"syscall"
|
"syscall"
|
||||||
: "=a"(ret)
|
: "=a"(ret)
|
||||||
: "a"(num), "D"(a1), "S"(a2), "d"(a3)
|
: "a"(num), "D"(a1), "S"(a2), "d"(a3)
|
||||||
:
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
+28
-4
@@ -1,5 +1,7 @@
|
|||||||
#include "../include/syscalls.h"
|
#include "../include/syscalls.h"
|
||||||
|
|
||||||
|
#define STDOUT 1
|
||||||
|
|
||||||
unsigned strlen(const char* str)
|
unsigned strlen(const char* str)
|
||||||
{
|
{
|
||||||
unsigned len = 0;
|
unsigned len = 0;
|
||||||
@@ -8,15 +10,37 @@ unsigned strlen(const char* str)
|
|||||||
++len;
|
++len;
|
||||||
++str;
|
++str;
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
syscall(1, 'A', 0, 0);
|
const char* path = "/qwerty.txt";
|
||||||
syscall(1, 'B', 0, 0);
|
const char* msg = "Suki Suki Daisuki Kekkon Shiyo, my honey!";
|
||||||
syscall(1, 'C', 0, 0);
|
|
||||||
|
|
||||||
|
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);
|
while (1);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user