From 1f954724fea19579bbd3c73a9fdb8085777c4396 Mon Sep 17 00:00:00 2001 From: keyboard-slayer Date: Thu, 25 Sep 2025 19:05:39 +0200 Subject: [PATCH] paging: wip --- meta/plugins/cli.py | 1 + meta/targets/kernel-x86_64.json | 9 ++- meta/targets/kernel-x86_64.ld | 2 + src/kernel/core/mod.c | 5 -- src/kernel/hal/rv32/boot.c | 2 + src/kernel/hal/x86_64/boot.c | 7 ++ src/kernel/hal/x86_64/exception.c | 65 +++++++++++++++ src/kernel/hal/x86_64/gdt.c | 61 ++++++++++++++ src/kernel/hal/x86_64/gdt.h | 82 +++++++++++++++++++ src/kernel/hal/x86_64/gdt.s | 21 +++++ src/kernel/hal/x86_64/idt.c | 32 ++++++++ src/kernel/hal/x86_64/idt.h | 37 +++++++++ src/kernel/hal/x86_64/idt.s | 57 ++++++++++++++ src/kernel/hal/x86_64/macro.s | 35 ++++++++ src/kernel/hal/x86_64/paging.c | 127 ++++++++++++++++++++++++++++++ src/kernel/hal/x86_64/paging.h | 26 ++++++ src/kernel/hal/x86_64/regs.c | 46 +++++++++++ src/kernel/hal/x86_64/regs.h | 36 +++++++++ src/libs/helpers/macro.h | 6 ++ 19 files changed, 649 insertions(+), 8 deletions(-) create mode 100644 src/kernel/hal/x86_64/exception.c create mode 100644 src/kernel/hal/x86_64/gdt.c create mode 100644 src/kernel/hal/x86_64/gdt.h create mode 100644 src/kernel/hal/x86_64/gdt.s create mode 100644 src/kernel/hal/x86_64/idt.c create mode 100644 src/kernel/hal/x86_64/idt.h create mode 100644 src/kernel/hal/x86_64/idt.s create mode 100644 src/kernel/hal/x86_64/macro.s create mode 100644 src/kernel/hal/x86_64/paging.c create mode 100644 src/kernel/hal/x86_64/paging.h create mode 100644 src/kernel/hal/x86_64/regs.c create mode 100644 src/kernel/hal/x86_64/regs.h create mode 100644 src/libs/helpers/macro.h diff --git a/meta/plugins/cli.py b/meta/plugins/cli.py index 4022b24..7ee269b 100644 --- a/meta/plugins/cli.py +++ b/meta/plugins/cli.py @@ -43,6 +43,7 @@ def _(args: StartArgs): *[ "qemu-system-x86_64", # "-enable-kvm", + # "-d", "int,guest_errors,cpu_reset", "-no-reboot", "-no-shutdown", "-display", diff --git a/meta/targets/kernel-x86_64.json b/meta/targets/kernel-x86_64.json index 9e452a8..26facb7 100644 --- a/meta/targets/kernel-x86_64.json +++ b/meta/targets/kernel-x86_64.json @@ -68,10 +68,13 @@ ] }, "as": { - "cmd": "nasm", + "cmd": "{shell.latest('clang')}", "args": [ - "-f", - "elf64" + "-Isrc/kernel/hal/x86_64", + "-target", + "x86_64-none-elf", + "-c", + "-g" ] } } diff --git a/meta/targets/kernel-x86_64.ld b/meta/targets/kernel-x86_64.ld index a4c7040..349db83 100644 --- a/meta/targets/kernel-x86_64.ld +++ b/meta/targets/kernel-x86_64.ld @@ -50,6 +50,8 @@ SECTIONS *(.note.gnu.build-id) } :rodata + rodata_end_addr = .; + /* Move to the next memory page for .data */ . = ALIGN(CONSTANT(MAXPAGESIZE)); diff --git a/src/kernel/core/mod.c b/src/kernel/core/mod.c index fcfcef6..0455ddc 100644 --- a/src/kernel/core/mod.c +++ b/src/kernel/core/mod.c @@ -1,13 +1,8 @@ -#include -#include -#include #include #include #include void kmain(void) { - kmalloc_init(); - Allocator kmalloc = kmalloc_allocator(); char* hello = (char*)kmalloc.alloc(&kmalloc, 14); memset(hello, 0, 14); diff --git a/src/kernel/hal/rv32/boot.c b/src/kernel/hal/rv32/boot.c index a76ecc9..d33f60c 100644 --- a/src/kernel/hal/rv32/boot.c +++ b/src/kernel/hal/rv32/boot.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ void rv32_start([[gnu::unused]] size_t hartid, uintptr_t dtb) { pmm_init(); paging_init(); + kmalloc_init(); kmain(); } diff --git a/src/kernel/hal/x86_64/boot.c b/src/kernel/hal/x86_64/boot.c index 2f16a59..805ac28 100644 --- a/src/kernel/hal/x86_64/boot.c +++ b/src/kernel/hal/x86_64/boot.c @@ -1,8 +1,12 @@ #include +#include #include #include #include +#include "gdt.h" +#include "idt.h" + [[gnu::used, gnu::section(".limine_requests")]] static volatile LIMINE_BASE_REVISION(3); [[gnu::used, gnu::section(".limine_requests_start")]] static volatile LIMINE_REQUESTS_START_MARKER; [[gnu::used, gnu::section(".limine_requests_end")]] static volatile LIMINE_REQUESTS_END_MARKER; @@ -10,7 +14,10 @@ void kmain(void); void x86_64_start(void) { + gdt_init(); + idt_init(); pmm_init(); + kmalloc_init(); kmain(); } diff --git a/src/kernel/hal/x86_64/exception.c b/src/kernel/hal/x86_64/exception.c new file mode 100644 index 0000000..c86b0e1 --- /dev/null +++ b/src/kernel/hal/x86_64/exception.c @@ -0,0 +1,65 @@ +#include + +#include "regs.h" + +#define IRQ0 (32) + +static char* exception_types[] = { + "Division By Zero", + "Debug", + "Non Maskable Interrupt", + "Breakpoint", + "Detected Overflow", + "Out Of Bounds", + "Invalid Opcode", + "No Coprocessor", + "Double Fault", + "Coprocessor Segment Overrun", + "Bad Tss", + "Segment Not Present", + "StackFault", + "General Protection Fault", + "Page Fault", + "Unknown Interrupt", + "Coprocessor Fault", + "Alignment Check", + "Machine Check", + "SIMD Floating-Point Exception", + "Virtualization Exception", + "Control Protection Exception", + "Reserved", + "Hypervisor Injection Exception", + "paging Communication Exception", + "Security Exception", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", +}; + +static void panic_handler(Stackframe* frame) { + print$("\n\x1b[0;31m!!! \x1b[33m---------------------------------------------------------------------------------------------------\x1b[0m\n\n"); + print$(" KERNEL PANIC\n\n"); + print$(" %s was raised\n", exception_types[frame->intno]); + print$(" interrupt: %x, err: %x\n\n", frame->intno, frame->err); + print$(" RAX %p RBX %p RCX %p RDX %p\n", frame->rax, frame->rbx, frame->rcx, frame->rdx); + print$(" RSI %p RDI %p RBP %p RSP %p\n", frame->rsi, frame->rdi, frame->rbp, frame->rsp); + print$(" R8 %p R9 %p R10 %p R11 %p\n", frame->r8, frame->r9, frame->r10, frame->r11); + print$(" R12 %p R13 %p R14 %p R15 %p\n", frame->r12, frame->r13, frame->r14, frame->r15); + print$(" CR0 %p CR2 %p CR3 %p CR4 %p\n", cr$(0), cr$(2), cr$(3), cr$(4)); + print$(" CS %p SS %p FLG %p\n", frame->cs, frame->ss, frame->rflags); + print$(" RIP \033[7m%p\033[0m\n\n", frame->rip); + print$("\n\x1b[33m--------------------------------------------------------------------------------------------------- \x1b[0;31m!!!\x1b[0m\n\n"); +} + +uint64_t interrupt_handler(uintptr_t rsp) { + Stackframe* frame = (Stackframe*)rsp; + + if (frame->intno < IRQ0) { + panic_handler(frame); + } + + return rsp; +} diff --git a/src/kernel/hal/x86_64/gdt.c b/src/kernel/hal/x86_64/gdt.c new file mode 100644 index 0000000..26523d2 --- /dev/null +++ b/src/kernel/hal/x86_64/gdt.c @@ -0,0 +1,61 @@ +#include + +#include "gdt.h" + +static Gdt gdt = {0}; + +static GdtDescriptor gdt_desc = { + .size = sizeof(gdt) - 1, + .offset = (uintptr_t)&gdt, +}; + +static void gdt_entry(GdtEntry* self, uint8_t access, uint8_t flags) { + memset(self, 0, sizeof(GdtEntry)); + + if (access == 0 && flags == 0) { + return; + } + + self->access = access | GDT_ACCESS_PRESENT | GDT_ACCESS_READ_WRITE | GDT_ACCESS_DESCRIPTOR; + self->flags = flags | GDT_FLAGS_GRANULARITY; + + self->base_high = 0; + self->base_middle = 0; + self->base_low = 0; + + self->limit_low = 0xffff; + self->limit_high = 0x0f; +} + +void gdt_load_tss(Tss* tss) { + uintptr_t tss_ptr = (uintptr_t)tss; + + gdt.tss_entry = (TssEntry){ + .length = sizeof(TssEntry), + + .base_low = tss_ptr & 0xffff, + .base_mid = (tss_ptr >> 16) & 0xff, + .base_high = (tss_ptr >> 24) & 0xff, + .base_upper = tss_ptr >> 32, + + .flags1 = TSS_FLAGS_PRESENT | TSS_FLAGS_64BITS_AVAILABLE, + .flags2 = 0, + + .reserved = 0, + }; +} + +void gdt_init(void) { + gdt_entry(&gdt.entries[GDT_NULL_DESC], 0, 0); + + gdt_entry(&gdt.entries[GDT_KERNEL_CODE], GDT_ACCESS_EXE, GDT_FLAGS_LONG_MODE); + gdt_entry(&gdt.entries[GDT_KERNEL_DATA], 0, GDT_FLAGS_SIZE); + + gdt_entry(&gdt.entries[GDT_USER_DATA], GDT_ACCESS_USER, GDT_FLAGS_SIZE); + gdt_entry(&gdt.entries[GDT_USER_CODE], GDT_ACCESS_USER | GDT_ACCESS_EXE, GDT_FLAGS_LONG_MODE); + + gdt_load_tss(NULL); + + gdt_flush((uintptr_t)&gdt_desc); + tss_flush(); +} diff --git a/src/kernel/hal/x86_64/gdt.h b/src/kernel/hal/x86_64/gdt.h new file mode 100644 index 0000000..4ad9125 --- /dev/null +++ b/src/kernel/hal/x86_64/gdt.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include + +enum gdtaccess : uint8_t { + GDT_ACCESS_READ_WRITE = (1 << 1), + GDT_ACCESS_EXE = (1 << 3), + GDT_ACCESS_DESCRIPTOR = (1 << 4), + GDT_ACCESS_USER = (3 << 5), + GDT_ACCESS_PRESENT = (1 << 7), +}; + +enum gdtflags : uint8_t { + GDT_FLAGS_LONG_MODE = (1 << 1), + GDT_FLAGS_SIZE = (1 << 2), + GDT_FLAGS_GRANULARITY = (1 << 3), +}; + +enum tssflags : uint8_t { + TSS_FLAGS_PRESENT = (1 << 7), + TSS_FLAGS_64BITS_AVAILABLE = (0x9), +}; + +enum : size_t { + GDT_NULL_DESC, + GDT_KERNEL_CODE, + GDT_KERNEL_DATA, + GDT_USER_DATA, + GDT_USER_CODE, + + GDT_ENTRIES_LENGTH +}; + +typedef struct [[gnu::packed]] { + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t limit_high : 4; + uint8_t flags : 4; + uint8_t base_high; +} GdtEntry; + +typedef struct [[gnu::packed]] { + uint16_t length; + uint16_t base_low; + uint8_t base_mid; + uint8_t flags1; + uint8_t flags2; + uint8_t base_high; + uint32_t base_upper; + uint32_t reserved; +} TssEntry; + +typedef struct [[gnu::packed]] { + uint32_t reserved; + uint64_t rsp[3]; + uint64_t reserved0; + uint64_t ist[7]; + uint32_t reserved1; + uint32_t reserved2; + uint16_t reserved3; + uint16_t iopb_offset; +} Tss; + +typedef struct [[gnu::packed]] { + uint16_t size; + uintptr_t offset; +} GdtDescriptor; + +typedef struct [[gnu::packed]] { + GdtEntry entries[GDT_ENTRIES_LENGTH]; + TssEntry tss_entry; +} Gdt; + +void gdt_init(void); +void gdt_load_tss(Tss* tss); + +extern void gdt_flush(uintptr_t); +extern void tss_flush(void); diff --git a/src/kernel/hal/x86_64/gdt.s b/src/kernel/hal/x86_64/gdt.s new file mode 100644 index 0000000..b26b6ee --- /dev/null +++ b/src/kernel/hal/x86_64/gdt.s @@ -0,0 +1,21 @@ +.globl gdt_flush +.globl tss_flush + +gdt_flush: + lgdt (%rdi) + + mov $0x10, %ax + mov %ax, %ss + mov %ax, %ds + mov %ax, %es + pop %rdi + + mov $0x08, %rax + push %rax + push %rdi + lretq + +tss_flush: + mov $0x28, %ax + ltr %ax + ret diff --git a/src/kernel/hal/x86_64/idt.c b/src/kernel/hal/x86_64/idt.c new file mode 100644 index 0000000..a805446 --- /dev/null +++ b/src/kernel/hal/x86_64/idt.c @@ -0,0 +1,32 @@ +#include + +#include "gdt.h" +#include "idt.h" + +static Idt idt; +static IdtDescriptor idt_desc = { + .size = sizeof(idt) - 1, + .offset = (uintptr_t)&idt, +}; + +static void idt_init_entry(IdtEntry* self, uint64_t base, uint8_t type) { + self->offset_low = base & 0xFFFF; + self->offset_mid = (base >> 16) & 0xFFFF; + self->offset_high = (base >> 32) & 0xFFFFFFFF; + self->ist = 0; + self->selector = GDT_KERNEL_CODE * 8; + self->type_attr = IDT_INT_PRESENT | type; + self->zero = 0; +} + +uintptr_t idt_descriptor(void) { + return (uintptr_t)&idt_desc; +} + +void idt_init(void) { + for (size_t i = 0; i < IDT_ENTRY_COUNT; i++) { + idt_init_entry(&idt.entries[i], __interrupts_vector[i], IDT_INT_GATE); + } + + idt_flush(idt_descriptor()); +} diff --git a/src/kernel/hal/x86_64/idt.h b/src/kernel/hal/x86_64/idt.h new file mode 100644 index 0000000..4fc41ed --- /dev/null +++ b/src/kernel/hal/x86_64/idt.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#define IDT_ENTRY_COUNT (256) + +enum { + IDT_INT_PRESENT = (1 << 7), + IDT_INT_GATE = (0xe), +}; + +typedef struct [[gnu::packed]] { + uint16_t size; + uintptr_t offset; +} IdtDescriptor; + +typedef struct packed { + uint16_t offset_low; + uint16_t selector; + uint8_t ist; + uint8_t type_attr; + uint16_t offset_mid; + uint32_t offset_high; + uint32_t zero; +} IdtEntry; + +typedef struct [[gnu::packed]] { + IdtEntry entries[IDT_ENTRY_COUNT]; +} Idt; + +void idt_init(void); + +uintptr_t idt_descriptor(void); + +extern uintptr_t __interrupts_vector[]; + +extern void idt_flush(uintptr_t); diff --git a/src/kernel/hal/x86_64/idt.s b/src/kernel/hal/x86_64/idt.s new file mode 100644 index 0000000..cafb57e --- /dev/null +++ b/src/kernel/hal/x86_64/idt.s @@ -0,0 +1,57 @@ +.include "macro.s" + +.altmacro +.globl idt_flush +.globl __interrupts_vector +.extern interrupt_handler + +.macro INTERRUPT_NAME intno + .quad __interrupt\intno +.endm + +.macro INTERRUPT_ERR intno +__interrupt\intno: + pushq $\intno + jmp __interrupt_common +.endm + +.macro INTERRUPT_NOERR intno +__interrupt\intno: + pushq $0 + pushq $\intno + jmp __interrupt_common +.endm + +__interrupt_common: + cld + __pusha + + movq %rsp, %rdi + call interrupt_handler + movq %rax, %rsp + + __popa + add $16, %rsp + iretq + +.set i,0 +.rept 48 + .if i != 8 && i != 10 && i != 11 && i != 12 && i != 13 && i != 14 && i != 17 && i != 30 + INTERRUPT_NOERR %i + .else + INTERRUPT_ERR %i + .endif + .set i,i+1 +.endr + +.align 8 +__interrupts_vector: +.set i,0 +.rept 48 + INTERRUPT_NAME %i + .set i,i+1 +.endr + +idt_flush: + lidt (%rdi) + ret diff --git a/src/kernel/hal/x86_64/macro.s b/src/kernel/hal/x86_64/macro.s new file mode 100644 index 0000000..4f5ae59 --- /dev/null +++ b/src/kernel/hal/x86_64/macro.s @@ -0,0 +1,35 @@ +.macro __pusha + push %rax + push %rbx + push %rcx + push %rdx + push %rsi + push %rdi + push %rbp + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 +.endm + +.macro __popa + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rbp + pop %rdi + pop %rsi + pop %rdx + pop %rcx + pop %rbx + pop %rax +.endm diff --git a/src/kernel/hal/x86_64/paging.c b/src/kernel/hal/x86_64/paging.c new file mode 100644 index 0000000..493d00a --- /dev/null +++ b/src/kernel/hal/x86_64/paging.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include + +#include "paging.h" + +static uint64_t* kernel_page_table = NULL; +static size_t mapping_page_size = mib$(2); + +static int64_t transform_flags(uint8_t flags) { + int64_t ret = PAGE_NO_EXECUTE | PAGE_PRESENT; + + if (flags & HAL_MAP_READ) { + } + + if (flags & HAL_MAP_NONE) { + ret &= ~PAGE_PRESENT; + } + + if (flags & HAL_MAP_WRITE) { + ret |= PAGE_WRITABLE; + } + + if (flags & HAL_MAP_EXEC) { + ret &= ~PAGE_NO_EXECUTE; + } + + if (flags & HAL_MAP_USER) { + ret |= PAGE_USER; + } + + if (flags & HAL_MAP_HUGE) { + ret |= PAGE_HUGE; + } + + return ret; +} + +static void* paging_get_pml_alloc(uint64_t* table, size_t index, bool alloc) { + if (table[index] & PAGE_PRESENT) { + return hal_mmap_l2h(PAGE_GET_PHYS(table[index])); + } else if (alloc) { + Allocator pmm = pmm_allocator(); + void* ptr = pmm.alloc(&pmm, page_size()); + if (ptr == NULL) { + return NULL; + } + memset(ptr, 0, page_size()); + table[index] = (uint64_t)hal_mmap_h2l((uint64_t)ptr) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER; + return ptr; + } + + return NULL; +} + +static HalMappingError map_page(uint64_t* table, uintptr_t vaddr, uintptr_t paddr, uint32_t flag) { + if (!aligned$(vaddr, page_size())) { + return HAL_MAP_VIRT_UNALIGNED; + } + + if (!aligned$(paddr, page_size())) { + return HAL_MAP_PHYS_UNALIGNED; + } + + size_t pml1_entry = PMLX_GET_INDEX(vaddr, 0); + size_t pml2_entry = PMLX_GET_INDEX(vaddr, 1); + size_t pml3_entry = PMLX_GET_INDEX(vaddr, 2); + size_t pml4_entry = PMLX_GET_INDEX(vaddr, 3); + + uintptr_t* pml3 = paging_get_pml_alloc(table, pml4_entry, true); + if (pml3 == NULL) { + return HAL_MAP_COULDNT_ALLOCATE; + } + + if (mapping_page_size == gib$(1) && flag & PAGE_HUGE) { + pml3[pml3_entry] = paddr | flag; + return HAL_MAP_OK; + } + + uintptr_t* pml2 = paging_get_pml_alloc(pml3, pml3_entry, true); + if (pml3 == NULL) { + return HAL_MAP_COULDNT_ALLOCATE; + } + + if (flag & PAGE_HUGE) { + pml2[pml2_entry] = paddr | flag; + return HAL_MAP_OK; + } + + uintptr_t* pml1 = paging_get_pml_alloc(pml2, pml2_entry, true); + if (pml1 == NULL) { + return HAL_MAP_COULDNT_ALLOCATE; + } + + pml1[pml1_entry] = paddr | flag; + return HAL_MAP_OK; +} + +HalMappingError hal_map_page(HalPage page, uintptr_t virt, uintptr_t phys, size_t length, uint8_t flags) { + size_t len = align_up$(length, page_size()); + uintptr_t aligned_virt = align_down$(virt, page_size()); + uintptr_t aligned_phys = align_down$(phys, page_size()); + uint32_t arch_flags = transform_flags(flags); + + for (size_t i = 0; i < len; i += page_size()) { + HalMappingError err = map_page(page.ptr, aligned_virt + i, aligned_phys + i, arch_flags); + + if (err != HAL_MAP_OK) { + return err; + } + } + + return HAL_MAP_OK; +} + +void paging_init(void) { + Allocator pmm = pmm_allocator(); + kernel_page_table = pmm.alloc(&pmm, page_size()); + + if (kernel_page_table == NULL) [[clang::unlikely]] { + panic$("Couldn't allocate kernel page table"); + } + + memset(kernel_page_table, 0, page_size()); +} diff --git a/src/kernel/hal/x86_64/paging.h b/src/kernel/hal/x86_64/paging.h new file mode 100644 index 0000000..fb7c726 --- /dev/null +++ b/src/kernel/hal/x86_64/paging.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#define PAGE_GET_PHYS(x) (x & 0x000ffffffffff000) +#define PAGE_GET_FLAGS(x) (x & 0xfff) +#define PMLX_GET_INDEX(addr, level) (((uint64_t)addr & ((uint64_t)0x1ff << (12 + level * 9))) >> (12 + level * 9)) + +enum pml_fields : uint64_t { + PAGE_PRESENT = 1 << 0, + PAGE_WRITABLE = 1 << 1, + PAGE_USER = 1 << 2, + PAGE_WRITE_THROUGH = 1 << 3, + PAGE_NO_CACHE = 1 << 4, + PAGE_ACCESSED = 1 << 5, + PAGE_DIRTY = 1 << 6, + PAGE_HUGE = 1 << 7, + PAGE_GLOBAL = 1 << 8, + PAGE_NO_EXECUTE = 1 << 63, +}; + +struct [[gnu::packed]] _hal_page { + uint64_t* ptr; +}; + +void paging_init(void); diff --git a/src/kernel/hal/x86_64/regs.c b/src/kernel/hal/x86_64/regs.c new file mode 100644 index 0000000..9980f01 --- /dev/null +++ b/src/kernel/hal/x86_64/regs.c @@ -0,0 +1,46 @@ +#include "regs.h" + +static uint64_t read_cr(uint8_t n) { + uint64_t value = 0; + switch (n) { + case 0: + __asm__ volatile("mov %%cr0, %0" : "=r"(value)); + break; + case 2: + __asm__ volatile("mov %%cr2, %0" : "=r"(value)); + break; + case 3: + __asm__ volatile("mov %%cr3, %0" : "=r"(value)); + break; + case 4: + __asm__ volatile("mov %%cr4, %0" : "=r"(value)); + break; + } + return value; +} + +static void write_cr(uint8_t n, uint64_t value) { + switch (n) { + case 0: + __asm__ volatile("mov %0, %%cr0" : : "r"(value) : "memory"); + break; + case 3: + __asm__ volatile("mov %0, %%cr3" : : "r"(value) : "memory"); + break; + case 4: + __asm__ volatile("mov %0, %%cr4" : : "r"(value) : "memory"); + break; + default: + // CR1, CR2 are either invalid or read-only + break; + } +} + +uint64_t __cr(size_t n, uint8_t no, uint64_t val) { + if (n == 1) { + return read_cr(no); + } + + write_cr(no, val); + return 0; +} diff --git a/src/kernel/hal/x86_64/regs.h b/src/kernel/hal/x86_64/regs.h new file mode 100644 index 0000000..838d34c --- /dev/null +++ b/src/kernel/hal/x86_64/regs.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +typedef struct [[gnu::packed]] { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rbp; + uint64_t rdi; + uint64_t rsi; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t rax; + + uint64_t intno; + uint64_t err; + + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +} Stackframe; + +uint64_t __cr(size_t n, uint8_t no, uint64_t val); + +#define cr$(...) __cr(GET_ARG_COUNT(__VA_ARGS__), __VA_ARGS__, 0) diff --git a/src/libs/helpers/macro.h b/src/libs/helpers/macro.h new file mode 100644 index 0000000..8e3227d --- /dev/null +++ b/src/libs/helpers/macro.h @@ -0,0 +1,6 @@ +#pragma once + +#define GET_ARG_COUNT(__args...) \ + __GET_ARG_COUNT(0, ##__args, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#define __GET_ARG_COUNT(_0, _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, _33_, _34_, _35_, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, count, ...) \ + count