paging: wip
This commit is contained in:
		
							parent
							
								
									2b3a27a398
								
							
						
					
					
						commit
						e5b7a172eb
					
				
					 25 changed files with 733 additions and 16 deletions
				
			
		|  | @ -43,10 +43,13 @@ def _(args: StartArgs): | |||
|                 *[ | ||||
|                     "qemu-system-x86_64", | ||||
|                     # "-enable-kvm", | ||||
|                     # "-d", "int,guest_errors,cpu_reset", | ||||
|                     "-no-reboot", | ||||
|                     "-no-shutdown", | ||||
|                     "-display", | ||||
|                     "none", | ||||
|                     "-m", | ||||
|                     "2G", | ||||
|                     "-smp", | ||||
|                     "4", | ||||
|                     "-serial", | ||||
|  |  | |||
|  | @ -42,7 +42,6 @@ class Image: | |||
|         with (rel_path / "limine.conf").open("w") as f: | ||||
|             f.writelines( | ||||
|                 [ | ||||
|                     "randomize_memory: yes\n", | ||||
|                     "timeout: 0\n\n", | ||||
|                     f"/{self.__name}\n", | ||||
|                     "    protocol: limine\n", | ||||
|  |  | |||
|  | @ -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" | ||||
|             ] | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -23,6 +23,8 @@ SECTIONS | |||
|     /* that is the beginning of the region. */ | ||||
|     . = 0xffffffff80000000; | ||||
| 
 | ||||
|     text_start_addr = .; | ||||
| 
 | ||||
|     /* Define a section to contain the Limine requests and assign it to its own PHDR */ | ||||
|     .limine_requests : { | ||||
|         KEEP(*(.limine_requests_start)) | ||||
|  | @ -37,9 +39,13 @@ SECTIONS | |||
|         *(.text .text.*) | ||||
|     } :text | ||||
| 
 | ||||
|     text_end_addr = .; | ||||
| 
 | ||||
|     /* Move to the next memory page for .rodata */ | ||||
|     . = ALIGN(CONSTANT(MAXPAGESIZE)); | ||||
| 
 | ||||
|     rodata_start_addr = .; | ||||
| 
 | ||||
|     .rodata : { | ||||
|         *(.rodata .rodata.*) | ||||
|     } :rodata | ||||
|  | @ -50,9 +56,13 @@ SECTIONS | |||
|         *(.note.gnu.build-id) | ||||
|     } :rodata | ||||
| 
 | ||||
|     rodata_end_addr = .; | ||||
| 
 | ||||
|     /* Move to the next memory page for .data */ | ||||
|     . = ALIGN(CONSTANT(MAXPAGESIZE)); | ||||
| 
 | ||||
|     data_start_addr = .; | ||||
| 
 | ||||
|     .data : { | ||||
|         *(.data .data.*) | ||||
|     } :data | ||||
|  | @ -66,6 +76,8 @@ SECTIONS | |||
|         *(COMMON) | ||||
|     } :data | ||||
| 
 | ||||
|    data_end_addr = .; | ||||
| 
 | ||||
