From e303a03e7c96bc5bf7fa93f7b46ce63196893d7a Mon Sep 17 00:00:00 2001 From: Ada Christine Date: Sun, 19 Dec 2021 22:41:15 +0000 Subject: moving files around --- kc/boot/Makefile | 37 ++++ kc/boot/kc_main.c | 73 +++++++ kc/component.ld | 75 ++++++++ kc/core/Makefile | 39 ++++ kc/core/cpu.c | 225 ++++++++++++++++++++++ kc/core/cpu.h | 9 + kc/core/exceptions.S | 54 ++++++ kc/core/exceptions.h | 7 + kc/core/kc_main.c | 69 +++++++ kc/core/kprint.c | 18 ++ kc/core/kprint.h | 5 + kc/core/main.c | 4 + kc/core/memory.c | 534 +++++++++++++++++++++++++++++++++++++++++++++++++++ kc/core/memory.h | 53 +++++ kc/core/panic.c | 25 +++ kc/core/panic.h | 13 ++ kc/core/port.c | 14 ++ kc/core/port.h | 5 + kc/core/serial.c | 41 ++++ kc/core/serial.h | 5 + kc/entry_x86_64.S | 18 ++ kc/reloc_x86_64.c | 69 +++++++ kernel/Makefile | 39 ---- kernel/cpu.c | 225 ---------------------- kernel/cpu.h | 9 - kernel/entry.c | 69 ------- kernel/exceptions.S | 54 ------ kernel/exceptions.h | 7 - kernel/kernel.ld | 33 ---- kernel/kprint.c | 18 -- kernel/kprint.h | 5 - kernel/main.c | 4 - kernel/memory.c | 534 --------------------------------------------------- kernel/memory.h | 53 ----- kernel/panic.c | 25 --- kernel/panic.h | 13 -- kernel/port.c | 14 -- kernel/port.h | 5 - kernel/serial.c | 41 ---- kernel/serial.h | 5 - lib/component.ld | 75 -------- lib/entry_x86_64.S | 18 -- lib/reloc_x86_64.c | 69 ------- shim/Makefile | 37 ---- shim/kc_main.c | 73 ------- 45 files changed, 1392 insertions(+), 1425 deletions(-) create mode 100644 kc/boot/Makefile create mode 100644 kc/boot/kc_main.c create mode 100644 kc/component.ld create mode 100644 kc/core/Makefile create mode 100644 kc/core/cpu.c create mode 100644 kc/core/cpu.h create mode 100644 kc/core/exceptions.S create mode 100644 kc/core/exceptions.h create mode 100644 kc/core/kc_main.c create mode 100644 kc/core/kprint.c create mode 100644 kc/core/kprint.h create mode 100644 kc/core/main.c create mode 100644 kc/core/memory.c create mode 100644 kc/core/memory.h create mode 100644 kc/core/panic.c create mode 100644 kc/core/panic.h create mode 100644 kc/core/port.c create mode 100644 kc/core/port.h create mode 100644 kc/core/serial.c create mode 100644 kc/core/serial.h create mode 100644 kc/entry_x86_64.S create mode 100644 kc/reloc_x86_64.c delete mode 100644 kernel/Makefile delete mode 100644 kernel/cpu.c delete mode 100644 kernel/cpu.h delete mode 100644 kernel/entry.c delete mode 100644 kernel/exceptions.S delete mode 100644 kernel/exceptions.h delete mode 100644 kernel/kernel.ld delete mode 100644 kernel/kprint.c delete mode 100644 kernel/kprint.h delete mode 100644 kernel/main.c delete mode 100644 kernel/memory.c delete mode 100644 kernel/memory.h delete mode 100644 kernel/panic.c delete mode 100644 kernel/panic.h delete mode 100644 kernel/port.c delete mode 100644 kernel/port.h delete mode 100644 kernel/serial.c delete mode 100644 kernel/serial.h delete mode 100644 lib/component.ld delete mode 100644 lib/entry_x86_64.S delete mode 100644 lib/reloc_x86_64.c delete mode 100644 shim/Makefile delete mode 100644 shim/kc_main.c diff --git a/kc/boot/Makefile b/kc/boot/Makefile new file mode 100644 index 0000000..76bd4d4 --- /dev/null +++ b/kc/boot/Makefile @@ -0,0 +1,37 @@ +include ../../defaults.mk + +VPATH := ../../lib ../ + +TARGET := efi.os +.DEFAULT: $(TARGET) + +# EFI API for temporary things + +EFIAPIDIR := /usr/local/include/efi + +CPPFLAGS += -I../../api -I$(EFIAPIDIR) -I$(EFIAPIDIR)/$(ARCH) -I$(EFIAPIDIR)/protocol +CFLAGS += -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden \ + -g -fshort-wchar -mgeneral-regs-only + +LIBDIRS += -L$(dir $(shell $(CC) -print-libgcc-file-name)) +LDSCRIPT := ../component.ld +LDFLAGS += -z max-page-size=4096 --export-dynamic -pic --no-dynamic-linker +LOADLIBES := -lgcc + +OBJS := entry_x86_64.o reloc_x86_64.o kc_main.o elf64.o memcmp.o memcpy.o \ + memmove.o memset.o +$(OBJS): CFLAGS += -fPIC + +DEPS := $(patsubst %.o,%.d,$(OBJS)) + +$(TARGET): $(LDSCRIPT) $(MAKEFILE_LIST) +$(TARGET): $(OBJS) + +CLEANLIST := $(wildcard $(OBJS) $(TARGET)) +DCLEANLIST := $(wildcard $(DEPS)) + +include ../../rules.mk +-include $(DEPS) + +.DEFAULT: $(TARGET) + diff --git a/kc/boot/kc_main.c b/kc/boot/kc_main.c new file mode 100644 index 0000000..1829616 --- /dev/null +++ b/kc/boot/kc_main.c @@ -0,0 +1,73 @@ +#include +#include + +#include + +#include "../lib/elf.h" + +struct efi_memory_map +{ + struct memory_range buffer; + UINTN size; + UINTN key; + UINTN descsize; + UINT32 descver; +}; + +struct efi_video_data +{ + struct memory_range buffer; + UINT32 width; + UINT32 height; + UINT32 pitch; + EFI_GRAPHICS_PIXEL_FORMAT format; + EFI_PIXEL_BITMASK mask; +}; + +struct efi_boot_data +{ + struct efi_memory_map memory_map; + struct efi_video_data video_data; + void *acpi_rsdp; + unsigned long acpi_version; +}; + +struct efi_loader_image kernel_image = +{ + .path = L"\\adasoft\\sophia\\kernel.os" +}; + +static struct efi_boot_data boot_data; + +// TODO: split relocation code out into library + +EFI_STATUS kc_main(struct efi_loader_interface *interface) +{ + // 1. load kernel and boot modules into memory + // 2. generate page tables for kernel and boot modules + // 2. gather boot data, store as type SystemMemoryType + // 3. exit boot services + // 5. ??????????? + + EFI_STATUS status; + + if (!interface) + { + return EFI_INVALID_PARAMETER; + } + + if (!EFI_ERROR((status = interface->image_open(&kernel_image))) && + !EFI_ERROR((status = interface->image_alloc(&kernel_image))) && + !EFI_ERROR((status = interface->image_load(&kernel_image)))) + { + (void)boot_data; + } + + __asm__ volatile ( + "cli\n\t" + "hlt\n\t" + ); + + return status; +} + diff --git a/kc/component.ld b/kc/component.ld new file mode 100644 index 0000000..3a48ae8 --- /dev/null +++ b/kc/component.ld @@ -0,0 +1,75 @@ +ENTRY(kc_entry) + +SECTIONS +{ + PROVIDE(kc_image_base = .); + + . = sizeof_headers; + + .rel : + { + *(.rel) + *(.rel.*) + } + + .rela : + { + *(.rel) + *(.rela.*) + } + + .hash : + { + *(.hash) + } + + .dynsym : + { + *(.dynsym) + } + + .dynstr : + { + *(.dynstr) + } + + .text : ALIGN(4K) + { + PROVIDE(kc_text_begin = .); + *(.text.start) + *(.text) + . = ALIGN(4K); + PROVIDE(kc_text_end = .); + } =0xcc + + .dynamic : ALIGN(4K) + { + *(.dynamic) + } + + .data : + { + PROVIDE(kc_data_begin = .); + *(.rodata) + *(.data) + } + + .data.rel : + { + *(.data.rel) + *(.data.rel.*) + } + + .bss : + { + *(.bss) + PROVIDE(kc_data_end = .); + } + + /DISCARD/ : + { + *(.eh_frame) + *(.comment) + } +} + diff --git a/kc/core/Makefile b/kc/core/Makefile new file mode 100644 index 0000000..2893b42 --- /dev/null +++ b/kc/core/Makefile @@ -0,0 +1,39 @@ +include ../../defaults.mk + +VPATH := ../../lib ../ + +TARGET := kernel.os +.DEFAULT: $(TARGET) + +CPPFLAGS += -I../../api +CFLAGS += -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden -g + +LIBDIRS += -L$(dir $(shell $(CC) -print-libgcc-file-name)) +LDSCRIPT := ../component.ld +LDFLAGS += -z max-page-size=4096 --export-dynamic -pic --no-dynamic-linker +LOADLIBES := -lgcc + +SOBJS := +GOBJS := entry_x86_64.o reloc_x86_64.o kprint.o serial.o port.o \ + kc_main.o memory.o memset.o memcpy.o memmove.o memcmp.o cpu.o \ + exceptions.o panic.o +IOBJS := + +# __attribute__((interrupt)) requires -mgeneral-regs-only +$(IOBJS): CFLAGS += -mgeneral-regs-only +$(IOBJS) $(GOBJS): CFLAGS += -mcmodel=small -fPIC + +OBJS := $(SOBJS) $(GOBJS) $(IOBJS) +DEPS := $(patsubst %.o,%.d,$(OBJS)) + +$(TARGET): $(LDSCRIPT) $(MAKEFILE_LIST) +$(TARGET): $(OBJS) + +CLEANLIST := $(wildcard $(OBJS) $(TARGET)) +DCLEANLIST := $(wildcard $(DEPS)) + +include ../../rules.mk +-include $(DEPS) + +.DEFAULT: $(TARGET) + diff --git a/kc/core/cpu.c b/kc/core/cpu.c new file mode 100644 index 0000000..ed1a04e --- /dev/null +++ b/kc/core/cpu.c @@ -0,0 +1,225 @@ +#include "cpu.h" +#include "exceptions.h" + +#include + +#define GDT_ENTRIES 16 +#define IDT_ENTRIES 256 + +#define CODE_SEG_INDEX 1 +#define DATA_SEG_INDEX 2 +#define TASK_SEG_INDEX 3 + +struct dtr64 +{ + uint16_t limit; + uint64_t base; +} __attribute__((packed)); + +struct segment_descriptor +{ + uint16_t limit0; + uint16_t base0; + uint8_t base16; + uint8_t access; + uint8_t flags_limit16; + uint8_t base24; +} __attribute__((packed)); + +enum segment_descriptor_type +{ + CODE64_SEG, + DATA_SEG, + TASK64_SEG, +}; + +struct gate_descriptor +{ + uint16_t offset0; + uint16_t selector; + uint8_t ist; + uint8_t access; + uint16_t offset16; + uint64_t offset32; +} __attribute__((packed)); + +enum gate_descriptor_type +{ + INT64_GATE, + TRAP64_GATE, +}; + +struct task64_segment +{ + uint32_t reserved0; + uint64_t rsp0; + uint64_t rsp1; + uint64_t rsp2; + uint64_t reserved1; + uint64_t ist[7]; + uint16_t reserved2; + uint16_t iomap_base; +}; + +static struct segment_descriptor gdt[GDT_ENTRIES]; +static struct gate_descriptor idt[IDT_ENTRIES]; +static struct task64_segment tss; + +static void set_gdt(int index, + uint64_t base, + uint64_t limit, + enum segment_descriptor_type type) +{ + gdt[index].limit0 = limit & 0xffff; + gdt[index].base0 = base & 0xffff; + gdt[index].base16 = (base >> 16) & 0xff; + gdt[index].flags_limit16 = (limit >> 16) & 0xf; + gdt[index].base24 = (base >> 24) & 0xff; + + switch (type) + { + case CODE64_SEG: + gdt[index].access = 0x9a; + gdt[index].flags_limit16 |= 0xa0; + break; + case DATA_SEG: + gdt[index].access = 0x92; + gdt[index].flags_limit16 |= 0xc0; + break; + case TASK64_SEG: + gdt[index].access = 0x89; + //TODO: make this cleaner i don't like it + gdt[index+1].limit0 = (base >> 32) & 0xffff; + gdt[index+1].base0 = (base >> 48) & 0xffff; + break; + }; +} + +static void set_idt(int vec, + uint16_t selector, + uint64_t offset, + enum gate_descriptor_type type) +{ + idt[vec].offset0 = offset & 0xffff; + idt[vec].selector = selector; + idt[vec].offset16 = (offset >> 16) & 0xffff; + idt[vec].offset32 = (offset >> 32) & 0xffffffff; + + switch (type) + { + case INT64_GATE: + idt[vec].access = 0x8e; + break; + case TRAP64_GATE: + idt[vec].access = 0x8f; + break; + } +} + +void set_ist(int vec, int ist_index) +{ + // non-destructively set the ist index. + idt[vec].access |= ist_index & 0x7; +} + +static void gdt_init(void) +{ + set_gdt(CODE_SEG_INDEX, 0, (uint64_t)-1, CODE64_SEG); + set_gdt(DATA_SEG_INDEX, 0, (uint64_t)-1, DATA_SEG); + set_gdt(TASK_SEG_INDEX, (uint64_t)&tss, sizeof(tss) - 1, TASK64_SEG); + + struct dtr64 gdtr = {sizeof(gdt) - 1, (uint64_t)&gdt}; + + __asm__ volatile + ( + // can't have interrupts during GDT reload + // but don't re-enable interrupts if they were already disabled + "pushf\n" + "cli\n" + "lgdt %0\n" + "mov %w2, %%ds\n" + "mov %w2, %%es\n" + "mov %w2, %%fs\n" + "mov %w2, %%gs\n" + "mov %w2, %%ss\n" + // make a far return frame on the stack + // [ss] @rsp+8 + // [rip] @rsp + "pushq %1\n" + "lea .Lflush(%%rip), %%rax\n" + "push %%rax\n" + // far return, now we're in the code segment + // defined here. + "lretq\n" + ".Lflush:\n" + "ltr %w3\n" + "popf\n" + // dependency on pre-boot GDT is now gone + : + : "m"(gdtr), + "i"(CODE_SEG_INDEX << 3), + "r"(DATA_SEG_INDEX << 3), + "r"(TASK_SEG_INDEX << 3) + ); +} + +static void idt_init(void) +{ + struct dtr64 idtr = {sizeof(idt) - 1, (uint64_t)&idt}; + + __asm__ volatile + ( + // can't have interrupts enabled during IDT reload--obviously. + // as with GDT don't re-enable interrupts if they were already + // disabled. + "pushf\n" + "cli\n" + "lidt %0\n" + "popf\n" + // much more straightforward than the gdt code. + :: "m"(idtr) + ); +} + +void cpu_init(void) +{ + gdt_init(); + idt_init(); + exceptions_init(); +} + +void exceptions_init(void) +{ + isr_install(PAGE_FAULT_VECTOR, &page_fault_isr, 0, 0); +} + +void isr_install(int vec, void (*isr)(void), int trap, int ist) +{ + enum gate_descriptor_type type = INT64_GATE; + + if (trap) + { + type = TRAP64_GATE; + } + + set_idt(vec, CODE_SEG_INDEX << 3, (uint64_t)isr, type); + if (ist) + { + set_ist(vec, ist); + } +} + +void ist_install(int ist, void *stack) +{ + tss.ist[ist] = (uint64_t)stack; +} + +void int_enable(void) +{ + __asm__ ("sti"); +} + +void int_disable(void) +{ + __asm__ ("cli"); +} diff --git a/kc/core/cpu.h b/kc/core/cpu.h new file mode 100644 index 0000000..56a4073 --- /dev/null +++ b/kc/core/cpu.h @@ -0,0 +1,9 @@ +#pragma once + +void cpu_init(void); + +void isr_install(int vec, void (*isr)(void), int ist, int trap); +void ist_install(int ist, void *stack); + +void int_enable(void); +void int_disable(void); diff --git a/kc/core/exceptions.S b/kc/core/exceptions.S new file mode 100644 index 0000000..80d49ee --- /dev/null +++ b/kc/core/exceptions.S @@ -0,0 +1,54 @@ +.extern page_fault_handler + +.global page_fault_isr +.type page_fault_isr, @function +page_fault_isr: + /* just in case something tried to be clever before */ + cld + /* push param registers */ + push %rdi + push %rsi + push %rdx + push %rcx + push %r8 + push %r9 + /* collect parameters for page fault handler */ + mov 48(%rsp), %rdi /* error code is first parameter */ + mov %cr2, %rsi /* PFLA is next parameter */ + /* caller-saved registers */ + push %rax + push %r10 + push %r11 + /* callee-saved registers */ + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + /* stack has to be aligned */ + mov %rsp, %rbp + and $-16, %rsp + call page_fault_handler + mov %rbp, %rsp + /* TODO: test for error code here and panic() */ + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %r11 + pop %r10 + pop %rax + pop %r9 + pop %r8 + pop %rcx + pop %rdx + pop %rsi + pop %rdi + /* unwind the error code from the stack */ + add $8, %rsp + /* leave the isr */ + iretq +.size page_fault_isr, . - page_fault_isr diff --git a/kc/core/exceptions.h b/kc/core/exceptions.h new file mode 100644 index 0000000..5d22284 --- /dev/null +++ b/kc/core/exceptions.h @@ -0,0 +1,7 @@ +#pragma once + +extern void page_fault_isr(void); + +#define PAGE_FAULT_VECTOR 0xe + +void exceptions_init(void); diff --git a/kc/core/kc_main.c b/kc/core/kc_main.c new file mode 100644 index 0000000..5eecaf2 --- /dev/null +++ b/kc/core/kc_main.c @@ -0,0 +1,69 @@ +#include "cpu.h" +#include "serial.h" +#include "kprint.h" +#include "memory.h" +#include "panic.h" + +#include + +#include + +#include +#include +#include +#include + +static void efi_memory_init(struct efi_memory_map_data *map) +{ + // FIXME: bad girl shit: overwriting on aliased pointers. + // this is a temporary solution to shortcomings with + // loader boot data. it's sort-of OK because the memory_range struct + // is smaller than EFI_MEMORY_DESCRIPTOR. it's still not good. + struct memory_range *ranges = (struct memory_range *)map->data; + int entries = map->size / map->descsize; + + for (int i = 0; i < entries; i++) + { + EFI_MEMORY_DESCRIPTOR *desc; + desc = (EFI_MEMORY_DESCRIPTOR *)((char *)map->data + i * map->descsize); + + enum memory_range_type type; + phys_addr_t base; + size_t size; + + base = desc->PhysicalStart; + size = desc->NumberOfPages * EFI_PAGE_SIZE; + + switch (desc->Type) + { + case EfiConventionalMemory: + case EfiBootServicesData: + case EfiBootServicesCode: + case EfiLoaderData: + case EfiLoaderCode: + type = AVAILABLE_MEMORY; + break; + case SystemMemoryType: + type = SYSTEM_MEMORY; + break; + default: + type = RESERVED_MEMORY; + } + + ranges[i].type = type; + ranges[i].base = base; + ranges[i].size = size; + } + + memory_init(ranges, entries); +} + +noreturn void kernel_entry(struct efi_boot_data *data) +{ + (void)data; + cpu_init(); + serial_init(); + kputs(" i'm in\r\n"); + efi_memory_init(data->memory_map); + halt(); +} diff --git a/kc/core/kprint.c b/kc/core/kprint.c new file mode 100644 index 0000000..0a15efd --- /dev/null +++ b/kc/core/kprint.c @@ -0,0 +1,18 @@ +#include "kprint.h" +#include "serial.h" + +int kputchar(int c) +{ + return serial_putchar(c); +} + +int kputs(const char *s) +{ + while (*s) + { + kputchar(*s++); + } + + return 0; +} + diff --git a/kc/core/kprint.h b/kc/core/kprint.h new file mode 100644 index 0000000..5b307a2 --- /dev/null +++ b/kc/core/kprint.h @@ -0,0 +1,5 @@ +#pragma once + +int kputchar(int c); +int kputs(const char *s); + diff --git a/kc/core/main.c b/kc/core/main.c new file mode 100644 index 0000000..2fb2e3e --- /dev/null +++ b/kc/core/main.c @@ -0,0 +1,4 @@ +void kernel_main(void) +{ +} + diff --git a/kc/core/memory.c b/kc/core/memory.c new file mode 100644 index 0000000..62f3a38 --- /dev/null +++ b/kc/core/memory.c @@ -0,0 +1,534 @@ +#include "memory.h" +#include "kprint.h" +#include "panic.h" + +#include + +#include +#include + +/* kernel virtual space guarantees + * + * the loader must set up the address space as follows + * 1. kernel virtual space is 2GiB in size on 2GiB alignment. + * 2. mappings begin at +0x7fc00000. this mapping space is sparse and its + * own mapping tables begin at +0x7fffe000. + */ + +#define kpm1_index(v) (((uint64_t)v >> pte_index_bits(1)) & 0x7ffff) +#define kpm2_index(v) (((uint64_t)v >> pte_index_bits(2)) & 0x3ff) + +#define align_next(v, a) (((uint64_t)v + a - 1) & ~(a - 1)) + +// a conservative 128MB for kernel heap +#define KERNEL_HEAP_SPACE_SIZE (128 << 20) + +typedef int (*page_fault_handler_func)(uint32_t code, void *address); + +enum memory_space_flags +{ + SYSTEM_MEMORY_SPACE, // memory that cannot fault + ANONYMOUS_MEMORY_SPACE, // memory that can fault +}; + +struct memory_space +{ + enum memory_space_flags flags; + page_fault_handler_func handler; + void *base; + void *head; + struct memory_space *next; + struct memory_space *prev; +}; + +struct page +{ + uint32_t next: 31; + uint32_t used: 1; +}; + +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 struct page *const page_array = (struct page *)0xffffffd800000000; +static int first_free_page_index = -1; +static size_t page_array_entries = 0; +static size_t free_pages = 0; + +// the temporary mapping place. never use this permanently. +static void *const temp = (void *)0xffffffffffa00000; +static uint64_t *const kernel_pm1 = (uint64_t *)0xffffffffffc00000; +static uint64_t *const kernel_pm2 = (uint64_t *)0xffffffffffffe000; + +static uint64_t *get_kernel_pm1e(void *vaddr); +static uint64_t *get_kernel_pm2e(void *vaddr); +static void *get_virtual_page(enum page_map_flags flags); +static void *page_map_at(void *vaddr, phys_addr_t paddr, enum page_map_flags flags); + +// handlers for memory space types +int anonymous_page_handler(uint32_t code, void *address); + +// the system memory_space's that are always present +static struct memory_space kernel_image_space; +static struct memory_space kernel_stack_space; +static struct memory_space kernel_pagemap_space; +// the kernel's own heap space +static struct memory_space kernel_heap_space; + +// NULL if the system address spaces are not set up +static struct memory_space *root_memory_space; + +static struct memory_range init_grab_pages(struct memory_range *ranges, + int count, + size_t size) +{ + struct memory_range request = {SYSTEM_MEMORY, + 0, + align_next(size, PAGE_SIZE)}; + + for (int i = 0; i < count; i++) + { + if (ranges[i].type != AVAILABLE_MEMORY || + ranges[i].base < (1 << 20)) // leave pages below 1MiB alone. + { + continue; + } + else if (ranges[i].size > request.size) + { + request.base = ranges[i].base; + ranges[i].base += request.size; + ranges[i].size -= request.size; + return request; + } + } + + request.type = INVALID_MEMORY; + return request; +} + +static size_t init_get_max_paddr(struct memory_range *ranges, int count) +{ + phys_addr_t max_paddr = 0; + + // get the highest usable physical address in all memory ranges. + for (int i = 0; i < count; i++) + { + if (ranges[i].type != AVAILABLE_MEMORY) + { + continue; + } + + if ((ranges[i].base + ranges[i].size - 1) > max_paddr) + { + max_paddr = ranges[i].base + ranges[i].size - 1; + } + } + + return max_paddr; +} + +static phys_addr_t get_kernel_pm4_phys(void) +{ + phys_addr_t pm4_phys; + __asm__ ( + "mov %%cr3, %0\n\t" + : "=r"(pm4_phys) + ); + + return page_address(pm4_phys, 1); +} + +static phys_addr_t get_kernel_pm3_phys(void) +{ + phys_addr_t pm3_phys; + // make a temporary mapping to read pm4 + uint64_t *pm4 = page_map_at(temp, + get_kernel_pm4_phys(), + CONTENT_RODATA|SIZE_2M); + + // pm3_phys is in pm4. + pm3_phys = page_address(pm4[pte_index(&k_virt_base, 4)], 1); + // never leave a temporary mapping + page_unmap(pm4); + + return pm3_phys; +} + +static void init_map_page_array_pm2(struct memory_range *pm2_pages) +{ + // now we need to write the physical address of each pm2 page for the + // page_array in the kernel's pm3. + uint64_t *pm3 = page_map_at(temp, + get_kernel_pm3_phys(), + CONTENT_RWDATA|SIZE_2M); + + // the first index is NOT zero! + for (size_t i = 0; i < (pm2_pages->size / PAGE_SIZE); i++) + { + pm3[pte_index(page_array, 3) + i] = (pm2_pages->base + i * + PAGE_SIZE)|PAGE_NX|PAGE_WR|PAGE_PR; + } + // never forget to unmap temporary mappings. + page_unmap(pm3); +} + +static void init_create_page_array_map(struct memory_range *pages, + struct memory_range *maps) +{ + // indices for page_array always start at 0 + size_t entry_count = pages->size / PAGE_SIZE; + + // every 512 entries we need to re-map and clean. + for (size_t i = 0; i < entry_count; i += PAGE_TABLE_INDEX_MASK) + { + uint64_t *pm1 = page_map_at(temp, + maps->base + i * PAGE_SIZE, + CONTENT_RWDATA|SIZE_2M); + memset(pm1, 0, PAGE_SIZE); + for (size_t j = 0; + (j < PAGE_TABLE_INDEX_MASK) && ((j + i) < entry_count); + j++) + { + pm1[j] = (pages->base + (i + j) * PAGE_SIZE)| + PAGE_NX|PAGE_WR|PAGE_PR; + } + + page_unmap(pm1); + } +} + +static void init_set_memory_range(struct memory_range *range) +{ + for (size_t i = 0; i < range->size / PAGE_SIZE; i++) + { + if (range->base / PAGE_SIZE + i > page_array_entries) + { + return; + } + + if (range->type == AVAILABLE_MEMORY) + { + page_free(range->base + PAGE_SIZE * i); + } + else + { + struct page *page = &page_array[range->base / PAGE_SIZE + i]; + page->used = 1; + } + } +} + +static void init_populate_page_array(struct memory_range *ranges, int count) +{ + for (int i = 0; i < count; i++) + { + init_set_memory_range(&ranges[i]); + } +} + +static void init_create_page_array(struct memory_range *ranges, int count) +{ + // the highest actual physical memory address. + size_t max_paddr = init_get_max_paddr(ranges, count); + page_array_entries = max_paddr / page_size(1); + size_t page_array_size = page_array_entries * sizeof(struct page); + + // the physical pages that will contain page_array + struct memory_range pa_pages = init_grab_pages(ranges, count, page_array_size); + + // the number of page tables needed to map pa_pages + // this will be 1 on systems with less than 2GB of memory. + size_t pm1_count = page_count(pa_pages.size, 2); + struct memory_range pm1_pages = init_grab_pages(ranges, + count, + pm1_count * page_size(1)); + + init_create_page_array_map(&pa_pages, &pm1_pages); + + // the number of page directories needed to map pa_pages + // this will be 1 on systems with less than 1TB of memory. + // who the fuck has 1TB of memory lol + size_t pm2_count = page_count(pa_pages.size, 3); + struct memory_range pm2_pages = init_grab_pages(ranges, + count, + pm2_count * page_size(1)); + + init_create_page_array_map(&pm1_pages, &pm2_pages); + + // ok here goes + init_map_page_array_pm2(&pm2_pages); + + memset(page_array, 0, page_array_size); + + init_populate_page_array(ranges, count); + init_populate_page_array(&pa_pages, 1); + init_populate_page_array(&pm1_pages, 1); + init_populate_page_array(&pm2_pages, 1); +} + +static struct memory_space init_system_space(void *base, void *head) +{ + struct memory_space space = {SYSTEM_MEMORY_SPACE, NULL, base, head, NULL, NULL}; + return space; +} + +static struct memory_space init_anonymous_space(void *base, void *head) +{ + struct memory_space space = {ANONYMOUS_MEMORY_SPACE, + &anonymous_page_handler, + base, + head, + NULL, + NULL}; + + return space; +} + +void memory_init(struct memory_range *ranges, int count) +{ + init_create_page_array(ranges, count); + // initialize always-present memory spaces for the vmm + kernel_image_space = init_system_space((void *)&k_text_begin, + (void *)align_next(&k_data_end, PAGE_SIZE)); + kernel_stack_space = init_system_space((void *)KERNEL_ENTRY_STACK_BASE, + (void *)KERNEL_ENTRY_STACK_HEAD); + kernel_pagemap_space = init_system_space(kernel_pm1, (void *)-1LL); + + // initialize the kernel heap space + kernel_heap_space = init_anonymous_space(kernel_image_space.head, + (char *)kernel_image_space.head + + KERNEL_HEAP_SPACE_SIZE); + + // set up the list links + kernel_image_space.next = &kernel_heap_space; + kernel_heap_space.prev = &kernel_image_space; + kernel_heap_space.next = &kernel_stack_space; + kernel_stack_space.prev = &kernel_heap_space; + kernel_stack_space.next = &kernel_pagemap_space; + kernel_pagemap_space.prev = &kernel_stack_space; + + root_memory_space = &kernel_image_space; +} + +static void *page_map_at(void *vaddr, + phys_addr_t paddr, + enum page_map_flags flags) +{ + uint64_t entry = PAGE_PR; + + switch (flags & CONTENT_MASK) + { + case CONTENT_RODATA: + entry |= PAGE_NX; + break; + case CONTENT_RWDATA: + entry |= PAGE_NX|PAGE_WR; + break; + default: + break; + } + + size_t offset; + uint64_t *pte; + + switch (flags & SIZE_MASK) + { + case SIZE_2M: + entry |= page_address(paddr, 2)|PAGE_LG; + offset = page_offset(paddr, 2); + pte = get_kernel_pm2e(vaddr); + break; + case SIZE_4K: + entry |= page_address(paddr, 1); + offset = page_offset(paddr, 1); + pte = get_kernel_pm1e(vaddr); + break; + default: + offset = 0; + pte = NULL; + } + + if (!pte) + { + return NULL; + } + + *pte = entry; + return (char *)vaddr + offset; +} + +void *page_map(phys_addr_t paddr, enum page_map_flags flags) +{ + return page_map_at(get_virtual_page(flags), paddr, flags); +} + +void page_unmap(void *vaddr) +{ + uint64_t *pte = get_kernel_pm2e(vaddr); + + if (pte && !(*pte & PAGE_LG)) + { + pte = get_kernel_pm1e(vaddr); + } + + if (pte) + { + *pte = 0; + } + __asm__ ("invlpg (%0)" :: "r"(vaddr)); +} + +phys_addr_t page_alloc(void) +{ + int index = first_free_page_index; + + if (index > 0) + { + page_array[index].used = 1; + first_free_page_index = page_array[index].next; + free_pages--; + } + + return (phys_addr_t)index * page_size(1); +} + +void page_free(phys_addr_t paddr) +{ + int index = paddr / page_size(1); + + if ((size_t)index > page_array_entries) + { + return; + } + + page_array[index].used = 0; + page_array[index].next = first_free_page_index; + first_free_page_index = index; + free_pages++; +} + +void *heap_alloc(size_t size) +{ + (void)size; + return NULL; +} + +void heap_free(void *block) +{ + (void)block; +} + +void *memory_alloc(size_t size) +{ + (void)size; + return NULL; +} + +void memory_free(void *block) +{ + (void)block; +} + +static uint64_t *get_kernel_pm1e(void *vaddr) +{ + return &kernel_pm1[kpm1_index(vaddr)]; +} + +static uint64_t *get_kernel_pm2e(void *vaddr) +{ + return &kernel_pm2[kpm2_index(vaddr)]; +} + +static void *get_virtual_page(enum page_map_flags flags) +{ + (void)flags; + return NULL; +} + +static struct memory_space *get_memory_space(void *address) +{ + // walk the memory space list + struct memory_space *space = root_memory_space; + + while (space) + { + if (space->base >= address && address <= space->head) + { + return space; + } + space = space->next; + } + + return NULL; +} + +int anonymous_page_handler(uint32_t code, void *address) +{ + if (code & PAGE_PR) + { + // there's no reason a protection violation should happen + // in anonymous space + panic(UNHANDLED_FAULT); + } + kputs("anonymous fault\n"); + // kernel page mappings are built different + if (address >= (void *)&k_virt_base) + { + uint64_t *pm2e = get_kernel_pm2e(address); + + if (!page_address(*pm2e, 1)) + { + // create a page table and install it + phys_addr_t pm1_phys = page_alloc(); + if (pm1_phys) + { + uint64_t *pm1; + pm1 = page_map_at(temp, pm1_phys, CONTENT_RWDATA|SIZE_2M); + // zero the page + memset(pm1, 0, PAGE_SIZE); + // put the table where it goes + *pm2e = page_address(pm1_phys, 1)|PAGE_WR|PAGE_PR; + page_unmap(pm1); + } + else + { + panic(OUT_OF_MEMORY); + } + } + + uint64_t *pm1e = get_kernel_pm1e(address); + + if (pm1e) + { + phys_addr_t page_phys = page_alloc(); + if (page_phys) + { + *pm1e = page_address(page_phys, 1)|PAGE_WR|PAGE_PR; + // clear a potentially dirty page. + memset((void *)page_address(address, 1), 0, page_size(1)); + } + } + } + + return 0; +} + +int page_fault_handler(uint32_t code, void *address) +{ + kputs("page faulmt\n"); + struct memory_space *space = get_memory_space(address); + if (space && space->handler) + { + int result = space->handler(code, address); + + if (result) + { + panic(UNHANDLED_FAULT); + } + } + + return 0; +} diff --git a/kc/core/memory.h b/kc/core/memory.h new file mode 100644 index 0000000..67b0648 --- /dev/null +++ b/kc/core/memory.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +#include + +typdef int (*memory_space_handler_func)(uint32_t code, void *vaddr); + +enum page_map_flags +{ + CONTENT_CODE = 0x1, + CONTENT_RODATA = 0x2, + CONTENT_RWDATA = 0x3, + CONTENT_MASK = 0x3, + + SIZE_4K = 0x4, + SIZE_2M = 0x8, + SIZE_1G = 0xc, + SIZE_MASK = 0xc, +}; + +enum memory_space_flags +{ + SYSTEM_SPACE = 0x1, // memory cannot be swapped +}; + +struct memory_space +{ + enum memory_space_flags flags; + memory_space_handler_func handler; + void *base; + void *head; +}; + +void memory_init(struct memory_range *ranges, int count); + +void *memcpy(void *dest, const void *src, size_t size); +void *memmove(void *dest, const void *src, size_t size); +void *memset(void *dest, int val, size_t size); +int memcmp(const void *str1, const void *str2, size_t count); + +void *page_map(phys_addr_t paddr, enum page_map_flags flags); +void page_unmap(void *vaddr); + +phys_addr_t page_alloc(void); +void page_free(phys_addr_t paddr); + +void *heap_alloc(size_t size); +void heap_free(void *block); + +void *memory_alloc(size_t size); +void memory_free(void *block); diff --git a/kc/core/panic.c b/kc/core/panic.c new file mode 100644 index 0000000..b0d9daf --- /dev/null +++ b/kc/core/panic.c @@ -0,0 +1,25 @@ +#include "panic.h" +#include "kprint.h" + +#include + +static char const *reason_strings[] = { + "general panic", + "unhandled fault", + "out of memory" +}; + +noreturn void panic(enum panic_reason reason) +{ + // TODO: kprintf() and friends + kputs("kernel panic: "); + kputs(reason_strings[reason]); + kputs("\n"); + halt(); +} + +noreturn void halt(void) +{ + __asm__ ("cli\n\t"); + while (true) __asm__ ("hlt\n\t"); +} diff --git a/kc/core/panic.h b/kc/core/panic.h new file mode 100644 index 0000000..0cfd7c2 --- /dev/null +++ b/kc/core/panic.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +enum panic_reason +{ + GENERAL_PANIC, + UNHANDLED_FAULT, + OUT_OF_MEMORY, +}; + +noreturn void panic(enum panic_reason reason); +noreturn void halt(void); diff --git a/kc/core/port.c b/kc/core/port.c new file mode 100644 index 0000000..17af396 --- /dev/null +++ b/kc/core/port.c @@ -0,0 +1,14 @@ +#include "port.h" + +uint8_t inb(uint16_t port) +{ + uint8_t data; + __asm__ ("inb %1, %0" : "=a"(data) : "d"(port)); + return data; +} + +void outb(uint16_t port, uint8_t data) +{ + __asm__ ("outb %0, %1" :: "a"(data), "d"(port)); +} + diff --git a/kc/core/port.h b/kc/core/port.h new file mode 100644 index 0000000..cc71973 --- /dev/null +++ b/kc/core/port.h @@ -0,0 +1,5 @@ +#include + +uint8_t inb(uint16_t port); +void outb(uint16_t port, uint8_t data); + diff --git a/kc/core/serial.c b/kc/core/serial.c new file mode 100644 index 0000000..77f453d --- /dev/null +++ b/kc/core/serial.c @@ -0,0 +1,41 @@ +#include "serial.h" +#include "port.h" + +#define PORT 0x3f8 // COM1 + +static int is_transmit_empty(void); + +int serial_init(void) { + outb(PORT + 0, 0x00); // Disable all interrupts + outb(PORT + 2, 0x80); // Enable DLAB (set baud rate divisor) + outb(PORT + -1, 0x03); // Set divisor to 3 (lo byte) 38400 baud + outb(PORT + 0, 0x00); // (hi byte) + outb(PORT + 2, 0x03); // 8 bits, no parity, one stop bit + outb(PORT + 1, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + outb(PORT + 3, 0x0B); // IRQs enabled, RTS/DSR set + outb(PORT + 3, 0x1E); // Set in loopback mode, test the serial chip + outb(PORT + -1, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) + + // Check if serial is faulty (i.e: not same byte as sent) + if(inb(PORT + -1) != 0xAE) { + return 0; + } + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#0 and OUT#2 bits enabled) + outb(PORT + 3, 0x0F); + return -1; +} + +int serial_putchar(int c) +{ + while (is_transmit_empty() == 0); + outb(PORT,(char)c); + return c; +} + +static int is_transmit_empty(void) +{ + return inb(PORT + 5) & 0x20; +} + diff --git a/kc/core/serial.h b/kc/core/serial.h new file mode 100644 index 0000000..2e22fa6 --- /dev/null +++ b/kc/core/serial.h @@ -0,0 +1,5 @@ +#pragma once + +int serial_init(void); +int serial_putchar(int c); + diff --git a/kc/entry_x86_64.S b/kc/entry_x86_64.S new file mode 100644 index 0000000..231953a --- /dev/null +++ b/kc/entry_x86_64.S @@ -0,0 +1,18 @@ +.section .text.start +.extern kc_reloc +.extern kc_main +.extern _DYNAMIC +.extern kc_image_base + +.global kc_entry +.type kc_entry, @function +kc_entry: + push %rdi + lea _DYNAMIC(%rip), %rdi + lea kc_image_base(%rip), %rsi + call kc_reloc + pop %rdi + call kc_main + ret +.size kc_entry, . - kc_entry + diff --git a/kc/reloc_x86_64.c b/kc/reloc_x86_64.c new file mode 100644 index 0000000..0204700 --- /dev/null +++ b/kc/reloc_x86_64.c @@ -0,0 +1,69 @@ +#include + +#include + +#include + +#define STARTCODE __attribute__((section(".text.start"))) + +STARTCODE +static void do_rela(Elf64_Rela *rela, void *base) +{ + union + { + Elf_Byte word8; + Elf64_Half word16; + Elf64_Word word32; + Elf64_Xword word64; + } + *fixup; + + switch (ELF64_R_TYPE(rela->r_info)) + { + case R_AMD64_RELATIVE: + fixup = (void *)(rela->r_offset + (uintptr_t)base); + fixup->word64 = (rela->r_addend + (uintptr_t)base); + break; + default: + break; + } +} + +STARTCODE +void kc_reloc(Elf64_Dyn *dyn, void *base) +{ + struct + { + Elf64_Rela *entries; + size_t *size; + size_t *entsize; + } + rela = {NULL, NULL, NULL}; + + // parse the dynamic segment + while (dyn && dyn++->d_tag != DT_NULL) + { + switch (dyn->d_tag) + { + case DT_RELA: + rela.entries = (Elf64_Rela *)(dyn->d_ptr + (uintptr_t)base); + break; + case DT_RELASZ: + rela.size = &dyn->d_val; + break; + case DT_RELAENT: + rela.entsize = &dyn->d_val; + break; + default: + break; + } + } + + // perform the actual relocation + + for (size_t i = 0; rela.entries && (i < *rela.size / *rela.entsize); i++) + { + do_rela(&rela.entries[i], base); + } +} + diff --git a/kernel/Makefile b/kernel/Makefile deleted file mode 100644 index 407c4bb..0000000 --- a/kernel/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -include ../defaults.mk - -VPATH := ../lib - -TARGET := kernel.os -.DEFAULT: $(TARGET) - -CFLAGS += -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden -g - -LIBDIRS += -L$(dir $(shell $(CC) -print-libgcc-file-name)) -LDSCRIPT := kernel.ld -LDFLAGS += -z max-page-size=4096 --export-dynamic -LOADLIBES := -lgcc - -SOBJS := -GOBJS := entry.o kprint.o serial.o port.o main.o memory.o \ - memset.o memcpy.o memmove.o memcmp.o cpu.o exceptions.o \ - panic.o -IOBJS := - -$(SOBJS): CFLAGS += -fPIC -# __attribute__((interrupt)) requires -mgeneral-regs-only -$(IOBJS): CFLAGS += -mgeneral-regs-only -$(IOBJS) $(GOBJS): CFLAGS += -mcmodel=kernel - -OBJS := $(SOBJS) $(GOBJS) $(IOBJS) -DEPS := $(patsubst %.o,%.d,$(OBJS)) - -$(TARGET): $(LDSCRIPT) $(MAKEFILE_LIST) -$(TARGET): $(OBJS) - -CLEANLIST := $(wildcard $(OBJS) $(TARGET)) -DCLEANLIST := $(wildcard $(DEPS)) - -include ../rules.mk --include $(DEPS) - -.DEFAULT: $(TARGET) - diff --git a/kernel/cpu.c b/kernel/cpu.c deleted file mode 100644 index ed1a04e..0000000 --- a/kernel/cpu.c +++ /dev/null @@ -1,225 +0,0 @@ -#include "cpu.h" -#include "exceptions.h" - -#include - -#define GDT_ENTRIES 16 -#define IDT_ENTRIES 256 - -#define CODE_SEG_INDEX 1 -#define DATA_SEG_INDEX 2 -#define TASK_SEG_INDEX 3 - -struct dtr64 -{ - uint16_t limit; - uint64_t base; -} __attribute__((packed)); - -struct segment_descriptor -{ - uint16_t limit0; - uint16_t base0; - uint8_t base16; - uint8_t access; - uint8_t flags_limit16; - uint8_t base24; -} __attribute__((packed)); - -enum segment_descriptor_type -{ - CODE64_SEG, - DATA_SEG, - TASK64_SEG, -}; - -struct gate_descriptor -{ - uint16_t offset0; - uint16_t selector; - uint8_t ist; - uint8_t access; - uint16_t offset16; - uint64_t offset32; -} __attribute__((packed)); - -enum gate_descriptor_type -{ - INT64_GATE, - TRAP64_GATE, -}; - -struct task64_segment -{ - uint32_t reserved0; - uint64_t rsp0; - uint64_t rsp1; - uint64_t rsp2; - uint64_t reserved1; - uint64_t ist[7]; - uint16_t reserved2; - uint16_t iomap_base; -}; - -static struct segment_descriptor gdt[GDT_ENTRIES]; -static struct gate_descriptor idt[IDT_ENTRIES]; -static struct task64_segment tss; - -static void set_gdt(int index, - uint64_t base, - uint64_t limit, - enum segment_descriptor_type type) -{ - gdt[index].limit0 = limit & 0xffff; - gdt[index].base0 = base & 0xffff; - gdt[index].base16 = (base >> 16) & 0xff; - gdt[index].flags_limit16 = (limit >> 16) & 0xf; - gdt[index].base24 = (base >> 24) & 0xff; - - switch (type) - { - case CODE64_SEG: - gdt[index].access = 0x9a; - gdt[index].flags_limit16 |= 0xa0; - break; - case DATA_SEG: - gdt[index].access = 0x92; - gdt[index].flags_limit16 |= 0xc0; - break; - case TASK64_SEG: - gdt[index].access = 0x89; - //TODO: make this cleaner i don't like it - gdt[index+1].limit0 = (base >> 32) & 0xffff; - gdt[index+1].base0 = (base >> 48) & 0xffff; - break; - }; -} - -static void set_idt(int vec, - uint16_t selector, - uint64_t offset, - enum gate_descriptor_type type) -{ - idt[vec].offset0 = offset & 0xffff; - idt[vec].selector = selector; - idt[vec].offset16 = (offset >> 16) & 0xffff; - idt[vec].offset32 = (offset >> 32) & 0xffffffff; - - switch (type) - { - case INT64_GATE: - idt[vec].access = 0x8e; - break; - case TRAP64_GATE: - idt[vec].access = 0x8f; - break; - } -} - -void set_ist(int vec, int ist_index) -{ - // non-destructively set the ist index. - idt[vec].access |= ist_index & 0x7; -} - -static void gdt_init(void) -{ - set_gdt(CODE_SEG_INDEX, 0, (uint64_t)-1, CODE64_SEG); - set_gdt(DATA_SEG_INDEX, 0, (uint64_t)-1, DATA_SEG); - set_gdt(TASK_SEG_INDEX, (uint64_t)&tss, sizeof(tss) - 1, TASK64_SEG); - - struct dtr64 gdtr = {sizeof(gdt) - 1, (uint64_t)&gdt}; - - __asm__ volatile - ( - // can't have interrupts during GDT reload - // but don't re-enable interrupts if they were already disabled - "pushf\n" - "cli\n" - "lgdt %0\n" - "mov %w2, %%ds\n" - "mov %w2, %%es\n" - "mov %w2, %%fs\n" - "mov %w2, %%gs\n" - "mov %w2, %%ss\n" - // make a far return frame on the stack - // [ss] @rsp+8 - // [rip] @rsp - "pushq %1\n" - "lea .Lflush(%%rip), %%rax\n" - "push %%rax\n" - // far return, now we're in the code segment - // defined here. - "lretq\n" - ".Lflush:\n" - "ltr %w3\n" - "popf\n" - // dependency on pre-boot GDT is now gone - : - : "m"(gdtr), - "i"(CODE_SEG_INDEX << 3), - "r"(DATA_SEG_INDEX << 3), - "r"(TASK_SEG_INDEX << 3) - ); -} - -static void idt_init(void) -{ - struct dtr64 idtr = {sizeof(idt) - 1, (uint64_t)&idt}; - - __asm__ volatile - ( - // can't have interrupts enabled during IDT reload--obviously. - // as with GDT don't re-enable interrupts if they were already - // disabled. - "pushf\n" - "cli\n" - "lidt %0\n" - "popf\n" - // much more straightforward than the gdt code. - :: "m"(idtr) - ); -} - -void cpu_init(void) -{ - gdt_init(); - idt_init(); - exceptions_init(); -} - -void exceptions_init(void) -{ - isr_install(PAGE_FAULT_VECTOR, &page_fault_isr, 0, 0); -} - -void isr_install(int vec, void (*isr)(void), int trap, int ist) -{ - enum gate_descriptor_type type = INT64_GATE; - - if (trap) - { - type = TRAP64_GATE; - } - - set_idt(vec, CODE_SEG_INDEX << 3, (uint64_t)isr, type); - if (ist) - { - set_ist(vec, ist); - } -} - -void ist_install(int ist, void *stack) -{ - tss.ist[ist] = (uint64_t)stack; -} - -void int_enable(void) -{ - __asm__ ("sti"); -} - -void int_disable(void) -{ - __asm__ ("cli"); -} diff --git a/kernel/cpu.h b/kernel/cpu.h deleted file mode 100644 index 56a4073..0000000 --- a/kernel/cpu.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -void cpu_init(void); - -void isr_install(int vec, void (*isr)(void), int ist, int trap); -void ist_install(int ist, void *stack); - -void int_enable(void); -void int_disable(void); diff --git a/kernel/entry.c b/kernel/entry.c deleted file mode 100644 index 5eecaf2..0000000 --- a/kernel/entry.c +++ /dev/null @@ -1,69 +0,0 @@ -#include "cpu.h" -#include "serial.h" -#include "kprint.h" -#include "memory.h" -#include "panic.h" - -#include - -#include - -#include -#include -#include -#include - -static void efi_memory_init(struct efi_memory_map_data *map) -{ - // FIXME: bad girl shit: overwriting on aliased pointers. - // this is a temporary solution to shortcomings with - // loader boot data. it's sort-of OK because the memory_range struct - // is smaller than EFI_MEMORY_DESCRIPTOR. it's still not good. - struct memory_range *ranges = (struct memory_range *)map->data; - int entries = map->size / map->descsize; - - for (int i = 0; i < entries; i++) - { - EFI_MEMORY_DESCRIPTOR *desc; - desc = (EFI_MEMORY_DESCRIPTOR *)((char *)map->data + i * map->descsize); - - enum memory_range_type type; - phys_addr_t base; - size_t size; - - base = desc->PhysicalStart; - size = desc->NumberOfPages * EFI_PAGE_SIZE; - - switch (desc->Type) - { - case EfiConventionalMemory: - case EfiBootServicesData: - case EfiBootServicesCode: - case EfiLoaderData: - case EfiLoaderCode: - type = AVAILABLE_MEMORY; - break; - case SystemMemoryType: - type = SYSTEM_MEMORY; - break; - default: - type = RESERVED_MEMORY; - } - - ranges[i].type = type; - ranges[i].base = base; - ranges[i].size = size; - } - - memory_init(ranges, entries); -} - -noreturn void kernel_entry(struct efi_boot_data *data) -{ - (void)data; - cpu_init(); - serial_init(); - kputs(" i'm in\r\n"); - efi_memory_init(data->memory_map); - halt(); -} diff --git a/kernel/exceptions.S b/kernel/exceptions.S deleted file mode 100644 index 80d49ee..0000000 --- a/kernel/exceptions.S +++ /dev/null @@ -1,54 +0,0 @@ -.extern page_fault_handler - -.global page_fault_isr -.type page_fault_isr, @function -page_fault_isr: - /* just in case something tried to be clever before */ - cld - /* push param registers */ - push %rdi - push %rsi - push %rdx - push %rcx - push %r8 - push %r9 - /* collect parameters for page fault handler */ - mov 48(%rsp), %rdi /* error code is first parameter */ - mov %cr2, %rsi /* PFLA is next parameter */ - /* caller-saved registers */ - push %rax - push %r10 - push %r11 - /* callee-saved registers */ - push %rbx - push %rbp - push %r12 - push %r13 - push %r14 - push %r15 - /* stack has to be aligned */ - mov %rsp, %rbp - and $-16, %rsp - call page_fault_handler - mov %rbp, %rsp - /* TODO: test for error code here and panic() */ - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %rbp - pop %rbx - pop %r11 - pop %r10 - pop %rax - pop %r9 - pop %r8 - pop %rcx - pop %rdx - pop %rsi - pop %rdi - /* unwind the error code from the stack */ - add $8, %rsp - /* leave the isr */ - iretq -.size page_fault_isr, . - page_fault_isr diff --git a/kernel/exceptions.h b/kernel/exceptions.h deleted file mode 100644 index 5d22284..0000000 --- a/kernel/exceptions.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -extern void page_fault_isr(void); - -#define PAGE_FAULT_VECTOR 0xe - -void exceptions_init(void); diff --git a/kernel/kernel.ld b/kernel/kernel.ld deleted file mode 100644 index 47dcf3b..0000000 --- a/kernel/kernel.ld +++ /dev/null @@ -1,33 +0,0 @@ -ENTRY(kernel_entry) - -PROVIDE(k_virt_base = 0xffffffff80000000); - -SECTIONS -{ - .text k_virt_base : AT(ADDR(.text) - k_virt_base) - { - PROVIDE(k_text_begin = .); - *(.text) - . = ALIGN(4K); - PROVIDE(k_text_end = .); - } =0xcc - - .data ALIGN(4K) : AT(ADDR(.data) - k_virt_base) - { - PROVIDE(k_data_begin = .); - *(.rodata) - *(.data) - } - - .bss : - { - *(.bss) - PROVIDE(k_data_end = .); - } - - /DISCARD/ : - { - *(.eh_frame) - } -} - diff --git a/kernel/kprint.c b/kernel/kprint.c deleted file mode 100644 index 0a15efd..0000000 --- a/kernel/kprint.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "kprint.h" -#include "serial.h" - -int kputchar(int c) -{ - return serial_putchar(c); -} - -int kputs(const char *s) -{ - while (*s) - { - kputchar(*s++); - } - - return 0; -} - diff --git a/kernel/kprint.h b/kernel/kprint.h deleted file mode 100644 index 5b307a2..0000000 --- a/kernel/kprint.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -int kputchar(int c); -int kputs(const char *s); - diff --git a/kernel/main.c b/kernel/main.c deleted file mode 100644 index 2fb2e3e..0000000 --- a/kernel/main.c +++ /dev/null @@ -1,4 +0,0 @@ -void kernel_main(void) -{ -} - diff --git a/kernel/memory.c b/kernel/memory.c deleted file mode 100644 index 62f3a38..0000000 --- a/kernel/memory.c +++ /dev/null @@ -1,534 +0,0 @@ -#include "memory.h" -#include "kprint.h" -#include "panic.h" - -#include - -#include -#include - -/* kernel virtual space guarantees - * - * the loader must set up the address space as follows - * 1. kernel virtual space is 2GiB in size on 2GiB alignment. - * 2. mappings begin at +0x7fc00000. this mapping space is sparse and its - * own mapping tables begin at +0x7fffe000. - */ - -#define kpm1_index(v) (((uint64_t)v >> pte_index_bits(1)) & 0x7ffff) -#define kpm2_index(v) (((uint64_t)v >> pte_index_bits(2)) & 0x3ff) - -#define align_next(v, a) (((uint64_t)v + a - 1) & ~(a - 1)) - -// a conservative 128MB for kernel heap -#define KERNEL_HEAP_SPACE_SIZE (128 << 20) - -typedef int (*page_fault_handler_func)(uint32_t code, void *address); - -enum memory_space_flags -{ - SYSTEM_MEMORY_SPACE, // memory that cannot fault - ANONYMOUS_MEMORY_SPACE, // memory that can fault -}; - -struct memory_space -{ - enum memory_space_flags flags; - page_fault_handler_func handler; - void *base; - void *head; - struct memory_space *next; - struct memory_space *prev; -}; - -struct page -{ - uint32_t next: 31; - uint32_t used: 1; -}; - -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 struct page *const page_array = (struct page *)0xffffffd800000000; -static int first_free_page_index = -1; -static size_t page_array_entries = 0; -static size_t free_pages = 0; - -// the temporary mapping place. never use this permanently. -static void *const temp = (void *)0xffffffffffa00000; -static uint64_t *const kernel_pm1 = (uint64_t *)0xffffffffffc00000; -static uint64_t *const kernel_pm2 = (uint64_t *)0xffffffffffffe000; - -static uint64_t *get_kernel_pm1e(void *vaddr); -static uint64_t *get_kernel_pm2e(void *vaddr); -static void *get_virtual_page(enum page_map_flags flags); -static void *page_map_at(void *vaddr, phys_addr_t paddr, enum page_map_flags flags); - -// handlers for memory space types -int anonymous_page_handler(uint32_t code, void *address); - -// the system memory_space's that are always present -static struct memory_space kernel_image_space; -static struct memory_space kernel_stack_space; -static struct memory_space kernel_pagemap_space; -// the kernel's own heap space -static struct memory_space kernel_heap_space; - -// NULL if the system address spaces are not set up -static struct memory_space *root_memory_space; - -static struct memory_range init_grab_pages(struct memory_range *ranges, - int count, - size_t size) -{ - struct memory_range request = {SYSTEM_MEMORY, - 0, - align_next(size, PAGE_SIZE)}; - - for (int i = 0; i < count; i++) - { - if (ranges[i].type != AVAILABLE_MEMORY || - ranges[i].base < (1 << 20)) // leave pages below 1MiB alone. - { - continue; - } - else if (ranges[i].size > request.size) - { - request.base = ranges[i].base; - ranges[i].base += request.size; - ranges[i].size -= request.size; - return request; - } - } - - request.type = INVALID_MEMORY; - return request; -} - -static size_t init_get_max_paddr(struct memory_range *ranges, int count) -{ - phys_addr_t max_paddr = 0; - - // get the highest usable physical address in all memory ranges. - for (int i = 0; i < count; i++) - { - if (ranges[i].type != AVAILABLE_MEMORY) - { - continue; - } - - if ((ranges[i].base + ranges[i].size - 1) > max_paddr) - { - max_paddr = ranges[i].base + ranges[i].size - 1; - } - } - - return max_paddr; -} - -static phys_addr_t get_kernel_pm4_phys(void) -{ - phys_addr_t pm4_phys; - __asm__ ( - "mov %%cr3, %0\n\t" - : "=r"(pm4_phys) - ); - - return page_address(pm4_phys, 1); -} - -static phys_addr_t get_kernel_pm3_phys(void) -{ - phys_addr_t pm3_phys; - // make a temporary mapping to read pm4 - uint64_t *pm4 = page_map_at(temp, - get_kernel_pm4_phys(), - CONTENT_RODATA|SIZE_2M); - - // pm3_phys is in pm4. - pm3_phys = page_address(pm4[pte_index(&k_virt_base, 4)], 1); - // never leave a temporary mapping - page_unmap(pm4); - - return pm3_phys; -} - -static void init_map_page_array_pm2(struct memory_range *pm2_pages) -{ - // now we need to write the physical address of each pm2 page for the - // page_array in the kernel's pm3. - uint64_t *pm3 = page_map_at(temp, - get_kernel_pm3_phys(), - CONTENT_RWDATA|SIZE_2M); - - // the first index is NOT zero! - for (size_t i = 0; i < (pm2_pages->size / PAGE_SIZE); i++) - { - pm3[pte_index(page_array, 3) + i] = (pm2_pages->base + i * - PAGE_SIZE)|PAGE_NX|PAGE_WR|PAGE_PR; - } - // never forget to unmap temporary mappings. - page_unmap(pm3); -} - -static void init_create_page_array_map(struct memory_range *pages, - struct memory_range *maps) -{ - // indices for page_array always start at 0 - size_t entry_count = pages->size / PAGE_SIZE; - - // every 512 entries we need to re-map and clean. - for (size_t i = 0; i < entry_count; i += PAGE_TABLE_INDEX_MASK) - { - uint64_t *pm1 = page_map_at(temp, - maps->base + i * PAGE_SIZE, - CONTENT_RWDATA|SIZE_2M); - memset(pm1, 0, PAGE_SIZE); - for (size_t j = 0; - (j < PAGE_TABLE_INDEX_MASK) && ((j + i) < entry_count); - j++) - { - pm1[j] = (pages->base + (i + j) * PAGE_SIZE)| - PAGE_NX|PAGE_WR|PAGE_PR; - } - - page_unmap(pm1); - } -} - -static void init_set_memory_range(struct memory_range *range) -{ - for (size_t i = 0; i < range->size / PAGE_SIZE; i++) - { - if (range->base / PAGE_SIZE + i > page_array_entries) - { - return; - } - - if (range->type == AVAILABLE_MEMORY) - { - page_free(range->base + PAGE_SIZE * i); - } - else - { - struct page *page = &page_array[range->base / PAGE_SIZE + i]; - page->used = 1; - } - } -} - -static void init_populate_page_array(struct memory_range *ranges, int count) -{ - for (int i = 0; i < count; i++) - { - init_set_memory_range(&ranges[i]); - } -} - -static void init_create_page_array(struct memory_range *ranges, int count) -{ - // the highest actual physical memory address. - size_t max_paddr = init_get_max_paddr(ranges, count); - page_array_entries = max_paddr / page_size(1); - size_t page_array_size = page_array_entries * sizeof(struct page); - - // the physical pages that will contain page_array - struct memory_range pa_pages = init_grab_pages(ranges, count, page_array_size); - - // the number of page tables needed to map pa_pages - // this will be 1 on systems with less than 2GB of memory. - size_t pm1_count = page_count(pa_pages.size, 2); - struct memory_range pm1_pages = init_grab_pages(ranges, - count, - pm1_count * page_size(1)); - - init_create_page_array_map(&pa_pages, &pm1_pages); - - // the number of page directories needed to map pa_pages - // this will be 1 on systems with less than 1TB of memory. - // who the fuck has 1TB of memory lol - size_t pm2_count = page_count(pa_pages.size, 3); - struct memory_range pm2_pages = init_grab_pages(ranges, - count, - pm2_count * page_size(1)); - - init_create_page_array_map(&pm1_pages, &pm2_pages); - - // ok here goes - init_map_page_array_pm2(&pm2_pages); - - memset(page_array, 0, page_array_size); - - init_populate_page_array(ranges, count); - init_populate_page_array(&pa_pages, 1); - init_populate_page_array(&pm1_pages, 1); - init_populate_page_array(&pm2_pages, 1); -} - -static struct memory_space init_system_space(void *base, void *head) -{ - struct memory_space space = {SYSTEM_MEMORY_SPACE, NULL, base, head, NULL, NULL}; - return space; -} - -static struct memory_space init_anonymous_space(void *base, void *head) -{ - struct memory_space space = {ANONYMOUS_MEMORY_SPACE, - &anonymous_page_handler, - base, - head, - NULL, - NULL}; - - return space; -} - -void memory_init(struct memory_range *ranges, int count) -{ - init_create_page_array(ranges, count); - // initialize always-present memory spaces for the vmm - kernel_image_space = init_system_space((void *)&k_text_begin, - (void *)align_next(&k_data_end, PAGE_SIZE)); - kernel_stack_space = init_system_space((void *)KERNEL_ENTRY_STACK_BASE, - (void *)KERNEL_ENTRY_STACK_HEAD); - kernel_pagemap_space = init_system_space(kernel_pm1, (void *)-1LL); - - // initialize the kernel heap space - kernel_heap_space = init_anonymous_space(kernel_image_space.head, - (char *)kernel_image_space.head + - KERNEL_HEAP_SPACE_SIZE); - - // set up the list links - kernel_image_space.next = &kernel_heap_space; - kernel_heap_space.prev = &kernel_image_space; - kernel_heap_space.next = &kernel_stack_space; - kernel_stack_space.prev = &kernel_heap_space; - kernel_stack_space.next = &kernel_pagemap_space; - kernel_pagemap_space.prev = &kernel_stack_space; - - root_memory_space = &kernel_image_space; -} - -static void *page_map_at(void *vaddr, - phys_addr_t paddr, - enum page_map_flags flags) -{ - uint64_t entry = PAGE_PR; - - switch (flags & CONTENT_MASK) - { - case CONTENT_RODATA: - entry |= PAGE_NX; - break; - case CONTENT_RWDATA: - entry |= PAGE_NX|PAGE_WR; - break; - default: - break; - } - - size_t offset; - uint64_t *pte; - - switch (flags & SIZE_MASK) - { - case SIZE_2M: - entry |= page_address(paddr, 2)|PAGE_LG; - offset = page_offset(paddr, 2); - pte = get_kernel_pm2e(vaddr); - break; - case SIZE_4K: - entry |= page_address(paddr, 1); - offset = page_offset(paddr, 1); - pte = get_kernel_pm1e(vaddr); - break; - default: - offset = 0; - pte = NULL; - } - - if (!pte) - { - return NULL; - } - - *pte = entry; - return (char *)vaddr + offset; -} - -void *page_map(phys_addr_t paddr, enum page_map_flags flags) -{ - return page_map_at(get_virtual_page(flags), paddr, flags); -} - -void page_unmap(void *vaddr) -{ - uint64_t *pte = get_kernel_pm2e(vaddr); - - if (pte && !(*pte & PAGE_LG)) - { - pte = get_kernel_pm1e(vaddr); - } - - if (pte) - { - *pte = 0; - } - __asm__ ("invlpg (%0)" :: "r"(vaddr)); -} - -phys_addr_t page_alloc(void) -{ - int index = first_free_page_index; - - if (index > 0) - { - page_array[index].used = 1; - first_free_page_index = page_array[index].next; - free_pages--; - } - - return (phys_addr_t)index * page_size(1); -} - -void page_free(phys_addr_t paddr) -{ - int index = paddr / page_size(1); - - if ((size_t)index > page_array_entries) - { - return; - } - - page_array[index].used = 0; - page_array[index].next = first_free_page_index; - first_free_page_index = index; - free_pages++; -} - -void *heap_alloc(size_t size) -{ - (void)size; - return NULL; -} - -void heap_free(void *block) -{ - (void)block; -} - -void *memory_alloc(size_t size) -{ - (void)size; - return NULL; -} - -void memory_free(void *block) -{ - (void)block; -} - -static uint64_t *get_kernel_pm1e(void *vaddr) -{ - return &kernel_pm1[kpm1_index(vaddr)]; -} - -static uint64_t *get_kernel_pm2e(void *vaddr) -{ - return &kernel_pm2[kpm2_index(vaddr)]; -} - -static void *get_virtual_page(enum page_map_flags flags) -{ - (void)flags; - return NULL; -} - -static struct memory_space *get_memory_space(void *address) -{ - // walk the memory space list - struct memory_space *space = root_memory_space; - - while (space) - { - if (space->base >= address && address <= space->head) - { - return space; - } - space = space->next; - } - - return NULL; -} - -int anonymous_page_handler(uint32_t code, void *address) -{ - if (code & PAGE_PR) - { - // there's no reason a protection violation should happen - // in anonymous space - panic(UNHANDLED_FAULT); - } - kputs("anonymous fault\n"); - // kernel page mappings are built different - if (address >= (void *)&k_virt_base) - { - uint64_t *pm2e = get_kernel_pm2e(address); - - if (!page_address(*pm2e, 1)) - { - // create a page table and install it - phys_addr_t pm1_phys = page_alloc(); - if (pm1_phys) - { - uint64_t *pm1; - pm1 = page_map_at(temp, pm1_phys, CONTENT_RWDATA|SIZE_2M); - // zero the page - memset(pm1, 0, PAGE_SIZE); - // put the table where it goes - *pm2e = page_address(pm1_phys, 1)|PAGE_WR|PAGE_PR; - page_unmap(pm1); - } - else - { - panic(OUT_OF_MEMORY); - } - } - - uint64_t *pm1e = get_kernel_pm1e(address); - - if (pm1e) - { - phys_addr_t page_phys = page_alloc(); - if (page_phys) - { - *pm1e = page_address(page_phys, 1)|PAGE_WR|PAGE_PR; - // clear a potentially dirty page. - memset((void *)page_address(address, 1), 0, page_size(1)); - } - } - } - - return 0; -} - -int page_fault_handler(uint32_t code, void *address) -{ - kputs("page faulmt\n"); - struct memory_space *space = get_memory_space(address); - if (space && space->handler) - { - int result = space->handler(code, address); - - if (result) - { - panic(UNHANDLED_FAULT); - } - } - - return 0; -} diff --git a/kernel/memory.h b/kernel/memory.h deleted file mode 100644 index 67b0648..0000000 --- a/kernel/memory.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include -#include - -#include - -typdef int (*memory_space_handler_func)(uint32_t code, void *vaddr); - -enum page_map_flags -{ - CONTENT_CODE = 0x1, - CONTENT_RODATA = 0x2, - CONTENT_RWDATA = 0x3, - CONTENT_MASK = 0x3, - - SIZE_4K = 0x4, - SIZE_2M = 0x8, - SIZE_1G = 0xc, - SIZE_MASK = 0xc, -}; - -enum memory_space_flags -{ - SYSTEM_SPACE = 0x1, // memory cannot be swapped -}; - -struct memory_space -{ - enum memory_space_flags flags; - memory_space_handler_func handler; - void *base; - void *head; -}; - -void memory_init(struct memory_range *ranges, int count); - -void *memcpy(void *dest, const void *src, size_t size); -void *memmove(void *dest, const void *src, size_t size); -void *memset(void *dest, int val, size_t size); -int memcmp(const void *str1, const void *str2, size_t count); - -void *page_map(phys_addr_t paddr, enum page_map_flags flags); -void page_unmap(void *vaddr); - -phys_addr_t page_alloc(void); -void page_free(phys_addr_t paddr); - -void *heap_alloc(size_t size); -void heap_free(void *block); - -void *memory_alloc(size_t size); -void memory_free(void *block); diff --git a/kernel/panic.c b/kernel/panic.c deleted file mode 100644 index b0d9daf..0000000 --- a/kernel/panic.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "panic.h" -#include "kprint.h" - -#include - -static char const *reason_strings[] = { - "general panic", - "unhandled fault", - "out of memory" -}; - -noreturn void panic(enum panic_reason reason) -{ - // TODO: kprintf() and friends - kputs("kernel panic: "); - kputs(reason_strings[reason]); - kputs("\n"); - halt(); -} - -noreturn void halt(void) -{ - __asm__ ("cli\n\t"); - while (true) __asm__ ("hlt\n\t"); -} diff --git a/kernel/panic.h b/kernel/panic.h deleted file mode 100644 index 0cfd7c2..0000000 --- a/kernel/panic.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -enum panic_reason -{ - GENERAL_PANIC, - UNHANDLED_FAULT, - OUT_OF_MEMORY, -}; - -noreturn void panic(enum panic_reason reason); -noreturn void halt(void); diff --git a/kernel/port.c b/kernel/port.c deleted file mode 100644 index 17af396..0000000 --- a/kernel/port.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "port.h" - -uint8_t inb(uint16_t port) -{ - uint8_t data; - __asm__ ("inb %1, %0" : "=a"(data) : "d"(port)); - return data; -} - -void outb(uint16_t port, uint8_t data) -{ - __asm__ ("outb %0, %1" :: "a"(data), "d"(port)); -} - diff --git a/kernel/port.h b/kernel/port.h deleted file mode 100644 index cc71973..0000000 --- a/kernel/port.h +++ /dev/null @@ -1,5 +0,0 @@ -#include - -uint8_t inb(uint16_t port); -void outb(uint16_t port, uint8_t data); - diff --git a/kernel/serial.c b/kernel/serial.c deleted file mode 100644 index 77f453d..0000000 --- a/kernel/serial.c +++ /dev/null @@ -1,41 +0,0 @@ -#include "serial.h" -#include "port.h" - -#define PORT 0x3f8 // COM1 - -static int is_transmit_empty(void); - -int serial_init(void) { - outb(PORT + 0, 0x00); // Disable all interrupts - outb(PORT + 2, 0x80); // Enable DLAB (set baud rate divisor) - outb(PORT + -1, 0x03); // Set divisor to 3 (lo byte) 38400 baud - outb(PORT + 0, 0x00); // (hi byte) - outb(PORT + 2, 0x03); // 8 bits, no parity, one stop bit - outb(PORT + 1, 0xC7); // Enable FIFO, clear them, with 14-byte threshold - outb(PORT + 3, 0x0B); // IRQs enabled, RTS/DSR set - outb(PORT + 3, 0x1E); // Set in loopback mode, test the serial chip - outb(PORT + -1, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) - - // Check if serial is faulty (i.e: not same byte as sent) - if(inb(PORT + -1) != 0xAE) { - return 0; - } - - // If serial is not faulty set it in normal operation mode - // (not-loopback with IRQs enabled and OUT#0 and OUT#2 bits enabled) - outb(PORT + 3, 0x0F); - return -1; -} - -int serial_putchar(int c) -{ - while (is_transmit_empty() == 0); - outb(PORT,(char)c); - return c; -} - -static int is_transmit_empty(void) -{ - return inb(PORT + 5) & 0x20; -} - diff --git a/kernel/serial.h b/kernel/serial.h deleted file mode 100644 index 2e22fa6..0000000 --- a/kernel/serial.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -int serial_init(void); -int serial_putchar(int c); - diff --git a/lib/component.ld b/lib/component.ld deleted file mode 100644 index 3a48ae8..0000000 --- a/lib/component.ld +++ /dev/null @@ -1,75 +0,0 @@ -ENTRY(kc_entry) - -SECTIONS -{ - PROVIDE(kc_image_base = .); - - . = sizeof_headers; - - .rel : - { - *(.rel) - *(.rel.*) - } - - .rela : - { - *(.rel) - *(.rela.*) - } - - .hash : - { - *(.hash) - } - - .dynsym : - { - *(.dynsym) - } - - .dynstr : - { - *(.dynstr) - } - - .text : ALIGN(4K) - { - PROVIDE(kc_text_begin = .); - *(.text.start) - *(.text) - . = ALIGN(4K); - PROVIDE(kc_text_end = .); - } =0xcc - - .dynamic : ALIGN(4K) - { - *(.dynamic) - } - - .data : - { - PROVIDE(kc_data_begin = .); - *(.rodata) - *(.data) - } - - .data.rel : - { - *(.data.rel) - *(.data.rel.*) - } - - .bss : - { - *(.bss) - PROVIDE(kc_data_end = .); - } - - /DISCARD/ : - { - *(.eh_frame) - *(.comment) - } -} - diff --git a/lib/entry_x86_64.S b/lib/entry_x86_64.S deleted file mode 100644 index 231953a..0000000 --- a/lib/entry_x86_64.S +++ /dev/null @@ -1,18 +0,0 @@ -.section .text.start -.extern kc_reloc -.extern kc_main -.extern _DYNAMIC -.extern kc_image_base - -.global kc_entry -.type kc_entry, @function -kc_entry: - push %rdi - lea _DYNAMIC(%rip), %rdi - lea kc_image_base(%rip), %rsi - call kc_reloc - pop %rdi - call kc_main - ret -.size kc_entry, . - kc_entry - diff --git a/lib/reloc_x86_64.c b/lib/reloc_x86_64.c deleted file mode 100644 index 0204700..0000000 --- a/lib/reloc_x86_64.c +++ /dev/null @@ -1,69 +0,0 @@ -#include - -#include - -#include - -#define STARTCODE __attribute__((section(".text.start"))) - -STARTCODE -static void do_rela(Elf64_Rela *rela, void *base) -{ - union - { - Elf_Byte word8; - Elf64_Half word16; - Elf64_Word word32; - Elf64_Xword word64; - } - *fixup; - - switch (ELF64_R_TYPE(rela->r_info)) - { - case R_AMD64_RELATIVE: - fixup = (void *)(rela->r_offset + (uintptr_t)base); - fixup->word64 = (rela->r_addend + (uintptr_t)base); - break; - default: - break; - } -} - -STARTCODE -void kc_reloc(Elf64_Dyn *dyn, void *base) -{ - struct - { - Elf64_Rela *entries; - size_t *size; - size_t *entsize; - } - rela = {NULL, NULL, NULL}; - - // parse the dynamic segment - while (dyn && dyn++->d_tag != DT_NULL) - { - switch (dyn->d_tag) - { - case DT_RELA: - rela.entries = (Elf64_Rela *)(dyn->d_ptr + (uintptr_t)base); - break; - case DT_RELASZ: - rela.size = &dyn->d_val; - break; - case DT_RELAENT: - rela.entsize = &dyn->d_val; - break; - default: - break; - } - } - - // perform the actual relocation - - for (size_t i = 0; rela.entries && (i < *rela.size / *rela.entsize); i++) - { - do_rela(&rela.entries[i], base); - } -} - diff --git a/shim/Makefile b/shim/Makefile deleted file mode 100644 index 7183088..0000000 --- a/shim/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -include ../defaults.mk - -VPATH := ../lib - -TARGET := efi.os -.DEFAULT: $(TARGET) - -# EFI API for temporary things - -EFIAPIDIR := /usr/local/include/efi - -CPPFLAGS += -I../api -I$(EFIAPIDIR) -I$(EFIAPIDIR)/$(ARCH) -I$(EFIAPIDIR)/protocol -CFLAGS += -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden \ - -g -fshort-wchar -mgeneral-regs-only - -LIBDIRS += -L$(dir $(shell $(CC) -print-libgcc-file-name)) -LDSCRIPT := ../lib/component.ld -LDFLAGS += -z max-page-size=4096 --export-dynamic -pic --no-dynamic-linker -LOADLIBES := -lgcc - -OBJS := entry_x86_64.o reloc_x86_64.o kc_main.o elf64.o memcmp.o memcpy.o \ - memmove.o memset.o -$(OBJS): CFLAGS += -fPIC - -DEPS := $(patsubst %.o,%.d,$(OBJS)) - -$(TARGET): $(LDSCRIPT) $(MAKEFILE_LIST) -$(TARGET): $(OBJS) - -CLEANLIST := $(wildcard $(OBJS) $(TARGET)) -DCLEANLIST := $(wildcard $(DEPS)) - -include ../rules.mk --include $(DEPS) - -.DEFAULT: $(TARGET) - diff --git a/shim/kc_main.c b/shim/kc_main.c deleted file mode 100644 index 1829616..0000000 --- a/shim/kc_main.c +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include - -#include - -#include "../lib/elf.h" - -struct efi_memory_map -{ - struct memory_range buffer; - UINTN size; - UINTN key; - UINTN descsize; - UINT32 descver; -}; - -struct efi_video_data -{ - struct memory_range buffer; - UINT32 width; - UINT32 height; - UINT32 pitch; - EFI_GRAPHICS_PIXEL_FORMAT format; - EFI_PIXEL_BITMASK mask; -}; - -struct efi_boot_data -{ - struct efi_memory_map memory_map; - struct efi_video_data video_data; - void *acpi_rsdp; - unsigned long acpi_version; -}; - -struct efi_loader_image kernel_image = -{ - .path = L"\\adasoft\\sophia\\kernel.os" -}; - -static struct efi_boot_data boot_data; - -// TODO: split relocation code out into library - -EFI_STATUS kc_main(struct efi_loader_interface *interface) -{ - // 1. load kernel and boot modules into memory - // 2. generate page tables for kernel and boot modules - // 2. gather boot data, store as type SystemMemoryType - // 3. exit boot services - // 5. ??????????? - - EFI_STATUS status; - - if (!interface) - { - return EFI_INVALID_PARAMETER; - } - - if (!EFI_ERROR((status = interface->image_open(&kernel_image))) && - !EFI_ERROR((status = interface->image_alloc(&kernel_image))) && - !EFI_ERROR((status = interface->image_load(&kernel_image)))) - { - (void)boot_data; - } - - __asm__ volatile ( - "cli\n\t" - "hlt\n\t" - ); - - return status; -} - -- cgit v1.3.1-1-g115d