Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
e5b7a172eb | |||
2b3a27a398 |
35 changed files with 764 additions and 46 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>
|
||||
|
@ -17,7 +18,7 @@ void kmain(void);
|
|||
static uint8_t early_heap[kib$(32)];
|
||||
static DTBNode* dtb_root = NULL;
|
||||
|
||||
void rv32_start(__attribute__((unused)) size_t hartid, uintptr_t dtb) {
|
||||
void rv32_start([[gnu::unused]] size_t hartid, uintptr_t dtb) {
|
||||
write_csr$(stvec, (uint32_t)interrupt_kernel);
|
||||
|
||||
BumpAllocator alloc = bump_allocator_create((void*)early_heap, sizeof(early_heap));
|
||||
|
@ -36,6 +37,7 @@ void rv32_start(__attribute__((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,10 +1,10 @@
|
|||
#include <hal>
|
||||
#include <handover>
|
||||
#include <helpers/mem.h>
|
||||
#include <logger>
|
||||
#include <pmm>
|
||||
#include <string.h>
|
||||
|
||||
#include "base/mod.h"
|
||||
#include "paging.h"
|
||||
#include "regs.h"
|
||||
|
||||
|
|
|
@ -31,9 +31,9 @@ enum mapping_flags {
|
|||
MAPPING_USER = 1 << 4,
|
||||
};
|
||||
|
||||
struct _hal_page {
|
||||
struct [[gnu::packed]] _hal_page {
|
||||
uint32_t* ptr;
|
||||
} __attribute__((packed));
|
||||
};
|
||||
|
||||
#define vpn1$(x) ((x >> 22) & 0x3FF)
|
||||
#define vpn0$(x) ((x >> 12) & 0x3FF)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
typedef struct [[gnu::packed]] {
|
||||
uint32_t ra;
|
||||
uint32_t gp;
|
||||
uint32_t tp;
|
||||
|
|
|
@ -1,16 +1,25 @@
|
|||
#include <dtb>
|
||||
#include <kmalloc>
|
||||
#include <limine>
|
||||
#include <logger>
|
||||
#include <pmm>
|
||||
|
||||
__attribute__((used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3);
|
||||
__attribute__((used, section(".limine_requests_start"))) static volatile LIMINE_REQUESTS_START_MARKER;
|
||||
__attribute__((used, section(".limine_requests_end"))) static volatile LIMINE_REQUESTS_END_MARKER;
|
||||
#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;
|
||||
|
||||
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
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include "serial.h"
|
||||
|
||||
__attribute__((used, section(".limine_requests"))) static volatile struct limine_hhdm_request hhdm_req = {
|
||||
[[gnu::used, gnu::section(".limine_requests")]] static volatile struct limine_hhdm_request hhdm_req = {
|
||||
.id = LIMINE_HHDM_REQUEST,
|
||||
.revision = 0,
|
||||
};
|
||||
|
@ -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)
|
|
@ -15,7 +15,7 @@ void kmalloc_init(void) {
|
|||
slabs[5] = slab_create(256, &pmm);
|
||||
}
|
||||
|
||||
static void* _alloc(__attribute__((unused)) void* ctx, size_t len) {
|
||||
static void* _alloc([[gnu::unused]] void* ctx, size_t len) {
|
||||
Allocator* alloc = NULL;
|
||||
|
||||
if (len <= 8) {
|
||||
|
@ -38,7 +38,7 @@ static void* _alloc(__attribute__((unused)) void* ctx, size_t len) {
|
|||
return alloc->alloc(alloc, len);
|
||||
}
|
||||
|
||||
static void _free(__attribute__((unused)) void* ctx, void* ptr, size_t len) {
|
||||
static void _free([[gnu::unused]] void* ctx, void* ptr, size_t len) {
|
||||
Allocator* alloc = NULL;
|
||||
|
||||
if (len <= 8) {
|
||||
|
|
|
@ -13,11 +13,16 @@ static HandoverPayload* payload = NULL;
|
|||
|
||||
/* --- Limine requests ------------------------------------------------------ */
|
||||
|
||||
__attribute__((used, section(".limine_requests"))) static volatile struct limine_memmap_request mmap_req = {
|
||||
[[gnu::used, gnu::section(".limine_requests")]] static volatile struct limine_memmap_request mmap_req = {
|
||||
.id = LIMINE_MEMMAP_REQUEST,
|
||||
.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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#include "stdlib.h"
|
||||
#include <hal>
|
||||
#include <logger>
|
||||
|
||||
__attribute__((noreturn)) void abort(void) {
|
||||
hal_brkpoint();
|
||||
#include "stdlib.h"
|
||||
|
||||
[[noreturn]] void abort(void) {
|
||||
panic$("Abort was called");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
__attribute__((noreturn)) void abort(void);
|
||||
[[noreturn]] void abort(void);
|
||||
|
|
|
@ -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) {
|
||||
|
@ -118,7 +119,7 @@ void pmm_free(PhysObj obj) {
|
|||
|
||||
// === ALLOCATOR ===
|
||||
|
||||
static void* _alloc(__attribute__((unused)) void* ctx, size_t len) {
|
||||
static void* _alloc([[gnu::unused]] void* ctx, size_t len) {
|
||||
PhysObj obj = pmm_alloc(len);
|
||||
if (obj.len == 0) {
|
||||
return NULL;
|
||||
|
@ -127,8 +128,8 @@ static void* _alloc(__attribute__((unused)) void* ctx, size_t len) {
|
|||
return hal_mmap_l2h(obj.base);
|
||||
}
|
||||
|
||||
static void _free(__attribute__((unused)) void* ctx, void* ptr, size_t len) {
|
||||
PhysObj obj = {.base = (uintptr_t)hal_mmap_h2l((uintptr_t)ptr), .len = len};
|
||||
static void _free([[gnu::unused]] void* ctx, void* ptr, size_t len) {
|
||||
PhysObj obj = {.base = hal_mmap_h2l((uintptr_t)ptr), .len = len};
|
||||
pmm_free(obj);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ static void* alloc(void* ctx, size_t len) {
|
|||
return (void*)ptr;
|
||||
}
|
||||
|
||||
static void free(void* ctx, __attribute__((unused)) void* ptr, __attribute__((unused)) size_t len) {
|
||||
static void free(void* ctx, [[gnu::unused]] void* ptr, [[gnu::unused]] size_t len) {
|
||||
BumpAllocator* self = (BumpAllocator*)ctx;
|
||||
self->allocations--;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ static size_t page_amount(size_t size) {
|
|||
}
|
||||
}
|
||||
|
||||
static void* _alloc(void* ctx, __attribute__((unused)) size_t len) {
|
||||
static void* _alloc(void* ctx, [[gnu::unused]] size_t len) {
|
||||
SlabAllocator* alloc = (SlabAllocator*)ctx;
|
||||
if (alloc->root == NULL) {
|
||||
return NULL;
|
||||
|
@ -30,7 +30,7 @@ static void* _alloc(void* ctx, __attribute__((unused)) size_t len) {
|
|||
return ptr;
|
||||
}
|
||||
|
||||
static void _free(void* ctx, void* ptr, __attribute__((unused)) size_t len) {
|
||||
static void _free(void* ctx, void* ptr, [[gnu::unused]] size_t len) {
|
||||
SlabAllocator* alloc = (SlabAllocator*)ctx;
|
||||
Slab* free = (Slab*)((uintptr_t)ptr - sizeof(Slab));
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#define FDT_NOP 0x4
|
||||
#define FDT_END 0x9
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
typedef struct [[gnu::packed]] {
|
||||
uint32_t magic;
|
||||
uint32_t totalsize;
|
||||
uint32_t off_dt_struct;
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
LIST(ENUM_ITEM) \
|
||||
} PREFIX##Error;
|
||||
|
||||
#define DECLARE_ERROR_STRING(PREFIX, LIST) \
|
||||
__attribute__((used)) static const char* PREFIX##ErrorStrings[] = { \
|
||||
LIST(STRINGIFY) \
|
||||
}; \
|
||||
\
|
||||
inline static char const* PREFIX##ErrorString(PREFIX##Error err) { \
|
||||
return PREFIX##ErrorStrings[err]; \
|
||||
#define DECLARE_ERROR_STRING(PREFIX, LIST) \
|
||||
[[gnu::used]] static const char* PREFIX##ErrorStrings[] = { \
|
||||
LIST(STRINGIFY) \
|
||||
}; \
|
||||
\
|
||||
inline static char const* PREFIX##ErrorString(PREFIX##Error err) { \
|
||||
return PREFIX##ErrorStrings[err]; \
|
||||
}
|
||||
|
|
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