|     /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ | ||||
|     /DISCARD/ : { | ||||
|         *(.eh_frame*) | ||||
|  |  | |||
|  | @ -1,13 +1,8 @@ | |||
| #include <allocators/slab.h> | ||||
| #include <fmt> | ||||
| #include <hal> | ||||
| #include <kmalloc> | ||||
| #include <logger> | ||||
| #include <string.h> | ||||
| 
 | ||||
| void kmain(void) { | ||||
|     kmalloc_init(); | ||||
| 
 | ||||
|     Allocator kmalloc = kmalloc_allocator(); | ||||
|     char* hello       = (char*)kmalloc.alloc(&kmalloc, 14); | ||||
|     memset(hello, 0, 14); | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ size_t page_size(void); | |||
| 
 | ||||
| void* hal_mmap_l2h(uintptr_t addr); | ||||
| 
 | ||||
| void* hal_mmap_h2l(uintptr_t addr); | ||||
| uintptr_t hal_mmap_h2l(uintptr_t addr); | ||||
| 
 | ||||
| /* === TASKS & SCHEDULING === */ | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include <hal> | ||||
| #include <handover-dtb> | ||||
| #include <helpers/mem.h> | ||||
| #include <kmalloc> | ||||
| #include <logger> | ||||
| #include <pmm> | ||||
| #include <stdio.h> | ||||
|  | @ -36,6 +37,7 @@ void rv32_start([[gnu::unused]] size_t hartid, uintptr_t dtb) { | |||
| 
 | ||||
|     pmm_init(); | ||||
|     paging_init(); | ||||
|     kmalloc_init(); | ||||
|     kmain(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,6 +18,6 @@ void* hal_mmap_l2h(uintptr_t addr) { | |||
|     return (void*)addr; | ||||
| } | ||||
| 
 | ||||
| void* hal_mmap_h2l(uintptr_t addr) { | ||||
|     return (void*)addr; | ||||
| uintptr_t hal_mmap_h2l(uintptr_t addr) { | ||||
|     return addr; | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,13 @@ | |||
| #include <dtb> | ||||
| #include <kmalloc> | ||||
| #include <limine> | ||||
| #include <logger> | ||||
| #include <pmm> | ||||
| 
 | ||||
| #include "gdt.h" | ||||
| #include "idt.h" | ||||
| #include "paging.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 +15,11 @@ | |||
| void kmain(void); | ||||
| 
 | ||||
| void x86_64_start(void) { | ||||
|     gdt_init(); | ||||
|     idt_init(); | ||||
|     pmm_init(); | ||||
|     paging_init(); | ||||
|     kmalloc_init(); | ||||
|     kmain(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										65
									
								
								src/kernel/hal/x86_64/exception.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/kernel/hal/x86_64/exception.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | |||
| #include <logger> | ||||
| 
 | ||||
| #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; | ||||
| } | ||||
							
								
								
									
										61
									
								
								src/kernel/hal/x86_64/gdt.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/kernel/hal/x86_64/gdt.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | |||
| #include <string.h> | ||||
| 
 | ||||
| #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(); | ||||
| } | ||||
							
								
								
									
										82
									
								
								src/kernel/hal/x86_64/gdt.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/kernel/hal/x86_64/gdt.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,82 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <helpers/errors.h> | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| 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); | ||||
							
								
								
									
										21
									
								
								src/kernel/hal/x86_64/gdt.s
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/kernel/hal/x86_64/gdt.s
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
|  | @ -35,10 +35,10 @@ void* hal_mmap_l2h(uintptr_t addr) { | |||
|     return (void*)(addr + hhdm_req.response->offset); | ||||
| } | ||||
| 
 | ||||
| void* hal_mmap_h2l(uintptr_t addr) { | ||||
| uintptr_t hal_mmap_h2l(uintptr_t addr) { | ||||
|     if (hhdm_req.response == NULL) [[clang::unlikely]] { | ||||
|         panic$("Couldn't get limine's HHDM"); | ||||
|     } | ||||
| 
 | ||||
|     return (void*)(addr - hhdm_req.response->offset); | ||||
|     return (addr - hhdm_req.response->offset); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										32
									
								
								src/kernel/hal/x86_64/idt.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/kernel/hal/x86_64/idt.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| #include <logger> | ||||
| 
 | ||||
| #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()); | ||||
| } | ||||
							
								
								
									
										37
									
								
								src/kernel/hal/x86_64/idt.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/kernel/hal/x86_64/idt.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #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); | ||||
							
								
								
									
										57
									
								
								src/kernel/hal/x86_64/idt.s
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/kernel/hal/x86_64/idt.s
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
							
								
								
									
										35
									
								
								src/kernel/hal/x86_64/macro.s
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/kernel/hal/x86_64/macro.s
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
							
								
								
									
										171
									
								
								src/kernel/hal/x86_64/paging.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								src/kernel/hal/x86_64/paging.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,171 @@ | |||
| #include <hal> | ||||
| #include <handover> | ||||
| #include <helpers/mem.h> | ||||
| #include <logger> | ||||
| #include <pmm> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #include "paging.h" | ||||
| #include "regs.h" | ||||
| 
 | ||||
| static uint64_t* kernel_page_table = NULL; | ||||
| static size_t mapping_page_size    = mib$(2); | ||||
| 
 | ||||
| extern char text_start_addr[]; | ||||
| extern char text_end_addr[]; | ||||
| extern char rodata_start_addr[]; | ||||
| extern char rodata_end_addr[]; | ||||
| extern char data_start_addr[]; | ||||
| extern char data_end_addr[]; | ||||
| 
 | ||||
| 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] = 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 hal_switch_space(HalPage space) { | ||||
|     cr$(3, hal_mmap_h2l((uintptr_t)space.ptr)); | ||||
| } | ||||
| 
 | ||||
| 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()); | ||||
| 
 | ||||
|     size_t text_start   = align_down$((uintptr_t)text_start_addr, page_size()); | ||||
|     size_t text_end     = align_up$((uintptr_t)text_end_addr, page_size()); | ||||
|     HalMappingError err = hal_map_page((HalPage){kernel_page_table}, text_start, text_start, text_end - text_start, HAL_MAP_READ | HAL_MAP_EXEC); | ||||
|     if (err != HAL_MAP_OK) { | ||||
|         panic$("Couldn't map kernel text, cause: %s", HalMappingErrorString(err)); | ||||
|     } | ||||
| 
 | ||||
|     size_t rodata_start = align_down$((uintptr_t)rodata_start_addr, page_size()); | ||||
|     size_t rodata_end   = align_up$((uintptr_t)rodata_end_addr, page_size()); | ||||
|     err                 = hal_map_page((HalPage){kernel_page_table}, rodata_start, rodata_start, rodata_end - rodata_start, HAL_MAP_READ); | ||||
|     if (err != HAL_MAP_OK) { | ||||
|         panic$("Couldn't map kernel rodata, cause: %s", HalMappingErrorString(err)); | ||||
|     } | ||||
| 
 | ||||
|     size_t data_start = align_down$((uintptr_t)data_start_addr, page_size()); | ||||
|     size_t data_end   = align_up$((uintptr_t)data_end_addr, page_size()); | ||||
|     err               = hal_map_page((HalPage){kernel_page_table}, data_start, data_start, data_end - data_start, HAL_MAP_READ | HAL_MAP_WRITE); | ||||
|     if (err != HAL_MAP_OK) { | ||||
|         panic$("Couldn't map kernel data, cause: %s", HalMappingErrorString(err)); | ||||
|     } | ||||
| 
 | ||||
|     HandoverRecord rec; | ||||
|     handover_foreach_record(handover(), rec) { | ||||
|         if (rec.tag != HANDOVER_FB && rec.start < gib$(4)) { | ||||
|             hal_map_page((HalPage){kernel_page_table}, rec.start, rec.start, rec.size, HAL_MAP_READ | HAL_MAP_WRITE); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     debug$("Switching to page table %p", kernel_page_table); | ||||
|     hal_switch_space((HalPage){kernel_page_table}); | ||||
| } | ||||
							
								
								
									
										26
									
								
								src/kernel/hal/x86_64/paging.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/kernel/hal/x86_64/paging.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #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); | ||||
							
								
								
									
										46
									
								
								src/kernel/hal/x86_64/regs.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/kernel/hal/x86_64/regs.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
							
								
								
									
										37
									
								
								src/kernel/hal/x86_64/regs.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/kernel/hal/x86_64/regs.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <helpers/macro.h> | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| 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(n, no, val, ...) __cr(n, no, val) | ||||
| #define cr$(...)             _cr(GET_ARG_COUNT(__VA_ARGS__), __VA_ARGS__, 0) | ||||
|  | @ -18,6 +18,11 @@ static HandoverPayload* payload          = NULL; | |||
|     .revision = 0 | ||||
| }; | ||||
| 
 | ||||
| [[gnu::used, gnu::section(".limine_requests")]] static volatile struct limine_kernel_address_request kaddr_req = { | ||||
|     .id       = LIMINE_KERNEL_ADDRESS_REQUEST, | ||||
|     .revision = 0, | ||||
| }; | ||||
| 
 | ||||
| static void handover_parse_mmap(HandoverPayload* self) { | ||||
|     if (mmap_req.response == NULL) [[clang::unlikely]] { | ||||
|         panic$("Couldn't get limine's memory maps"); | ||||
|  | @ -86,6 +91,18 @@ HandoverPayload* handover(void) { | |||
|     if (payload == NULL) { | ||||
|         payload       = (HandoverPayload*)handover_buffer; | ||||
|         payload->size = kib$(16); | ||||
| 
 | ||||
|         if (kaddr_req.response == NULL) [[clang::unlikely]] { | ||||
|             return NULL; | ||||
|         } | ||||
| 
 | ||||
|         handover_append(payload, (HandoverRecord){ | ||||
|                                      .tag   = HANDOVER_KERNEL, | ||||
|                                      .more  = kaddr_req.response->virtual_base, | ||||
|                                      .start = kaddr_req.response->physical_base, | ||||
|                                      .size  = 0, | ||||
|                                  }); | ||||
| 
 | ||||
|         handover_parse_mmap(payload); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ | |||
| #include <logger> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #include "base/mod.h" | ||||
| #include "mod.h" | ||||
| 
 | ||||
| static PmmBitmap bitmap = {0}; | ||||
|  | @ -75,6 +74,8 @@ void pmm_init(void) { | |||
|             pmm_mark_free(record.start, record.size); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pmm_mark_used(0, page_size()); | ||||
| } | ||||
| 
 | ||||
| PhysObj pmm_alloc(size_t len) { | ||||
|  | @ -128,7 +129,7 @@ static void* _alloc([[gnu::unused]] void* ctx, size_t len) { | |||
| } | ||||
| 
 | ||||
| static void _free([[gnu::unused]] void* ctx, void* ptr, size_t len) { | ||||
|     PhysObj obj = {.base = (uintptr_t)hal_mmap_h2l((uintptr_t)ptr), .len = len}; | ||||
|     PhysObj obj = {.base = hal_mmap_h2l((uintptr_t)ptr), .len = len}; | ||||
|     pmm_free(obj); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										6
									
								
								src/libs/helpers/macro.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/libs/helpers/macro.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
		Loading…
	
	Add table
		
		Reference in a new issue