summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2021-04-02 18:04:26 +0000
committerAda Christine <adachristine18@gmail.com>2021-04-02 18:04:26 +0000
commit167481f8988a860ea6d7ea8bbdb7155e4eb7abeb (patch)
treec348e1ea1bec525039decf6f15477d381f2d0bd7
parenta41f11851c23390510a8cf9d0a932b9d08636fb0 (diff)
kernel has gdt now and loads segment register and we can allocate pages
-rw-r--r--api/kernel/memory/paging.h2
-rwxr-xr-xdebug.sh3
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/cpu.c48
-rw-r--r--kernel/cpu.h4
-rw-r--r--kernel/entry_efi.c116
-rw-r--r--kernel/kernel.ld8
-rw-r--r--kernel/memory.c96
-rw-r--r--kernel/memory.h16
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)
diff --git a/debug.sh b/debug.sh
index 47f87ff..1d606af 100755
--- a/debug.sh
+++ b/debug.sh
@@ -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);
+