diff --git a/build.sh b/build.sh index 2d6c5f8..f855533 100755 --- a/build.sh +++ b/build.sh @@ -15,3 +15,4 @@ dd if=build/bootloader.bin of=build/os.img bs="${sector_size}" seek=1 count="$(( mkfs.fat -F 16 --offset "${partition_offset}" build/os.img mcopy -i build/os.img@@"$((partition_offset * sector_size))" src ::src mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/kernel.bin ::kernel.bin +mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/hello.bin ::hello.bin diff --git a/meson.build b/meson.build index a5c2807..acd5f80 100644 --- a/meson.build +++ b/meson.build @@ -31,6 +31,14 @@ custom_target( build_by_default: true, ) +custom_target( + 'hello', + input: 'src/app/hello.asm', + output: 'hello.bin', + command: [nasm, '-f', 'bin', '-l', 'hello.lst', '@INPUT@', '-o', '@OUTPUT@'], + build_by_default: true, +) + kernel_entry_o = custom_target( 'kernel_entry', input: 'src/kernel_entry.asm', @@ -38,6 +46,12 @@ kernel_entry_o = custom_target( command: [nasm, '-f', 'elf64', '@INPUT@', '-o', '@OUTPUT@'], ) +syscall_o = custom_target('syscall', + input: 'src/syscall.asm', + output: 'syscall.o', + command: [nasm, '-f', 'elf64', '@INPUT@', '-o', '@OUTPUT@'], +) + cc = meson.get_compiler('c') kernel_sources = files( @@ -47,6 +61,7 @@ kernel_sources = files( 'src/ata.c', 'src/fat16.c', 'src/fs.c', + 'src/gdt.c', 'src/idt.c', 'src/kernel.c', 'src/keyboard.c', @@ -54,19 +69,23 @@ kernel_sources = files( 'src/panic.c', 'src/path.c', 'src/pic.c', + 'src/process.c', 'src/string.c', + 'src/syscall.c', + 'src/tss.c', 'src/vga.c', ) kernel_elf = executable( 'kernel.elf', - sources: [kernel_entry_o, kernel_sources], + sources: [kernel_entry_o, syscall_o, kernel_sources], c_args: [ '-ffreestanding', '-nostdlib', '-nostartfiles', '-mno-red-zone', '-mgeneral-regs-only', + '-mcmodel=kernel', '-Wno-unused-command-line-argument', '-Wconversion', '-DVERSION="' + meson.project_version() + '"', diff --git a/src/app/hello.asm b/src/app/hello.asm new file mode 100644 index 0000000..b8bb7fd --- /dev/null +++ b/src/app/hello.asm @@ -0,0 +1,16 @@ +bits 64 +org 0x400000 + +section .text + mov rax, 1 + mov rdi, 1 + lea rsi, [rel msg] + mov rdx, 14 + syscall + + mov rax, 60 + xor rdi, rdi + syscall + +section .data +msg: db "Hello, ring 3!", 10 diff --git a/src/app/terminal.c b/src/app/terminal.c index f5f7c6e..8968c5c 100644 --- a/src/app/terminal.c +++ b/src/app/terminal.c @@ -270,9 +270,7 @@ void terminal(process_t *p, __attribute__((unused)) uint8_t argc, __attribute__( proc = p; - char *greeting = string_format("Welcome to FreywarOS v%s!\n\n", VERSION); - WRITE_D(greeting); - memory_free(greeting); + WRITE_D("Welcome to FreywarOS v" VERSION "!\n\n"); print_prompt(); diff --git a/src/bootloader.asm b/src/bootloader.asm index 6be8331..bbb8b58 100644 --- a/src/bootloader.asm +++ b/src/bootloader.asm @@ -224,30 +224,30 @@ jmp load_gdt gdt_start: gdt_0: dq 0x0000000000000000 -gdt_1: +gdt_32_code: .limit_low: dw 0xFFFF .base_low: dw 0x0000 .base_middle: db 0x00 .access: db 10011010b ; present, ring 0, code, executable, readable .flags: db 11001111b ; 32-bit, 4KB granularity .base_high: db 0x00 -gdt_1_end: -gdt_2: +gdt_32_code_end: +gdt_64_code: .limit_low: dw 0xFFFF .base_low: dw 0x0000 .base_middle: db 0x00 -.access: db 10011010b ; present, ring 0, code, executable, readable +.access: db 10011010b ; present, ring 0, code, executable, readable .flags: db 10101111b ; long mode (L bit) .base_high: db 0x00 -gdt_2_end: -gdt_3: +gdt_64_code_end: +gdt_data: .limit_low: dw 0xFFFF .base_low: dw 0x0000 .base_middle: db 0x00 .access: db 10010010b ; present, ring 0, data, writable .flags: db 00000000b .base_high: db 0x00 -gdt_3_end: +gdt_data_end: gdt_end: gdt_descriptor: @@ -276,23 +276,30 @@ protected_mode: mov ss, ax mov esp, 0x00090000 - ; zero page table memory at 0x00010000 (3 pages = 768 dwords) + ; zero page table memory mov edi, 0x00010000 - mov ecx, 768 + mov ecx, 256 * 5 xor eax, eax rep stosd ; PML4[0] -> PDPT at 0x00011000 mov dword [0x00010000], 0x00011003 - ; PDPT[0] -> PD at 0x00012000 - mov dword [0x00011000], 0x00012003 + ; PML4[511] -> PDPT at 0x00012000 + mov dword [0x00010FF8], 0x00012003 + ; PML4[0].PDPT[0] -> PD at 0x00013000 + mov dword [0x00011000], 0x00013003 + ; PML4[511].PDPT[510] -> PD at 0x00014000 + mov dword [0x00012FF0], 0x00014003 ; PD: fill 64 entries, each mapping 2MB - mov edi, 0x00012000 + mov edi, 0x00013000 mov eax, 0x00000083 ; present, writable, huge page, base 0 mov ecx, 64 .fill_pd: + mov ebx, edi + add ebx, 0x1000 mov dword [edi], eax + mov dword [ebx], eax add edi, 8 add eax, 0x00200000 ; next 2MB loop .fill_pd @@ -327,11 +334,11 @@ long_mode: mov ds, ax mov es, ax mov ss, ax - mov rsp, 0x0000000000090000 + mov rsp, 0xFFFFFFFF80090000 xor rax, rax xor rbx, rbx xor rcx, rcx xor rdx, rdx - jmp 0x00020000 + jmp 0xFFFFFFFF80020000 diff --git a/src/fs.h b/src/fs.h index cd1334a..571d5b5 100644 --- a/src/fs.h +++ b/src/fs.h @@ -11,7 +11,6 @@ typedef struct fs_node { uint8_t type; } fs_node_t; - fs_node_t *fs_mount(); fs_node_t *fs_open_by(const fs_node_t *directory, const char *name); diff --git a/src/gdt.c b/src/gdt.c new file mode 100644 index 0000000..89a8535 --- /dev/null +++ b/src/gdt.c @@ -0,0 +1,68 @@ +#include "src/gdt.h" +#include "src/tss.h" +#include + +typedef struct { + uint16_t limit_low; + uint16_t base_low; + uint8_t base_mid; + uint8_t access; + uint8_t flags_limit_high; + uint8_t base_high; +} __attribute__((packed)) gdt_entry_t; + +typedef struct { + gdt_entry_t base; + uint32_t base_upper; + uint32_t reserved; +} __attribute__((packed)) gdt_system_entry_t; + +typedef struct { + gdt_entry_t gdt[6]; + gdt_system_entry_t tss_entry; +} __attribute__((packed)) gdt_table_t; + +typedef struct { + uint16_t limit; + uint64_t offset; +} __attribute__((packed)) gdt_descriptor_t; + +static gdt_table_t gdt; +static gdt_descriptor_t desc; + +static void set_entry(gdt_entry_t *e, uint8_t access, uint8_t flags) { + e->limit_low = 0xFFFF; + e->base_low = 0; + e->base_mid = 0; + e->access = access; + e->flags_limit_high = flags | 0x0F; + e->base_high = 0; +} + +static void set_tss_entry(void *base) { + uint64_t ibase = (uint64_t)base; + gdt.tss_entry.base.limit_low = sizeof(tss_t) - 1; + gdt.tss_entry.base.base_low = ibase & 0xFFFF; + gdt.tss_entry.base.base_mid = (ibase >> 16) & 0xFF; + gdt.tss_entry.base.access = 0x89; // present, type=TSS available + gdt.tss_entry.base.flags_limit_high = 0x00; + gdt.tss_entry.base.base_high = (ibase >> 24) & 0xFF; + gdt.tss_entry.base_upper = ibase >> 32; + gdt.tss_entry.reserved = 0; +} + +void gdt_init() { + gdt.gdt[0] = (gdt_entry_t){0}; + set_entry(&gdt.gdt[1], 0x9A, 0xCF); // present, ring 0, code, executable, readable, 32-bit, 4KB granularity + set_entry(&gdt.gdt[2], 0x9A, 0xA0); // present, ring 0, code, executable, readable, 64-bit + set_entry(&gdt.gdt[3], 0x92, 0x00); // present, ring 0, data, writable + set_entry(&gdt.gdt[4], 0xF2, 0x00); // present, ring 3, data, writable + set_entry(&gdt.gdt[5], 0xFA, 0xA0); // present, ring 3, code, executable, readable, 64-bit + set_tss_entry(&tss); + + desc.limit = sizeof(gdt) - 1; + desc.offset = (uint64_t)&gdt; + + __asm__ volatile("lgdt %0" : : "m"(desc)); + __asm__ volatile("ltr %0" : : "r"((uint16_t)TSS_SEL)); +} diff --git a/src/gdt.h b/src/gdt.h new file mode 100644 index 0000000..9de9ec9 --- /dev/null +++ b/src/gdt.h @@ -0,0 +1,12 @@ +#pragma once + +#define OBSOLETE_CS 0x08 +#define KERNEL_CS (OBSOLETE_CS + 0x08) +#define KERNEL_DS (KERNEL_CS + 0x08) +#define USER_DS_BASE (KERNEL_DS + 0x08) +#define USER_DS (USER_DS_BASE | 3) +#define USER_CS_BASE (USER_DS_BASE + 0x08) +#define USER_CS (USER_CS_BASE | 3) +#define TSS_SEL (USER_CS_BASE + 0x08) + +void gdt_init(); diff --git a/src/kernel.c b/src/kernel.c index f5ff1f0..cc790ee 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,11 +1,13 @@ -#include "src/app/terminal.h" #include "src/fs.h" +#include "src/gdt.h" #include "src/idt.h" #include "src/keyboard.h" #include "src/memory.h" +#include "src/panic.h" #include "src/path.h" #include "src/pic.h" #include "src/process.h" +#include "src/syscall.h" #include "src/util.h" #include "src/vga.h" @@ -42,15 +44,34 @@ void kernel_main() { idt_set_entry(46, isr_ata_primary, 0x8E); __asm__ volatile("sti"); + gdt_init(); + syscall_init(); + memory_init(); - process_t *proc = memory_allocate(sizeof(process_t)); - proc->cwd = memory_allocate(sizeof(path_t)); - proc->root = fs_mount(); - proc->stdin = keyboard_init(); - proc->stdout = vga_init(); + process_t *kp = memory_allocate(sizeof(process_t)); + kp->root = fs_mount(); + kp->cwd = memory_allocate(sizeof(path_t)); + kp->stdin = keyboard_init(); + kp->stdout = vga_init(); + + fs_node_t *hello = fs_open_by(kp->root, "HELLO.BIN"); + + ASSERT(hello, "kernel: hello.bin not found"); + + uint8_t *hello_code = memory_allocate(hello->size); + fs_read(hello, 0, hello->size, hello_code); + + process_t *proc = process_create(kp, hello_code, hello->size); + + memory_free(hello_code); + fs_close(hello); + + process_run(proc); + + while (1); - terminal(proc, 0, NUL); + fs_unmount(kp->root); outw(0x604, 0x2000); // TODO: parse ACPI tables for real hardware __asm__ volatile("cli; hlt"); diff --git a/src/linker.ld b/src/linker.ld index 07fcbff..af8bc01 100644 --- a/src/linker.ld +++ b/src/linker.ld @@ -1,7 +1,7 @@ ENTRY(kernel_main) SECTIONS { - . = 0x0000000000020000; + . = 0xFFFFFFFF80020000; .text : { *(.text) diff --git a/src/memory.c b/src/memory.c index f3070b6..da22192 100644 --- a/src/memory.c +++ b/src/memory.c @@ -1,11 +1,7 @@ #include "src/memory.h" #include "src/panic.h" #include "src/util.h" -#include -#define MEMORY_SIZE 134217728 -#define PAGE_SIZE 4096 -#define PAGE_COUNT (MEMORY_SIZE / PAGE_SIZE) #define MAP_UNIT 64 #define FULL_UNIT 0xFFFFFFFFFFFFFFFF @@ -26,7 +22,7 @@ static void set_allocated(uint16_t page, uint8_t allocated) { } } -static void *memory_page_allocate() { +void *memory_page_allocate() { ASSERT(free_page < PAGE_COUNT, "memory_page_allocate: out of memory"); const uint16_t page = free_page; set_allocated(page, 1); @@ -40,7 +36,7 @@ static void *memory_page_allocate() { return (void *)((uint64_t)page * PAGE_SIZE); } -__attribute__((unused)) static void memory_page_free(void *address) { +void memory_page_free(void *address) { uint16_t page = (uint16_t)((uint64_t)address / PAGE_SIZE); ASSERT(get_allocated(page), "memory_page_free: page not allocated") set_allocated(page, 0); @@ -49,7 +45,65 @@ __attribute__((unused)) static void memory_page_free(void *address) { } } -#define HEAP_PAGE_COUNT 256 +void memory_page_map(uint64_t *pml4, void *virt, void *phys, uint64_t flags) { + const uint64_t ivirt = (uint64_t)virt; + const uint64_t pml4_index = (ivirt >> 39) & 0x1FF; + const uint64_t pdpt_index = (ivirt >> 30) & 0x1FF; + const uint64_t pd_index = (ivirt >> 21) & 0x1FF; + const uint64_t pt_index = (ivirt >> 12) & 0x1FF; + + if (!(pml4[pml4_index] & PAGE_PRESENT)) { + uint64_t *pdpt = memory_page_allocate(); + memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pdpt)); + pml4[pml4_index] = (uint64_t)pdpt | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER; + } + + uint64_t *pdpt = PHYS_TO_VIRT(pml4[pml4_index] & ~(uint64_t)0xFFF); + if (!(pdpt[pdpt_index] & PAGE_PRESENT)) { + uint64_t *pd = memory_page_allocate(); + memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pd)); + pdpt[pdpt_index] = (uint64_t)pd | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER; + } + + uint64_t *pd = PHYS_TO_VIRT(pdpt[pdpt_index] & ~(uint64_t)0xFFF); + ASSERT(!(pd[pd_index] & 0x80), "memory_page_map: huge page in PD"); + if (!(pd[pd_index] & PAGE_PRESENT)) { + uint64_t *pt = memory_page_allocate(); + memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pt)); + pd[pd_index] = (uint64_t)pt | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER; + } + + uint64_t *pt = PHYS_TO_VIRT(pd[pd_index] & ~(uint64_t)0xFFF); + pt[pt_index] = (uint64_t)phys | flags | PAGE_PRESENT; +} + +void memory_page_unmap(uint64_t *pml4, void *virt) { + const uint64_t ivirt = (uint64_t)virt; + const uint64_t pml4_index = (ivirt >> 39) & 0x1FF; + const uint64_t pdpt_index = (ivirt >> 30) & 0x1FF; + const uint64_t pd_index = (ivirt >> 21) & 0x1FF; + const uint64_t pt_index = (ivirt >> 12) & 0x1FF; + + if (!(pml4[pml4_index] & PAGE_PRESENT)) { + return; + } + + uint64_t *pdpt = PHYS_TO_VIRT(pml4[pml4_index] & ~(uint64_t)0xFFF); + if (!(pdpt[pdpt_index] & PAGE_PRESENT)) { + return; + } + + uint64_t *pd = PHYS_TO_VIRT(pdpt[pdpt_index] & ~(uint64_t)0xFFF); + if (!(pd[pd_index] & PAGE_PRESENT)) { + return; + } + + uint64_t *pt = PHYS_TO_VIRT(pd[pd_index] & ~(uint64_t)0xFFF); + memory_page_free((void *)(pt[pt_index] & ~(uint64_t)0xFFF)); + pt[pt_index] = 0; + + __asm__ volatile("invlpg (%0)" : : "r"(virt) : "memory"); +} typedef struct free_chunk { uint64_t size; // header + data @@ -59,9 +113,9 @@ typedef struct free_chunk { static free_chunk_t *free_list; void memory_init() { - free_list = memory_page_allocate(); + free_list = PHYS_TO_VIRT(memory_page_allocate()); for (uint64_t i = 1; i < HEAP_PAGE_COUNT; i++) { - memory_page_allocate(); // TODO Map the pages. + memory_page_allocate(); } free_list->size = HEAP_PAGE_COUNT * PAGE_SIZE; free_list->next = NUL; diff --git a/src/memory.h b/src/memory.h index 137e30c..eb2cf1b 100644 --- a/src/memory.h +++ b/src/memory.h @@ -3,8 +3,44 @@ #include "src/panic.h" #include +#define PAGE_PRESENT 0x01 +#define PAGE_WRITABLE 0x02 +#define PAGE_USER 0x04 +#define PAGE_PWT 0x08 +#define PAGE_PCD 0x10 +#define PAGE_ACCESSED 0x20 +#define PAGE_DIRTY 0x40 +#define PAGE_HUGE 0x80 +#define PAGE_GLOBAL 0x100 +#define PAGE_NX (1ULL << 63) + +#define MEMORY_SIZE 0x08000000 +#define PAGE_SIZE 4096 +#define PAGE_COUNT (MEMORY_SIZE / PAGE_SIZE) + +#define HEAP_PAGE_COUNT 256 + +#define KERNEL_VIRTUAL_BASE 0xFFFFFFFF80000000ULL +#define PHYS_TO_VIRT(phys) ((void *)((uint64_t)(phys) + KERNEL_VIRTUAL_BASE)) +#define VIRT_TO_PHYS(virt) ((uint64_t)(virt) - KERNEL_VIRTUAL_BASE) + +#define KERNEL_PML4 0xFFFFFFFF80010000ULL + +#define USER_VIRTUAL_BASE 0x0000000000000000ULL +#define USER_VIRTUAL_CODE (USER_VIRTUAL_BASE + 0x400000) +#define USER_VIRTUAL_HEAP (USER_VIRTUAL_CODE + 0x400000) +#define USER_VIRTUAL_STACK (0x0000700000000000ULL - PAGE_SIZE) + void memory_init(); +void *memory_page_allocate(); + +void memory_page_free(void *page); + +void memory_page_map(uint64_t *pml4, void *virt, void *phys, uint64_t flags); + +void memory_page_unmap(uint64_t *pml4, void *virt); + void *memory_allocate(uint64_t size); void memory_free(void *pointer); diff --git a/src/path.c b/src/path.c index fb488ce..cca28fe 100644 --- a/src/path.c +++ b/src/path.c @@ -3,7 +3,6 @@ #include "src/memory.h" #include "src/string.h" #include "src/util.h" -#include path_t *path_open(const fs_node_t *root, const path_t *source, char *path) { path_t *result = memory_allocate(sizeof(path_t)); diff --git a/src/process.c b/src/process.c new file mode 100644 index 0000000..1b193e8 --- /dev/null +++ b/src/process.c @@ -0,0 +1,112 @@ +#include "src/process.h" +#include "src/gdt.h" +#include "src/memory.h" +#include "src/panic.h" +#include "src/path.h" +#include "src/tss.h" + +process_t *current_process; + +process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t size) { + ASSERT(size <= USER_VIRTUAL_HEAP - USER_VIRTUAL_CODE, "process_create: binary too big"); + + process_t *proc = memory_allocate(sizeof(process_t)); + + proc->kernel_stack = (uint8_t *)memory_allocate(PAGE_SIZE) + PAGE_SIZE; + + proc->pml4 = PHYS_TO_VIRT(memory_page_allocate()); + memory_set(0, PAGE_SIZE / 2, proc->pml4); + memory_copy((uint64_t *)KERNEL_PML4 + 256, PAGE_SIZE / 2, proc->pml4 + 256); + + memory_page_map(proc->pml4, (void *)USER_VIRTUAL_STACK, memory_page_allocate(), PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER); + + for (uint64_t page = 0; size > 0; page++) { + void *p = memory_page_allocate(); + uint64_t s = size < PAGE_SIZE ? size : PAGE_SIZE; + memory_page_map(proc->pml4, (void *)(USER_VIRTUAL_CODE + page * PAGE_SIZE), p, PAGE_PRESENT | PAGE_USER); + memory_copy(code, s, PHYS_TO_VIRT(p)); + code += s; + size -= s; + } + + for (uint64_t page = 0; page < HEAP_PAGE_COUNT; page++) { + memory_page_map(proc->pml4, (void *)(USER_VIRTUAL_HEAP + page * PAGE_SIZE), memory_page_allocate(), + PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER); + } + + proc->cwd = memory_allocate(sizeof(path_t)); + proc->cwd->depth = parent->cwd->depth; + for (uint8_t i = 0; i < parent->cwd->depth; i++) { + proc->cwd->stack[i] = fs_open_again(parent->cwd->stack[i]); + } + + proc->root = parent->root; + proc->stdin = parent->stdin; + proc->stdout = parent->stdout; + + return proc; +} + +void process_run(process_t *proc) { + current_process = proc; + tss.rsp0 = (uint64_t)proc->kernel_stack; + + __asm__ volatile("mov %0, %%cr3" : : "r"(VIRT_TO_PHYS(proc->pml4)) : "memory"); + + __asm__ volatile("push %0\n" // ss + "push %1\n" // rsp + "push %2\n" // rflags + "push %3\n" // cs + "push %4\n" // rip + "iretq" + : + : "r"((uint64_t)USER_DS), "r"(USER_VIRTUAL_STACK + PAGE_SIZE), "r"((uint64_t)USER_RFLAGS), "r"((uint64_t)USER_CS), + "r"(USER_VIRTUAL_CODE) + : "memory"); +} + +void process_destroy(process_t *proc) { + path_close(proc->cwd); + + for (uint16_t pml4i = 0; pml4i < 256; pml4i++) { + if (!(proc->pml4[pml4i] & PAGE_PRESENT)) { + continue; + } + + uint64_t *pdpt = PHYS_TO_VIRT(proc->pml4[pml4i] & ~(uint64_t)0xFFF); + for (uint16_t pdpti = 0; pdpti < 512; pdpti++) { + if (!(pdpt[pdpti] & PAGE_PRESENT)) { + continue; + } + + uint64_t *pd = PHYS_TO_VIRT(pdpt[pdpti] & ~(uint64_t)0xFFF); + for (uint16_t pdi = 0; pdi < 512; pdi++) { + if (!(pd[pdi] & PAGE_PRESENT)) { + continue; + } + + if (pd[pdi] & PAGE_HUGE) { + memory_page_free((void *)(pd[pdi] & ~(uint64_t)0xFFF)); + continue; + } + + uint64_t *pt = PHYS_TO_VIRT(pd[pdi] & ~(uint64_t)0xFFF); + for (uint16_t pti = 0; pti < 512; pti++) { + if (!(pt[pti] & PAGE_PRESENT)) { + continue; + } + memory_page_free((void *)(pt[pti] & ~(uint64_t)0xFFF)); + } + memory_page_free((void *)(pd[pdi] & ~(uint64_t)0xFFF)); + } + memory_page_free((void *)(pdpt[pdpti] & ~(uint64_t)0xFFF)); + } + memory_page_free((void *)(proc->pml4[pml4i] & ~(uint64_t)0xFFF)); + } + + memory_page_free((void *)VIRT_TO_PHYS(proc->pml4)); + + memory_free(proc->kernel_stack); + + memory_free(proc); +} diff --git a/src/process.h b/src/process.h index fc2a4e1..2429dcf 100644 --- a/src/process.h +++ b/src/process.h @@ -5,14 +5,26 @@ #include "src/stream.h" #include "src/string.h" -typedef struct { - path_t *cwd; +#define USER_RFLAGS 0x202 + +typedef struct process { + uint64_t *pml4; + void *kernel_stack; fs_node_t *root; + path_t *cwd; stream_t *stdin; stream_t *stdout; } process_t; typedef void (*app_t)(process_t *proc, uint8_t argc, char **argv); +extern process_t *current_process; + +process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t size); + +void process_run(process_t *proc); + +void process_destroy(process_t *proc); + #define WRITE_S(s) proc->stdout->write(proc->stdout, s, sizeof(s) - 1); #define WRITE_D(s) proc->stdout->write(proc->stdout, s, string_length(s)); diff --git a/src/string.c b/src/string.c index add1fda..27f3e3e 100644 --- a/src/string.c +++ b/src/string.c @@ -1,7 +1,5 @@ #include "src/string.h" -#include "src/memory.h" #include -#include uint8_t bytes_equal(const char *l, const char *r, uint64_t count) { while (count--) { @@ -164,41 +162,39 @@ uint64_t string_uint_to_hex(uint64_t value, uint64_t max, char *result) { return i; } -char *string_format(const char *format, ...) { +uint64_t string_format(const char *format, uint64_t max, char *output, ...) { va_list args; - va_start(args, format); + va_start(args, output); - uint64_t limit = 1023; - - char *result = memory_allocate(limit + 1); + uint64_t limit = max - 1; uint64_t fi = 0, ri = 0; while (format[fi] && ri < limit) { if (format[fi] != '%') { - result[ri++] = format[fi++]; + output[ri++] = format[fi++]; } else { switch (format[fi + 1]) { case 'c': - result[ri++] = (char)va_arg(args, int); + output[ri++] = (char)va_arg(args, int); fi += 2; break; case 'd': - string_int_to_decimal(va_arg(args, int64_t), limit - ri, result + ri); - while (result[ri]) { + string_int_to_decimal(va_arg(args, int64_t), limit - ri, output + ri); + while (output[ri]) { ri++; } fi += 2; break; case 'u': - string_uint_to_decimal(va_arg(args, uint64_t), limit - ri, result + ri); - while (result[ri]) { + string_uint_to_decimal(va_arg(args, uint64_t), limit - ri, output + ri); + while (output[ri]) { ri++; } fi += 2; break; case 'x': - string_uint_to_hex(va_arg(args, uint64_t), limit - ri, result + ri); - while (result[ri]) { + string_uint_to_hex(va_arg(args, uint64_t), limit - ri, output + ri); + while (output[ri]) { ri++; } fi += 2; @@ -206,25 +202,26 @@ char *string_format(const char *format, ...) { case 's': { char *s = va_arg(args, char *); while (*s && ri < limit) { - result[ri++] = *s; + output[ri++] = *s; s++; } fi += 2; break; } case '%': { - result[ri++] = '%'; + output[ri++] = '%'; fi += 2; break; } default: - result[ri++] = format[fi++]; - result[ri++] = format[fi++]; + output[ri++] = format[fi++]; + output[ri++] = format[fi++]; break; } } } - result[ri] = '\0'; + output[ri] = '\0'; va_end(args); - return result; + + return ri; } diff --git a/src/string.h b/src/string.h index 37de9f6..5c28377 100644 --- a/src/string.h +++ b/src/string.h @@ -20,4 +20,4 @@ uint64_t string_int_to_decimal(int64_t value, uint64_t max, char *result); uint64_t string_uint_to_hex(uint64_t value, uint64_t max, char *result); -char *string_format(const char *format, ...); +uint64_t string_format(const char *format, uint64_t max, char *output, ...); diff --git a/src/syscall.asm b/src/syscall.asm new file mode 100644 index 0000000..4a54ab9 --- /dev/null +++ b/src/syscall.asm @@ -0,0 +1,39 @@ +bits 64 + +extern tss +extern syscall_dispatch + +global syscall_entry + +syscall_entry: + mov [user_rsp_tmp], rsp + mov rsp, [tss + 4] + + push rcx + push r11 + push rbp + push rbx + push r12 + push r13 + push r14 + push r15 + + mov rcx, rdx ; arg3 + mov rdx, rsi ; arg2 + mov rsi, rdi ; arg1 + mov rdi, rax ; syscall number + call syscall_dispatch + + pop r15 + pop r14 + pop r13 + pop r12 + pop rbx + pop rbp + pop r11 + pop rcx + + mov rsp, [rel user_rsp_tmp] + o64 sysret + +user_rsp_tmp: dq 0 diff --git a/src/syscall.c b/src/syscall.c new file mode 100644 index 0000000..c325e81 --- /dev/null +++ b/src/syscall.c @@ -0,0 +1,62 @@ +#include "src/syscall.h" +#include "src/gdt.h" +#include "src/memory.h" +#include "src/process.h" +#include "src/util.h" + +#define MSR_EFER 0xC0000080 +#define MSR_STAR 0xC0000081 +#define MSR_LSTAR 0xC0000082 +#define MSR_FMASK 0xC0000084 + +static inline uint64_t rdmsr(uint32_t msr) { + uint32_t lo, hi; + __asm__ volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr)); + return ((uint64_t)hi << 32) | lo; +} + +static inline void wrmsr(uint32_t msr, uint64_t value) { + __asm__ volatile("wrmsr" : : "c"(msr), "a"((uint32_t)value), "d"((uint32_t)(value >> 32))); +} + +extern void syscall_entry(); + +void syscall_init() { + wrmsr(MSR_EFER, rdmsr(MSR_EFER) | 0x01); + wrmsr(MSR_STAR, ((uint64_t)KERNEL_DS << 48) | ((uint64_t)KERNEL_CS << 32)); + wrmsr(MSR_LSTAR, (uint64_t)syscall_entry); + wrmsr(MSR_FMASK, 0x200); +} + +static void write(uint64_t fd, uint64_t buf, uint64_t size) { + (void)fd; + current_process->stdout->write(current_process->stdout, (const char *)buf, size); +} + +static void exit() { + __asm__ volatile("mov %0, %%cr3" : : "r"(KERNEL_PML4) : "memory"); + + + process_destroy(current_process); + current_process = NUL; + + while (1) + ; + + // shutdown for now + // outw(0x604, 0x2000); + // __asm__ volatile("cli; hlt"); +} + +void syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3) { + switch (func) { + case SYSCALL_WRITE: + write(arg1, arg2, arg3); + break; + case SYSCALL_EXIT: + exit(); + break; + default: + break; + } +} diff --git a/src/syscall.h b/src/syscall.h new file mode 100644 index 0000000..b4d26e6 --- /dev/null +++ b/src/syscall.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#define SYSCALL_WRITE 1 +#define SYSCALL_EXIT 60 + +void syscall_init(); + +void syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3); diff --git a/src/tss.c b/src/tss.c new file mode 100644 index 0000000..a8ec480 --- /dev/null +++ b/src/tss.c @@ -0,0 +1,9 @@ +#include "src/tss.h" + +tss_t tss = { + .iopb_offset = sizeof(tss_t) // points past end of TSS = no I/O permissions +}; + +void tss_set_kernel_stack(void *rsp0) { + tss.rsp0 = (uint64_t)rsp0; +} diff --git a/src/tss.h b/src/tss.h new file mode 100644 index 0000000..c355967 --- /dev/null +++ b/src/tss.h @@ -0,0 +1,20 @@ +// tss.h +#pragma once + +#include + +typedef struct __attribute__((packed)) { + uint32_t reserved0; + uint64_t rsp0; + uint64_t rsp1; + uint64_t rsp2; + uint64_t reserved1; + uint64_t ist[7]; + uint64_t reserved2; + uint16_t reserved3; + uint16_t iopb_offset; +} tss_t; + +extern tss_t tss; + +void tss_set_kernel_stack(void *rsp0); diff --git a/src/vga.c b/src/vga.c index 49e9e69..6203d0e 100644 --- a/src/vga.c +++ b/src/vga.c @@ -1,9 +1,8 @@ #include "src/vga.h" #include "src/memory.h" #include "src/util.h" -#include -static uint16_t *vga = (uint16_t *)0x000B8000; +static uint16_t *vga = (uint16_t *)0xFFFFFFFF800B8000; static uint16_t color = (uint16_t)0x0F << 8; static uint16_t offset = 0;