diff options
| author | Ada Christine <adachristine18@gmail.com> | 2021-04-02 18:04:26 +0000 |
|---|---|---|
| committer | Ada Christine <adachristine18@gmail.com> | 2021-04-02 18:04:26 +0000 |
| commit | 167481f8988a860ea6d7ea8bbdb7155e4eb7abeb (patch) | |
| tree | c348e1ea1bec525039decf6f15477d381f2d0bd7 | |
| parent | a41f11851c23390510a8cf9d0a932b9d08636fb0 (diff) | |
kernel has gdt now and loads segment register and we can allocate pages
| -rw-r--r-- | api/kernel/memory/paging.h | 2 | ||||
| -rwxr-xr-x | debug.sh | 3 | ||||
| -rw-r--r-- | kernel/Makefile | 2 | ||||
| -rw-r--r-- | kernel/cpu.c | 48 | ||||
| -rw-r--r-- | kernel/cpu.h | 4 | ||||
| -rw-r--r-- | kernel/entry_efi.c | 116 | ||||
| -rw-r--r-- | kernel/kernel.ld | 8 | ||||
| -rw-r--r-- | kernel/memory.c | 96 | ||||
| -rw-r--r-- | kernel/memory.h | 16 |
9 files changed, 202 insertions, 93 deletions
diff --git a/api/kernel/memory/paging.h b/api/kernel/memory/paging.h index 3d13eda..1f4ae47 100644 --- a/api/kernel/memory/paging.h +++ b/api/kernel/memory/paging.h @@ -1,5 +1,7 @@ #pragma once +#define PAGE_SIZE 0x1000 + #define PAGE_PR (1ULL << 0) #define PAGE_WR (1ULL << 1) #define PAGE_NX (1ULL << 63) @@ -8,5 +8,6 @@ make -C kernel && qemu-system-x86_64 -cpu qemu64 \ -drive if=pflash,format=raw,unit=0,file=/usr/share/ovmf/x64/OVMF_CODE.fd,readonly=on \ -drive if=pflash,format=raw,unit=1,file=OVMF_VARS.fd \ - -net none -drive file=uefi.img,if=ide -monitor stdio -serial file:sophia.log + -net none -drive file=uefi.img,if=ide -monitor stdio -serial file:sophia.log -d int \ + -no-shutdown -no-reboot -s -S diff --git a/kernel/Makefile b/kernel/Makefile index 7835041..1e6ce69 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -19,7 +19,7 @@ LOADLIBES := -lgcc SOBJS := GOBJS := entry_efi.o kprint.o serial.o port.o main.o memory.o \ - memset.o memcpy.o memmove.o memcmp.o + memset.o memcpy.o memmove.o memcmp.o cpu.o IOBJS := $(SOBJS): CFLAGS += -fPIC diff --git a/kernel/cpu.c b/kernel/cpu.c new file mode 100644 index 0000000..0d3a404 --- /dev/null +++ b/kernel/cpu.c @@ -0,0 +1,48 @@ +#include "cpu.h" + +#include <stdint.h> + +#define KERNEL_CODE_DESC 0x00af9a000000ffff +#define KERNEL_DATA_DESC 0x00cf92000000ffff + +#define KERNEL_CODE_SEL 0x8 +#define KERNEL_DATA_SEL 0x10 + +struct gdtr64 +{ + uint16_t limit; + uint64_t base; +} __attribute__((packed)); + +static uint64_t gdt[16]; + +void cpu_init(void) +{ + gdt[0] = 0; + gdt[1] = KERNEL_CODE_DESC; + gdt[2] = KERNEL_DATA_DESC; + + struct gdtr64 gdtr = {sizeof(gdt) - 1, (uint64_t)&gdt}; + + __asm__ volatile + ( "pushf\n" + "mov %%rsp, %%rcx\n" + "cli\n" + "lgdt %0\n" + "movw %w2, %%ds\n" + "movw %w2, %%es\n" + "movw %w2, %%fs\n" + "movw %w2, %%gs\n" + "push %q2\n" + "push %%rcx\n" + "pushf\n" + "push %q1\n" + "lea .flush(%%rip), %%rax\n" + "push %%rax\n" + "iretq\n" + ".flush:\n" + "popf\n" + :: "m"(gdtr), "a"(KERNEL_CODE_SEL), "d"(KERNEL_DATA_SEL) + ); +} + diff --git a/kernel/cpu.h b/kernel/cpu.h new file mode 100644 index 0000000..954762f --- /dev/null +++ b/kernel/cpu.h @@ -0,0 +1,4 @@ +#pragma once + +void cpu_init(void); + diff --git a/kernel/entry_efi.c b/kernel/entry_efi.c index 5400a77..4eaebc0 100644 --- a/kernel/entry_efi.c +++ b/kernel/entry_efi.c @@ -1,127 +1,65 @@ +#include <boot/entry_efi.h> + #include <stdbool.h> #include <stddef.h> #include <stdint.h> #include <stdnoreturn.h> -#include <boot/entry/entry_efi.h> - +#include "cpu.h" #include "serial.h" #include "kprint.h" +#include "memory.h" -#define ENTRY_STACK_SIZE 0x2000 -#define align2(x, a) ((x + a - 1) & ~(a - 1)) - -extern void kernel_main(void); - -enum page_range_type -{ - UNUSABLE_MEMORY, - RESERVED_MEMORY, - AVAILABLE_MEMORY -}; - -struct page_range -{ - uint64_t type; - uint64_t base; - size_t size; -}; - -static char entry_heap[0x10000]; -static char *entry_heap_base; -static char *entry_heap_head; - -static struct page_range *system_ranges; -static size_t system_ranges_count; +static noreturn void hang(void); -static void entry_heap_init(void) +static void free_memory_descriptor(EFI_MEMORY_DESCRIPTOR *desc) { - kputs("entry_heap_init() called\r\n"); + kputs("free_memory_descriptor() called\r\n"); + size_t size = desc->NumberOfPages * EFI_PAGE_SIZE; - entry_heap_base = entry_heap; - entry_heap_head = entry_heap; -} - -static void *entry_malloc(size_t size) -{ - kputs("entry_malloc() called\r\n"); - - void *buffer; - - size = align2(size, 16); - - if ((entry_heap_head - entry_heap_base + size) > sizeof(entry_heap)) - { - return NULL; - } - else + do { - buffer = entry_heap_head; - entry_heap_head += size; + size -= EFI_PAGE_SIZE; + page_free(desc->PhysicalStart + size); } - - return buffer; + while (size); } -static void parse_memory_ranges(struct efi_memory_map_data *map) +static void parse_efi_memmap(struct efi_memory_map_data *map) { - kputs("parse_memory_ranges() called\r\n"); - system_ranges_count = map->size/map->descsize; - system_ranges = entry_malloc(sizeof(*system_ranges) * system_ranges_count); + int entries = map->size / map->descsize; - for (unsigned int i = 0; i < system_ranges_count; i++) + for (int i = 0; i < entries; i++) { EFI_MEMORY_DESCRIPTOR *desc; - desc = (EFI_MEMORY_DESCRIPTOR *)(map->descsize * i + (char *)map->data); - system_ranges[i].base = desc->PhysicalStart; - system_ranges[i].size = desc->NumberOfPages * EFI_PAGE_SIZE; - + desc = (EFI_MEMORY_DESCRIPTOR *)((char *)map->data + i * map->descsize); + switch (desc->Type) { case EfiConventionalMemory: - case EfiBootServicesCode: case EfiBootServicesData: - case EfiLoaderCode: + case EfiBootServicesCode: case EfiLoaderData: - system_ranges[i].type = AVAILABLE_MEMORY; - break; - case SystemMemoryType: - system_ranges[i].type = RESERVED_MEMORY; + case EfiLoaderCode: + free_memory_descriptor(desc); break; default: - system_ranges[i].type = UNUSABLE_MEMORY; + break; } } } noreturn void kernel_entry(struct efi_boot_data *data) { + cpu_init(); serial_init(); kputs("<hacker voice> i'm in\r\n"); - entry_heap_init(); - - parse_memory_ranges(data->memory_map); - - void *acpi_rsdp = data->acpi_rsdp; - (void)acpi_rsdp; - - // we no longer need any loader data from here on. - // get the entry stack and clean up loader mappings - - char *entry_stack_base = entry_malloc(ENTRY_STACK_SIZE); - char *entry_stack_head = entry_stack_base + ENTRY_STACK_SIZE; - - __asm__("mov %0, %%rsp" :: "r"(entry_stack_head)); - - uint64_t pml4_raw; - __asm__("mov %%cr3, %0" : "=r"(pml4_raw)); - uint64_t *pml4 = (uint64_t *)(pml4_raw & ~((1ULL << 12) - 1)); - pml4[0] = 0; - __asm__("mov %0, %%cr3" :: "r"(pml4_raw)); - - // we can now go to the kernel proper - kernel_main(); + parse_efi_memmap(data->memory_map); + hang(); +} +static noreturn void hang(void) +{ __asm__ ("cli\n\t"); while (true) __asm__ ("hlt\n\t"); } diff --git a/kernel/kernel.ld b/kernel/kernel.ld index 17cb8b4..47dcf3b 100644 --- a/kernel/kernel.ld +++ b/kernel/kernel.ld @@ -1,17 +1,20 @@ ENTRY(kernel_entry) -k_virt_base = 0xffffffff80000000; +PROVIDE(k_virt_base = 0xffffffff80000000); SECTIONS { .text k_virt_base : AT(ADDR(.text) - k_virt_base) { + PROVIDE(k_text_begin = .); *(.text) . = ALIGN(4K); - } =0x90 + PROVIDE(k_text_end = .); + } =0xcc .data ALIGN(4K) : AT(ADDR(.data) - k_virt_base) { + PROVIDE(k_data_begin = .); *(.rodata) *(.data) } @@ -19,6 +22,7 @@ SECTIONS .bss : { *(.bss) + PROVIDE(k_data_end = .); } /DISCARD/ : diff --git a/kernel/memory.c b/kernel/memory.c new file mode 100644 index 0000000..b6fa5b2 --- /dev/null +++ b/kernel/memory.c @@ -0,0 +1,96 @@ +#include "memory.h" + +#include <kernel/memory/paging.h> + +/* + * kernel virtual space guarantees + * + * 1. there are two kernel page directories, one each for the lower and upper + * GiB of space. they are self-mapped as tables in the trailing entries + * of the table for the upper space. these must exist. + * 2. because of (1.) the kernel page tables (directoires inclusive) occupy + * the upper 4MiB of kernel address space. + * 3. the kernel is always at the beginning of its virtual space. + * currently this is 0xffffffff80000000 but that may change + * 4. the entry stack's head is always -4MiB from the end of the address space. + * its size is currently 64KiB. this may change. + */ + +#define kpde_index(v) ((v >> (PAGE_MAP_BITS + PAGE_OFFSET_BITS)) & 0x3ff) +#define kpte_index(v) ((v >> PAGE_OFFSET_BITS) & 0x7ffff) + +extern char k_virt_base; +extern char k_text_begin; +extern char k_text_end; +extern char k_data_begin; +extern char k_data_end; + +static uint64_t *const kernel_ptes = (uint64_t *)0xffffffffffc00000; +static uint64_t *const kernel_pdes = (uint64_t *)0xffffffffffffe000; + +// we can track 4GiB of physical pages with this bitmap. +#define PAGE_BITMAP_ENTRIES 16384 +#define PAGE_BITMAP_WIDTH 64 +static uint64_t page_bitmap[PAGE_BITMAP_ENTRIES]; + +static phys_addr_t bitmap_alloc(void) +{ + static uint64_t *page_bitmap_last = NULL; + + if (!page_bitmap_last || !*page_bitmap_last) + { + for (int i = 0; i < PAGE_BITMAP_ENTRIES; i++) + { + if (page_bitmap[i]) + { + page_bitmap_last = &page_bitmap[i]; + break; + } + } + } + + int index = page_bitmap_last - page_bitmap; + int bit = __builtin_ffsll(*page_bitmap_last); + + return (index * PAGE_BITMAP_WIDTH + bit) * PAGE_SIZE; +} + +static void bitmap_free(phys_addr_t page) +{ + int index = (page >> PAGE_OFFSET_BITS) / PAGE_BITMAP_WIDTH; + int bit = (page >> PAGE_OFFSET_BITS) % PAGE_BITMAP_WIDTH; + page_bitmap[index] |= (1 << bit); +} +/* +static virt_addr_t virtual_alloc(void) +{ +} + +static void virtual_free(virt_addr_t vpage) +{ +} +*/ +static uint64_t *get_kernel_pde(virt_addr_t vaddr) +{ + return &kernel_pdes[kpde_index(vaddr)]; +} + +static uint64_t *get_kernel_pte(uint64_t vaddr) +{ + return &kernel_ptes[kpte_index(vaddr)]; +} + +void memory_init() +{ +} + +phys_addr_t page_alloc(void) +{ + return bitmap_alloc(); +} + +void page_free(phys_addr_t page) +{ + bitmap_free(page); +} + diff --git a/kernel/memory.h b/kernel/memory.h new file mode 100644 index 0000000..da573da --- /dev/null +++ b/kernel/memory.h @@ -0,0 +1,16 @@ +#pragma once + +#include <stddef.h> +#include <stdint.h> + +typedef uint64_t phys_addr_t; +typedef uint64_t virt_addr_t; + +void memory_init(); + +void *kmalloc(size_t size); +void kfree(void *block); + +phys_addr_t page_alloc(void); +void page_free(phys_addr_t page); + |
