summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2024-05-22 13:00:41 -0400
committerJon Santmyer <jon@jonsantmyer.com>2024-05-22 13:00:41 -0400
commitace65b453151845bc361f21f3e5b651c35f9f126 (patch)
tree262ebd29b0ca1d8584f0b6f1efa7a00d9f4f3e43
parentf004c1ade8d617a82cea2fe249434cccb47a2358 (diff)
downloadjove-kernel-ace65b453151845bc361f21f3e5b651c35f9f126.tar.gz
jove-kernel-ace65b453151845bc361f21f3e5b651c35f9f126.tar.bz2
jove-kernel-ace65b453151845bc361f21f3e5b651c35f9f126.zip
massive refactor for mp and organizationHEADmaster
-rw-r--r--Makefile19
-rw-r--r--arch/arch.h8
-rw-r--r--arch/x86_64/cpu.c35
-rw-r--r--arch/x86_64/cpu.h13
-rw-r--r--arch/x86_64/elf.c55
-rw-r--r--arch/x86_64/elf.h78
-rw-r--r--arch/x86_64/elf_load.c58
-rw-r--r--arch/x86_64/gdt.c83
-rw-r--r--arch/x86_64/idt.c68
-rw-r--r--arch/x86_64/int_handler.c52
-rw-r--r--arch/x86_64/interrupt.h11
-rw-r--r--arch/x86_64/kexec.c50
-rw-r--r--arch/x86_64/msr.c67
-rw-r--r--arch/x86_64/page.c173
-rw-r--r--arch/x86_64/page.h (renamed from arch/x86_64/paging.h)0
-rw-r--r--arch/x86_64/pagedirectory.c138
-rw-r--r--arch/x86_64/pagefault.c39
-rw-r--r--arch/x86_64/paging.c257
-rw-r--r--arch/x86_64/processor.c40
-rw-r--r--arch/x86_64/restore.S20
-rw-r--r--arch/x86_64/savestate.S39
-rw-r--r--arch/x86_64/serial.c62
-rw-r--r--arch/x86_64/serial.h27
-rw-r--r--arch/x86_64/syscall.c1
-rw-r--r--arch/x86_64/syscall_entry.c25
-rw-r--r--arch/x86_64/syscall_setup.S41
-rw-r--r--arch/x86_64/tables.c8
-rw-r--r--arch/x86_64/tasking.c86
-rw-r--r--arch/x86_64/tcb_prepare.c9
-rw-r--r--arch/x86_64/tcb_switch.c18
-rw-r--r--arch/x86_64/umode_enter.S8
-rw-r--r--arch/x86_64/umode_enter.c17
-rw-r--r--arch/x86_64/vm_tophys.c23
-rw-r--r--boot/cmdline.c27
-rw-r--r--boot/cmdline.h10
-rw-r--r--boot/limine/limine.c2
-rw-r--r--compile_flags.txt4
-rw-r--r--config.mk5
-rw-r--r--device/processor.c4
-rw-r--r--device/serial.c77
-rw-r--r--include/api/errno.h9
-rw-r--r--include/api/syscall.h39
-rw-r--r--include/arch/cpu.h14
-rw-r--r--include/arch/elf.h12
-rw-r--r--include/arch/page.h34
-rw-r--r--include/arch/processor.h39
-rw-r--r--include/arch/x86_64/cpu.h6
-rw-r--r--include/arch/x86_64/elf.h93
-rw-r--r--include/arch/x86_64/gdt.h23
-rw-r--r--include/arch/x86_64/idt.h25
-rw-r--r--include/arch/x86_64/msr.h56
-rw-r--r--include/arch/x86_64/page.h40
-rw-r--r--include/arch/x86_64/processor.h17
-rw-r--r--include/arch/x86_64/tables.h (renamed from arch/x86_64/tables.h)17
-rw-r--r--include/arch/x86_64/tss.h (renamed from arch/x86_64/tss.h)2
-rw-r--r--include/assert.h10
-rw-r--r--include/boot.h (renamed from boot/boot.h)2
-rw-r--r--include/commandline.h8
-rw-r--r--include/device/serial.h48
-rw-r--r--include/device/uart.h (renamed from arch/x86_64/uart.h)2
-rw-r--r--include/initrd.h17
-rw-r--r--include/jove.h (renamed from lib/jove.h)2
-rw-r--r--include/memory.h49
-rw-r--r--include/print.h25
-rw-r--r--include/slab.h44
-rw-r--r--include/string.h (renamed from lib/string.h)0
-rw-r--r--include/tasking.h44
-rw-r--r--include/umode_vma.h10
-rw-r--r--include/zone.h38
-rw-r--r--initrd/initrd.c (renamed from ird/initrd.c)54
-rw-r--r--initrd/tar.h (renamed from ird/tar.h)6
-rw-r--r--io/interrupt.h6
-rw-r--r--io/log.c68
-rw-r--r--io/log.h22
-rw-r--r--ird/initrd.h21
-rw-r--r--klib/buddymap.c (renamed from lib/buddymap.c)2
-rw-r--r--klib/buddymap.h (renamed from lib/buddymap.h)0
-rw-r--r--klib/format.h (renamed from lib/format.h)0
-rw-r--r--klib/hash.h18
-rw-r--r--klib/kpanic.c (renamed from lib/kpanic.c)5
-rw-r--r--klib/linkedlist.c (renamed from lib/linkedlist.c)0
-rw-r--r--klib/linkedlist.h (renamed from lib/linkedlist.h)0
-rw-r--r--klib/ltostr.c (renamed from lib/ltostr.c)0
-rw-r--r--klib/mem.c (renamed from lib/mem.c)4
-rw-r--r--klib/rbtree.c361
-rw-r--r--klib/rbtree.h48
-rw-r--r--klib/sfmt.c (renamed from lib/sfmt.c)5
-rw-r--r--klib/spinlock.h (renamed from lib/spinlock.h)0
-rw-r--r--klib/string.c (renamed from lib/string.c)0
-rw-r--r--klib/toupper.c (renamed from lib/toupper.c)0
-rw-r--r--lib/hashtable.c109
-rw-r--r--lib/hashtable.h34
-rw-r--r--main.c41
-rw-r--r--mem/memory.c10
-rw-r--r--mem/memory.h94
-rw-r--r--mem/phys.c39
-rw-r--r--mem/slab.h33
-rw-r--r--mem/zone.h71
-rw-r--r--memory/alloc/calloc.c21
-rw-r--r--memory/alloc/free.c80
-rw-r--r--memory/alloc/malloc.c206
-rw-r--r--memory/alloc/malloc.h183
-rw-r--r--memory/alloc/realloc.c73
-rw-r--r--memory/alloc/reallocarray.c37
-rw-r--r--memory/bump.c33
-rw-r--r--memory/bump.h10
-rw-r--r--memory/memory.c39
-rw-r--r--memory/phys.c39
-rw-r--r--memory/slab.c (renamed from mem/slab.c)107
-rw-r--r--memory/zone.c (renamed from mem/zone.c)35
-rw-r--r--print.c40
-rw-r--r--sys/errno.h10
-rw-r--r--sys/permission.h11
-rw-r--r--sys/syscall.h69
-rw-r--r--sys/types.h32
-rw-r--r--syscall/dbg_log.c19
-rw-r--r--syscall/exit.c17
-rw-r--r--syscall/handler.c23
-rw-r--r--syscall/handler.h19
-rw-r--r--task/exrtab.c19
-rw-r--r--task/init.c22
-rw-r--r--task/stack.c14
-rw-r--r--task/tasking.c45
-rw-r--r--task/umode_vma.c37
-rw-r--r--usr/elf.h12
-rw-r--r--usr/syscall.c104
-rw-r--r--usr/syscall.h11
-rw-r--r--usr/tasking.c7
-rw-r--r--usr/tasking.h28
-rw-r--r--usr/umode.c39
-rw-r--r--usr/umode.h8
131 files changed, 3139 insertions, 1843 deletions
diff --git a/Makefile b/Makefile
index 6697fc6..84244de 100644
--- a/Makefile
+++ b/Makefile
@@ -1,24 +1,19 @@
include config.mk
+CDIRS := boot device initrd klib memory task syscall
+CDIRS += memory/alloc
+CDIRS += boot/$(TARGET_BOOTLOADER)
+CDIRS += arch/$(TARGET_MACHINE)
+
CFILES := $(wildcard *.c)
-CFILES += $(wildcard */*.c)
-CFILES += $(wildcard boot/$(TARGET_BOOTLOADER)/*.c)
-CFILES += $(wildcard arch/$(TARGET_MACHINE)/*.c)
-CFILES += $(wildcard arch/$(TARGET_MACHINE)/*/*.c)
+CFILES += $(foreach dir, $(CDIRS), $(wildcard $(dir)/*.c))
SFILES := $(wildcard *.S)
-SFILES += $(wildcard */*.S)
-SFILES += $(wildcard arch/$(TARGET_MACHINE)/*.S)
-SFILES += $(wildcard arch/$(TARGET_MACHINE)/*/*.S)
+SFILES += $(foreach dir, $(CDIRS), $(wildcard $(dir)/*.S))
OBJFILES := $(patsubst %.c,%.o,$(CFILES))
OBJFILES += $(patsubst %.S,%.o,$(SFILES))
-DFILES := $(wildcard *.d)
-DFILES += $(wildcard */*.d)
-DFILES += $(wildcard arch/$(TARGET_MACHINE)/*.d)
-DFILES += $(wildcard arch/$(TARGET_MACHINE)/*/*.d)
-
BIN := jove.elf
all: $(BIN)
diff --git a/arch/arch.h b/arch/arch.h
deleted file mode 100644
index 6e569fd..0000000
--- a/arch/arch.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef JOVE_ARCH_H
-#define JOVE_ARCH_H 1
-
-extern void serial_setup(void);
-
-extern void arch_tables_setup(void);
-
-#endif
diff --git a/arch/x86_64/cpu.c b/arch/x86_64/cpu.c
new file mode 100644
index 0000000..d088fcd
--- /dev/null
+++ b/arch/x86_64/cpu.c
@@ -0,0 +1,35 @@
+#include "arch/cpu.h"
+#include "arch/x86_64/msr.h"
+
+extern void _syscall_entry(void);
+
+extern void idt_init();
+
+void
+cpu_setup(void)
+{
+ idt_init();
+
+ cpu_arch_enable_sce();
+ cpu_set_syscall_entry((void*)_syscall_entry);
+}
+
+void cpu_arch_enable_sce(void)
+{
+ msr_efer_t feat = msr_efer_read();
+ feat.sce = 1;
+ msr_efer_write(feat);
+
+ msr_star_t star = msr_star_read();
+ star.kcs = 0x08;
+ star.ucs = 0x18;
+ msr_star_write(star);
+}
+
+void
+cpu_set_syscall_entry(void *ptr)
+{
+ msr_lstar_t lstar = (msr_lstar_t)ptr;
+ msr_lstar_write(lstar);
+}
+
diff --git a/arch/x86_64/cpu.h b/arch/x86_64/cpu.h
deleted file mode 100644
index 942c8d9..0000000
--- a/arch/x86_64/cpu.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef ARCH_x86_64_CPU_H
-#define ARCH_x86_64_CPU_H 1
-
-#include <stdint.h>
-
-struct Registers
-{
- uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
- uint64_t bp, di, si, dx, cx, bx, ax;
- uint64_t ip, cs, flags, sp, ss;
-};
-
-#endif
diff --git a/arch/x86_64/elf.c b/arch/x86_64/elf.c
deleted file mode 100644
index 969cbf0..0000000
--- a/arch/x86_64/elf.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include "elf.h"
-#include "lib/string.h"
-#include "usr/elf.h"
-#include "io/log.h"
-#include "mem/memory.h"
-
-void*
-elf_load(const void *data, size_t len)
-{
- if(data == NULL) return NULL;
- if(len < 4) return NULL;
-
- struct ELF_header *ehdr = (struct ELF_header*)data;
- if(ehdr->e_ident[EI_MAG0] != E_IDENT_MAG0 &&
- ehdr->e_ident[EI_MAG1] != E_IDENT_MAG1 &&
- ehdr->e_ident[EI_MAG2] != E_IDENT_MAG2 &&
- ehdr->e_ident[EI_MAG3] != E_IDENT_MAG3)
- return NULL;
-
- if(ehdr->e_ident[EI_CLASS] != E_IDENT_CLASS64) {
- klogf("Jove does not support ELF files of class CLASS32\n");
- return NULL;
- }
-
- if(ehdr->e_type != ET_EXEC) {
- klogf("Jove does not support ELF files other than ET_EXEC\n");
- return NULL;
- }
-
- uint64_t entry = ehdr->e_entry;
-
- size_t phdrc = ehdr->e_phnum;
- struct ELF_phdr *phdrs = (struct ELF_phdr*)((uintptr_t)data + ehdr->e_phoff);
-
- for(size_t phdri = 0; phdri < phdrc; phdri++)
- {
- struct ELF_phdr *phdr = &phdrs[phdri];
- void *pdata = (void*)phdr->p_vaddr;
-
- mem_ensure_range(
- phdr->p_vaddr,
- phdr->p_vaddr + phdr->p_memsz,
- (page_flags_t) {
- .present = true,
- .writeable = true,
- .useraccess = true,
- .executable = true
- });
- if(phdr->p_type == PT_LOAD)
- {
- memcpy(pdata, (void*)((uintptr_t)data + phdr->p_offset), phdr->p_filesz);
- }
- }
- return (void*)entry;
-}
diff --git a/arch/x86_64/elf.h b/arch/x86_64/elf.h
deleted file mode 100644
index ebcd228..0000000
--- a/arch/x86_64/elf.h
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef JOVE_ARCH_x86_64_ELF_H
-#define JOVE_ARCH_x86_64_ELF_H 1
-
-#include <stdint.h>
-
-#define EI_MAG0 0
-#define EI_MAG1 1
-#define EI_MAG2 2
-#define EI_MAG3 3
-#define EI_CLASS 4
-#define EI_DATA 5
-#define EI_VERSION 6
-#define EI_OSABI 7
-#define EI_ABIVERSION 8
-#define EI_PAD 9
-
-#define E_IDENT_MAG0 0x7F
-#define E_IDENT_MAG1 'E'
-#define E_IDENT_MAG2 'L'
-#define E_IDENT_MAG3 'F'
-
-#define E_IDENT_CLASS32 1
-#define E_IDENT_CLASS64 2
-
-#define ET_EXEC 0x02
-
-struct ELF_header
-{
- uint8_t e_ident[15];
- uint16_t e_type;
- uint16_t e_machine;
- uint32_t e_version;
- uint64_t e_entry;
- uint64_t e_phoff;
- uint64_t e_shoff;
- uint32_t e_flags;
- uint16_t e_ehsize;
- uint16_t e_phentsize;
- uint16_t e_phnum;
- uint16_t e_shentsize;
- uint16_t e_shnum;
- uint16_t e_shstrndx;
-};
-
-#define PT_NULL 0
-#define PT_LOAD 1
-
-#define PF_X 1
-#define PF_W 2
-#define PF_R 4
-
-struct ELF_phdr
-{
- uint32_t p_type;
- uint32_t p_flags;
- uint64_t p_offset;
- uint64_t p_vaddr;
- uint64_t p_paddr;
- uint64_t p_filesz;
- uint64_t p_memsz;
- uint64_t p_align;
-};
-
-struct ELF_shdr
-{
- uint32_t sh_name;
- uint32_t sh_type;
- uint64_t sh_flags;
- uint64_t sh_addr;
- uint64_t sh_offset;
- uint64_t sh_size;
- uint32_t sh_link;
- uint32_t sh_info;
- uint64_t sh_addralign;
- uint64_t sh_entsize;
-};
-
-#endif
diff --git a/arch/x86_64/elf_load.c b/arch/x86_64/elf_load.c
new file mode 100644
index 0000000..d7d1b29
--- /dev/null
+++ b/arch/x86_64/elf_load.c
@@ -0,0 +1,58 @@
+#include "arch/elf.h"
+#include "string.h"
+#include "memory.h"
+#include "print.h"
+
+uintptr_t
+elf_load(const void *data, size_t len)
+{
+ if(data == NULL) return 0;
+ if(len < 4) return 0;
+
+ elf_header_t *ehdr = (elf_header_t*)data;
+ if(ehdr->ei_mag[0] != EI_MAG0 ||
+ ehdr->ei_mag[1] != EI_MAG1 ||
+ ehdr->ei_mag[2] != EI_MAG2 ||
+ ehdr->ei_mag[3] != EI_MAG3) return 0;
+
+ if(ehdr->ei_class != EI_CLASS_64) {
+ kerrf("Jove does not support ELF files of class CLASS32\n");
+ return 0;
+ }
+
+ if(ehdr->e_type != ET_EXEC) {
+ kerrf("Jove does not support ELF files other than ET_EXEC\n");
+ return 0;
+ }
+
+ uint64_t entry = ehdr->e_entry;
+
+ size_t phdrc = ehdr->e_phnum;
+ elf_phdr_t *phdrs = (elf_phdr_t*)((uintptr_t)data + ehdr->e_phoff);
+
+ for(size_t phdri = 0; phdri < phdrc; phdri++)
+ {
+ elf_phdr_t *phdr = &phdrs[phdri];
+ void *pdata = (void*)phdr->p_vaddr;
+
+ vm_ensure(
+ phdr->p_vaddr,
+ phdr->p_vaddr + phdr->p_memsz,
+ (page_flags_t) {
+ .present = true,
+ .writeable = true,
+ .useraccess = true,
+ .executable = true
+ });
+
+ if(phdr->p_type == PT_LOAD)
+ {
+ kdbgf("PT_LOAD %#016X [%#016X] -> %#016X\n",
+ (uintptr_t)data + phdr->p_offset,
+ phdr->p_filesz,
+ pdata);
+ memcpy(pdata, (void*)((uintptr_t)data + phdr->p_offset), phdr->p_filesz);
+ }
+ }
+ return entry;
+}
diff --git a/arch/x86_64/gdt.c b/arch/x86_64/gdt.c
index 07a8097..614ec30 100644
--- a/arch/x86_64/gdt.c
+++ b/arch/x86_64/gdt.c
@@ -1,24 +1,10 @@
-#include "tables.h"
-#include "tss.h"
+#include "arch/x86_64/gdt.h"
+#include "arch/x86_64/tss.h"
+#include "arch/processor.h"
+#include "string.h"
+#include "print.h"
-enum
-{
- GDT_SEGMENT_KERNEL_NULL = 0,
- GDT_SEGMENT_KERNEL_CODE,
- GDT_SEGMENT_KERNEL_DATA,
-
- GDT_SEGMENT_USER_NULL,
- GDT_SEGMENT_USER_DATA,
- GDT_SEGMENT_USER_CODE,
-
- GDT_SEGMENT_TSS_LOW,
- GDT_SEGMENT_TSS_HIGH,
-
- GDT_SEGMENT_COUNT
-};
-
-__attribute__((aligned(0x1000)))
-static struct SegmentDescriptor s_gdtd[GDT_SEGMENT_COUNT] =
+static gdt_t s_baseline_gdt =
{
{ 0 }, /* Kernel NULL */
{ /* Kernel Code (64-bit RO EX DPL0) */
@@ -99,43 +85,40 @@ static struct SegmentDescriptor s_gdtd[GDT_SEGMENT_COUNT] =
},
{ 0 }
};
-static struct XDTR s_gdtr = {
- .length = sizeof(s_gdtd) - 1,
- .address = (uintptr_t)&s_gdtd
-};
-static struct TSS s_tss = {
-
-};
-
-extern void x86_64_lgdt(struct XDTR *gdtr);
-extern void x86_64_flush_tss(void);
void
-x86_64_load_gdt(void)
+gdt_setup(processor_t *proc)
{
- {
- struct SegmentDescriptor *tss_lo = &s_gdtd[GDT_SEGMENT_TSS_LOW];
- struct SegmentDescriptor *tss_hi = &s_gdtd[GDT_SEGMENT_TSS_HIGH];
- uintptr_t tssb = (uintptr_t)&s_tss;
- tss_lo->base_0_15 = tssb & 0xFFFF;
- tss_lo->base_16_23 = (tssb >> 16) & 0xFF;
- tss_lo->base_24_31 = (tssb >> 24) & 0xFF;
- tss_hi->limit_0_15 = (tssb >> 32) & 0xFFFF;
- tss_hi->base_0_15 = (tssb >> 48) & 0xFFFF;
+ memcpy(proc->_gdt, s_baseline_gdt, sizeof(gdt_t));
+ proc->_gdtr = (struct XDTR) {
+ .length = sizeof(gdt_t) - 1,
+ .address = (uintptr_t)&proc->_gdt
+ };
+ klogf("Processor %i GDT %#016X L%i\n", proc->id, proc->_gdt, proc->_gdtr.length);
+}
- size_t tssl = sizeof(struct TSS) - 1;
- tss_lo->limit_0_15 = tssl & 0xFFFF;
- tss_lo->limit_16_19 = (tssl >> 16) & 0xF;
+void
+tss_setup(processor_t *proc)
+{
+ segment_descriptor_t *tss_lo = &proc->_gdt[GDT_SEGMENT_TSS_LOW];
+ segment_descriptor_t *tss_hi = &proc->_gdt[GDT_SEGMENT_TSS_HIGH];
+ uintptr_t tssb = (uintptr_t)&(proc->_tss);
+ tss_lo->base_0_15 = tssb & 0xFFFF;
+ tss_lo->base_16_23 = (tssb >> 16) & 0xFF;
+ tss_lo->base_24_31 = (tssb >> 24) & 0xFF;
+ tss_hi->limit_0_15 = (tssb >> 32) & 0xFFFF;
+ tss_hi->base_0_15 = (tssb >> 48) & 0xFFFF;
- s_tss.iobp = sizeof(struct TSS);
- }
+ size_t tssl = sizeof(struct TSS) - 1;
+ tss_lo->limit_0_15 = tssl & 0xFFFF;
+ tss_lo->limit_16_19 = (tssl >> 16) & 0xF;
- x86_64_lgdt(&s_gdtr);
- x86_64_flush_tss();
+ proc->_tss.iobp = sizeof(struct TSS);
}
-void tss_set_rsp(uint8_t dpl, uintptr_t rsp)
+void
+tss_set_rsp(struct TSS *tss, uint8_t dpl, uintptr_t rsp)
{
- s_tss.rsp[dpl][0] = rsp & 0xFFFFFFFF;
- s_tss.rsp[dpl][1] = (rsp >> 32) & 0xFFFFFFFF;
+ tss->rsp[dpl][0] = rsp & 0xFFFFFFFF;
+ tss->rsp[dpl][1] = (rsp >> 32) & 0xFFFFFFFF;
}
diff --git a/arch/x86_64/idt.c b/arch/x86_64/idt.c
index 05dcf43..5ddda50 100644
--- a/arch/x86_64/idt.c
+++ b/arch/x86_64/idt.c
@@ -1,64 +1,25 @@
-#include "tables.h"
-#include "cpu.h"
-#include "lib/jove.h"
-#include "io/log.h"
+#include <stddef.h>
+#include "arch/x86_64/tables.h"
+#include "arch/x86_64/idt.h"
+#include "arch/processor.h"
+#include "print.h"
+#include "jove.h"
PAGEALIGN
-static struct InterruptTrapGate s_idtd[48];
-static struct Registers *(*s_int_handlers[48])(struct Registers*);
-static struct XDTR s_idtr = {
- .length = sizeof(s_idtd) - 1,
- .address = (uintptr_t)&s_idtd
-};
+static interrupt_gate_t s_idtd[48];
uint64_t __isr_err;
uint64_t __isr_num;
-void
-int_set_handler(uint8_t code, struct Registers *(*handler)(struct Registers*))
-{
- if(code >= 48) return;
- s_int_handlers[code] = handler;
-}
-
-struct Registers*
-irq_handle(struct Registers *state)
-{
- if(__isr_num < 48) {
- if(s_int_handlers[__isr_num] != NULL) {
- return s_int_handlers[__isr_num](state);
- }
- }
- klogf("Interrupt %i\nerror code %#016X\n", __isr_num, __isr_err);
- klogf("IP: %#016X\n", state->ip);
- klogf("AX: %#016X\n", state->ax);
- klogf("BX: %#016X\n", state->bx);
- klogf("CX: %#016X\n", state->cx);
- klogf("DX: %#016X\n", state->dx);
- klogf("SI: %#016X\n", state->si);
- klogf("DI: %#016X\n", state->di);
- klogf("BP: %#016X\n", state->bp);
- klogf("R8: %#016X\n", state->r8);
- klogf("R9: %#016X\n", state->r9);
- klogf("R10: %#016X\n", state->r10);
- klogf("R11: %#016X\n", state->r11);
- klogf("R12: %#016X\n", state->r12);
- klogf("R13: %#016X\n", state->r13);
- klogf("R14: %#016X\n", state->r14);
- klogf("R15: %#016X\n", state->r15);
- kpanic("Unhandled exception\n");
- return state;
-}
-
extern void x86_64_lidt(struct XDTR *idtr);
void
-x86_64_load_idt(void)
+idt_init(void)
{
extern uintptr_t __isr_stubs[22];
for(int i = 0; i < 22; i++)
{
uintptr_t base = __isr_stubs[i];
- s_idtd[i] = (struct InterruptTrapGate){
+ s_idtd[i] = (interrupt_gate_t){
.base_0_15 = (base & 0xFFFF),
.segment_selector = 0x8,
.ist = 0,
@@ -71,7 +32,14 @@ x86_64_load_idt(void)
.base_32_63 = (base >> 32) & 0xFFFFFFFF,
.resv = 0
};
- klogf("INT %2i : %#016X (%016X)\n", i, base, s_idtd[i]);
}
- x86_64_lidt(&s_idtr);
+}
+
+void
+idt_setup(processor_t *proc)
+{
+ proc->_idtr = (struct XDTR){
+ .length = sizeof(s_idtd) - 1,
+ .address = (uintptr_t)s_idtd
+ };
}
diff --git a/arch/x86_64/int_handler.c b/arch/x86_64/int_handler.c
new file mode 100644
index 0000000..3674d1c
--- /dev/null
+++ b/arch/x86_64/int_handler.c
@@ -0,0 +1,52 @@
+#include "arch/x86_64/idt.h"
+#include "arch/processor.h"
+#include "print.h"
+#include "jove.h"
+#include "assert.h"
+#include <stddef.h>
+
+static int_handler_t s_handlers[48];
+
+int_state_t*
+irq_handle(int_state_t *state)
+{
+ if(__isr_num < 48) {
+ if(s_handlers[__isr_num] != NULL) {
+ return s_handlers[__isr_num](state);
+ }
+ }
+
+ klogf("Interrupt %i\nerror code %#016X\n", __isr_num, __isr_err);
+ int_state_print(state);
+ kpanic("Unhandled exception\n");
+ return state;
+}
+
+void
+int_handler_set(uint8_t i, int_handler_t handler)
+{
+ assert(i < 48);
+ s_handlers[i] = handler;
+}
+
+int_handler_t
+int_handler_get(uint8_t i)
+{
+ assert(i < 48);
+ return s_handlers[i];
+}
+
+void
+int_state_print(int_state_t *state)
+{
+ if(!state) return;
+ klogf("IP: %016p\n", state->ip);
+ klogf("AX: %016p BX: %016p\n", state->ax, state->bx);
+ klogf("CX: %016p DX: %016p\n", state->cx, state->dx);
+ klogf("SI: %016p DI: %016p\n", state->si, state->di);
+ klogf("SP: %016p BP: %016p\n", state->sp, state->bp);
+ klogf("R8: %016p R9: %016p\n", state->r8, state->r9);
+ klogf("R10: %016p R11: %016p\n", state->r10, state->r11);
+ klogf("R12: %016p R13: %016p\n", state->r12, state->r13);
+ klogf("R14: %016p R15: %016p\n", state->r14, state->r15);
+}
diff --git a/arch/x86_64/interrupt.h b/arch/x86_64/interrupt.h
deleted file mode 100644
index 9ae63f9..0000000
--- a/arch/x86_64/interrupt.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef JOVE_ARCH_INTERRUPT_H
-#define JOVE_ARCH_INTERRUPT_H 1
-
-#include "cpu.h"
-
-/**Register a handler for a specified interrupt code.
- * @param code interrupt to handle.
- * @param handler to call.*/
-void int_set_handler(unsigned char code, struct Registers *(*handler)(struct Registers*));
-
-#endif
diff --git a/arch/x86_64/kexec.c b/arch/x86_64/kexec.c
new file mode 100644
index 0000000..406e8e7
--- /dev/null
+++ b/arch/x86_64/kexec.c
@@ -0,0 +1,50 @@
+#include "tasking.h"
+#include "memory.h"
+#include "string.h"
+#include "arch/cpu.h"
+
+#define UMODE_STACK_TOP (USERLAND_MEMORY_LIMIT)
+#define UMODE_STACKW PAGE_SIZE
+
+static void*
+s_umode_stack(void)
+{
+ uintptr_t top = UMODE_STACK_TOP;
+ uintptr_t bottom = top - (UMODE_STACKW - 1);
+
+ vm_ensure(bottom, top, (page_flags_t) {
+ .present = true,
+ .writeable = true,
+ .useraccess = true,
+ .executable = false
+ });
+ return (void*)top;
+}
+
+static inline void*
+s_stack_push(void *sp, void *data, size_t len)
+{
+ sp = (void*)((uintptr_t)sp - len);
+ memcpy(sp, data, len);
+ return sp;
+}
+
+void
+kexec(void *ip, int kargc, char **kargv, int kenvc, char **kenvp)
+{
+ /* Allocate a page for the user stack. */
+ void *sp = s_umode_stack();
+
+ intmax_t argc = kargc;
+ sp = s_stack_push(sp, &argc, sizeof(intmax_t));
+
+ /* TODO: Proper argv, envp*/
+ sp = s_stack_push(sp, &kargv, sizeof(char**));
+
+ intmax_t envc = kenvc;
+ sp = s_stack_push(sp, &envc, sizeof(intmax_t));
+
+ sp = s_stack_push(sp, &kenvp, sizeof(char**));
+
+ umode_enter(ip, sp);
+}
diff --git a/arch/x86_64/msr.c b/arch/x86_64/msr.c
new file mode 100644
index 0000000..1891126
--- /dev/null
+++ b/arch/x86_64/msr.c
@@ -0,0 +1,67 @@
+#include "arch/x86_64/msr.h"
+
+void
+msr_write(uint32_t msr, uint64_t v)
+{
+ __asm__ volatile("wrmsr":: "a"(v), "d"(v >> 32), "c"(msr));
+}
+
+uint64_t
+msr_read(uint32_t msr)
+{
+ uint32_t lo, hi;
+ __asm__ volatile("rdmsr": "=a"(lo), "=d"(hi): "c"(msr));
+ uint64_t v = hi;
+ v = (v << 32) | lo;
+ return v;
+}
+
+void
+msr_efer_write(msr_efer_t v)
+{
+ msr_write(MSR_EFER, *((uintptr_t*)&v));
+}
+
+msr_efer_t
+msr_efer_read(void)
+{
+ uint64_t rawv = msr_read(MSR_EFER);
+ return *((msr_efer_t*)&rawv);
+}
+
+void
+msr_star_write(msr_star_t v)
+{
+ msr_write(MSR_STAR, *((uintptr_t*)&v));
+}
+
+msr_star_t
+msr_star_read(void)
+{
+ uint64_t rawv = msr_read(MSR_STAR);
+ return *((msr_star_t*)&rawv);
+}
+
+void
+msr_lstar_write(msr_lstar_t v)
+{
+ msr_write(MSR_LSTAR, v);
+}
+
+msr_lstar_t
+msr_lstar_read(void)
+{
+ return msr_read(MSR_LSTAR);
+}
+
+void
+msr_gsbase_write(uintptr_t gsbase)
+{
+ msr_write(MSR_GSBASE, gsbase);
+}
+
+uintptr_t
+msr_gsbase_read(void)
+{
+ return msr_read(MSR_GSBASE);
+}
diff --git a/arch/x86_64/page.c b/arch/x86_64/page.c
new file mode 100644
index 0000000..d816f66
--- /dev/null
+++ b/arch/x86_64/page.c
@@ -0,0 +1,173 @@
+#include "arch/x86_64/page.h"
+#include "klib/rbtree.h"
+#include "arch/processor.h"
+#include "string.h"
+#include "jove.h"
+#include "memory.h"
+#include "print.h"
+
+extern void *_kernel_end;
+
+struct PageDirectoryListEntry {
+ struct PageDirectoryListEntry *next;
+ page_directory_t pd;
+};
+
+struct PageStateCache {
+ page_directory_t *pd;
+ size_t pmli[4];
+ pmle_t *pml[4];
+} s_state_cache;
+
+const uintptr_t USERLAND_MEMORY_BASE = KiB;
+const uintptr_t USERLAND_MEMORY_LIMIT = 0x00007FFFFFFFFFFFULL;
+
+const uintptr_t PHYSMAP_MEMORY_BASE = 0xFFFF800000000000ULL;
+const uintptr_t PHYSMAP_MEMORY_LIMIT = PHYSMAP_MEMORY_BASE + (1 * GiB);
+
+const uintptr_t KERNEL_MEMORY_BASE = 0xFFFF800000000000ULL;
+const uintptr_t KERNEL_MEMORY_LIMIT = 0xFFFFFFFFFFFFFFFFULL;
+
+static size_t
+s_paging_pmli(size_t l, uintptr_t addr)
+{
+ size_t shift = (PAGE_SHIFT + (9 * l));
+ return (addr & (0x1FFULL << shift)) >> shift;
+}
+
+static pmle_t*
+s_paging_fetch_table(pmle_t *pml, size_t l, uintptr_t virt)
+{
+ size_t pmli = s_paging_pmli(l, virt);
+ if(s_state_cache.pmli[l] == pmli && s_state_cache.pml[l] != NULL)
+ return s_state_cache.pml[l];
+
+ pmle_t entry = pml[pmli];
+ bool entry_new = false;
+ if(!entry.p) {
+ entry_new = true;
+ entry.value = pm_alloc(1);
+ entry.p = 1;
+ entry.rw = 1;
+ entry.us = 1;
+ pml[pmli] = entry;
+ }
+ pmle_t *table = (pmle_t*)(pm_tovirt(entry.paddr << PAGE_SHIFT));
+ if(entry_new) memset(table, 0, PAGE_SIZE);
+
+ s_state_cache.pmli[l] = pmli;
+ s_state_cache.pml[l] = table;
+ return table;
+}
+
+static void
+s_paging_cache_tables(page_directory_t *pd, uintptr_t virt)
+{
+ pmle_t *pml4 = pd->pml;
+ if(s_state_cache.pd != pd) memset(&s_state_cache, 0, sizeof(s_state_cache));
+
+ pmle_t *pml3 = s_paging_fetch_table(pml4, 3, virt);
+ pmle_t *pml2 = s_paging_fetch_table(pml3, 2, virt);
+ pmle_t *pml1 = s_paging_fetch_table(pml2, 1, virt);
+}
+
+static pmle_t*
+s_paging_get_table(pmle_t *pt, size_t l, uintptr_t virt)
+{
+ if(pt == NULL) return NULL;
+ size_t pmli = s_paging_pmli(l, virt);
+ if(s_state_cache.pmli[l] == pmli && s_state_cache.pml[l] != NULL)
+ return s_state_cache.pml[l];
+
+ pmle_t entry = pt[pmli];
+ if(!entry.p) return NULL;
+ return (pmle_t*)(pm_tovirt(entry.paddr << PAGE_SHIFT));
+}
+
+page_mapping_t
+vm_pd_mapping_get(page_directory_t *pd, uintptr_t addr)
+{
+ spinlock_acquire(pd->lock);
+ page_mapping_t mapping = { 0 };
+
+ pmle_t *pml4 = pd->pml;
+ if(s_state_cache.pd != pd) memset(&s_state_cache, 0, sizeof(s_state_cache));
+
+ pmle_t *pml3 = s_paging_get_table(pml4, 3, addr);
+ pmle_t *pml2 = s_paging_get_table(pml3, 2, addr);
+ pmle_t *pml1 = s_paging_get_table(pml2, 1, addr);
+ if(pml1 == NULL) goto release_return;
+
+ size_t pml1i = s_paging_pmli(0, addr);
+ pmle_t pml1e = pml1[pml1i];
+
+ mapping = (page_mapping_t) {
+ .phys = (pml1e.paddr << PAGE_SHIFT) & ~PAGE_MASK,
+ .pf = {
+ .present = pml1e.p,
+ .writeable = pml1e.rw,
+ .useraccess = pml1e.us,
+ .executable = !pml1e.xd
+ }
+ };
+release_return:
+ spinlock_release(pd->lock);
+ return mapping;
+}
+
+page_mapping_t vm_mapping_get(uintptr_t addr)
+{ return vm_pd_mapping_get(pd_current(), addr); }
+
+void
+mem_set_mapping_as(page_directory_t *pd, page_mapping_t mapping, uintptr_t virt)
+{
+ spinlock_acquire(pd->lock);
+ s_paging_cache_tables(pd, virt);
+ pmle_t *pml1 = s_state_cache.pml[0];
+ size_t pml1i = s_paging_pmli(0, virt);
+
+ pml1[pml1i] = (pmle_t) {
+ .p = mapping.pf.present,
+ .rw = mapping.pf.writeable,
+ .us = mapping.pf.useraccess,
+ .xd = !mapping.pf.executable,
+ .paddr = mapping.phys >> PAGE_SHIFT
+ };
+ spinlock_release(pd->lock);
+}
+
+void mem_set_mapping(page_mapping_t mapping, uintptr_t virt)
+{ mem_set_mapping_as(pd_current(), mapping, virt); }
+
+void
+vm_pd_ensure(page_directory_t *pd, uintptr_t from, uintptr_t to, page_flags_t flg)
+{
+ spinlock_acquire(pd->lock);
+ from &= ~(PAGE_SIZE - 1);
+ to += (to % PAGE_SIZE > 0 ? (PAGE_SIZE - (to % PAGE_SIZE)) : 0);
+
+ if(to < from) to = from;
+ size_t pages = (to - from) >> PAGE_SHIFT;
+ if(pages == 0) pages = 1;
+ for(size_t i = 0; i < pages; i++) {
+ uintptr_t waddr = from + (i << PAGE_SHIFT);
+ s_paging_cache_tables(pd, waddr);
+ pmle_t *pml1 = s_state_cache.pml[1];
+ size_t pml1i = s_paging_pmli(0, waddr);
+
+ if(!pml1[pml1i].p) {
+ physptr_t phys = pm_alloc(1);
+ pml1[pml1i] = (pmle_t) {
+ .p = flg.present,
+ .rw = flg.writeable,
+ .us = flg.useraccess,
+ .xd = !flg.executable,
+ .paddr = phys >> PAGE_SHIFT
+ };
+ }
+ }
+ spinlock_release(pd->lock);
+}
+
+void vm_ensure(uintptr_t from, uintptr_t to, page_flags_t flg)
+{ vm_pd_ensure(pd_current(), from, to, flg); }
diff --git a/arch/x86_64/paging.h b/arch/x86_64/page.h
index 28dfad2..28dfad2 100644
--- a/arch/x86_64/paging.h
+++ b/arch/x86_64/page.h
diff --git a/arch/x86_64/pagedirectory.c b/arch/x86_64/pagedirectory.c
new file mode 100644
index 0000000..cdfffeb
--- /dev/null
+++ b/arch/x86_64/pagedirectory.c
@@ -0,0 +1,138 @@
+#include "arch/page.h"
+#include "arch/processor.h"
+#include "klib/rbtree.h"
+#include "boot.h"
+#include "memory.h"
+#include "string.h"
+#include "print.h"
+
+PAGEALIGN static uint64_t s_kernel_initial_pml4[512];
+PAGEALIGN static uint64_t s_kernel_initial_pml3[2][512];
+PAGEALIGN static uint64_t s_kernel_initial_pml2[2][512];
+PAGEALIGN static uint64_t s_kernel_initial_pml1[2][512];
+static page_directory_t s_kernel_initial_pd;
+
+static rbtree_t s_page_directories;
+static intmax_t s_next_pdid = 0;
+
+page_directory_t*
+pd_new()
+{
+ page_directory_t newpd = {
+ .id = s_next_pdid++,
+ .phys = pm_alloc(1),
+ };
+ newpd.pml = (void*)pm_tovirt(newpd.phys);
+ for(size_t i = 256; i < 512; i++) {
+ pmle_t *kpe = &(s_kernel_initial_pd.pml)[i];
+ pmle_t *ppe = &(newpd.pml)[i];
+ *ppe = *kpe;
+ }
+
+ return rbtree_insert(&s_page_directories, newpd.id, &newpd);
+}
+
+static void
+s_pd_dup_pml(pmle_t *src, pmle_t *dest, size_t l, size_t i)
+{
+ pmle_t srce = src[i];
+ if(!srce.p) return;
+
+ dest[i] = srce;
+ dest[i].paddr = pm_alloc(1);
+ pmle_t dste = dest[i];
+
+ pmle_t *srct = (pmle_t*)pm_tovirt(srce.paddr << PAGE_SHIFT);
+ pmle_t *dstt = (pmle_t*)pm_tovirt(dste.paddr << PAGE_SHIFT);
+
+ if(l == 0) {
+ memcpy(dstt, srct, PAGE_SIZE);
+ return;
+ }
+
+ for(i = 0; i < 512; i++) {
+ dstt[i] = srct[i];
+ if(!srct[i].p) continue;
+ s_pd_dup_pml(srct, dstt, l - 1, i);
+ }
+}
+
+page_directory_t*
+pd_dup(page_directory_t *pd)
+{
+ page_directory_t *newpd = pd_new();
+ for(size_t i = 0; i < 256; i++) {
+ s_pd_dup_pml(pd->pml, newpd->pml, 3, i);
+ }
+ return newpd;
+}
+
+page_directory_t*
+pd_get(pdid_t pdid)
+{
+ return rbtree_find(&s_page_directories, pdid);
+}
+
+void
+pd_switch(page_directory_t *pd)
+{
+ processor_t *pc = processor_current();
+ if(pc->pd == pd) return;
+ pc->pd = pd;
+ __asm__ volatile("movq %0, %%cr3":: "r"(pd->phys));
+}
+
+void
+vm_setup_early(void)
+{
+ memset(s_kernel_initial_pml4, 0, PAGE_SIZE);
+ memset(s_kernel_initial_pml3, 0, 2 * PAGE_SIZE);
+ memset(s_kernel_initial_pml2, 0, 2 * PAGE_SIZE);
+ memset(s_kernel_initial_pml1, 0, PAGE_SIZE);
+ s_kernel_initial_pd = (page_directory_t){
+ .phys = vm_tophys_koff((uintptr_t)&s_kernel_initial_pml4),
+ .pml = (pmle_t*)&s_kernel_initial_pml4,
+ .id = s_next_pdid++
+ };
+ processor_current()->pd = &s_kernel_initial_pd;
+
+ /* Map first few GiBs */
+ s_kernel_initial_pml4[256] =
+ vm_tophys_koff((uintptr_t)&s_kernel_initial_pml3[0])
+ | 3;
+ s_kernel_initial_pml3[0][0] =
+ vm_tophys_koff((uintptr_t)&s_kernel_initial_pml2[0])
+ | 3;
+ for(int i = 0; i < 512; i++) {
+ s_kernel_initial_pml2[0][i] = (i * (PAGE_SIZE * 512)) | 0x80 | 3;
+ }
+
+ size_t kernel_pml3e = (_kernel_virtual_base >> (30)) % 512;
+ size_t kernel_pml2e = (_kernel_virtual_base >> (21)) % 512;
+ size_t kernel_npages = ((((uintptr_t)&_kernel_end) - _kernel_virtual_base) >> 12) + 1;
+ klogf("Kernel has %i pages\n", kernel_npages);
+
+ /* Map kernel pages */
+ s_kernel_initial_pml4[511] =
+ vm_tophys_koff((uintptr_t)&s_kernel_initial_pml3[1]) | 3;
+ s_kernel_initial_pml3[1][kernel_pml3e] =
+ vm_tophys_koff((uintptr_t)&s_kernel_initial_pml2[1]) | 3;
+ s_kernel_initial_pml2[1][kernel_pml2e] =
+ vm_tophys_koff((uintptr_t)&s_kernel_initial_pml1[0]) | 3;
+ for(size_t i = 0; i < kernel_npages; i++) {
+ s_kernel_initial_pml1[0][i] = (i * PAGE_SIZE) + boot_kernel_physical_address | 3;
+ }
+
+ extern int_state_t *_pagefault_handler(int_state_t*);
+ int_handler_set(14, _pagefault_handler);
+ __asm__ volatile("mov %0, %%cr3":: "r"(s_kernel_initial_pd.phys));
+}
+
+void
+vm_setup(void)
+{
+ rbtree_new(&s_page_directories, page_directory_t);
+
+ processor_t *proc = processor_current();
+ pd_switch(pd_new());
+}
diff --git a/arch/x86_64/pagefault.c b/arch/x86_64/pagefault.c
new file mode 100644
index 0000000..5bba20b
--- /dev/null
+++ b/arch/x86_64/pagefault.c
@@ -0,0 +1,39 @@
+#include "arch/x86_64/idt.h"
+#include "arch/processor.h"
+#include "memory.h"
+#include "print.h"
+#include "jove.h"
+
+#include <stdbool.h>
+
+int_state_t*
+_pagefault_handler(int_state_t *state)
+{
+ extern uint64_t __isr_err;
+
+ uintptr_t fault_addr = 0;
+ __asm__ volatile("movq %%cr2, %0": "=r"(fault_addr));
+
+ if(fault_addr < USERLAND_MEMORY_LIMIT) {
+ // Check if there is an entry in the exception return table.
+ processor_t *proc = processor_current();
+ if(proc->ert_i > 0) {
+ state->ip = (uintptr_t)_exrtab_pop();
+ return state;
+ }
+ }
+
+ bool present = __isr_err & 1;
+ bool write = __isr_err & 2;
+ bool user = __isr_err & 4;
+
+ klogf("Page fault at %016X\n", fault_addr);
+ klogf("%s %s from a %s address\n",
+ user ? "user" : "kernel",
+ write ? "wrote" : "read",
+ present ? "present" : "non-present");
+
+ int_state_print(state);
+ kpanic("Unhandled page fault\n");
+ return state;
+}
diff --git a/arch/x86_64/paging.c b/arch/x86_64/paging.c
deleted file mode 100644
index dc27ca2..0000000
--- a/arch/x86_64/paging.c
+++ /dev/null
@@ -1,257 +0,0 @@
-#include "paging.h"
-#include "interrupt.h"
-#include "io/log.h"
-#include "lib/jove.h"
-#include "lib/string.h"
-#include "lib/hashtable.h"
-#include "mem/memory.h"
-#include "boot/boot.h"
-
-extern void *_kernel_end;
-
-PAGEALIGN static uint64_t s_kernel_initial_pml4[512];
-PAGEALIGN static uint64_t s_kernel_initial_pml3[2][512];
-PAGEALIGN static uint64_t s_kernel_initial_pml2[2][512];
-PAGEALIGN static uint64_t s_kernel_initial_pml1[2][512];
-static intmax_t s_next_pdid = 0;
-static page_directory_t s_kernel_initial_pd;
-
-page_directory_t *current_page_directory;
-
-struct PageStateCache {
- page_directory_t *pd;
- size_t pmli[4];
- pmle_t *pml[4];
-} s_state_cache;
-
-physptr_t
-mem_linear_tophys_koffset(uintptr_t virt)
-{
- return (virt - boot_kernel_virtual_base) + boot_kernel_physical_address;
-}
-
-uintptr_t
-mem_phys_tolinear(physptr_t phys)
-{
- return (uintptr_t)(phys + 0xFFFF800000000000ULL);
-}
-
-static size_t
-s_paging_pmli(size_t l, uintptr_t addr)
-{
- size_t shift = (12 + (9 * l));
- return (addr & (0x1FFULL << shift)) >> shift;
-}
-
-static pmle_t*
-s_paging_fetch_table(pmle_t *pml, size_t l, uintptr_t virt)
-{
- size_t pmli = s_paging_pmli(l, virt);
- if(s_state_cache.pmli[l] == pmli && s_state_cache.pml[l] != NULL)
- return s_state_cache.pml[l];
-
- pmle_t entry = pml[pmli];
- bool entry_new = false;
- if(!entry.p) {
- entry_new = true;
- entry.value = mem_phys_alloc(1);
- entry.p = 1;
- entry.rw = 1;
- entry.us = 1;
- pml[pmli] = entry;
- }
- pmle_t *table = (pmle_t*)(mem_phys_tolinear(entry.paddr << 12));
- if(entry_new) memset(table, 0, PAGE_SIZE);
-
- s_state_cache.pmli[l] = pmli;
- s_state_cache.pml[l] = table;
- return table;
-}
-
-static void
-s_paging_cache_tables(page_directory_t *pd, uintptr_t virt)
-{
- pmle_t *pml4 = (pmle_t*)pd->virt;
- if(s_state_cache.pd != pd) memset(&s_state_cache, 0, sizeof(s_state_cache));
-
- pmle_t *pml3 = s_paging_fetch_table(pml4, 3, virt);
- pmle_t *pml2 = s_paging_fetch_table(pml3, 2, virt);
- pmle_t *pml1 = s_paging_fetch_table(pml2, 1, virt);
-}
-
-static pmle_t*
-s_paging_get_table(pmle_t *pt, size_t l, uintptr_t virt)
-{
- if(pt == NULL) return NULL;
- size_t pmli = s_paging_pmli(l, virt);
- if(s_state_cache.pmli[l] == pmli && s_state_cache.pml[l] != NULL)
- return s_state_cache.pml[l];
-
- pmle_t entry = pt[pmli];
- if(!entry.p) return NULL;
- return (pmle_t*)(mem_phys_tolinear(entry.paddr << 12));
-}
-
-page_mapping_t
-mem_get_mapping_as(page_directory_t *pd, uintptr_t addr)
-{
- spinlock_acquire(pd->lock);
- page_mapping_t mapping = { 0 };
-
- pmle_t *pml4 = (pmle_t*)pd->virt;
- if(s_state_cache.pd != pd) memset(&s_state_cache, 0, sizeof(s_state_cache));
-
- pmle_t *pml3 = s_paging_get_table(pml4, 3, addr);
- pmle_t *pml2 = s_paging_get_table(pml3, 2, addr);
- pmle_t *pml1 = s_paging_get_table(pml2, 1, addr);
- if(pml1 == NULL) goto release_return;
-
- size_t pml1i = s_paging_pmli(0, addr);
- pmle_t pml1e = pml1[pml1i];
-
- mapping = (page_mapping_t) {
- .phys = (pml1e.paddr << 12) & ~PAGE_MASK,
- .pf = {
- .present = pml1e.p,
- .writeable = pml1e.rw,
- .useraccess = pml1e.us,
- .executable = !pml1e.xd
- }
- };
-release_return:
- spinlock_release(pd->lock);
- return mapping;
-}
-
-page_mapping_t mem_get_mapping(uintptr_t addr)
-{ return mem_get_mapping_as(current_page_directory, addr); }
-
-
-bool
-mem_check_ptr(const void *ptr)
-{
- return mem_get_mapping((uintptr_t)ptr).pf.present != 0;
-}
-
-void
-mem_set_mapping_as(page_directory_t *pd, page_mapping_t mapping, uintptr_t virt)
-{
- spinlock_acquire(pd->lock);
- s_paging_cache_tables(pd, virt);
- pmle_t *pml1 = s_state_cache.pml[0];
- size_t pml1i = s_paging_pmli(0, virt);
-
- pml1[pml1i] = (pmle_t) {
- .p = mapping.pf.present,
- .rw = mapping.pf.writeable,
- .us = mapping.pf.useraccess,
- .xd = !mapping.pf.executable,
- .paddr = mapping.phys >> 12
- };
- spinlock_release(pd->lock);
-}
-
-void mem_set_mapping(page_mapping_t mapping, uintptr_t virt)
-{ mem_set_mapping_as(current_page_directory, mapping, virt); }
-
-void
-mem_ensure_range_as(page_directory_t *pd, uintptr_t from, uintptr_t to, page_flags_t flg)
-{
- spinlock_acquire(pd->lock);
- from &= ~(PAGE_SIZE - 1);
-
- if(to < from) to = from;
- size_t pages = (to - from) >> 12;
- if(pages == 0) pages = 1;
- for(size_t i = 0; i < pages; i++) {
- uintptr_t waddr = from + (i << 12);
- s_paging_cache_tables(pd, waddr);
- pmle_t *pml1 = s_state_cache.pml[1];
- size_t pml1i = s_paging_pmli(0, waddr);
-
- if(!pml1[pml1i].p) {
- physptr_t phys = mem_phys_alloc(1);
- pml1[pml1i] = (pmle_t) {
- .p = flg.present,
- .rw = flg.writeable,
- .us = flg.useraccess,
- .xd = !flg.executable,
- .paddr = phys >> 12
- };
- }
- }
- spinlock_release(pd->lock);
-}
-
-void mem_ensure_range(uintptr_t from, uintptr_t to, page_flags_t flg)
-{ mem_ensure_range_as(current_page_directory, from, to, flg); }
-
-struct Registers*
-s_pagefault_handler(struct Registers *state)
-{
- extern uint64_t __isr_err;
-
- uintptr_t fault_addr = 0;
- __asm__ volatile("movq %%cr2, %0": "=r"(fault_addr));
-
- bool present = __isr_err & 1;
- bool write = __isr_err & 2;
- bool user = __isr_err & 4;
- bool fetch = __isr_err & 16;
-
- klogf("Page fault at %016X\n", fault_addr);
- klogf("%s %s from a %s address\n",
- user ? "user" : "kernel",
- write ? "wrote" : "read",
- present ? "present" : "non-present");
-
- kpanic("Unhandled page fault at %016X\n", state->ip);
- return state;
-}
-
-void
-mem_paging_setup(void)
-{
- memset(s_kernel_initial_pml4, 0, PAGE_SIZE);
- memset(s_kernel_initial_pml3, 0, 2 * PAGE_SIZE);
- memset(s_kernel_initial_pml2, 0, 2 * PAGE_SIZE);
- memset(s_kernel_initial_pml1, 0, PAGE_SIZE);
- s_kernel_initial_pd = (page_directory_t){
- .phys = mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml4),
- .virt = (union PageEntry*)&s_kernel_initial_pml4,
- .ref = 1,
- .id = s_next_pdid++
- };
- current_page_directory = &s_kernel_initial_pd;
-
- /* Map first few GiBs */
- s_kernel_initial_pml4[256] =
- mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml3[0])
- | 3;
- s_kernel_initial_pml3[0][0] =
- mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml2[0])
- | 3;
- for(int i = 0; i < 512; i++) {
- s_kernel_initial_pml2[0][i] = (i * (PAGE_SIZE * 512)) | 0x80 | 3;
- }
-
- size_t kernel_pml4e = (boot_kernel_virtual_base >> (39));
- size_t kernel_pml3e = (boot_kernel_virtual_base >> (30)) % 512;
- size_t kernel_pml2e = (boot_kernel_virtual_base >> (21)) % 512;
- size_t kernel_npages = ((((uintptr_t)&_kernel_end) - boot_kernel_virtual_base) >> 12) + 1;
- klogf("Kernel has %i pages\n", kernel_npages);
-
- /* Map kernel pages */
- s_kernel_initial_pml4[511] =
- mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml3[1]) | 3;
- s_kernel_initial_pml3[1][kernel_pml3e] =
- mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml2[1]) | 3;
- s_kernel_initial_pml2[1][kernel_pml2e] =
- mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml1[0]) | 3;
- for(int i = 0; i < kernel_npages; i++) {
- s_kernel_initial_pml1[0][i] = (i * PAGE_SIZE) + boot_kernel_physical_address | 3;
- }
-
- int_set_handler(14, s_pagefault_handler);
- __asm__ volatile("mov %0, %%cr3":: "r"(s_kernel_initial_pd.phys));
-}
diff --git a/arch/x86_64/processor.c b/arch/x86_64/processor.c
new file mode 100644
index 0000000..44d437a
--- /dev/null
+++ b/arch/x86_64/processor.c
@@ -0,0 +1,40 @@
+#include "arch/processor.h"
+#include "arch/cpu.h"
+#include "arch/x86_64/msr.h"
+
+processor_t s_processors[PROCESSOR_MAX];
+processor_t *proc_bsp = &s_processors[0];
+
+extern void x86_64_lgdt(struct XDTR *gdtr);
+extern void x86_64_flush_tss(void);
+extern void x86_64_lidt(struct XDTR *idtr);
+
+extern void gdt_setup(processor_t*);
+extern void tss_setup(processor_t*);
+extern void idt_setup(processor_t*);
+
+void
+processor_setup(processor_t *proc)
+{
+ gdt_setup(proc);
+ tss_setup(proc);
+ idt_setup(proc);
+
+ x86_64_lgdt(&proc->_gdtr);
+ x86_64_lidt(&proc->_idtr);
+ x86_64_flush_tss();
+
+ msr_gsbase_write((uintptr_t)proc);
+}
+
+processor_t*
+processor_list(void)
+{
+ return s_processors;
+}
+
+processor_t*
+processor_current(void)
+{
+ return (processor_t*)msr_gsbase_read();
+}
diff --git a/arch/x86_64/restore.S b/arch/x86_64/restore.S
new file mode 100644
index 0000000..f4aa939
--- /dev/null
+++ b/arch/x86_64/restore.S
@@ -0,0 +1,20 @@
+.global _arch_context_restore
+.type _arch_context_restore @function
+_arch_context_restore:
+ movq %rdi, %rsp
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+ popq %rbp
+ popq %rdi
+ popq %rsi
+ popq %rdx
+ popq %rcx
+ popq %rbx
+ popq %rax
+ retq
diff --git a/arch/x86_64/savestate.S b/arch/x86_64/savestate.S
deleted file mode 100644
index c89933b..0000000
--- a/arch/x86_64/savestate.S
+++ /dev/null
@@ -1,39 +0,0 @@
-.global saveregs
-.type saveregs @function
-saveregs:
- pushq %rax
- pushq %rbx
- pushq %rcx
- pushq %rdx
- pushq %rsi
- pushq %rdi
- pushq %rbp
- pushq %r8
- pushq %r9
- pushq %r10
- pushq %r11
- pushq %r12
- pushq %r13
- pushq %r14
- pushq %r15
- retq
-
-.global loadregs
-.type loadregs @function
-loadregs:
- popq %r15
- popq %r14
- popq %r13
- popq %r12
- popq %r11
- popq %r10
- popq %r9
- popq %r8
- popq %rbp
- popq %rdi
- popq %rsi
- popq %rdx
- popq %rcx
- popq %rbx
- popq %rax
-
diff --git a/arch/x86_64/serial.c b/arch/x86_64/serial.c
deleted file mode 100644
index 1b49e3f..0000000
--- a/arch/x86_64/serial.c
+++ /dev/null
@@ -1,62 +0,0 @@
-#include "serial.h"
-#include "uart.h"
-#include "io/log.h"
-
-static struct LogDevice s_serial_logdev =
- { .out = serial_out, .chain = NULL };
-
-bool serial_supported = true;
-
-void
-serial_setup(void)
-{
- /* Disable interrupts. */
- poutb(SERIAL_UART_COM_IER(SERIAL_UART_COM1), 0x0);
- /* Enable DLAB. */
- poutb(SERIAL_UART_COM_LCR(SERIAL_UART_COM1), 0x80);
- /* Set divisor to 3 (38400 baud)*/
- poutb(SERIAL_UART_COM_DLAB_DLL(SERIAL_UART_COM1), 3);
- poutb(SERIAL_UART_COM_DLAB_DLH(SERIAL_UART_COM1), 0);
- /* Set flags for LCR (8 bits, no parity, one stop)*/
- poutb(SERIAL_UART_COM_LCR(SERIAL_UART_COM1), 1 | 2);
- /* Enable & clear FIFO, 14-byte threshold */
- poutb(SERIAL_UART_COM_FCR(SERIAL_UART_COM1), 1 | 2 | 4 | 0xC0);
- /* Enable interrupts, set RTS/DSR. */
- poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 1 | 2 | 8);
- /* Set loopback mode for testing. */
- poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 2 | 4 | 8 | 0x10);
- /* Test serial output. */
- poutb(SERIAL_UART_COM1, 0xAE);
- if(pinb(SERIAL_UART_COM1) != 0xAE) {
- serial_supported = false;
- return;
- }
-
- /* Serial is not faulty.
- * No loopback, enable output 1 & 2.*/
- poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 1 | 2 | 4 | 8);
-
- klog_newdev(&s_serial_logdev);
-}
-
-static ALWAYS_INLINE bool
-serial_transmit_empty(uint16_t com)
-{
- return pinb(SERIAL_UART_COM_LSR(com) & 0x20);
-}
-
-static inline void
-serial_outb(uint16_t com, uint8_t b)
-{
- if(b == '\n') serial_outb(com, '\r');
- while(!serial_transmit_empty(SERIAL_UART_COM1));
- poutb(com, b);
-}
-
-void
-serial_out(const char *s, size_t len)
-{
- if(!serial_supported) return;
- for(; len > 0; len--)
- serial_outb(SERIAL_UART_COM1, *(s++));
-}
diff --git a/arch/x86_64/serial.h b/arch/x86_64/serial.h
deleted file mode 100644
index ecb896d..0000000
--- a/arch/x86_64/serial.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef JOVE_KERNEL_ARCH_x86_64_SERIAL_H
-#define JOVE_KERNEL_ARCH_x86_64_SERIAL_H 1
-
-#include <stdbool.h>
-#include <stddef.h>
-
-#define SERIAL_UART_COM1 0x3F8
-#define SERIAL_UART_COM2 0x2F8
-
-#define SERIAL_UART_COM_THR(COM) COM
-#define SERIAL_UART_COM_RBR(COM) COM
-#define SERIAL_UART_COM_DLAB_DLL(COM) COM
-#define SERIAL_UART_COM_IER(COM) (COM + 1)
-#define SERIAL_UART_COM_DLAB_DLH(COM) (COM + 1)
-#define SERIAL_UART_COM_IIR(COM) (COM + 2)
-#define SERIAL_UART_COM_FCR(COM) (COM + 2)
-#define SERIAL_UART_COM_LCR(COM) (COM + 3)
-#define SERIAL_UART_COM_MCR(COM) (COM + 4)
-#define SERIAL_UART_COM_LSR(COM) (COM + 5)
-#define SERIAL_UART_COM_MSR(COM) (COM + 6)
-#define SERIAL_UART_COM_SR(COM) (COM + 7)
-
-extern bool serial_supported;
-
-void serial_out(const char *s, size_t len);
-
-#endif
diff --git a/arch/x86_64/syscall.c b/arch/x86_64/syscall.c
deleted file mode 100644
index 0398f11..0000000
--- a/arch/x86_64/syscall.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "usr/umode.h"
diff --git a/arch/x86_64/syscall_entry.c b/arch/x86_64/syscall_entry.c
new file mode 100644
index 0000000..56dedce
--- /dev/null
+++ b/arch/x86_64/syscall_entry.c
@@ -0,0 +1,25 @@
+#include "arch/processor.h"
+#include "syscall/handler.h"
+
+__attribute__((naked))
+void _syscall_entry()
+{
+ __asm__ volatile(" \
+ pushq %%r11; \
+ pushq %%rcx; \
+ swapgs; \
+ movq %%gs:%c[tcb], %%rax; \
+ movq %%rsp, %c[sp](%%rax); \
+ movq %c[ksp](%%rax), %%rsp; \
+ pushq %c[sp](%%rax); \
+ callq _syscall_handler; \
+ swapgs; \
+ popq %%rsp; \
+ popq %%rcx; \
+ popq %%r11; \
+ sysretq; \
+ "
+ :: [tcb] "i"(offsetof(processor_t, tcb)),
+ [sp] "i"(offsetof(tcb_t, sp)),
+ [ksp] "i"(offsetof(tcb_t, ksp)));
+}
diff --git a/arch/x86_64/syscall_setup.S b/arch/x86_64/syscall_setup.S
deleted file mode 100644
index 4f5c6f0..0000000
--- a/arch/x86_64/syscall_setup.S
+++ /dev/null
@@ -1,41 +0,0 @@
-.extern _kernel_task_sp
-.extern syscall_handler
-
-.global syscall_entry
-.type syscall_entry @function
-syscall_entry:
- swapgs
- movq %rsp, %rax
- movq _kernel_task_bp, %rsp
- pushq %rax
- pushq %rbp
- pushq %rcx
- pushq %r11
- call syscall_handler
- popq %r11
- popq %rcx
- popq %rbp
- popq %rsp
- swapgs
- sysretq
-
-.global syscall_setup_syscall
-.type syscall_setup_syscall @function
-syscall_setup_syscall:
- movq $0xc0000080, %rcx
- rdmsr
- or $1, %eax
- wrmsr
-
- movq $0xc0000081, %rcx
- rdmsr
- mov $0x001b0008, %edx
- wrmsr
-
- movq $0xc0000082, %rcx
- leaq syscall_entry, %rdx
- mov %edx, %eax
- shr $32, %rdx
- wrmsr
-
- retq
diff --git a/arch/x86_64/tables.c b/arch/x86_64/tables.c
deleted file mode 100644
index f530089..0000000
--- a/arch/x86_64/tables.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "tables.h"
-
-void
-arch_tables_setup(void)
-{
- x86_64_load_gdt();
- x86_64_load_idt();
-}
diff --git a/arch/x86_64/tasking.c b/arch/x86_64/tasking.c
deleted file mode 100644
index 9b29330..0000000
--- a/arch/x86_64/tasking.c
+++ /dev/null
@@ -1,86 +0,0 @@
-#include "usr/tasking.h"
-#include "mem/memory.h"
-#include "io/log.h"
-#include "lib/hashtable.h"
-#include "lib/string.h"
-#include "paging.h"
-#include "cpu.h"
-#include "tss.h"
-
-struct TaskBody {
- struct Task base;
- struct Registers state;
-};
-
-struct Task *task_current;
-uintptr_t _kernel_task_bp = 0;
-
-//static struct SLinkedList s_tasks;
-static struct HashTable s_tasks;
-
-static struct SlabCache s_task_cache;
-static struct SlabCache s_kbp_cache;
-
-static tid_t s_task_id_next = 1;
-
-static size_t
-s_task_hash_func(const void* tid, size_t _)
-{
- return (tid_t)tid;
-}
-
-void
-tasking_setup(void)
-{
- hashtable_new(&s_tasks, struct TaskBody*, tid_t);
- s_tasks.hash_function = s_task_hash_func;
-
- mem_slabcache_new(&s_task_cache, "tasks", sizeof(struct TaskBody));
- mem_slabcache_new(&s_kbp_cache, "kernel stacks", 4096);
-
- struct TaskBody *ktask = mem_slab_alloc(&s_task_cache);
- *ktask = (struct TaskBody){
- .base.id = s_task_id_next++,
- .base.kbp = ((uintptr_t)mem_slab_alloc(&s_kbp_cache)) + 0xFF0,
- .base.perm = (size_t)-1,
- .base.pd = current_page_directory
- };
- hashtable_insert(&s_tasks, 0, ktask);
-
- task_current = (struct Task*)ktask;
- tss_set_rsp(0, task_current->kbp);
- _kernel_task_bp = task_current->kbp;
-}
-
-struct Task*
-task_new(struct Task *parent)
-{
- struct TaskBody *new = mem_slab_alloc(&s_task_cache);
- memcpy(new, parent, sizeof(struct TaskBody));
- new->base.id = s_task_id_next++;
-
- uintptr_t ksp_base = (uintptr_t)mem_slab_alloc(&s_kbp_cache);
- new->base.kbp = ksp_base + 0xFFF;
- new->base.perm = parent->perm;
-
- hashtable_insert(&s_tasks, (void*)new->base.id, new);
- return (struct Task*)new;
-}
-
-struct Task*
-task_get(tid_t id)
-{
- struct Task **task = hashtable_get(&s_tasks, (void*)id, struct Task*);
- if(task == NULL) return NULL;
- return *task;
-}
-
-void
-task_free(struct Task *task)
-{
- struct TaskBody *body = (struct TaskBody*)task;
- task->pd->ref--;
- task->kbp -= 0xFFF;
- mem_slab_free(&s_kbp_cache, (void*)(task->kbp));
- klogf("Need impl for task_free\n");
-}
diff --git a/arch/x86_64/tcb_prepare.c b/arch/x86_64/tcb_prepare.c
new file mode 100644
index 0000000..238d70d
--- /dev/null
+++ b/arch/x86_64/tcb_prepare.c
@@ -0,0 +1,9 @@
+#include "tasking.h"
+
+void
+tcb_prepare(tcb_t *tcb, void *ip)
+{
+ uintptr_t state[15] = { 0 };
+ tcb_stack_push(tcb, &ip, sizeof(void*));
+ tcb_stack_push(tcb, state, sizeof(state));
+}
diff --git a/arch/x86_64/tcb_switch.c b/arch/x86_64/tcb_switch.c
new file mode 100644
index 0000000..bc8808d
--- /dev/null
+++ b/arch/x86_64/tcb_switch.c
@@ -0,0 +1,18 @@
+#include "tasking.h"
+#include "arch/processor.h"
+
+extern void _arch_context_restore(uintptr_t rsp);
+
+void
+tcb_switch(tcb_t *to)
+{
+ processor_t *proc = processor_current();
+ tcb_t *from = proc->tcb;
+
+ proc->tcb = to;
+ if(from != to) {
+ pd_switch(to->pd);
+ }
+ tss_set_rsp(&proc->_tss, 0, to->ksp);
+ _arch_context_restore(to->ksp);
+}
diff --git a/arch/x86_64/umode_enter.S b/arch/x86_64/umode_enter.S
deleted file mode 100644
index 29aa4e3..0000000
--- a/arch/x86_64/umode_enter.S
+++ /dev/null
@@ -1,8 +0,0 @@
-.global umode_enter
-.type umode_enter @function
-umode_enter:
- movq %rdi, %rcx
- movq %rsi, %rsp
- movq $0x0202, %r11
- cli
- sysretq
diff --git a/arch/x86_64/umode_enter.c b/arch/x86_64/umode_enter.c
new file mode 100644
index 0000000..3c7fa18
--- /dev/null
+++ b/arch/x86_64/umode_enter.c
@@ -0,0 +1,17 @@
+#include "tasking.h"
+
+__attribute__((noreturn))
+void
+umode_enter(void *ip, void *sp)
+{
+ __asm__ volatile("mov %0, %%rsp; \
+ push %%rcx; \
+ mov %1, %%rcx; \
+ mov $0x202, %%r11; \
+ cli; \
+ swapgs; \
+ sysretq"::
+ "r"(sp), "r"(ip):
+ "memory");
+ for(;;);
+}
diff --git a/arch/x86_64/vm_tophys.c b/arch/x86_64/vm_tophys.c
new file mode 100644
index 0000000..2b16880
--- /dev/null
+++ b/arch/x86_64/vm_tophys.c
@@ -0,0 +1,23 @@
+#include "memory.h"
+#include "boot.h"
+
+uintptr_t
+pm_tovirt(physptr_t phys)
+{
+ if(phys < (1 * GiB))
+ return (uintptr_t)(phys + PHYSMAP_MEMORY_BASE);
+ kpanic("Missing impl for physical addresses > 1GiB (%#016X)\n",
+ phys);
+}
+
+physptr_t
+vm_tophys(uintptr_t virt)
+{
+ return vm_mapping_get(virt).phys;
+}
+
+physptr_t
+vm_tophys_koff(uintptr_t virt)
+{
+ return (virt - _kernel_virtual_base) + boot_kernel_physical_address;
+}
diff --git a/boot/cmdline.c b/boot/cmdline.c
index aa6aa05..5a68466 100644
--- a/boot/cmdline.c
+++ b/boot/cmdline.c
@@ -1,15 +1,18 @@
-#include "cmdline.h"
+#include "commandline.h"
+#include "klib/hash.h"
+#include "klib/rbtree.h"
+#include "string.h"
#include "boot.h"
-#include "mem/memory.h"
-#include "lib/string.h"
-#include "io/log.h"
+#include "memory.h"
+#include "print.h"
-static struct HashTable s_cmdline_kernel;
+static rbtree_t s_cmdline_kernel;
const char*
cmdline_get(const char *key)
{
- const char** value = hashtable_get(&s_cmdline_kernel, key, const char*);
+ intmax_t hash = string_hash(key);
+ char** value = rbtree_find(&s_cmdline_kernel, hash);
if(value == NULL) return NULL;
return *value;
}
@@ -17,7 +20,7 @@ cmdline_get(const char *key)
void
cmdline_kernel_setup(void)
{
- hashtable_news(&s_cmdline_kernel, const char*);
+ rbtree_new(&s_cmdline_kernel, char*);
size_t cmdi = 0;
const char *cmdline = boot_kernel_cmdline;
@@ -28,23 +31,23 @@ cmdline_kernel_setup(void)
size_t keyi = cmdi;
while(cmdline[keyi] != '=' && cmdline[keyi] != 0) keyi++;
if(cmdline[keyi] == 0 || keyi == 0) {
- klogf("kernel cmdline is empty or malformed; skipping.\n");
+ kwarnf("kernel cmdline is empty or malformed; skipping.\n");
break;
}
size_t keylen = keyi - cmdi;
- char *key = mem_alloc(keylen);
+ char *key = kmalloc(keylen);
memcpy(key, &cmdline[cmdi], keylen);
size_t valuei = keyi + 1;
while(cmdline[valuei] != ' ' && cmdline[valuei] != 0) valuei++;
size_t valuelen = (valuei - keyi) - 1;
- char *value = mem_alloc(valuelen);
+ char *value = kmalloc(valuelen);
if(valuelen != 0) memcpy(value, &cmdline[keyi + 1], valuelen);
- klogf("%s = %s\n", key, value);
- hashtable_insert(&s_cmdline_kernel, key, &value);
+ kdbgf("%s = %s\n", key, value);
+ rbtree_insert(&s_cmdline_kernel, string_hash(key), &value);
cmdi = valuei + 1;
}
}
diff --git a/boot/cmdline.h b/boot/cmdline.h
deleted file mode 100644
index b1162b7..0000000
--- a/boot/cmdline.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef JOVE_BOOT_CMDLINE_H
-#define JOVE_BOOT_CMDLINE_H 1
-
-#include "lib/hashtable.h"
-
-const char *cmdline_get(const char *key);
-
-void cmdline_kernel_setup(void);
-
-#endif
diff --git a/boot/limine/limine.c b/boot/limine/limine.c
index 7cc50d0..14f85f5 100644
--- a/boot/limine/limine.c
+++ b/boot/limine/limine.c
@@ -1,5 +1,5 @@
#include "limine.h"
-#include "boot/boot.h"
+#include "boot.h"
static char s_kernel_stack[KERNEL_INITIAL_STACK_WIDTH];
diff --git a/compile_flags.txt b/compile_flags.txt
deleted file mode 100644
index 8a9f09e..0000000
--- a/compile_flags.txt
+++ /dev/null
@@ -1,4 +0,0 @@
--I.
--ffreestanding
--nostdlib
--lgcc
diff --git a/config.mk b/config.mk
index 11ce9f4..e2a9836 100644
--- a/config.mk
+++ b/config.mk
@@ -10,7 +10,8 @@ CFLAGS = \
-fno-pie \
-fno-pic \
-g \
- -D$(TARGET_MACHINE) \
+ -D__$(TARGET_MACHINE)__ \
+ -Iinclude \
-I.
LDFLAGS = -nostdlib \
@@ -20,5 +21,5 @@ LDFLAGS = -nostdlib \
ifeq "$(TARGET_MACHINE)" "x86_64"
CFLAGS += -mno-red-zone \
-mcmodel=kernel \
- -MMD
+ -mfsgsbase
endif
diff --git a/device/processor.c b/device/processor.c
new file mode 100644
index 0000000..5c4b500
--- /dev/null
+++ b/device/processor.c
@@ -0,0 +1,4 @@
+#include "arch/processor.h"
+
+page_directory_t *pd_current(void) { return processor_current()->pd; }
+tcb_t *tcb_current(void) { return processor_current()->tcb; }
diff --git a/device/serial.c b/device/serial.c
new file mode 100644
index 0000000..5000e0e
--- /dev/null
+++ b/device/serial.c
@@ -0,0 +1,77 @@
+#include "device/serial.h"
+#include "device/uart.h"
+#include "jove.h"
+
+serial_dev_t COM1;
+
+serial_dev_t
+serial_new(uint16_t com)
+{
+ serial_dev_t dev = { .com = com };
+ serial_set_int(&dev, false);
+ serial_set_baud(&dev, 3);
+ serial_set_lcr(&dev, 1 | 2);
+ serial_set_fcr(&dev, 1 | 2 | 4 | 0xC0);
+ serial_set_fcr(&dev, 1 | 2 | 8);
+ serial_set_mcr(&dev, 1 | 2 | 4 | 8);
+ return dev;
+}
+
+void
+serial_set_int(serial_dev_t *dev, bool enable)
+{
+ poutb(SERIAL_UART_COM_IER(dev->com), enable);
+}
+
+void
+serial_set_baud(serial_dev_t *dev, uint16_t baud)
+{
+ /* Enable DLAB. */
+ poutb(SERIAL_UART_COM_LCR(dev->com), SERIAL_UART_COM_LCR(dev->com) | 0x80);
+ /* Write low & high bits. */
+ poutb(SERIAL_UART_COM_DLAB_DLL(dev->com), baud & 0xFF);
+ poutb(SERIAL_UART_COM_DLAB_DLH(dev->com), (baud >> 8) & 0xFF);
+ /* Disable DLAB. */
+ poutb(SERIAL_UART_COM_LCR(dev->com), SERIAL_UART_COM_LCR(dev->com) & 0x7F);
+}
+
+void
+serial_set_fcr(serial_dev_t *dev, uint16_t flg)
+{
+ poutb(SERIAL_UART_COM_FCR(dev->com), flg);
+}
+
+void
+serial_set_lcr(serial_dev_t *dev, uint16_t flg)
+{
+ poutb(SERIAL_UART_COM_LCR(dev->com), flg);
+}
+
+void
+serial_set_mcr(serial_dev_t *dev, uint16_t flg)
+{
+ poutb(SERIAL_UART_COM_MCR(dev->com), flg);
+}
+
+uint8_t
+serial_line_status(serial_dev_t *dev)
+{
+ return pinb(SERIAL_UART_COM_LSR(dev->com));
+}
+
+void
+serial_write(serial_dev_t *dev, const char *s, size_t len)
+{
+ for(; len > 0; len--) {
+ char c = *(s++);
+ while((serial_line_status(dev) & 0x20) == 0) {}
+ if(c == '\n') poutb(dev->com, '\r');
+ poutb(dev->com, c);
+ }
+}
+
+void
+serial_setup(void)
+{
+ COM1 = serial_new(SERIAL_UART_COM1);
+}
diff --git a/include/api/errno.h b/include/api/errno.h
new file mode 100644
index 0000000..51921d2
--- /dev/null
+++ b/include/api/errno.h
@@ -0,0 +1,9 @@
+#ifndef _JOVE_ERRNO_H
+#define _JOVE_ERRNO_H 1
+
+enum {
+ EFAIL = 1,
+ EACCESS
+};
+
+#endif
diff --git a/include/api/syscall.h b/include/api/syscall.h
new file mode 100644
index 0000000..eb4235d
--- /dev/null
+++ b/include/api/syscall.h
@@ -0,0 +1,39 @@
+#ifndef _JOVE_API_SYSCALL_H
+#define _JOVE_API_SYSCALL_H 1
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef intmax_t syscall_id_t;
+
+static int __syscall(void *data)
+{
+ intmax_t r;
+ __asm__ volatile(" \
+ movq %1, %%rdi; \
+ syscall; \
+ movq %%rax, %0"
+ : "=r"(r)
+ : "r"(data));
+ return r;
+}
+
+enum {
+ SC_DBG_LOGF = 0,
+ SC_EXIT
+};
+
+struct sc_dbg_log
+{
+ syscall_id_t id;
+ size_t w;
+ const char *s;
+};
+
+struct sc_exit
+{
+ syscall_id_t id;
+ int exit_code;
+};
+
+#endif
diff --git a/include/arch/cpu.h b/include/arch/cpu.h
new file mode 100644
index 0000000..fe89dc0
--- /dev/null
+++ b/include/arch/cpu.h
@@ -0,0 +1,14 @@
+#ifndef _JOVE_ARCH_CPU_H
+#define _JOVE_ARCH_CPU_H 1
+
+#ifdef __x86_64__
+#include "x86_64/cpu.h"
+#endif
+
+void cpu_setup(void);
+
+void cpu_set_syscall_entry(void *entry);
+
+void umode_enter(void *ip, void *sp);
+
+#endif
diff --git a/include/arch/elf.h b/include/arch/elf.h
new file mode 100644
index 0000000..1b8c3dc
--- /dev/null
+++ b/include/arch/elf.h
@@ -0,0 +1,12 @@
+#ifndef _JOVE_ARCH_ELF_H
+#define _JOVE_ARCH_ELF_H 1
+
+#ifdef __x86_64__
+#include "x86_64/elf.h"
+#endif
+
+#include <stddef.h>
+
+uintptr_t elf_load(const void *data, size_t len);
+
+#endif
diff --git a/include/arch/page.h b/include/arch/page.h
new file mode 100644
index 0000000..25c5294
--- /dev/null
+++ b/include/arch/page.h
@@ -0,0 +1,34 @@
+#ifndef _JOVE_ARCH_PAGE_H
+#define _JOVE_ARCH_PAGE_H 1
+
+#define PAGE_SHIFT (12)
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define PAGE_MASK (PAGE_SIZE - 1)
+
+#ifdef __x86_64__
+#include "x86_64/page.h"
+#endif
+
+typedef struct page_mapping_flags
+{
+ char present : 1;
+ char writeable : 1;
+ char useraccess : 1;
+ char executable : 1;
+} page_flags_t;
+
+typedef struct page_mapping
+{
+ uintptr_t phys;
+ page_flags_t pf;
+} page_mapping_t;
+
+typedef intmax_t pdid_t;
+
+page_directory_t *pd_new(void);
+page_directory_t *pd_dup(page_directory_t *pd);
+page_directory_t *pd_get(pdid_t id);
+
+void pd_switch(page_directory_t *pd);
+
+#endif
diff --git a/include/arch/processor.h b/include/arch/processor.h
new file mode 100644
index 0000000..871e5c7
--- /dev/null
+++ b/include/arch/processor.h
@@ -0,0 +1,39 @@
+#ifndef _JOVE_ARCH_PROCESSOR_H
+#define _JOVE_ARCH_PROCESSOR_H 1
+
+#ifdef __x86_64__
+#include "x86_64/processor.h"
+#endif
+
+#include "memory.h"
+#include "tasking.h"
+#include "klib/spinlock.h"
+
+#define _EXRTAB_C (PAGE_SIZE / sizeof(uintptr_t))
+
+typedef struct processor
+{
+ ARCH_SPECIFIC_PROCESSOR_MEMBERS;
+ unsigned int id;
+ unsigned int isr_depth;
+ page_directory_t *pd;
+ tcb_t *tcb;
+
+ uintptr_t exrtab[_EXRTAB_C];
+ size_t ert_i;
+} processor_t;
+
+extern processor_t *proc_bsp;
+
+void processor_setup(processor_t *proc);
+
+processor_t *processor_list(void);
+
+processor_t *processor_current(void);
+page_directory_t *pd_current(void);
+tcb_t *tcb_current(void);
+
+void _exrtab_push(void *v);
+void *_exrtab_pop(void);
+
+#endif
diff --git a/include/arch/x86_64/cpu.h b/include/arch/x86_64/cpu.h
new file mode 100644
index 0000000..6e467c1
--- /dev/null
+++ b/include/arch/x86_64/cpu.h
@@ -0,0 +1,6 @@
+#ifndef _JOVE_x86_64_CPU_H
+#define _JOVE_x86_64_CPU_H 1
+
+void cpu_arch_enable_sce(void);
+
+#endif
diff --git a/include/arch/x86_64/elf.h b/include/arch/x86_64/elf.h
new file mode 100644
index 0000000..1aaf116
--- /dev/null
+++ b/include/arch/x86_64/elf.h
@@ -0,0 +1,93 @@
+#ifndef _JOVE_x86_64_ELF_H
+#define _JOVE_x86_64_ELF_H 1
+
+#include <stdint.h>
+
+#define EI_MAG0 0x7F
+#define EI_MAG1 'E'
+#define EI_MAG2 'L'
+#define EI_MAG3 'F'
+
+#define EI_CLASS_32 1
+#define EI_CLASS_64 2
+
+#define EI_DATA_LE 1
+#define EI_DATA_BE 2
+
+#define EI_VERSION_CURRENT 1
+
+#define ET_NONE 0
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+
+typedef struct elf64_file_header
+{
+ union {
+ struct {
+ uint8_t ei_mag[4];
+ uint8_t ei_class;
+ uint8_t ei_data;
+ uint8_t ei_version;
+ uint8_t ei_osabi;
+ uint8_t ei_abiver;
+ uint8_t ei_pad[7];
+ };
+ uint8_t e_ident[16];
+ };
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint64_t e_entry;
+ uint64_t e_phoff;
+ uint64_t e_shoff;
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+} elf_header_t;
+
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_TLS 7
+
+#define PF_X 1
+#define PF_W 2
+#define PF_R 4
+
+typedef struct elf64_program_header
+{
+ uint32_t p_type;
+ uint32_t p_flags;
+ uint64_t p_offset;
+ uint64_t p_vaddr;
+ uint64_t p_paddr;
+ uint64_t p_filesz;
+ uint64_t p_memsz;
+ uint64_t p_align;
+} elf_phdr_t;
+
+#define SHT_NULL 0
+#define SHT_PROGBITS 1
+
+typedef struct elf64_section_header
+{
+ uint32_t sh_name;
+ uint32_t sh_type;
+ uint64_t sh_flags;
+ uint64_t sh_addr;
+ uint64_t sh_offset;
+ uint64_t sh_size;
+ uint64_t sh_addralign;
+ uint64_t sh_entsize;
+} elf_shdr_t;
+
+#endif
diff --git a/include/arch/x86_64/gdt.h b/include/arch/x86_64/gdt.h
new file mode 100644
index 0000000..c17c9eb
--- /dev/null
+++ b/include/arch/x86_64/gdt.h
@@ -0,0 +1,23 @@
+#ifndef _JOVE_x86_64_GDT_H
+#define _JOVE_x86_64_GDT_H 1
+
+#include "tables.h"
+
+enum
+{
+ GDT_SEGMENT_KERNEL_NULL = 0,
+ GDT_SEGMENT_KERNEL_CODE,
+ GDT_SEGMENT_KERNEL_DATA,
+
+ GDT_SEGMENT_USER_NULL,
+ GDT_SEGMENT_USER_DATA,
+ GDT_SEGMENT_USER_CODE,
+
+ GDT_SEGMENT_TSS_LOW,
+ GDT_SEGMENT_TSS_HIGH,
+
+ GDT_SEGMENT_COUNT
+};
+typedef segment_descriptor_t gdt_t[GDT_SEGMENT_COUNT];
+
+#endif
diff --git a/include/arch/x86_64/idt.h b/include/arch/x86_64/idt.h
new file mode 100644
index 0000000..7a5c468
--- /dev/null
+++ b/include/arch/x86_64/idt.h
@@ -0,0 +1,25 @@
+#ifndef _JOVE_x86_64_IDT_H
+#define _JOVE_x86_64_IDT_H 1
+
+#include "tables.h"
+
+typedef struct interrupt_state
+{
+ uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
+ uint64_t bp, di, si, dx, cx, bx, ax;
+ uint64_t ip, cs, flags, sp, ss;
+} int_state_t;
+
+typedef interrupt_gate_t idt_t[48];
+
+typedef int_state_t *(*int_handler_t)(int_state_t *);
+
+void int_handler_set(uint8_t i, int_handler_t handler);
+int_handler_t int_handler_get(uint8_t i);
+
+void int_state_print(int_state_t *state);
+
+extern uint64_t __isr_err;
+extern uint64_t __isr_num;
+
+#endif
diff --git a/include/arch/x86_64/msr.h b/include/arch/x86_64/msr.h
new file mode 100644
index 0000000..c20f8fc
--- /dev/null
+++ b/include/arch/x86_64/msr.h
@@ -0,0 +1,56 @@
+#ifndef _JOVE_x86_64_MSR_H
+#define _JOVE_x86_64_MSR_H 1
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define MSR_EFER 0xC0000080
+#define MSR_STAR 0xC0000081
+#define MSR_LSTAR 0xC0000082
+#define MSR_SFMASK 0xC0000084
+
+#define MSR_FSBASE 0xC0000100
+#define MSR_GSBASE 0xC0000101
+#define MSR_KERNELGSBASE 0xC0000102
+
+typedef union msr_efer
+{
+ struct {
+ uint8_t sce : 1;
+ uint8_t resv : 7;
+ uint8_t lme : 1;
+ uint8_t unk0 : 1;
+ uint8_t lma : 1;
+ uint8_t nxe : 1;
+ uint8_t svme : 1;
+ uint8_t lmsle : 1;
+ uint8_t ffxsr : 1;
+ uint8_t tce : 1;
+ };
+ uint32_t v[2];
+} msr_efer_t;
+
+typedef union msr_star
+{
+ struct {
+ uint32_t eip;
+ uint16_t kcs;
+ uint16_t ucs;
+ };
+ uint32_t v[2];
+} msr_star_t;
+typedef uintptr_t msr_lstar_t;
+
+void msr_efer_write(msr_efer_t v);
+msr_efer_t msr_efer_read(void);
+
+void msr_star_write(msr_star_t v);
+msr_star_t msr_star_read(void);
+
+void msr_lstar_write(msr_lstar_t v);
+msr_lstar_t msr_lstar_read(void);
+
+void msr_gsbase_write(uintptr_t gsbase);
+uintptr_t msr_gsbase_read(void);
+
+#endif
diff --git a/include/arch/x86_64/page.h b/include/arch/x86_64/page.h
new file mode 100644
index 0000000..cbbf642
--- /dev/null
+++ b/include/arch/x86_64/page.h
@@ -0,0 +1,40 @@
+#ifndef _JOVE_x86_64_PAGE_H
+#define _JOVE_x86_64_PAGE_H 1
+
+#include <stdint.h>
+#include "klib/spinlock.h"
+#include "assert.h"
+
+typedef union page_mapping_level_entry
+{
+ struct {
+ uint8_t p : 1; /* Present */
+ uint8_t rw : 1; /* Read/write. 0 for RO.*/
+ uint8_t us : 1; /* User/supervisor. 0 for DPL3 forbid */
+ uint8_t pwt : 1;
+ uint8_t pcd : 1;
+ uint8_t a : 1; /* Accessed */
+ uint8_t d : 1; /* Dirty */
+ uint8_t ps_pat : 1;
+ uint8_t g : 1; /* Global */
+ uint8_t _r0 : 2;
+ uint8_t r : 1;
+ uint64_t paddr : 35;
+ uint8_t _r1;
+ uint8_t pk : 4;
+ uint8_t xd : 1;
+ }__attribute__((packed));
+ uint64_t value;
+} __attribute__((packed)) pmle_t;
+
+typedef struct page_directory
+{
+ spinlock_t lock;
+ intmax_t id;
+ uintptr_t phys;
+ pmle_t *pml;
+} page_directory_t;
+
+#define _kernel_virtual_base 0xFFFFFFFF80000000ULL
+
+#endif
diff --git a/include/arch/x86_64/processor.h b/include/arch/x86_64/processor.h
new file mode 100644
index 0000000..c208eb1
--- /dev/null
+++ b/include/arch/x86_64/processor.h
@@ -0,0 +1,17 @@
+#ifndef _JOVE_x86_64_PROCESSOR_H
+#define _JOVE_x86_64_PROCESSOR_H 1
+
+#include "tables.h"
+#include "gdt.h"
+#include "idt.h"
+#include "tss.h"
+
+#define PROCESSOR_MAX 8
+
+#define ARCH_SPECIFIC_PROCESSOR_MEMBERS \
+ __attribute__((aligned(0x1000))) gdt_t _gdt; \
+ struct TSS _tss; \
+ struct XDTR _gdtr; \
+ struct XDTR _idtr
+
+#endif
diff --git a/arch/x86_64/tables.h b/include/arch/x86_64/tables.h
index e160c66..e311192 100644
--- a/arch/x86_64/tables.h
+++ b/include/arch/x86_64/tables.h
@@ -1,5 +1,5 @@
-#ifndef JOVE_ARCH_X86_64_TABLES_H
-#define JOVE_ARCH_X86_64_TABLES_H 1
+#ifndef _JOVE_X86_64_TABLES_H
+#define _JOVE_X86_64_TABLES_H 1
#include <stdint.h>
@@ -16,7 +16,7 @@
#define S_SEGMENT_TYPE_INT_GATE 14
#define S_SEGMENT_TYPE_TRAP_GATE 15
-struct SegmentDescriptor
+typedef struct segment_descriptor
{
uint16_t limit_0_15; /* Segment limit. */
uint16_t base_0_15; /* Segment base. */
@@ -24,16 +24,16 @@ struct SegmentDescriptor
uint8_t type : 4; /* Segment type. */
uint8_t s : 1; /* Descriptor type (0 = system, 1 = code/data)*/
uint8_t dpl : 2; /* Descriptor privilege level. */
- uint8_t p : 1; ; /* Present. */
+ uint8_t p : 1; /* Present. */
uint8_t limit_16_19 : 4;
uint8_t avl : 1; /* Available for use by system software. */
uint8_t l : 1; /* 64-bit segment (Ext). */
uint8_t d_b : 1; /* Default operation size (0 = 16-bit, 1 = 32-bit)*/
uint8_t g : 1; /* Granularity. */
uint8_t base_24_31;
-}__attribute__((packed));
+}__attribute__((packed)) segment_descriptor_t;
-struct InterruptTrapGate
+typedef struct interrupt_gate
{
uint16_t base_0_15;
uint16_t segment_selector;
@@ -46,7 +46,7 @@ struct InterruptTrapGate
uint16_t base_16_31;
uint32_t base_32_63;
uint32_t resv;
-}__attribute__((packed));
+}__attribute__((packed)) interrupt_gate_t;
struct XDTR /* Generic table descriptor struct */
{
@@ -54,7 +54,4 @@ struct XDTR /* Generic table descriptor struct */
uint64_t address;
}__attribute__((packed));
-void x86_64_load_gdt(void);
-void x86_64_load_idt(void);
-
#endif
diff --git a/arch/x86_64/tss.h b/include/arch/x86_64/tss.h
index dcdd01c..3184df5 100644
--- a/arch/x86_64/tss.h
+++ b/include/arch/x86_64/tss.h
@@ -15,6 +15,6 @@ struct TSS
uint16_t iobp;
};
-void tss_set_rsp(uint8_t dpl, uintptr_t rsp);
+void tss_set_rsp(struct TSS *tss, uint8_t dpl, uintptr_t rsp);
#endif
diff --git a/include/assert.h b/include/assert.h
new file mode 100644
index 0000000..f208235
--- /dev/null
+++ b/include/assert.h
@@ -0,0 +1,10 @@
+#ifndef JOVE_LIB_ASSERT_H
+#define JOVE_LIB_ASSERT_H 1
+
+#include "jove.h"
+
+#define assert(cond) \
+ if(!(cond)) \
+ kpanic("Assert failure : %s\n", #cond)
+
+#endif
diff --git a/boot/boot.h b/include/boot.h
index cfdfa68..c4aa541 100644
--- a/boot/boot.h
+++ b/include/boot.h
@@ -35,6 +35,4 @@ extern struct MemoryMap boot_memorymap;
extern struct BootModule boot_modules[BOOT_MODULE_MAX_ENTRIES];
extern size_t boot_module_count;
-#define boot_kernel_virtual_base 0xFFFFFFFF80000000ULL
-
#endif
diff --git a/include/commandline.h b/include/commandline.h
new file mode 100644
index 0000000..5c66cd3
--- /dev/null
+++ b/include/commandline.h
@@ -0,0 +1,8 @@
+#ifndef _JOVE_COMMANDLINE_H
+#define _JOVE_COMMANDLINE_H 1
+
+const char *cmdline_get(const char *key);
+
+void cmdline_kernel_setup(void);
+
+#endif
diff --git a/include/device/serial.h b/include/device/serial.h
new file mode 100644
index 0000000..d59b00f
--- /dev/null
+++ b/include/device/serial.h
@@ -0,0 +1,48 @@
+#ifndef _JOVE_DEVICE_SERIAL_H
+#define _JOVE_DEVICE_SERIAL_H 1
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include "klib/spinlock.h"
+
+#define SERIAL_UART_COM1 0x3F8
+#define SERIAL_UART_COM2 0x2F8
+
+#define SERIAL_UART_COM_THR(COM) COM
+#define SERIAL_UART_COM_RBR(COM) COM
+#define SERIAL_UART_COM_DLAB_DLL(COM) COM
+#define SERIAL_UART_COM_IER(COM) (COM + 1)
+#define SERIAL_UART_COM_DLAB_DLH(COM) (COM + 1)
+#define SERIAL_UART_COM_IIR(COM) (COM + 2)
+#define SERIAL_UART_COM_FCR(COM) (COM + 2)
+#define SERIAL_UART_COM_LCR(COM) (COM + 3)
+#define SERIAL_UART_COM_MCR(COM) (COM + 4)
+#define SERIAL_UART_COM_LSR(COM) (COM + 5)
+#define SERIAL_UART_COM_MSR(COM) (COM + 6)
+#define SERIAL_UART_COM_SR(COM) (COM + 7)
+
+typedef struct serial_device
+{
+ uint16_t com;
+ spinlock_t lock;
+} serial_dev_t;
+
+extern serial_dev_t COM1;
+
+void serial_setup(void);
+serial_dev_t serial_new(uint16_t com);
+
+void serial_set_int(serial_dev_t *dev, bool enable);
+void serial_set_baud(serial_dev_t *dev, uint16_t baud);
+
+void serial_set_fcr(serial_dev_t *dev, uint16_t flg);
+void serial_set_lcr(serial_dev_t *dev, uint16_t flg);
+void serial_set_mcr(serial_dev_t *dev, uint16_t flg);
+void serial_set_lsr(serial_dev_t *dev, uint16_t flg);
+void serial_set_msr(serial_dev_t *dev, uint16_t flg);
+
+uint8_t serial_line_status(serial_dev_t *dev);
+void serial_write(serial_dev_t *dev, const char *s, size_t len);
+
+#endif
diff --git a/arch/x86_64/uart.h b/include/device/uart.h
index 8386eb7..1724eb5 100644
--- a/arch/x86_64/uart.h
+++ b/include/device/uart.h
@@ -1,7 +1,7 @@
#ifndef JOVE_KERNEL_ARCH_x86_64_UART_H
#define JOVE_KERNEL_ARCH_x86_64_UART_H 1
-#include "lib/jove.h"
+#include "jove.h"
#include <stdint.h>
ALWAYS_INLINE uint8_t pinb(uint16_t port)
diff --git a/include/initrd.h b/include/initrd.h
new file mode 100644
index 0000000..7e7fe1e
--- /dev/null
+++ b/include/initrd.h
@@ -0,0 +1,17 @@
+#ifndef _JOVE_INITRD_H
+#define _JOVE_INITRD_H 1
+
+#include <stddef.h>
+
+typedef struct initrd_file {
+ void *header;
+ const char *name;
+ const void *data;
+ size_t size;
+} initrd_file_t;
+
+void initrd_setup(void);
+
+initrd_file_t *ird_getfile(const char *path);
+
+#endif
diff --git a/lib/jove.h b/include/jove.h
index 6015112..2330492 100644
--- a/lib/jove.h
+++ b/include/jove.h
@@ -4,8 +4,6 @@
#define ALWAYS_INLINE inline __attribute__((always_inline))
#define PAGEALIGN __attribute__((aligned(0x1000)))
-#define LOG2(n) (31 - __builtin_clz(n))
-
extern void *_kernel_start;
extern void *_kernel_end;
diff --git a/include/memory.h b/include/memory.h
new file mode 100644
index 0000000..35198e6
--- /dev/null
+++ b/include/memory.h
@@ -0,0 +1,49 @@
+#ifndef _JOVE_MEMORY_H
+#define _JOVE_MEMORY_H 1
+
+#define KiB 1024ULL
+#define MiB (KiB * KiB)
+#define GiB (MiB * KiB)
+#define TiB (GiB * KiB)
+
+#include <stdbool.h>
+#include <stddef.h>
+#include "arch/page.h"
+
+typedef uintptr_t physptr_t;
+
+extern const uintptr_t USERLAND_MEMORY_BASE;
+extern const uintptr_t USERLAND_MEMORY_LIMIT;
+extern const uintptr_t PHYSMAP_MEMORY_BASE;
+extern const uintptr_t PHYSMAP_MEMORY_LIMIT;
+extern const uintptr_t KERNEL_MEMORY_BASE;
+extern const uintptr_t KERNEL_MEMORY_LIMIT;
+
+page_mapping_t vm_pd_mapping_get(page_directory_t *pd, uintptr_t addr);
+void vm_pd_mapping_set(page_directory_t *pd, page_mapping_t mapping, uintptr_t addr);
+void vm_pd_ensure(page_directory_t *pd, uintptr_t from, uintptr_t to, page_flags_t flg);
+
+page_mapping_t vm_mapping_get(uintptr_t addr);
+void vm_mapping_set(page_mapping_t mapping, uintptr_t virt);
+void vm_ensure(uintptr_t from, uintptr_t to, page_flags_t flg);
+
+physptr_t vm_tophys(uintptr_t virt);
+physptr_t vm_tophys_koff(uintptr_t virt);
+
+uintptr_t pm_tovirt(physptr_t phys);
+
+physptr_t pm_alloc(size_t pages);
+void pm_reserve(physptr_t start, physptr_t end);
+void pm_release(physptr_t start, physptr_t end);
+
+void mm_setup_early(void);
+void vm_setup_early(void);
+
+void mm_setup(void);
+void vm_setup(void);
+
+void* kmalloc(size_t width);
+void *krealloc(void *ptr, size_t width);
+void kfree(void *ptr);
+
+#endif
diff --git a/include/print.h b/include/print.h
new file mode 100644
index 0000000..38a1dbc
--- /dev/null
+++ b/include/print.h
@@ -0,0 +1,25 @@
+#ifndef _JOVE_PRINT_H
+#define _JOVE_PRINT_H 1
+
+#include <stdarg.h>
+
+enum {
+ PRINT_DEBUG = 0,
+ PRINT_LOG,
+ PRINT_WARN,
+ PRINT_ERROR
+};
+
+#define PRINT_BUFFERW 512
+
+void prawf(const char *fmt, ...);
+
+void _plogvf(const char *file, const char *func, int line, int lvl, const char *fmt, va_list ap);
+void _plogf(const char *file, const char *func, int line, int lvl, const char *fmt, ...);
+
+#define kdbgf(...) _plogf(__FILE__, __FUNCTION__, __LINE__, PRINT_DEBUG, __VA_ARGS__)
+#define klogf(...) _plogf(__FILE__, __FUNCTION__, __LINE__, PRINT_LOG , __VA_ARGS__)
+#define kwarnf(...) _plogf(__FILE__, __FUNCTION__, __LINE__, PRINT_WARN, __VA_ARGS__)
+#define kerrf(...) _plogf(__FILE__, __FUNCTION__, __LINE__, PRINT_ERROR, __VA_ARGS__)
+
+#endif
diff --git a/include/slab.h b/include/slab.h
new file mode 100644
index 0000000..04d42e4
--- /dev/null
+++ b/include/slab.h
@@ -0,0 +1,44 @@
+#ifndef JOVE_MEMORY_SLAB_H
+#define JOVE_MEMORY_SLAB_H 1
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#define SLABCACHE_NAME_LIMIT 32
+typedef struct slab_cache
+{
+ char name[SLABCACHE_NAME_LIMIT];
+
+ struct slab *list_free;
+ struct slab *list_partial;
+ struct slab *list_full;
+
+ size_t obj_count;
+ size_t obj_size;
+ size_t obj_capacity;
+
+ size_t slab_pages;
+} slab_cache_t;
+
+typedef struct slab
+{
+ struct slab *prev;
+ struct slab *next;
+ void *slab_base;
+ void *obj_base;
+
+ size_t free_count;
+ int free_index;
+ uintptr_t free[];
+} slab_t;
+
+void slabcache_new(slab_cache_t *cache, char *name, size_t objsize);
+
+void* slab_alloc(slab_cache_t *cache);
+void slab_free(slab_cache_t *cache, void *ptr);
+
+void* slab_get(slab_cache_t *cache, size_t index);
+void slab_set(slab_cache_t *cache, size_t index, void *data);
+
+#endif
diff --git a/lib/string.h b/include/string.h
index a91ec94..a91ec94 100644
--- a/lib/string.h
+++ b/include/string.h
diff --git a/include/tasking.h b/include/tasking.h
new file mode 100644
index 0000000..04118a9
--- /dev/null
+++ b/include/tasking.h
@@ -0,0 +1,44 @@
+#ifndef _JOVE_TASKING_H
+#define _JOVE_TASKING_H 1
+
+#include "arch/page.h"
+#include <stddef.h>
+#include <stdbool.h>
+
+#define KERNEL_STACKW 4096
+
+typedef intmax_t tcbid_t;
+
+typedef enum
+{
+ TCB_RUNNING,
+ TCB_PAUSED,
+ TCB_DEAD
+} tcb_state_t;
+
+typedef struct task_control_block
+{
+ tcbid_t id;
+ void *stack;
+ uintptr_t sp, ksp;
+ page_directory_t *pd;
+ tcb_state_t state;
+
+ int exit_code;
+} tcb_t;
+
+void tasking_setup(void);
+
+tcb_t *tcb_new(void *ip, page_directory_t *pd);
+void tcb_prepare(tcb_t *tcb, void *ip);
+void tcb_kill(tcb_t *tcb, int code);
+
+void tcb_switch(tcb_t *to);
+
+void tcb_stack_push(tcb_t *tcb, void *data, size_t len);
+
+void kexec(void *ip, int kargc, char **kargv, int kenvc, char **kenvp);
+
+void *umode_stack_new(void);
+
+#endif
diff --git a/include/umode_vma.h b/include/umode_vma.h
new file mode 100644
index 0000000..23619be
--- /dev/null
+++ b/include/umode_vma.h
@@ -0,0 +1,10 @@
+#ifndef _JOVE_UMODE_VMA_H
+#define _JOVE_UMODE_VMA_H 1
+
+#include <stdbool.h>
+#include <stddef.h>
+
+int user_vma_read(void *dest, const void *src, size_t w);
+int user_vma_write(void *dest, const void *src, size_t w);
+
+#endif
diff --git a/include/zone.h b/include/zone.h
new file mode 100644
index 0000000..002d1fc
--- /dev/null
+++ b/include/zone.h
@@ -0,0 +1,38 @@
+#ifndef JOVE_MEM_ZONE_H
+#define JOVE_MEM_ZONE_H 1
+
+#include <stdint.h>
+#include "klib/buddymap.h"
+
+enum {
+ MEM_ZONE_STANDARD = 0, /* First GiB of physical memory. */
+ MEM_ZONE_HIGHER,
+ MEM_ZONE_COUNT
+};
+
+#define MEM_ZONE_STANDARD_BASE 0
+#define MEM_ZONE_STANDARD_LIMIT (1 * GiB)
+#define MEM_ZONE_HIGHER_BASE MEM_ZONE_STANDARD_LIMIT
+
+#define MEM_BUDDY_ORDERS 12
+struct PhysicalMemoryZone
+{
+ const char *name;
+
+ uintptr_t base;
+ uintptr_t limit;
+
+ struct BuddyMap freemap;
+};
+
+int pm_zone_for(uintptr_t addr);
+uintptr_t pm_zone_bound_lower(size_t zone);
+uintptr_t pm_zone_bound_upper(size_t zone);
+size_t pm_zone_pages_free(size_t zone);
+int pm_zone_resv(size_t zone, uintptr_t base, uintptr_t limit);
+int pm_zone_free(size_t zone, uintptr_t base, uintptr_t limit);
+uintptr_t pm_zone_alloc(size_t zone, size_t pages);
+
+void pm_zone_setup(void);
+
+#endif
diff --git a/ird/initrd.c b/initrd/initrd.c
index f219243..8fe0f01 100644
--- a/ird/initrd.c
+++ b/initrd/initrd.c
@@ -1,12 +1,14 @@
#include "initrd.h"
-#include "lib/string.h"
-#include "io/log.h"
-#include "boot/boot.h"
-#include "boot/cmdline.h"
-#include "mem/memory.h"
+#include "tar.h"
+#include "string.h"
+#include "commandline.h"
+#include "memory.h"
+#include "print.h"
+#include "klib/rbtree.h"
+#include "klib/hash.h"
+#include "boot.h"
-struct SlabCache s_initrd_cache;
-struct SLinkedList s_initrd_files;
+static rbtree_t s_initrd_files;
static size_t
s_tar_oct_dec(const char *oct)
@@ -23,40 +25,35 @@ s_tar_oct_dec(const char *oct)
static void
s_initrd_parse(struct BootModule *module)
{
- struct TARSector *sector = (struct TARSector*)module->addr;
+ struct tar_block *sector = (struct tar_block*)module->addr;
while(true) {
- struct TARHeader *header = (struct TARHeader*)sector;
+ tar_header_t *header = (tar_header_t*)sector;
if(header->name[0] == 0) break;
- struct InitrdFile *file = mem_slab_alloc(&s_initrd_cache);
- *file = (struct InitrdFile){
+ initrd_file_t file_tmp;
+ initrd_file_t *file = rbtree_insert(
+ &s_initrd_files,
+ string_hash(header->name),
+ &file_tmp);
+
+ *file = (initrd_file_t){
.header = header,
.name = header->name,
.size = s_tar_oct_dec(header->size),
.data = &sector[1]
};
- klogf("File %s size %i\n", file->name, file->size);
- sll_push(&s_initrd_files, file);
+ kdbgf("File %s size %i\n", file->name, file->size);
sector = &sector[(file->size / 512) + 1];
if(file->size % 512 > 0) sector = &sector[1];
}
}
-struct InitrdFile *
+initrd_file_t *
ird_getfile(const char *path)
{
- for(struct SLLNode *node = s_initrd_files.head; node != NULL; node = node->next) {
- struct InitrdFile *file = (struct InitrdFile*)node;
- if(strcmp(file->name, path) == 0) return file;
- }
- return NULL;
-}
-
-struct SLinkedList *
-ird_getfiles(void)
-{
- return &s_initrd_files;
+ initrd_file_t *file = rbtree_find(&s_initrd_files, string_hash(path));
+ return file;
}
void
@@ -64,10 +61,10 @@ initrd_setup(void)
{
const char *initrd_path = cmdline_get("initrd");
if(initrd_path == 0) {
- klogf("No initrd loaded!\n");
+ kerrf("No initrd loaded!\n");
return;
}
- klogf("Initrd located in module path %s\n", initrd_path);
+ kdbgf("Initrd located in module path %s\n", initrd_path);
struct BootModule *initrd_module = NULL;
for(size_t i = 0; i < boot_module_count; i++) {
struct BootModule *module = &boot_modules[i];
@@ -82,7 +79,6 @@ initrd_setup(void)
return;
}
- sll_new(&s_initrd_files, sizeof(struct InitrdFile));
- mem_slabcache_new(&s_initrd_cache, "initrd files", sizeof(struct InitrdFile));
+ rbtree_new(&s_initrd_files, initrd_file_t);
s_initrd_parse(initrd_module);
}
diff --git a/ird/tar.h b/initrd/tar.h
index 5c72620..5325a51 100644
--- a/ird/tar.h
+++ b/initrd/tar.h
@@ -1,9 +1,9 @@
#ifndef JOVE_INITRD_TAR_H
#define JOVE_INITRD_TAR_H 1
-struct TARSector { char data[512]; };
+struct tar_block { char data[512]; };
-struct TARHeader {
+typedef struct tar_header {
char name[100];
char mode[8];
char owner[8];
@@ -13,6 +13,6 @@ struct TARHeader {
char checksum[8];
char link;
char linkname[100];
-};
+} tar_header_t;
#endif
diff --git a/io/interrupt.h b/io/interrupt.h
deleted file mode 100644
index 444ff01..0000000
--- a/io/interrupt.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef JOVE_IO_INTERRUPT_H
-#define JOVE_IO_INTERRUPT_H 1
-
-
-
-#endif
diff --git a/io/log.c b/io/log.c
deleted file mode 100644
index 14397a7..0000000
--- a/io/log.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include "log.h"
-#include "lib/jove.h"
-#include "lib/string.h"
-#include "lib/format.h"
-
-static struct LogDevice *s_first_logdev = NULL;
-
-void
-klog_newdev(struct LogDevice *dev)
-{
- if(s_first_logdev == NULL) {
- s_first_logdev = dev;
- }else{
- dev->chain = s_first_logdev;
- s_first_logdev = dev;
- }
-}
-
-static void
-s_klogc(struct LogDevice *dev, char c)
-{
- dev->out(&c, 1);
- if(dev->chain != NULL)
- s_klogc(dev->chain, c);
-}
-
-void
-klogc(char c)
-{
- s_klogc(s_first_logdev, c);
-}
-
-static void
-s_klogs(struct LogDevice *dev, const char *s, size_t slen)
-{
- dev->out(s, slen);
- if(dev->chain != NULL)
- s_klogs(dev->chain, s, slen);
-}
-
-void
-klogs(const char *s)
-{
- size_t slen = strlen(s);
- s_klogs(s_first_logdev, s, slen);
-}
-
-void
-klogsn(const char *s, size_t len)
-{
- s_klogs(s_first_logdev, s, len);
-}
-
-void
-kvlogf(const char *fmt, va_list ap)
-{
- char buffer[256];
- svfmt(buffer, 256, fmt, ap);
- klogs(buffer);
-}
-
-void klogf(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- kvlogf(fmt, ap);
- va_end(ap);
-}
diff --git a/io/log.h b/io/log.h
deleted file mode 100644
index ad1526d..0000000
--- a/io/log.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef JOVE_IO_LOG_H
-#define JOVE_IO_LOG_H 1
-
-#include <stddef.h>
-
-struct LogDevice
-{
- void (*out)(const char*, size_t);
- struct LogDevice *chain;
-};
-
-void klog_newdev(struct LogDevice *dev);
-
-void klogc(char c);
-void klogs(const char *s);
-void klogsn(const char *s, size_t len);
-
-#include <stdarg.h>
-void kvlogf(const char *fmt, va_list ap);
-void klogf(const char *fmt, ...);
-
-#endif
diff --git a/ird/initrd.h b/ird/initrd.h
deleted file mode 100644
index f236fa1..0000000
--- a/ird/initrd.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef JOVE_INITRD_H
-#define JOVE_INITRD_H 1
-
-#include <stddef.h>
-#include "tar.h"
-#include "lib/linkedlist.h"
-
-struct InitrdFile {
- struct InitrdFile *next;
- struct TARHeader *header;
- const char *name;
- size_t size;
- const void *data;
-};
-
-void initrd_setup(void);
-
-struct InitrdFile *ird_getfile(const char *path);
-struct SLinkedList *ird_getfiles(void);
-
-#endif
diff --git a/lib/buddymap.c b/klib/buddymap.c
index 6a616c9..62cecf1 100644
--- a/lib/buddymap.c
+++ b/klib/buddymap.c
@@ -1,8 +1,10 @@
#include "buddymap.h"
#include "jove.h"
+#include "print.h"
#define BLOCK_AT_LAYER(blocks, l, i) blocks[l][i / BUDDY_BLOCK_BITS]
#define BLOCK_BITMASK(i) (1ULL << (i % BUDDY_BLOCK_BITS))
+#define LOG2(v) (31 - __builtin_clz(v))
bool
buddy_bit_test(struct BuddyMap *map, size_t l, size_t i)
diff --git a/lib/buddymap.h b/klib/buddymap.h
index 1af8dfb..1af8dfb 100644
--- a/lib/buddymap.h
+++ b/klib/buddymap.h
diff --git a/lib/format.h b/klib/format.h
index 5a2b75c..5a2b75c 100644
--- a/lib/format.h
+++ b/klib/format.h
diff --git a/klib/hash.h b/klib/hash.h
new file mode 100644
index 0000000..03b0f3a
--- /dev/null
+++ b/klib/hash.h
@@ -0,0 +1,18 @@
+#ifndef JOVE_LIB_HASH_H
+#define JOVE_LIB_HASH_H 1
+
+#include <stdint.h>
+
+static intmax_t
+string_hash(const char *str)
+{
+ /* Hash function courtesy of the following website:
+ * http://www.cse.yorku.ca/~oz/hash.html*/
+ intmax_t r = 5381;
+ while (*str) {
+ r = (r * 33) ^ *(str++);
+ }
+ return r;
+}
+
+#endif
diff --git a/lib/kpanic.c b/klib/kpanic.c
index 97e42eb..2918711 100644
--- a/lib/kpanic.c
+++ b/klib/kpanic.c
@@ -1,7 +1,8 @@
#include "jove.h"
-#include "io/log.h"
+#include "print.h"
#include <stdarg.h>
+#include <stddef.h>
__attribute__((noreturn))
void _kpanic(const char *file, int line, const char *fmt, ...)
@@ -9,7 +10,7 @@ void _kpanic(const char *file, int line, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
klogf("!!! PANIC !!!\n%s:%i\n", file, line);
- kvlogf(fmt, ap);
+ _plogvf(NULL, NULL, 0, PRINT_LOG, fmt, ap);
va_end(ap);
for(;;) __asm__ volatile("hlt");
}
diff --git a/lib/linkedlist.c b/klib/linkedlist.c
index 6cc6403..6cc6403 100644
--- a/lib/linkedlist.c
+++ b/klib/linkedlist.c
diff --git a/lib/linkedlist.h b/klib/linkedlist.h
index 26c148e..26c148e 100644
--- a/lib/linkedlist.h
+++ b/klib/linkedlist.h
diff --git a/lib/ltostr.c b/klib/ltostr.c
index e28be31..e28be31 100644
--- a/lib/ltostr.c
+++ b/klib/ltostr.c
diff --git a/lib/mem.c b/klib/mem.c
index b60fbbd..cf9e2aa 100644
--- a/lib/mem.c
+++ b/klib/mem.c
@@ -1,5 +1,5 @@
#include "string.h"
-#include "mem/memory.h"
+#include "memory.h"
void*
memset(void *dest, int c, size_t n)
@@ -46,7 +46,7 @@ char*
strdup(const char *s)
{
size_t slen = strlen(s);
- char *ret = mem_alloc(slen);
+ char *ret = kmalloc(slen);
memcpy(ret, s, slen);
return ret;
}
diff --git a/klib/rbtree.c b/klib/rbtree.c
new file mode 100644
index 0000000..2920384
--- /dev/null
+++ b/klib/rbtree.c
@@ -0,0 +1,361 @@
+#include "rbtree.h"
+#include "assert.h"
+#include "string.h"
+
+#define BLACK 0
+#define RED 1
+
+#define LEFT 0
+#define left children[LEFT]
+
+#define RIGHT 1
+#define right children[RIGHT]
+
+#define CHILD_DIR(c) (c->parent->children[LEFT] == c ? LEFT : RIGHT)
+
+/**Given a root and a direction, rotate the subtree such that the order of the
+ * elements are unchanged.
+ * The opposite direction child of the given root is treated as the pivot point
+ * The dir-most child of the pivot becomes the opposite dir child of the root.
+ * The pivot becomes the root and vice-versa.
+ * @param tree to do rotation on.
+ * @param root of rotation.
+ * @param dir to rotate by.
+ * @return new root node.*/
+rbnode_t*
+s_node_rotate(rbtree_t *tree, rbnode_t *root, bool dir)
+{
+ assert(root != NULL);
+ rbnode_t *gparent = root->parent;
+ rbnode_t *sibling = root->children[1-dir];
+ rbnode_t *child = NULL;
+
+ assert(sibling != NULL);
+ child = sibling->children[dir];
+
+ /* Opposite child of root is dir-most child of sibling.*/
+ root->children[1-dir] = child;
+ if(child != NULL) child->parent = root;
+
+ /* Child of sibling is the root.*/
+ sibling->children[ dir] = root;
+ root->parent = sibling;
+
+ /* Parent of sibling is the grandparent. */
+ sibling->parent = gparent;
+ if(gparent != NULL)
+ gparent->children[CHILD_DIR(root)] = sibling;
+ else
+ tree->root = sibling;
+
+ return sibling;
+}
+
+/**Search the rbtree for a node that matches the key.
+ * If no such node is found, returns NULL.
+ * @param tree to search through.
+ * @param key to search for.
+ * @return found node.*/
+rbnode_t*
+s_find(rbtree_t *tree, intmax_t key)
+{
+ rbnode_t *node = tree->root;
+ while(node != NULL && node->key != key) {
+ node = node->children[node->key > key];
+ }
+ return node;
+}
+
+rbnode_t*
+s_closest(rbtree_t *tree, intmax_t key)
+{
+ rbnode_t *node = tree->root;
+ while(node != NULL && node->key != key) {
+ rbnode_t *child = node->children[node->key > key];
+ if(child == NULL) return node;
+ node = child;
+ }
+ return node;
+}
+
+/**Find the left-most node for this subtree.
+ * @param node root of the subtree to search through.
+ * @return left-most node.*/
+rbnode_t*
+s_node_min(rbnode_t *node)
+{
+ while(node->left != NULL) node = node->left;
+ return node;
+}
+
+/**Find the successor for the specified node.
+ * The successor is defined as the left-most node of the right sub-tree.
+ * (the smallest node larger than the root)
+ * @param node to search for.
+ * @return the successor.*/
+rbnode_t*
+s_node_successor(rbnode_t *node)
+{
+ if(node->right != NULL)
+ return s_node_min(node->right);
+ /* If the node has no left child (meaning that the node is larger than it's
+ * parents), we cycle up through the RHS of the parent tree (such that each
+ * parent is smaller than the child) until we reach a point by which the
+ * child node is smaller than the parent.*/
+ rbnode_t *parent = node->parent;
+ while(parent != NULL && node == parent->right) {
+ node = parent;
+ parent = node->parent;
+ }
+ return parent;
+}
+
+/**Copy the data from one node onto another, keeping parent and child relations.
+ * @prarm tree for metadata purposes.
+ * @param dest destination node.
+ * @param src source node.*/
+void
+s_node_copy_value(rbtree_t *tree, rbnode_t *dest, rbnode_t *src)
+{
+ dest->key = src->key;
+ memcpy(dest->data, src->data, tree->objw);
+}
+
+/**Perform tree adjustments after insertion to rebalance the rbtree.
+ * @param tree to rebalance.
+ * @param node that was inserted.
+ * @param parent of the node.
+ * @param dir that the node was inserted in.*/
+void
+s_node_insert_fix(
+ rbtree_t *tree,
+ rbnode_t *node,
+ rbnode_t *parent,
+ bool dir)
+{
+ rbnode_t *gparent;
+ rbnode_t *uncle;
+ while((parent = node->parent) != NULL) {
+ if(parent->color == BLACK) return; /* Tree is valid. no fixes needed.*/
+ /*Parent is known to be red.*/
+ if((gparent = parent->parent) == NULL) {
+ /*Parent is red and the root. We can just fix it and return.*/
+ parent->color = BLACK;
+ return;
+ }
+ /* Parent is red and has a parent.
+ * We now need to fix the parent.*/
+ dir = CHILD_DIR(parent);
+ uncle = gparent->children[1-dir];
+ if(uncle == NULL || uncle->color == BLACK) {
+ /* Parent is red, but uncle (opposite child of gparent) is black.
+ * We need to rotate the gparent node such that the parent takes
+ * its place. However, if the current node is an inner child of
+ * gparent, we need to rotate N into P.*/
+ if(node == parent->children[1-dir]) {
+ /* Node is an inner child. We need to rotate N and P first.*/
+ s_node_rotate(tree, parent, dir);
+ node = parent;
+ parent = gparent->children[dir];
+ }
+ /* N is not an inner child, we can rotate the tree properly.*/
+ s_node_rotate(tree, gparent, 1-dir);
+ parent->color = BLACK;
+ gparent->color = RED;
+ return;
+ }
+ }
+}
+
+/**Insert a node into the rbtree on the parent and direction given.
+ * @param tree to insert into.
+ * @param node to insert.
+ * @param parent node to insert onto.
+ * @param dir direction to insert node.*/
+void
+s_node_insert(rbtree_t *tree, rbnode_t *node, rbnode_t *parent, bool dir)
+{
+ node->color = RED;
+ node->left = NULL;
+ node->right = NULL;
+ node->parent = parent;
+ if(parent == NULL) {
+ tree->root = node;
+ return;
+ }
+ parent->children[dir] = node;
+ s_node_insert_fix(tree, node, parent, dir);
+}
+
+void
+s_node_remove_fixup(rbtree_t *tree, rbnode_t *node)
+{
+ bool dir;
+ rbnode_t *parent = node->parent;
+ rbnode_t *sibling;
+ rbnode_t *cnephew;
+ rbnode_t *dnephew;
+
+ dir = CHILD_DIR(node);
+ parent->children[dir] = NULL;
+ while((parent = node->parent) != NULL)
+ {
+ dir = CHILD_DIR(node);
+ sibling = parent->children[1-dir];
+ cnephew = parent->children[ dir];
+ dnephew = parent->children[1-dir];
+ if(sibling->color == RED)
+ goto case3;
+ if(dnephew != NULL && dnephew->color == RED)
+ goto case6;
+ if(cnephew != NULL && cnephew->color == RED)
+ goto case5;
+ if(parent->color == RED)
+ goto case4;
+
+ /* The parent, both nephews, and sibling are black. We need to paint
+ * the sibling black and move up a level.*/
+ sibling->color = RED;
+ node = parent;
+ }
+ return;
+
+case3:
+ /* The sibling is red, which means both nephews and the parent are black.
+ * We rotate the subtree so that the parent moves to become the siblings
+ * left child. The tree is then repainted.*/
+ s_node_rotate(tree, parent, dir);
+ parent->color = RED;
+ sibling->color = BLACK;
+ /* Now we are working on the sibling subtree.*/
+ sibling = cnephew;
+ dnephew = sibling->children[1-dir];
+ if(dnephew != NULL && dnephew->color == BLACK)
+ goto case6;
+ cnephew = sibling->children[dir];
+ if(cnephew != NULL && cnephew->color == RED)
+ goto case5;
+
+case4:
+ sibling->color = RED;
+ parent->color = BLACK;
+ return;
+
+case5:
+ s_node_rotate(tree, sibling, 1-dir);
+ sibling->color = RED;
+ cnephew->color = BLACK;
+ dnephew = sibling;
+ sibling = cnephew;
+
+case6:
+ s_node_rotate(tree, parent, dir);
+ sibling->color = parent->color;
+ parent->color = BLACK;
+ dnephew->color = BLACK;
+}
+
+void
+s_node_remove(rbtree_t *tree, rbnode_t *node)
+{
+ rbnode_t *parent = node->parent;
+ if(node->left != NULL && node->right != NULL) {
+ /* Node is a full tree. We can replace the node with it's successor to
+ * keep the balance.
+ * Needs to recurse if the successor has a right-most child, which is
+ * dealt with in the next case.*/
+ rbnode_t *successor = s_node_successor(node);
+ s_node_copy_value(tree, node, successor);
+ s_node_remove(tree, successor);
+ return;
+ } else if(node->left == NULL && node->right == NULL) {
+ if(parent == NULL) {
+ tree->root = NULL;
+ kfree(node);
+ return;
+ }
+ if(node->color == RED) {
+ parent->children[CHILD_DIR(node)] = NULL;
+ kfree(node);
+ return;
+ }
+ s_node_remove_fixup(tree, node);
+ } else {
+ /* Node has a single child. Because the child must be red as per spec,
+ * and this node must be black, we can simply replace the node
+ * with it's child and color it black.*/
+ rbnode_t *child = node->left == NULL ? node->right : node->left;
+ memcpy(node, child, sizeof(rbnode_t) + tree->objw);
+ node->parent = parent;
+ node->color = BLACK;
+ kfree(child);
+ return;
+ }
+}
+
+void
+__rbtree_new(rbtree_t *tree, size_t objw)
+{
+ *tree = (rbtree_t) {
+ .root = NULL,
+ .objw = objw,
+ };
+}
+
+void*
+rbtree_find(rbtree_t *tree, intmax_t key)
+{
+ rbnode_t *found = s_find(tree, key);
+ if(found == NULL) return NULL;
+ return found->data;
+}
+
+rbnode_t*
+s_node_new(rbtree_t *tree, intmax_t key, void *data)
+{
+ rbnode_t *node = kmalloc(sizeof(rbnode_t) + tree->objw);
+ if(data != NULL) memcpy(node->data, data, tree->objw);
+ node->key = key;
+ return node;
+}
+
+void*
+rbtree_insert(rbtree_t *tree, intmax_t key, void *data)
+{
+ assert(tree != NULL);
+
+ rbnode_t *node = s_closest(tree, key);
+ if(node != NULL && node->key == key) {
+ memcpy(node->data, data, tree->objw);
+ } else if(node != NULL) {
+ rbnode_t *child = s_node_new(tree, key, data);
+ s_node_insert(tree, child, node, node->key > key);
+ return child->data;
+ } else {
+ node = s_node_new(tree, key, data);
+ node->parent = NULL;
+ node->children[0] = node->children[1] = NULL;
+ node->color = BLACK;
+ tree->root = node;
+ }
+ return node->data;
+}
+
+void *rbtree_reserve(rbtree_t *tree, intmax_t key)
+{
+ assert(tree != NULL);
+
+ rbnode_t *node = s_closest(tree, key);
+ if(node != NULL && node->key == key) {
+ return node->data;
+ } else if(node != NULL) {
+ rbnode_t *child = s_node_new(tree, key, NULL);
+ s_node_insert(tree, child, node, node->key > key);
+ return child->data;
+ } else {
+ node = s_node_new(tree, key, NULL);
+ tree->root = node;
+ }
+ return node->data;
+}
+
diff --git a/klib/rbtree.h b/klib/rbtree.h
new file mode 100644
index 0000000..4376713
--- /dev/null
+++ b/klib/rbtree.h
@@ -0,0 +1,48 @@
+#ifndef JOVE_LIB_RBTREE_H
+#define JOVE_LIB_RBTREE_H 1
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include "memory.h"
+
+typedef struct rbnode
+{
+ struct rbnode *parent;
+ struct rbnode *children[2];
+ intmax_t key;
+ bool color;
+ char data[];
+} rbnode_t;
+
+typedef struct rbtree
+{
+ rbnode_t *root;
+ size_t objw;
+} rbtree_t;
+
+/**Instantiate a new tree based on the given type.
+ * @param tree to instantiate into.
+ * @param type to instantiate for.*/
+#define rbtree_new(tree, type) __rbtree_new(tree, sizeof(type))
+void __rbtree_new(rbtree_t *tree, size_t objw);
+
+/**Find the data corresponding to the key in the tree.
+ * usage: rbtree_find(type)(tree, key);
+ * @param tree to search through.
+ * @param key to search for.
+ * @return */
+void *rbtree_find(rbtree_t *tree, intmax_t key);
+
+/**Insert a value into the given tree using the given key.
+ * If the key is already present within the tree, the existing data is
+ * overwritten.
+ * @param tree to insert into.
+ * @param key to insert.
+ * @param value to insert.
+ * @return pointer to inserted data.
+ * */
+void *rbtree_insert(rbtree_t *tree, intmax_t key, void *value);
+void *rbtree_reserve(rbtree_t *tree, intmax_t key);
+
+#endif
diff --git a/lib/sfmt.c b/klib/sfmt.c
index f903cbf..519fbf4 100644
--- a/lib/sfmt.c
+++ b/klib/sfmt.c
@@ -62,8 +62,11 @@ svfmt(char *s, size_t limit, const char *fmt, va_list ap)
case '%':
s[si++] = '%';
break;
+ case 'p':
+ radix = 16;
+ alt = true;
case 'b':
- radix = 2;
+ if(radix == 10) radix = 2;
case 'X':
upper = true;
case 'x':
diff --git a/lib/spinlock.h b/klib/spinlock.h
index 75af28a..75af28a 100644
--- a/lib/spinlock.h
+++ b/klib/spinlock.h
diff --git a/lib/string.c b/klib/string.c
index 4bb1bad..4bb1bad 100644
--- a/lib/string.c
+++ b/klib/string.c
diff --git a/lib/toupper.c b/klib/toupper.c
index 807eb38..807eb38 100644
--- a/lib/toupper.c
+++ b/klib/toupper.c
diff --git a/lib/hashtable.c b/lib/hashtable.c
deleted file mode 100644
index 17f1e74..0000000
--- a/lib/hashtable.c
+++ /dev/null
@@ -1,109 +0,0 @@
-#include "hashtable.h"
-#include "string.h"
-#include "mem/memory.h"
-
-static size_t
-s_hash_function_mul(const void *data, size_t len)
-{
- size_t hash = 1;
- const char *cdata = (const char*)data;
- for(size_t i = 0; i < len; i++) {
- hash *= ((size_t)cdata[i]) + 1;
- }
- return hash;
-}
-
-static size_t
-s_hash_function_mul_s(const void *data, size_t _)
-{
- return s_hash_function_mul(data, strlen(data));
-}
-
-void
-_hashtable_new(struct HashTable *table, size_t obj_size, size_t key_size)
-{
- *table = (struct HashTable){
- .buckets = NULL,
- .bucket_count = 0,
- .bucket_capacity = 2,
- .obj_size = obj_size,
- .key_size = key_size,
- .hash_function = s_hash_function_mul
- };
- table->buckets = mem_alloc(sizeof(struct SLinkedList) * 2);
-}
-
-void
-_hashtable_news(struct HashTable *table, size_t obj_size)
-{
- *table = (struct HashTable){
- .buckets = NULL,
- .bucket_count = 0,
- .bucket_capacity = 2,
- .obj_size = obj_size,
- .key_size = -1,
- .hash_function = s_hash_function_mul_s
- };
- table->buckets = mem_alloc(sizeof(struct SLinkedList) * 2);
-}
-
-void
-hashtable_insert(struct HashTable *table, const void *key, void *data)
-{
- size_t hash = table->hash_function(key, table->key_size);
- if(table->bucket_capacity == table->bucket_count) {
- struct SLinkedList *old_buckets = table->buckets;
- size_t old_buckets_count = table->bucket_count;
-
- table->bucket_capacity *= 2;
- table->bucket_count = 0;
- table->buckets = mem_alloc(sizeof(struct SLinkedList) * table->bucket_capacity);
- for(size_t i = 0; i < old_buckets_count; i++) {
- for(struct SLLNode *node = old_buckets[i].head; node != NULL; node = node->next) {
- struct HashTableValue *value = (struct HashTableValue*)(&node->data);
- hashtable_insert(table, value->key, value->value);
- mem_free(node);
- }
- }
- }
-
- size_t index = hash % table->bucket_capacity;
- struct SLinkedList *bucket = &table->buckets[index];
- struct SLLNode *node = mem_alloc(sizeof(struct SLLNode) + sizeof(struct HashTableValue) + table->obj_size);
- struct HashTableValue *value = (struct HashTableValue*)(node->data);
-
- value->key = key;
- memcpy(value->value, data, table->obj_size);
-
- table->bucket_count++;
- if(bucket->count == 0) {
- sll_new(bucket, table->obj_size);
- sll_push(bucket, node);
- return;
- }
- for(struct SLLNode *onode = bucket->head; onode != NULL; onode = onode->next)
- {
- struct HashTableValue *ovalue = (struct HashTableValue*)onode->data;
- size_t keylen = table->key_size > 0 ? table->key_size : strlen((const char*)key) + 1;
- if(memcmp(ovalue->key, value->key, keylen) == 0) {
- memcpy(ovalue->value, value->value, table->obj_size);
- return;
- }
- }
- sll_push(bucket, node);
-}
-
-void*
-_hashtable_get(struct HashTable *table, const void *key)
-{
- size_t hash = table->hash_function(key, table->key_size);
- size_t index = hash % table->bucket_capacity;
- struct SLinkedList *bucket = &table->buckets[index];
- for(struct SLLNode *node = bucket->head; node != NULL; node = node->next)
- {
- struct HashTableValue *value = (struct HashTableValue*)node->data;
- size_t keylen = table->key_size > 0 ? table->key_size : strlen((const char*)value->key);
- if(memcmp(key, value->key, keylen) == 0) return value->value;
- }
- return NULL;
-}
diff --git a/lib/hashtable.h b/lib/hashtable.h
deleted file mode 100644
index fe6f5c3..0000000
--- a/lib/hashtable.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef JOVE_LIB_HASHTABLE_H
-#define JOVE_LIB_HASHTABLE_H 1
-
-#include <stddef.h>
-#include <stdint.h>
-#include "linkedlist.h"
-
-struct HashTableValue
-{
- const void *key;
- char value[];
-};
-
-struct HashTable {
- struct SLinkedList *buckets;
- size_t bucket_count;
- size_t bucket_capacity;
-
- size_t obj_size;
- int key_size;
- size_t (*hash_function)(const void*, size_t);
-};
-
-void _hashtable_new(struct HashTable *table, size_t obj_size, size_t key_size);
-#define hashtable_new(table, type, keytype) _hashtable_new(table, sizeof(type), sizeof(keytype))
-
-void _hashtable_news(struct HashTable *table, size_t obj_size);
-#define hashtable_news(table, type) _hashtable_news(table, sizeof(type))
-
-void hashtable_insert(struct HashTable *table, const void *key, void *data);
-void *_hashtable_get(struct HashTable *table, const void *key);
-#define hashtable_get(table, key, type) (type*)_hashtable_get(table, key)
-
-#endif
diff --git a/main.c b/main.c
index 91125af..a586287 100644
--- a/main.c
+++ b/main.c
@@ -1,26 +1,37 @@
-#include "arch/arch.h"
-#include "io/log.h"
-#include "mem/memory.h"
-#include "mem/zone.h"
-#include "boot/cmdline.h"
-#include "ird/initrd.h"
-#include "usr/tasking.h"
-#include "usr/umode.h"
-#include "lib/jove.h"
+#include "device/serial.h"
+#include "arch/processor.h"
+#include "arch/cpu.h"
+#include "memory.h"
+#include "commandline.h"
+#include "tasking.h"
+#include "initrd.h"
+#include "print.h"
+/**Setup datastructures and other fields required for the execution manager
+ * and interfaces used by init.*/
void
kernel_main(void)
{
serial_setup();
- arch_tables_setup();
- mem_setup();
+ cpu_setup();
+ processor_setup(proc_bsp);
- cmdline_kernel_setup();
- initrd_setup();
+ mm_setup_early();
+ mm_setup();
tasking_setup();
- umode_setup();
+ kpanic("Reached end of kernel_main\n");
+}
+
+/**Kernel execution context that sets up init.*/
+void
+kernel_stage2(void)
+{
+ cmdline_kernel_setup();
+
+ initrd_setup();
- kpanic("Reached end of kernel main\n");
+ extern void kinit(void);
+ kinit();
}
diff --git a/mem/memory.c b/mem/memory.c
deleted file mode 100644
index 26bbbd8..0000000
--- a/mem/memory.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "memory.h"
-#include "zone.h"
-
-void
-mem_setup(void)
-{
- mem_zone_setup_standard();
- mem_paging_setup();
- mem_slab_setup();
-}
diff --git a/mem/memory.h b/mem/memory.h
deleted file mode 100644
index 251c6f5..0000000
--- a/mem/memory.h
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef JOVE_MEM_H
-#define JOVE_MEM_H 1
-
-#define PAGE_SHIFT 12
-#define PAGE_SIZE (1 << PAGE_SHIFT)
-#define PAGE_MASK (PAGE_SIZE - 1)
-
-#define KiB 1024ULL
-#define MiB (KiB * KiB)
-#define GiB (MiB * KiB)
-#define TiB (GiB * KiB)
-
-#include "lib/spinlock.h"
-#include "sys/types.h"
-
-typedef struct page_directory
-{
- spinlock_t lock;
- size_t id;
- size_t ref;
- physptr_t phys;
- void *virt;
-} page_directory_t;
-
-#include "slab.h"
-
-extern page_directory_t *current_page_directory;
-
-/**Setup the kernel structures responsible for handling physical memory translation.*/
-void mem_paging_setup(void);
-
-/**Check if a given pointer is valid.
- * @param ptr pointer to check.
- * @return if the pointer is valid.*/
-bool mem_check_ptr(const void *ptr);
-
-/** Return the physical memory mapping for the given address.
- * @param pd page directory to get mapping in.
- * @param addr address to get mapping for.
- * @return HAL compliant page mapping.*/
-page_mapping_t mem_get_mapping_as(page_directory_t *pd, uintptr_t addr);
-
-/** Return the physical memory mapping for the given address.
- * @param addr address to get mapping for.
- * @return HAL compliant page mapping.*/
-page_mapping_t mem_get_mapping(uintptr_t addr);
-
-/** Map a page mapping to a given virtual address.
- * @param pd pointer to the page directory to edit.
- * @param mapping mapping to apply.
- * @param virt virtual address to map to. */
-void mem_set_mapping_as(page_directory_t *pd, page_mapping_t mapping, uintptr_t virt);
-
-/** Map a page mapping to a given virtual address.
- * @param pd pointer to the page directory to edit.
- * @param mapping mapping to apply.
- * @param virt virtual address to map to. */
-void mem_set_mapping(page_mapping_t mapping, uintptr_t virt);
-
-/** Make sure the range indicated is available in memory for specified pd
- * If necessary, allocate new pages using the passed flags
- * @param pd pointer to page directory to edit
- * @param from start of the range
- * @param to end of the range
- * @param rw flag to mark page is writeable
- * @param user flag to mark page as user accessable*/
-void mem_ensure_range_as(page_directory_t *pd, uintptr_t from, uintptr_t to, page_flags_t flg);
-
-/**Make sure the range indicated is available in memory
- * If necessary, allocate new pages using the passed flags
- * @param from start of the range.
- * @param to end of the range.
- * @param rw flag to mark page is writeable.
- * @param user flag to mark page as user accessable*/
-void mem_ensure_range(uintptr_t from, uintptr_t to, page_flags_t flg);
-
-void mem_slab_setup(void);
-void mem_slabcache_new(struct SlabCache *cache, char *name, size_t objsize);
-
-void* mem_slab_alloc(struct SlabCache *cache);
-void mem_slab_free(struct SlabCache *cache, void *ptr);
-
-void* mem_alloc(size_t width);
-void mem_free(void *ptr);
-
-/*Physical*/
-
-physptr_t mem_phys_alloc(size_t pages);
-void mem_phys_reserve(physptr_t start, physptr_t end);
-void mem_phys_release(physptr_t start, physptr_t end);
-
-void mem_setup(void);
-
-#endif
diff --git a/mem/phys.c b/mem/phys.c
deleted file mode 100644
index bf56b77..0000000
--- a/mem/phys.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "memory.h"
-#include "zone.h"
-#include "lib/jove.h"
-
-void
-mem_phys_reserve(physptr_t start, physptr_t end)
-{
- size_t zone = mem_zone_for(start);
- size_t limit = mem_zone_bound_upper(zone);
-
- if(end > limit) {
- mem_phys_reserve(limit, end);
- end = limit;
- }
- mem_zone_resv(MEM_ZONE_STANDARD, start, end);
-}
-
-void
-mem_phys_release(physptr_t start, physptr_t end)
-{
- size_t zone = mem_zone_for(start);
- size_t limit = mem_zone_bound_upper(zone);
-
- if(end > limit) {
- mem_phys_release(limit, end);
- end = limit;
- }
- mem_zone_free(MEM_ZONE_STANDARD, start, end);
-}
-
-physptr_t
-mem_phys_alloc(size_t pages)
-{
- if(mem_zone_pages_free(MEM_ZONE_HIGHER) >= pages)
- return mem_zone_alloc(MEM_ZONE_HIGHER, pages);
- if(mem_zone_pages_free(MEM_ZONE_STANDARD) >= pages)
- return mem_zone_alloc(MEM_ZONE_STANDARD, pages);
- kpanic("Kernel ran out of physical memory!\n");
-}
diff --git a/mem/slab.h b/mem/slab.h
deleted file mode 100644
index 074d278..0000000
--- a/mem/slab.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef JOVE_MEMORY_SLAB_H
-#define JOVE_MEMORY_SLAB_H 1
-
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-
-#define SLABCACHE_NAME_LIMIT 32
-struct SlabCache
-{
- char name[SLABCACHE_NAME_LIMIT];
-
- struct SlabDescriptor *list_free;
- struct SlabDescriptor *list_partial;
- struct SlabDescriptor *list_full;
-
- size_t obj_size;
- size_t slab_pages;
-};
-
-struct SlabDescriptor
-{
- struct SlabDescriptor *prev;
- struct SlabDescriptor *next;
- void *slab_base;
- void *obj_base;
-
- size_t free_count;
- int free_index;
- uintptr_t free[];
-};
-
-#endif
diff --git a/mem/zone.h b/mem/zone.h
deleted file mode 100644
index c0b0f52..0000000
--- a/mem/zone.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef JOVE_MEM_ZONE_H
-#define JOVE_MEM_ZONE_H 1
-
-#include <stdint.h>
-#include "lib/buddymap.h"
-
-enum {
- MEM_ZONE_STANDARD = 0, /* First GiB of physical memory. */
- MEM_ZONE_HIGHER,
- MEM_ZONE_COUNT
-};
-
-#define MEM_ZONE_STANDARD_BASE 0
-#define MEM_ZONE_STANDARD_LIMIT (1 * GiB)
-#define MEM_ZONE_HIGHER_BASE MEM_ZONE_STANDARD_LIMIT
-
-#define MEM_BUDDY_ORDERS 12
-struct PhysicalMemoryZone
-{
- const char *name;
-
- uintptr_t base;
- uintptr_t limit;
-
- struct BuddyMap freemap;
-};
-
-/**Return the zone index for the given address
- * @param addr address to look up
- * @return zone index*/
-int mem_zone_for(uintptr_t addr);
-
-/**Return the lower bound for the given zone index.
- * @param zone index into zones.
- * @return lower bound.*/
-uintptr_t mem_zone_bound_lower(size_t zone);
-
-/**Return the upper bound for the given zone index.
- * @param zone index into zones.
- * @return upper bound.*/
-uintptr_t mem_zone_bound_upper(size_t zone);
-
-/**Return the number of pages free in the given zone.
- * @param zone index into zones.
- * @return number of free pages.*/
-size_t mem_zone_pages_free(size_t zone);
-
-/** Using a given zone, reserve a range of physical addresses
- * @param zone identifier of zone to modify
- * @param base starting address to reserve
- * @param limit ending address to reserve
- * @return error code or 0 if success */
-int mem_zone_resv(size_t zone, uintptr_t base, uintptr_t limit);
-
-/** Using a given zone, free a range of physical addresses
- * @param zone identifier of zone to modify
- * @param base starting address to free
- * @param limit ending address to free
- * @return error code or 0 if success*/
-int mem_zone_free(size_t zone, uintptr_t base, uintptr_t limit);
-
-/** Allocate a number of pages from the given zone
- * @param zone identifier of the zone to modify
- * @param pages number of pages to allocate
- * @return physical memory address of allocation
- * zero if allocation failed*/
-uintptr_t mem_zone_alloc(size_t zone, size_t pages);
-
-void mem_zone_setup_standard(void);
-
-#endif
diff --git a/memory/alloc/calloc.c b/memory/alloc/calloc.c
new file mode 100644
index 0000000..cd272af
--- /dev/null
+++ b/memory/alloc/calloc.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) Jon Santmyer.
+ * This source file is released under the LGPL Version 3 as detailed in
+ * the LICENSE file provided in the following repository:
+ * https://git.jonsantmyer.com/heap/
+ * */
+
+#include "malloc.h"
+#include <string.h>
+
+void*
+__calloc_impl(heap_cache_t *cache, size_t nmemb, size_t w)
+{
+ w = REALW(w);
+ void *ptr = __malloc_impl(cache, w * nmemb);
+ if(ptr == NULL) return NULL;
+
+ /* Zero newly allocated memory as per spec.*/
+ memset(ptr, 0, w * nmemb);
+ return ptr;
+}
diff --git a/memory/alloc/free.c b/memory/alloc/free.c
new file mode 100644
index 0000000..e2cc060
--- /dev/null
+++ b/memory/alloc/free.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) Jon Santmyer.
+ * This source file is released under the LGPL Version 3 as detailed in
+ * the LICENSE file provided in the following repository:
+ * https://git.jonsantmyer.com/heap/
+ * */
+
+#include "malloc.h"
+#include "assert.h"
+
+bucket_t*
+__bucket_from_obj(heap_cache_t *cache, bucket_obj_t *obj)
+{
+ assert(cache != NULL);
+ assert(cache->head != NULL);
+ /* Buckets are always aligned to the nearest page boundary, and that the
+ * metadata is always below the object. We use this fact to quickly find
+ * owning buckets.*/
+ uintptr_t objptr = (uintptr_t)obj;
+ uintptr_t bktptr = objptr & ~0xFFF;
+ while(1) {
+ /* If the page boundary is below the head, we are below the heap memory
+ * region and can stop.*/
+ if(bktptr < (uintptr_t)cache->head) return NULL;
+
+ /* At each page boundary below the object, check for the heap checksum.
+ * If it is found, we can assume that we found a bucket.*/
+ bucket_t *bucket = (bucket_t*)bktptr;
+ if(OBJ_VALID(bucket)) {
+ if(bucket->limit > objptr) return NULL;
+ return bucket;
+ }
+
+ bktptr -= BUCKET_ALIGN;
+ }
+}
+
+void
+__free_impl(heap_cache_t *cache, void *ptr)
+{
+ DBGPRINT("free: asking to free ptr %p\n", ptr);
+ assert(cache != NULL);
+ /* free(NULL) does nothing.*/
+ if(ptr == NULL) return;
+
+ /* Make sure the pointer actually comes from the heap.*/
+ assert((uintptr_t)ptr < (uintptr_t)cache->tail);
+ assert((uintptr_t)ptr > (uintptr_t)cache->head);
+ bucket_obj_t *obj = OBJ_FROM_PTR(ptr);
+ assert(OBJ_VALID(obj));
+
+ /* Mask the taken bit in the object to mark it free.*/
+ DBGPRINT("free: masking taken bit in object %p (was %i, now ",
+ obj, obj->size_taken);
+ obj->size_taken &= ~1;
+ DBGPRINT("%i)\n", obj->size_taken);
+
+ /* If the buckets' lastfree is greater than this new free object, this
+ * object will be the lastfree.*/
+ bucket_t *bucket = __bucket_from_obj(cache, obj);
+ if(bucket != NULL && bucket->firstfree > obj)
+ bucket->firstfree = obj;
+
+ /* Start trying to merge this free object with the next object.
+ * If the object after is taken, do nothing.*/
+ bucket_obj_t *after = OBJ_AFTER(obj);
+ if((uintptr_t)after > bucket->limit) return;
+ assert(OBJ_VALID(after));
+ if(OBJ_TAKEN(after)) return;
+
+ /* Merge with the next object.
+ * from:
+ * [meta| -objw-][meta| -afterw-]
+ * to:
+ * [meta| ---------objw---------]*/
+ DBGPRINT("free: obj %p merging with adjacent free object %p (was %i, now \n",
+ obj, after, obj->size_taken);
+ obj->size_taken += sizeof(bucket_obj_t) + after->size_taken;
+ DBGPRINT("%i)\n", obj->size_taken);
+}
diff --git a/memory/alloc/malloc.c b/memory/alloc/malloc.c
new file mode 100644
index 0000000..ba1e2d2
--- /dev/null
+++ b/memory/alloc/malloc.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) Jon Santmyer.
+ * This source file is released under the LGPL Version 3 as detailed in
+ * the LICENSE file provided in the following repository:
+ * https://git.jonsantmyer.com/heap/
+ * */
+
+#include "malloc.h"
+#include "assert.h"
+#include "jove.h"
+#include "memory/bump.h"
+
+/**Allocate memory for a new bucket in the heap.
+ * Automatically aligns new memory to BUCKET_ALIGN.
+ * Instantiates a new free object spanning the entire bucket.
+ * Then adds the new bucket to the heap cache.
+ * If sbrk encounters an error, pass through errno and return NULL.
+ * @param cache to allocate for.
+ * @param objw width of the object the bucket is assumed to hold.
+ * @return bucket created by this function.*/
+bucket_t*
+s_bucket_new(heap_cache_t *cache, size_t objw)
+{
+ DBGPRINT("malloc: ask for new bucket for cache %p with objw %i\n", cache, objw);
+ size_t bucketw = BUCKET_WIDTH(objw);
+ /* Assuming sbrk allocates memory for after the program break, make sure
+ * we allocate enough for the requested bucket width and any adjustments
+ * to ensure page alignment.*/
+ uintptr_t pbrk = (uintptr_t)bump_where();
+ uintptr_t brko = pbrk % BUCKET_ALIGN;
+ uintptr_t nbrk = (uintptr_t)bump_alloc(bucketw + brko);
+
+ bucket_t *bucket = (bucket_t*)(nbrk + brko);
+ DBGPRINT("malloc: got new bucket at %p\n", bucket);
+
+ *bucket = (bucket_t){
+ .checksum = OBJ_CHECKSUM,
+ .next = NULL,
+ .limit = (uintptr_t)bucket + bucketw,
+ };
+ /* Create a new object spanning the entire bucket. This new object will
+ * be the first free.*/
+ bucket_obj_t *obj0 = (bucket_obj_t*)bucket->objs;
+ *obj0 = (bucket_obj_t) {
+ .checksum = OBJ_CHECKSUM,
+ .size_taken = bucketw - sizeof(bucket_t) - sizeof(bucket_obj_t)
+ };
+ bucket->firstfree = obj0;
+
+ /* If the cache is empty, this will be the first and last bucket.*/
+ if(cache->head == NULL) {
+ cache->head = cache->tail = bucket;
+ return bucket;
+ }
+ /* Add the bucket to the heap cache bucket list.*/
+ cache->tail->next = bucket;
+ cache->tail = bucket;
+ return bucket;
+}
+
+/**Given an existing object and a size, split the object so that the original
+ * has size w.
+ * If the object is smaller than or is already the correct size, do nothing.
+ * Space after the split is allocated to a new free object after the resized
+ * original.
+ * If the original == bucket->firstfree, the new object is assigned to
+ * that variable.
+ * If the heap is corrupted, assert fail.
+ * @param bucket object's parent bucket.
+ * @param parent object to split.
+ * @param w requested size for original object. */
+void
+s_obj_take_split(bucket_t *bucket, bucket_obj_t *parent, size_t w)
+{
+ DBGPRINT("malloc: requesting to split object %p (last %p) for size %i (was %i)\n",
+ bucket, parent, w, parent->size_taken);
+
+ /* Assert fail on corrupted heap.*/
+ assert(OBJ_VALID(bucket));
+ assert(OBJ_VALID(parent));
+ assert(w >= OBJ_SIZE_MIN);
+
+ size_t objw = OBJ_WIDTH(parent);
+ if(w == objw) { /* Obj is already correct size, take and ignore.*/
+ if(bucket->firstfree == parent)
+ bucket->firstfree = OBJ_AFTER(parent);
+ /* Ensure that firstfree does not exceed bucket limits.*/
+ if((uintptr_t)bucket->firstfree > bucket->limit)
+ bucket->firstfree = NULL;
+ DBGPRINT("malloc: Object is already right size, ignoring\n");
+
+ /* Mark object as taken.*/
+ parent->size_taken = w | 1;
+ return;
+ }
+ /* New object created by split will be the original width minus the new
+ * width and metadata size.
+ *
+ * from:
+ * [meta| --------objw-------- ]
+ *
+ * to:
+ * [meta| -w- ][meta| -afterw- ]*/
+ size_t afterw = objw - sizeof(bucket_obj_t) - w;
+
+ parent->size_taken = w | 1;
+ bucket_obj_t *obj = OBJ_AFTER(parent);
+ DBGPRINT("malloc: New object created inplace at %p with size %i\n",
+ obj, afterw);
+
+ /* In-place allocate after obj.*/
+ *obj = (bucket_obj_t){
+ .checksum = OBJ_CHECKSUM,
+ .size_taken = afterw,
+ };
+ if(bucket->firstfree == parent)
+ bucket->firstfree = obj;
+}
+
+/* Look for a free object in the given bucket that closest matches size w.
+ * Uses bucket->firstfree as a starting point to save checks against taken
+ * objects.
+ * If the heap is corrupted, assert fail.
+ * If there are no good objects in this bucket, return NULL.
+ * @param bucket to search in.
+ * @param w to search for.
+ * @return best-fitting object or NULL if none are found.
+ * */
+bucket_obj_t*
+s_obj_bestfit(bucket_t *bucket, size_t w)
+{
+ assert(bucket != NULL);
+ assert(OBJ_VALID(bucket));
+
+ bucket_obj_t *best = NULL;
+ bucket_obj_t *obj = bucket->firstfree;
+ if(obj == NULL) return NULL;
+ for(; (uintptr_t)obj < bucket->limit; obj = OBJ_AFTER(obj))
+ {
+ assert(OBJ_VALID(obj));
+ if(OBJ_TAKEN(obj)) continue;
+ size_t objw = OBJ_WIDTH(obj);
+ if(objw < w) continue;
+ if(best == NULL) best = obj;
+
+ size_t bestw = OBJ_WIDTH(best);
+ if(objw < bestw) best = obj;
+ }
+
+ DBGPRINT("malloc: Bucket %p returns best fit at %p for size %i ",
+ bucket, best, w);
+ if(best != NULL) { DBGPRINT("(size %i)\n", best->size_taken); }
+ else { DBGPRINT("(is NULL)\n"); }
+
+ return best;
+}
+
+/**Searching through the entire heap, or until an object is found, find a
+ * free object that best fits the requested width and place the resulting
+ * bucket in the passed pointer.
+ * If the heap is corrupted, assert fail.
+ * If no object is found in any of the buckets, return NULL.
+ * @param cache heap to search through.
+ * @param w object width to search for.
+ * @param bucket pointer to bucket pointer owning the returned bucket.
+ * If no object is found, variable is untouched.
+ * @return object that fits the given width.*/
+bucket_obj_t*
+s_bucket_bestfit(heap_cache_t *cache, size_t w, bucket_t **bucket)
+{
+ *bucket = cache->head;
+ for(; *bucket != NULL; *bucket = (*bucket)->next)
+ {
+ bucket_obj_t *obj = s_obj_bestfit(*bucket, w);
+ /* Object is already found, don't waste cycles searching through
+ * the entire heap.*/
+ if(obj != NULL) return obj;
+ }
+ return NULL;
+}
+
+void*
+__malloc_impl(heap_cache_t *cache, size_t w)
+{
+ assert(cache != NULL);
+ /* w == 0 is ub, just return NULL.*/
+ if(w == 0) return NULL;
+ /* Ensure that w is valid.*/
+ w = REALW(w);
+
+ DBGPRINT("malloc: Asking to malloc for size %i\n", w);
+
+ bucket_t *bucket = NULL;
+ bucket_obj_t *obj = s_bucket_bestfit(cache, w, &bucket);
+ if(obj == NULL) {
+ /* No bucket in the heap has an appropriate space.
+ * Allocate a new bucket and take the first object.
+ * If the bucket allocation fails, return -1 and pass errno through.*/
+ bucket = s_bucket_new(cache, w);
+ if(bucket == NULL) return (void*)(-1);
+ obj = (bucket_obj_t*)bucket->objs;
+ }
+ /* Split the bucket to make the object bestfit.*/
+ s_obj_take_split(bucket, obj, w);
+ return obj->data;
+}
diff --git a/memory/alloc/malloc.h b/memory/alloc/malloc.h
new file mode 100644
index 0000000..abe87ff
--- /dev/null
+++ b/memory/alloc/malloc.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) Jon Santmyer.
+ * This source file is released under the LGPL Version 3 as detailed in
+ * the LICENSE file provided in the following repository:
+ * https://git.jonsantmyer.com/heap/
+ * */
+
+#ifndef _MALLOC_H
+#define _MALLOC_H 1
+
+/* A bucket-based malloc implementation for 2^n sized objects.
+ * Allocates memory at pbrk for use in dynamic allocations, called "objects".
+ * Each object is pre-empted by metadata, which stores a checksum, the width,
+ * and a bit to mark it as taken.
+ *
+ * Each alloc-able region is pre-empted by a "bucket", which stores metadata
+ * about the bucket's state, the width, the first free object, and the next
+ * bucket in the chain.
+ *
+ * Buckets are allocated when needed. The width of the new bucket is determined
+ * by the object that needs the bucket.
+ * Buckets are always page aligned, and the size is a multiple of a page width.
+ *
+ * Dependencies:
+ * stddef.h
+ * stdint.h
+ * errno.h
+ * assert.h
+ * assert
+ * string.h
+ * memset
+ * memcpy
+ * unistd.h
+ * sbrk
+ * brk
+ *
+ * with MALLOC_DBG:
+ * stdio.h
+ * printf*/
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define DBGPRINT(...)
+#ifdef MALLOC_DBG
+#include "io/log.h"
+#undef DBGPRINT
+#define DBGPRINT(...) klogf(__VA_ARGS__)
+#endif
+
+/* Bucket checksum is a 64-bit value containing the string "BUCKET\0\0"*/
+#define OBJ_CHECKSUM \
+ (((uintmax_t)'B') | \
+ ((uintmax_t)'U' << 8) | \
+ ((uintmax_t)'C' << 16) | \
+ ((uintmax_t)'K' << 24) | \
+ ((uintmax_t)'E' << 32) | \
+ ((uintmax_t)'T' << 40))
+
+/* For an object to be valid, the object must have the correct checksum.*/
+#define OBJ_VALID(obj) (obj->checksum == OBJ_CHECKSUM)
+
+/* Object width is assumed to be a multiple of two. The first bit is reserved
+ * for the taken flag.*/
+#define OBJ_WIDTH(obj) (obj->size_taken & ~1)
+#define OBJ_TAKEN(obj) (obj->size_taken & 1)
+
+/* Gets the object struct after this object.
+ * Since objects are allocated in-place, we can get the next object using
+ * the object's size and it's pointer to the start of data.
+ *
+ * The same is true for getting the metadata for any given data pointer.
+ * We take the pointer and subtract the size of the object struct from it
+ * since the metadata is behind the actual data.*/
+#define OBJ_AFTER(obj) \
+ ((bucket_obj_t*)(((uintptr_t)obj->data) + OBJ_WIDTH(obj)))
+#define OBJ_FROM_PTR(ptr) ((bucket_obj_t*)((uintptr_t)ptr - sizeof(bucket_obj_t)));
+
+typedef struct bucket_obj
+{
+ uintmax_t checksum;
+ size_t size_taken;
+ char data[];
+} bucket_obj_t;
+
+#define LOG2(n) ((31) - __builtin_clz(n))
+/* Buckets are always aligned to the page boundary for cache friendliness.*/
+#define BUCKET_ALIGN (4096)
+/* Buckets should always be a multiple of the page width, expanding with the
+ * initial object size.*/
+#define BUCKET_WIDTH(w) \
+ (1UL << (12 + (w < BUCKET_ALIGN ? 0 : LOG2(w + 1) - 11)))
+
+/* Bucket metadata is stored behind the object metadata.*/
+typedef struct bucket
+{
+ size_t checksum;
+ struct bucket *next;
+
+ uintptr_t limit;
+ bucket_obj_t *firstfree; /* Helpful for fast object allocations.*/
+ char objs[];
+} bucket_t;
+
+/* The overall size of an object (data + metadata) should be 2*metadata.*/
+#define OBJ_SIZE_MIN (sizeof(bucket_obj_t))
+/* Data width is always a power of two.*/
+#define REALW(n) \
+ (n < OBJ_SIZE_MIN ? OBJ_SIZE_MIN : (1UL << (LOG2(n) + 1)))
+
+typedef struct heap_cache
+{
+ bucket_t *head;
+ bucket_t *tail;
+} heap_cache_t;
+
+/**Given the heap cache and an object, find the bucket to which the object
+ * belongs.
+ * Since buckets are always page aligned, we can check each page boundary
+ * for the checksum until we find it, then check the limit.
+ * Since we also know the first bucket in the cache, we can also check if the
+ * passed object is invalid and return NULL.
+ * @param heap cache.
+ * @param obj to find the bucket for.
+ * @return bucket owning obj, or NULL if obj is invalid.*/
+bucket_t *__bucket_from_obj(heap_cache_t *heap, bucket_obj_t *obj);
+
+/**Allocate w bytes into the given heap.
+ * If w == 0, returns NULL.
+ * If w is not a power of 2, rounds to the nearest pow2.
+ * If the heap is corrupted, assert fail.
+ * If the program is OOM, errno is assumed to be set and returns (void*)-1
+ * @param heap cache.
+ * @param w n-bytes to allocate.
+ * @return pointer to allocated memory.*/
+void* __malloc_impl(heap_cache_t *heap, size_t w);
+
+/**Allocate a contiguous array of nmemb members each w wide.
+ * Newly allocated memory is zero'd.
+ * If w == 0 || nmemb == 0, returns NULL
+ * If w is not a power of 2, rounds to nearest pow2
+ * If the heap is corrupted, assert fail
+ * If the program is OON, ernno is assumed to be set and returns (void*)-1
+ * @param heap cache.
+ * @param nmemb number of members.
+ * @param w number of bytes per member.
+ * @return pointer to allocated memory.*/
+void* __calloc_impl(heap_cache_t *heap, size_t nmemb, size_t w);
+
+/**Resize the given allocated memory region to fit w.
+ * If w is less than the original width, does nothing.
+ * If w == 0, frees p
+ * If the heap is corrupted, assert fail.
+ * If the heap is OOM, errno is assumed to be set and returns (void*)-1
+ * @param heap cache.
+ * @param p pointer to reallocate.
+ * @param w width to fit p to.
+ * @return pointer to memory allocated to fit w.*/
+void* __realloc_impl(heap_cache_t *heap, void *p, size_t w);
+
+/**Resize the given allocated contiguous array to fit nmemb members of w width
+ * objects.
+ * Zeros the new members excluding already existing data.
+ * If w * nmemb is less than the original width, does nothing.
+ * If w == 0 || nmemb == 0, frees p
+ * If the heap is corrupted, assert fail.
+ * If the heap is OOM, errno is assumed to be set and returns (void*)-1
+ * @param heap cache.
+ * @param p pointer to reallocate.
+ * @param nmemb number of members.
+ * @param w width to fit p to.
+ * @return pointer to memory allocated to fit w * nmemb.*/
+void* __reallocarray_impl(heap_cache_t *heap, void *p, size_t nmemb, size_t w);
+
+/**Free a pointer in the given heap.
+ * If p == NULL, do nothing.
+ * If p does not fall in the range of heap, assert fail.
+ * If the heap is corrupted, assert fail.
+ * @param heap cache.
+ * @param p pointer to free.*/
+void __free_impl(heap_cache_t *heap, void *p);
+
+#endif
diff --git a/memory/alloc/realloc.c b/memory/alloc/realloc.c
new file mode 100644
index 0000000..1b90e8c
--- /dev/null
+++ b/memory/alloc/realloc.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) Jon Santmyer.
+ * This source file is released under the LGPL Version 3 as detailed in
+ * the LICENSE file provided in the following repository:
+ * https://git.jonsantmyer.com/heap/
+ * */
+
+#include "malloc.h"
+#include "assert.h"
+#include "string.h"
+
+void*
+__realloc_impl(heap_cache_t *cache, void *ptr, size_t w)
+{
+ if(w == 0) {
+ DBGPRINT("realloc: called with w == 0, freeing %p\n", ptr);
+ __free_impl(cache, ptr);
+ return NULL;
+ }
+ if(ptr == NULL) {
+ DBGPRINT("realloc: called with NULL ptr, alloc %i\n", w);
+ return __malloc_impl(cache, w);
+ }
+
+ w = REALW(w);
+ bucket_obj_t *obj = OBJ_FROM_PTR(ptr);
+
+ assert(OBJ_VALID(obj));
+ size_t objw = OBJ_WIDTH(obj);
+ if(objw > w) return ptr;
+
+ size_t wdiff = w - objw;
+ DBGPRINT("realloc: ptr %p needs %i new bytes\n", ptr, wdiff);
+
+ bucket_obj_t *after = OBJ_AFTER(obj);
+ size_t afterw = 0;
+ bucket_t *bucket = __bucket_from_obj(cache, obj);
+ void *newptr = NULL;
+
+ if(bucket == NULL)
+ goto resize_fail;
+
+ if((uintptr_t)after > bucket->limit) goto resize_fail;
+ assert(OBJ_VALID(after));
+ afterw = OBJ_WIDTH(after);
+
+ if(OBJ_TAKEN(after))
+ goto resize_fail;
+
+ DBGPRINT("realloc: obj %p after obj %p is free (w %i)\n", after, obj, afterw);
+ if(objw + sizeof(bucket_obj_t) + afterw < w)
+ goto resize_fail;
+
+ obj->size_taken = w | 1;
+ if(bucket->firstfree == after)
+ bucket->firstfree = OBJ_AFTER(obj);
+
+ after = OBJ_AFTER(obj);
+ *after = (bucket_obj_t){
+ .checksum = OBJ_CHECKSUM,
+ .size_taken = afterw - wdiff
+ };
+ DBGPRINT("realloc: moved obj %p (%i) to resize obj %p (%i)\n",
+ after, after->size_taken, obj, obj->size_taken);
+ return ptr;
+
+resize_fail:
+ DBGPRINT("realloc: could not resize existing object, calling malloc\n");
+ newptr = __malloc_impl(cache, w);
+ memcpy(newptr, ptr, obj->size_taken & ~1);
+ __free_impl(cache, ptr);
+ return newptr;
+}
diff --git a/memory/alloc/reallocarray.c b/memory/alloc/reallocarray.c
new file mode 100644
index 0000000..c58dfe9
--- /dev/null
+++ b/memory/alloc/reallocarray.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) Jon Santmyer.
+ * This source file is released under the LGPL Version 3 as detailed in
+ * the LICENSE file provided in the following repository:
+ * https://git.jonsantmyer.com/heap/
+ * */
+
+#include "malloc.h"
+#include "assert.h"
+#include "string.h"
+
+void*
+__reallocarray_impl(heap_cache_t *cache, void *ptr, size_t nmemb, size_t w)
+{
+ /* Free if w == nmemb == 0*/
+ if(w == 0 || nmemb == 0) {
+ __free_impl(cache, ptr);
+ return NULL;
+ }
+
+ if(ptr == NULL)
+ return __calloc_impl(cache, nmemb, w);
+
+ size_t allocw = w * nmemb;
+ w = REALW(w);
+
+ bucket_obj_t *obj = OBJ_FROM_PTR(ptr);
+ assert(OBJ_VALID(obj));
+ size_t oldw = OBJ_WIDTH(obj);
+ if(allocw < oldw) return ptr;
+
+ ptr = __realloc_impl(cache, ptr, allocw);
+ size_t wdiff = allocw - oldw;
+ void *zeroat = (void*)(((uintptr_t)ptr) + oldw);
+ memset(zeroat, 0, wdiff);
+ return ptr;
+}
diff --git a/memory/bump.c b/memory/bump.c
new file mode 100644
index 0000000..a6b0228
--- /dev/null
+++ b/memory/bump.c
@@ -0,0 +1,33 @@
+#include "bump.h"
+#include "memory.h"
+
+static void *s_next_free;
+
+void*
+bump_where(void)
+{
+ return s_next_free;
+}
+
+void *bump_alloc(size_t size)
+{
+ void *ret = s_next_free;
+ s_next_free = (void*)((uintptr_t)s_next_free + size);
+ vm_ensure(
+ (uintptr_t)ret,
+ (uintptr_t)s_next_free,
+ (page_flags_t) {
+ .present = true,
+ .writeable = true,
+ .useraccess = false,
+ .executable = false
+ });
+ return ret;
+}
+
+void
+bump_setup(void)
+{
+ extern void *_kernel_end;
+ s_next_free = (void*)&_kernel_end;
+}
diff --git a/memory/bump.h b/memory/bump.h
new file mode 100644
index 0000000..5b1c2b7
--- /dev/null
+++ b/memory/bump.h
@@ -0,0 +1,10 @@
+#ifndef JOVE_MEMORY_BUMP_H
+#define JOVE_MEMORY_BUMP_H 1
+
+#include <stddef.h>
+
+void *bump_where(void);
+void *bump_alloc(size_t size);
+void bump_setup(void);
+
+#endif
diff --git a/memory/memory.c b/memory/memory.c
new file mode 100644
index 0000000..2a0e8f2
--- /dev/null
+++ b/memory/memory.c
@@ -0,0 +1,39 @@
+#include "memory.h"
+#include "alloc/malloc.h"
+#include "zone.h"
+#include "bump.h"
+
+heap_cache_t heap_cache;
+
+void*
+kmalloc(size_t width)
+{
+ return __malloc_impl(&heap_cache, width);
+}
+
+void*
+krealloc(void *ptr, size_t width)
+{
+ return __realloc_impl(&heap_cache, ptr, width);
+}
+
+void
+kfree(void *ptr)
+{
+ __free_impl(&heap_cache, ptr);
+}
+
+void
+mm_setup_early(void)
+{
+ pm_zone_setup();
+ vm_setup_early();
+}
+
+void
+mm_setup(void)
+{
+ heap_cache = (heap_cache_t) { NULL, NULL };
+ bump_setup();
+ vm_setup();
+}
diff --git a/memory/phys.c b/memory/phys.c
new file mode 100644
index 0000000..4d9dbc1
--- /dev/null
+++ b/memory/phys.c
@@ -0,0 +1,39 @@
+#include "memory.h"
+#include "zone.h"
+#include "jove.h"
+
+void
+pm_reserve(physptr_t start, physptr_t end)
+{
+ size_t zone = pm_zone_for(start);
+ size_t limit = pm_zone_bound_upper(zone);
+
+ if(end > limit) {
+ pm_reserve(limit, end);
+ end = limit;
+ }
+ pm_zone_resv(MEM_ZONE_STANDARD, start, end);
+}
+
+void
+pm_release(physptr_t start, physptr_t end)
+{
+ size_t zone = pm_zone_for(start);
+ size_t limit = pm_zone_bound_upper(zone);
+
+ if(end > limit) {
+ pm_release(limit, end);
+ end = limit;
+ }
+ pm_zone_free(MEM_ZONE_STANDARD, start, end);
+}
+
+physptr_t
+pm_alloc(size_t pages)
+{
+ if(pm_zone_pages_free(MEM_ZONE_HIGHER) >= pages)
+ return pm_zone_alloc(MEM_ZONE_HIGHER, pages);
+ if(pm_zone_pages_free(MEM_ZONE_STANDARD) >= pages)
+ return pm_zone_alloc(MEM_ZONE_STANDARD, pages);
+ kpanic("Kernel ran out of physical memory!\n");
+}
diff --git a/mem/slab.c b/memory/slab.c
index 30bc23a..dc8aeda 100644
--- a/mem/slab.c
+++ b/memory/slab.c
@@ -1,33 +1,10 @@
#include "slab.h"
+#include "bump.h"
#include "memory.h"
-#include "lib/format.h"
-#include "lib/string.h"
-#include "lib/jove.h"
-#include "io/log.h"
-
-extern void *_kernel_end;
-
-static uintptr_t s_addr_next_free;
-
-#define GENERIC_CACHEC 8
-static struct SlabCache s_generic_caches[GENERIC_CACHEC];
-
-static uintptr_t
-s_next_free(size_t width)
-{
- uintptr_t ret = s_addr_next_free;
- s_addr_next_free += width;
- mem_ensure_range(
- ret,
- s_addr_next_free,
- (page_flags_t) {
- .present = true,
- .writeable = true,
- .useraccess = false,
- .executable = false
- });
- return ret;
-}
+#include "string.h"
+#include "jove.h"
+#include "print.h"
+#include "klib/format.h"
static int
s_get_free_listw(size_t slabw, size_t objw)
@@ -41,27 +18,28 @@ s_get_free_listw(size_t slabw, size_t objw)
return freelistc;
}
-static struct SlabDescriptor
-*s_slab_new(struct SlabCache *cache, struct SlabDescriptor *last)
+static slab_t
+*s_slab_new(slab_cache_t *cache, slab_t *last)
{
size_t slab_width = (cache->slab_pages << PAGE_SHIFT);
- uintptr_t descr_base = s_next_free(slab_width);
- struct SlabDescriptor *descr = (struct SlabDescriptor*)descr_base;
+ uintptr_t descr_base = (uintptr_t)bump_alloc(slab_width);
+ slab_t *descr = (slab_t*)descr_base;
size_t free_listc = s_get_free_listw(
- slab_width - sizeof(struct SlabDescriptor),
+ slab_width - sizeof(slab_t),
cache->obj_size);
- size_t descriptor_width = sizeof(struct SlabDescriptor)
+ size_t descriptor_width = sizeof(slab_t)
+ (free_listc * sizeof(uintptr_t));
uintptr_t obj_base = descr_base + descriptor_width;
if(free_listc < 8) {
- free_listc = ((slab_width - sizeof(struct SlabDescriptor)) / cache->obj_size);
- descr = mem_alloc(sizeof(struct SlabDescriptor) + (free_listc * sizeof(uintptr_t)));
+ free_listc = ((slab_width - sizeof(slab_t)) / cache->obj_size);
+ descr = kmalloc(sizeof(slab_t) + (free_listc * sizeof(uintptr_t)));
obj_base = descr_base;
}
+ cache->obj_capacity += free_listc;
- *descr = (struct SlabDescriptor) {
+ *descr = (slab_t) {
.prev = last,
.next = (last == NULL ? NULL : last->next),
.slab_base = (void*)descr_base,
@@ -77,11 +55,11 @@ static struct SlabDescriptor
}
void
-mem_slabcache_new(struct SlabCache *cache, char *name, size_t objsize)
+slabcache_new(slab_cache_t *cache, char *name, size_t objsize)
{
if(objsize % 8 > 0) objsize += (8 - (objsize % 8));
size_t pages = objsize > 512 ? (objsize >> 9) : 1;
- *cache = (struct SlabCache){
+ *cache = (slab_cache_t){
.obj_size = objsize,
.slab_pages = pages,
.list_free = NULL,
@@ -97,10 +75,10 @@ mem_slabcache_new(struct SlabCache *cache, char *name, size_t objsize)
}
void*
-mem_slab_alloc(struct SlabCache *cache)
+slab_alloc(slab_cache_t *cache)
{
// Get a free slab
- struct SlabDescriptor *slab = NULL;
+ slab_t *slab = NULL;
if(cache->list_partial != NULL) slab = cache->list_partial;
if(slab == NULL && cache->list_free != NULL) {
slab = cache->list_free;
@@ -121,11 +99,11 @@ mem_slab_alloc(struct SlabCache *cache)
}
void
-mem_slab_free(struct SlabCache *cache, void *ptr)
+slab_free(slab_cache_t *cache, void *ptr)
{
uintptr_t addr = (uintptr_t)ptr;
//Look for the pointer in the bounds of every slab
- for(struct SlabDescriptor *slab = cache->list_full;
+ for(slab_t *slab = cache->list_full;
slab != NULL; slab = slab->next)
{
uintptr_t base = (uintptr_t)slab->obj_base;
@@ -145,7 +123,7 @@ mem_slab_free(struct SlabCache *cache, void *ptr)
cache->list_partial = slab;
return;
}
- for(struct SlabDescriptor *slab = cache->list_partial;
+ for(slab_t *slab = cache->list_partial;
slab != NULL; slab = slab->next)
{
uintptr_t base = (uintptr_t)slab->obj_base;
@@ -160,7 +138,7 @@ mem_slab_free(struct SlabCache *cache, void *ptr)
slab->free_index++;
slab->free[slab->free_index] = addr;
- if(slab->free_index == (slab->free_count - 1)) {
+ if(slab->free_index == ((int)slab->free_count - 1)) {
cache->list_partial = slab->next;
slab->next = cache->list_free;
cache->list_free = slab;
@@ -168,42 +146,3 @@ mem_slab_free(struct SlabCache *cache, void *ptr)
return;
}
}
-
-void*
-mem_alloc(size_t width)
-{
- size_t width_log2 = (__builtin_clz(width) ^ 31) + 1;
- if(width_log2 < 6) width_log2 = 6;
- width_log2 -= 6;
- if(width_log2 >= GENERIC_CACHEC) {
- klogf("Allocation size %i too big for generic caches!\n", width);
- return NULL;
- }
-
- struct SlabCache *generic_cache = &s_generic_caches[width_log2];
- return mem_slab_alloc(generic_cache);
-}
-
-void
-mem_free(void *ptr)
-{
- for(int i = 0; i < GENERIC_CACHEC; i++) {
- mem_slab_free(&s_generic_caches[i], ptr);
- }
-}
-
-void
-mem_slab_setup(void)
-{
- s_addr_next_free = (uintptr_t)&_kernel_end;
- s_addr_next_free = ((s_addr_next_free >> 12) + 1) << 12;
- s_get_free_listw(PAGE_SIZE - sizeof(struct SlabDescriptor), 32);
-
- for(int i = 0; i < GENERIC_CACHEC; i++)
- {
- size_t objsize = 1 << (i + 6);
- char slab_name[SLABCACHE_NAME_LIMIT];
- sfmt(slab_name, SLABCACHE_NAME_LIMIT, "generic_%i", 1 << (i + 6));
- mem_slabcache_new(&s_generic_caches[i], slab_name, objsize);
- }
-}
diff --git a/mem/zone.c b/memory/zone.c
index 42a056e..4201cee 100644
--- a/mem/zone.c
+++ b/memory/zone.c
@@ -1,10 +1,9 @@
#include "zone.h"
+#include "boot.h"
#include "memory.h"
-#include "boot/boot.h"
-#include "lib/string.h"
-#include "lib/jove.h"
-#include "sys/errno.h"
-#include "io/log.h"
+#include "jove.h"
+#include "string.h"
+#include "print.h"
#define MEM_ZONE_STANDARD_PAGES (MEM_ZONE_STANDARD_LIMIT >> PAGE_SHIFT)
@@ -37,7 +36,7 @@ static struct PhysicalMemoryZone s_zones[MEM_ZONE_COUNT] =
};
int
-mem_zone_for(uintptr_t addr)
+pm_zone_for(uintptr_t addr)
{
addr &= ~PAGE_MASK;
for(size_t zonei = 0; zonei < MEM_ZONE_COUNT; zonei++)
@@ -45,25 +44,25 @@ mem_zone_for(uintptr_t addr)
struct PhysicalMemoryZone *pmz = &s_zones[zonei];
if(addr >= pmz->base && addr < pmz->limit) return zonei;
}
- return -ENOTFOUND;
+ return -1;
}
uintptr_t
-mem_zone_bound_lower(size_t zone)
+pm_zone_bound_lower(size_t zone)
{
if(zone >= MEM_ZONE_COUNT) return 0;
return s_zones[zone].base;
}
uintptr_t
-mem_zone_bound_upper(size_t zone)
+pm_zone_bound_upper(size_t zone)
{
if(zone >= MEM_ZONE_COUNT) return 0;
return s_zones[zone].limit;
}
size_t
-mem_zone_pages_free(size_t zone)
+pm_zone_pages_free(size_t zone)
{
if(zone >= MEM_ZONE_COUNT) return 0;
return s_zones[zone].freemap.free;
@@ -82,9 +81,9 @@ _zone_free(struct PhysicalMemoryZone *zone, uintptr_t base, uintptr_t limit)
}
int
-mem_zone_resv(size_t zone, uintptr_t base, uintptr_t limit)
+pm_zone_resv(size_t zone, uintptr_t base, uintptr_t limit)
{
- if(zone >= MEM_ZONE_COUNT) return -EINVAL;
+ assert(zone < MEM_ZONE_COUNT);
size_t base_off = base % PAGE_SIZE;
@@ -95,9 +94,9 @@ mem_zone_resv(size_t zone, uintptr_t base, uintptr_t limit)
}
int
-mem_zone_free(size_t zone, uintptr_t base, uintptr_t limit)
+pm_zone_free(size_t zone, uintptr_t base, uintptr_t limit)
{
- if(zone >= MEM_ZONE_COUNT) return -EINVAL;
+ assert(zone < MEM_ZONE_COUNT);
size_t base_off = base % PAGE_SIZE;
@@ -108,7 +107,7 @@ mem_zone_free(size_t zone, uintptr_t base, uintptr_t limit)
}
uintptr_t
-mem_zone_alloc(size_t zone, size_t pages)
+pm_zone_alloc(size_t zone, size_t pages)
{
if(zone >= MEM_ZONE_COUNT) return 0;
@@ -122,7 +121,7 @@ mem_zone_alloc(size_t zone, size_t pages)
}
void
-mem_zone_setup_standard(void)
+pm_zone_setup(void)
{
struct PhysicalMemoryZone *standard_zone = &s_zones[MEM_ZONE_STANDARD];
uintmax_t *map_block_layer_base = s_zone_standard_freemap_blocks_flat;
@@ -135,12 +134,12 @@ mem_zone_setup_standard(void)
for(int i = 0; i < boot_memorymap.count; i++) {
struct MemoryMapEntry *entry = &boot_memorymap.entries[i];
- klogf("%2i\t%#016X -> %#016X (%i)\n",
+ kdbgf("%2i\t%#016X -> %#016X (%i)\n",
i, entry->base, entry->base + entry->length, entry->usable);
if(entry->base > MEM_ZONE_STANDARD_LIMIT) continue;
size_t limit = entry->base + entry->length;
if(limit > MEM_ZONE_STANDARD_LIMIT) limit = MEM_ZONE_STANDARD_LIMIT;
if(entry->usable)
- mem_zone_free(MEM_ZONE_STANDARD, entry->base, limit);
+ pm_zone_free(MEM_ZONE_STANDARD, entry->base, limit);
}
}
diff --git a/print.c b/print.c
new file mode 100644
index 0000000..dc5597b
--- /dev/null
+++ b/print.c
@@ -0,0 +1,40 @@
+#include "print.h"
+#include "jove.h"
+#include "string.h"
+#include "device/serial.h"
+#include "klib/format.h"
+#include "klib/spinlock.h"
+
+static spinlock_t s_print_lock;
+static char s_print_buffer[PRINT_BUFFERW];
+
+static char *s_print_level_str[PRINT_ERROR + 1] = {
+ "[D] %s/%s:%i | ",
+ "[I] ",
+ "[W] %s/%s:%i | ",
+ "[!!E!!] %s/%s:%i | "
+};
+
+void
+_plogvf(const char *file, const char *func, int line, int lvl, const char *fmt, va_list ap)
+{
+ spinlock_acquire(s_print_lock);
+
+ char *buf = sfmt(s_print_buffer, PRINT_BUFFERW, s_print_level_str[lvl],
+ file, func, line);
+ size_t prew = strlen(buf);
+
+ svfmt(&buf[prew], PRINT_BUFFERW - 128, fmt, ap);
+ serial_write(&COM1, buf, strlen(buf));
+
+ spinlock_release(s_print_lock);
+}
+
+void
+_plogf(const char *file, const char *func, int line, int lvl, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ _plogvf(file, func, line, lvl, fmt, ap);
+ va_end(ap);
+}
diff --git a/sys/errno.h b/sys/errno.h
deleted file mode 100644
index 8d0c980..0000000
--- a/sys/errno.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _SYS_ERRNO_H
-#define _SYS_ERRNO_H 1
-
-#define ENOPERM 1
-#define EFAULT 2
-#define EINVAL 3
-#define ENOSYS 4
-#define ENOTFOUND 5
-
-#endif
diff --git a/sys/permission.h b/sys/permission.h
deleted file mode 100644
index 08bb765..0000000
--- a/sys/permission.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _SYS_PERMISSION_H
-#define _SYS_PERMISSION_H 1
-
-#define PERM_MEM_PHYS_RESV 1 /* Reserve physical memory. */
-#define PERM_MEM_PHYS_FREE 2 /* Free physical memory. */
-#define PERM_MEM_PHYS_ALLOC 4 /* Allocate physical memory. */
-
-#define PERM_MEM_VIRT_PD 8 /* Work on any PD. */
-#define PERM_MEM_VIRT_MAP 0x10 /* Map physical memory to virtual memory. */
-
-#endif
diff --git a/sys/syscall.h b/sys/syscall.h
deleted file mode 100644
index d8b64bb..0000000
--- a/sys/syscall.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef _SYS_SYSCALL_H
-#define _SYS_SYSCALL_H 1
-
-#include <stdint.h>
-#include <stddef.h>
-#include "types.h"
-
-typedef struct syscall {
- int id;
-} syscall_t;
-
-struct syscall_log {
- syscall_t syscall;
- const char *message;
-};
-
-struct syscall_mem_phys_range_op {
- syscall_t syscall;
- uintptr_t base;
- uintptr_t limit;
-};
-
-struct syscall_mem_phys_alloc {
- syscall_t syscall;
- size_t npages;
- uintptr_t *result;
-};
-
-struct syscall_mem_virt_mapping {
- syscall_t syscall;
- linear_address_t addr;
- page_mapping_t *result;
-};
-
-struct syscall_mem_virt_map {
- syscall_t syscall;
- linear_address_t addr;
- page_mapping_t map;
-};
-
-struct syscall_mem_virt_alloc {
- syscall_t syscall;
- linear_address_t from;
- uintptr_t to;
- page_flags_t flg;
-};
-
-enum
-{
- SYSCALL_LOG = 0,
- SYSCALL_TID,
-
- SYSCALL_MEM_PHYS_RESV,
- SYSCALL_MEM_PHYS_FREE,
- SYSCALL_MEM_PHYS_ALLOC,
-
- SYSCALL_MEM_VIRT_MAPPING,
- SYSCALL_MEM_VIRT_MAP,
- SYSCALL_MEM_VIRT_ALLOC,
-
- SYSCALL_COUNT
-};
-
-#define _SYSCALL(data) \
- intmax_t ax; \
- __asm__ volatile("movq %0, %%rdi\nsyscall": "=a"(ax): "r"(data): "memory"); \
- return ax
-
-#endif
diff --git a/sys/types.h b/sys/types.h
deleted file mode 100644
index 0a519c5..0000000
--- a/sys/types.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _SYS_TYPES_H
-#define _SYS_TYPES_H 1
-
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-
-typedef intmax_t tid_t;
-
-typedef struct {
- intmax_t tid;
- uintmax_t addr;
-} linear_address_t;
-
-typedef uintptr_t physptr_t;
-
-typedef struct page_flags
-{
- bool present;
- bool writeable;
- bool useraccess;
- bool executable;
-} page_flags_t;
-
-typedef struct page_mapping
-{
- physptr_t phys;
- page_flags_t pf;
-} page_mapping_t;
-
-
-#endif
diff --git a/syscall/dbg_log.c b/syscall/dbg_log.c
new file mode 100644
index 0000000..9055498
--- /dev/null
+++ b/syscall/dbg_log.c
@@ -0,0 +1,19 @@
+#include "handler.h"
+#include "print.h"
+#include "umode_vma.h"
+#include "api/errno.h"
+
+int
+_handler_dbg_log(struct sc_dbg_log *u_sc)
+{
+ struct sc_dbg_log sc;
+ if(user_vma_read(&sc, u_sc, sizeof(struct sc_dbg_log)) != 0)
+ return -EFAIL;
+
+ char buf[sc.w];
+ if(user_vma_read(buf, sc.s, sc.w) != 0)
+ return -EFAIL;
+
+ klogf("%s", buf);
+ return 0;
+}
diff --git a/syscall/exit.c b/syscall/exit.c
new file mode 100644
index 0000000..307ea7a
--- /dev/null
+++ b/syscall/exit.c
@@ -0,0 +1,17 @@
+#include "api/syscall.h"
+#include "api/errno.h"
+#include "umode_vma.h"
+#include "arch/processor.h"
+#include "handler.h"
+
+int
+_handler_exit(struct sc_exit *sc)
+{
+ int exit_code = 0;
+ if(user_vma_read(&exit_code, &sc->exit_code, sizeof(int)) != 0)
+ return -EFAIL;
+
+ tcb_t *tcb = tcb_current();
+ tcb_kill(tcb, exit_code);
+ return 0;
+}
diff --git a/syscall/handler.c b/syscall/handler.c
new file mode 100644
index 0000000..5cafdc6
--- /dev/null
+++ b/syscall/handler.c
@@ -0,0 +1,23 @@
+#include "handler.h"
+#include "print.h"
+#include "umode_vma.h"
+#include "api/errno.h"
+
+static void *s_handlers[] = {
+ (void*)_handler_dbg_log,
+ (void*)_handler_exit
+};
+static size_t s_handlers_size = sizeof(s_handlers);
+
+int
+_syscall_handler(void *data)
+{
+ uintmax_t req_id = 0;
+ if(user_vma_read(&req_id, data, sizeof(uintmax_t)) != 0)
+ return -EFAIL;
+
+ if(req_id >= s_handlers_size) return -1;
+ int (*handle)(void*) = (int (*)(void*))s_handlers[req_id];
+ kdbgf("syscall id %i handle %p\n", req_id, handle);
+ return handle(data);
+}
diff --git a/syscall/handler.h b/syscall/handler.h
new file mode 100644
index 0000000..f746dcc
--- /dev/null
+++ b/syscall/handler.h
@@ -0,0 +1,19 @@
+#ifndef _JOVE_SYSCALL_HANDLER_H
+#define _JOVE_SYSCALL_HANDLER_H 1
+
+#include "api/syscall.h"
+#include "memory.h"
+
+int _syscall_handler(void *data);
+
+#define CHECKPTR(p) { \
+ page_mapping_t mapping = vm_mapping_get((uintptr_t)p); \
+ if(mapping.phys == 0 || /* Mapping must not map to NULL phys page. */ \
+ mapping.pf.present == 0 || /* Mapping must be present. */\
+ mapping.pf.useraccess == 0 /* Mapping must be useraccess. */) \
+ return -1; }
+
+int _handler_dbg_log(struct sc_dbg_log *sc);
+int _handler_exit(struct sc_exit *sc);
+
+#endif
diff --git a/task/exrtab.c b/task/exrtab.c
new file mode 100644
index 0000000..82b9e29
--- /dev/null
+++ b/task/exrtab.c
@@ -0,0 +1,19 @@
+#include "arch/processor.h"
+#include "assert.h"
+
+void
+_exrtab_push(void *v)
+{
+ processor_t *proc = processor_current();
+ proc->exrtab[proc->ert_i++] = (uintptr_t)v;
+}
+
+void*
+_exrtab_pop(void)
+{
+ processor_t *proc = processor_current();
+
+ assert(proc->ert_i != 0);
+ uintptr_t r = proc->exrtab[--proc->ert_i];
+ return (void*)r;
+}
diff --git a/task/init.c b/task/init.c
new file mode 100644
index 0000000..c4c8bad
--- /dev/null
+++ b/task/init.c
@@ -0,0 +1,22 @@
+#include "commandline.h"
+#include "jove.h"
+#include "initrd.h"
+#include "tasking.h"
+#include "arch/elf.h"
+
+__attribute__((noreturn)) void
+kinit(void)
+{
+ const char *init_filepath = cmdline_get("init");
+ if(init_filepath == NULL)
+ kpanic("init filepath not found in kernel commandline\n");
+
+ initrd_file_t *init_file = ird_getfile(init_filepath);
+ if(init_file == NULL)
+ kpanic("init file not found in initrd [filepath=\"%s\"]\n", init_filepath);
+
+ uintptr_t ip = elf_load(init_file->data, init_file->size);
+
+ kexec((void*)ip, 0, NULL, 0, NULL);
+ kpanic("Reached end of kinit\n");
+}
diff --git a/task/stack.c b/task/stack.c
new file mode 100644
index 0000000..396ab3e
--- /dev/null
+++ b/task/stack.c
@@ -0,0 +1,14 @@
+#include "tasking.h"
+#include "string.h"
+#include "assert.h"
+
+void
+tcb_stack_push(tcb_t *tcb, void *data, size_t len)
+{
+ assert(tcb != NULL);
+ void *spo = (void*)(tcb->ksp - len);
+ assert(spo >= tcb->stack);
+
+ memcpy(spo, data, len);
+ tcb->ksp = (uintptr_t)spo;
+}
diff --git a/task/tasking.c b/task/tasking.c
new file mode 100644
index 0000000..ee57a13
--- /dev/null
+++ b/task/tasking.c
@@ -0,0 +1,45 @@
+#include "tasking.h"
+#include "slab.h"
+#include "klib/rbtree.h"
+#include "arch/processor.h"
+
+rbtree_t s_tcbs;
+tcbid_t s_tcb_nextid = 0;
+slab_cache_t s_kstack_slab;
+
+void
+tasking_setup(void)
+{
+ rbtree_new(&s_tcbs, tcb_t);
+ slabcache_new(&s_kstack_slab, "kernel stack", KERNEL_STACKW);
+
+ extern void kernel_stage2(void);
+ tcb_t *init_tcb = tcb_new((void*)kernel_stage2, pd_current());
+
+ tcb_switch(init_tcb);
+}
+
+tcb_t*
+tcb_new(void *ip, page_directory_t *pd)
+{
+ void *stack = slab_alloc(&s_kstack_slab);
+ tcb_t *tcb = rbtree_reserve(&s_tcbs, s_tcb_nextid);
+ *tcb = (tcb_t) {
+ .id = s_tcb_nextid++,
+ .stack = stack,
+ .ksp = ((uintptr_t)stack) + (KERNEL_STACKW - 1),
+ .pd = pd,
+ .state = TCB_RUNNING
+ };
+
+ tcb_prepare(tcb, ip);
+ return tcb;
+}
+
+void
+tcb_kill(tcb_t *tcb, int code)
+{
+ if(tcb->id == 0) kpanic("init thread killed!\n");
+ tcb->state = TCB_DEAD;
+ tcb->exit_code = code;
+}
diff --git a/task/umode_vma.c b/task/umode_vma.c
new file mode 100644
index 0000000..880e047
--- /dev/null
+++ b/task/umode_vma.c
@@ -0,0 +1,37 @@
+#include "umode_vma.h"
+#include "arch/processor.h"
+#include "api/errno.h"
+#include "print.h"
+
+__attribute__((naked))
+int
+_umode_vma_fail(void)
+{
+ __asm__ volatile(" \
+ movq %%rbp, %%rsp; \
+ popq %%rbp; \
+ mov $1, %%eax; \
+ retq":::);
+}
+
+int
+user_vma_read(void *dest, const void *src, size_t w)
+{
+ if((uintptr_t)src > USERLAND_MEMORY_LIMIT) return -EACCESS;
+
+ _exrtab_push((void*)_umode_vma_fail);
+ for(size_t i = 0; i < w; i++) ((char*)dest)[i] = ((const char*)src)[i];
+ _exrtab_pop();
+ return 0;
+}
+
+int
+user_vma_write(void *dest, const void *src, size_t w)
+{
+ if((uintptr_t)dest > USERLAND_MEMORY_LIMIT) return -EACCESS;
+
+ _exrtab_push((void*)_umode_vma_fail);
+ for(size_t i = 0; i < w; i++) ((char*)dest)[i] = ((const char*)src)[i];
+ _exrtab_pop();
+ return 0;
+}
diff --git a/usr/elf.h b/usr/elf.h
deleted file mode 100644
index d805e55..0000000
--- a/usr/elf.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef JOVE_USER_ELF_H
-#define JOVE_USER_ELF_H 1
-
-#include <stddef.h>
-
-/**Load an ELF file into usermode memory.
- * @param data pointer to ELF file data buffer
- * @param len length of ELF file data buffer
- * @return entry point for loaded ELF exec*/
-void *elf_load(const void *data, size_t len);
-
-#endif
diff --git a/usr/syscall.c b/usr/syscall.c
deleted file mode 100644
index fbc5fe7..0000000
--- a/usr/syscall.c
+++ /dev/null
@@ -1,104 +0,0 @@
-#include "syscall.h"
-#include "sys/errno.h"
-#include "sys/permission.h"
-#include "usr/tasking.h"
-#include "mem/memory.h"
-#include "io/log.h"
-
-#define ENSURE_ADDR(ptr) \
- if(!mem_check_ptr(ptr)) { klogf("User passed bad address %#016X\n", ptr); return -EFAULT; }
-
-#define ENSURE_PERM(p) \
- if(!(task_current->perm & p)) return -ENOPERM
-
-#define PD_FOR_LINEAR_ADDRESS(addr) current_page_directory; \
- if(addr.tid == -1) addr.tid = task_current->id; \
- if(addr.tid != task_current->id) { \
- ENSURE_PERM(PERM_MEM_VIRT_PD); \
- struct Task *task = task_get(addr.tid); \
- if(task == NULL) return -EFAULT; \
- pd = task->pd; \
- }
-
-int _syscall_handler_log(struct syscall_log *req)
-{
- ENSURE_ADDR(req->message);
- klogf("%s", req->message);
- return 0;
-}
-
-intmax_t _syscall_handler_tid(syscall_t *req)
-{
- return task_current->id;
-}
-
-int _syscall_handler_mem_phys_resv(struct syscall_mem_phys_range_op *req)
-{
- ENSURE_PERM(PERM_MEM_PHYS_RESV);
- mem_phys_reserve(req->base, req->limit);
- return 0;
-}
-
-int _syscall_handler_mem_phys_free(struct syscall_mem_phys_range_op *req)
-{
- ENSURE_PERM(PERM_MEM_PHYS_FREE);
- mem_phys_release(req->base, req->limit);
- return 0;
-}
-
-int _syscall_handler_mem_phys_alloc(struct syscall_mem_phys_alloc *req)
-{
- ENSURE_ADDR(req->result);
- ENSURE_PERM(PERM_MEM_PHYS_ALLOC);
- *req->result = mem_phys_alloc(req->npages);
- return 0;
-}
-
-int _syscall_handler_mem_virt_mapping(struct syscall_mem_virt_mapping *req)
-{
- ENSURE_ADDR(req->result);
- ENSURE_PERM(PERM_MEM_VIRT_MAP);
- page_directory_t *pd = PD_FOR_LINEAR_ADDRESS(req->addr);
- *req->result = mem_get_mapping_as(pd, req->addr.addr);
- return 0;
-}
-
-int _syscall_handler_mem_virt_map(struct syscall_mem_virt_map *req)
-{
- ENSURE_PERM(PERM_MEM_VIRT_MAP);
- page_directory_t *pd = PD_FOR_LINEAR_ADDRESS(req->addr);
- mem_set_mapping_as(pd, req->map, req->addr.addr);
- return 0;
-}
-
-int _syscall_handler_mem_virt_alloc(struct syscall_mem_virt_alloc *req)
-{
- ENSURE_PERM(PERM_MEM_VIRT_MAP);
- ENSURE_PERM(PERM_MEM_PHYS_ALLOC);
- page_directory_t *pd = PD_FOR_LINEAR_ADDRESS(req->from);
- mem_ensure_range_as(pd, req->from.addr, req->to, req->flg);
- return 0;
-}
-
-void *_syscall_handlers[SYSCALL_COUNT] = {
- _syscall_handler_log,
- _syscall_handler_tid,
-
- _syscall_handler_mem_phys_resv,
- _syscall_handler_mem_phys_free,
- _syscall_handler_mem_phys_alloc,
-
- _syscall_handler_mem_virt_mapping,
- _syscall_handler_mem_virt_map,
- _syscall_handler_mem_virt_alloc,
-};
-
-int
-syscall_handler(syscall_t *req)
-{
- ENSURE_ADDR(req);
- if(req->id >= SYSCALL_COUNT) return -ENOSYS;
-
- ENSURE_ADDR(_syscall_handlers[req->id]);
- return ((syscall_handler_t)(_syscall_handlers[req->id]))(req);
-}
diff --git a/usr/syscall.h b/usr/syscall.h
deleted file mode 100644
index 5cc82b8..0000000
--- a/usr/syscall.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef JOVE_USER_SYSCALL_H
-#define JOVE_USER_SYSCALL_H 1
-
-#include "sys/syscall.h"
-
-typedef int (*syscall_handler_t)(syscall_t*);
-
-int _syscall_handler_log(struct syscall_log *req);
-intmax_t _syscall_handler_tid(syscall_t *req);
-
-#endif
diff --git a/usr/tasking.c b/usr/tasking.c
deleted file mode 100644
index cb4df25..0000000
--- a/usr/tasking.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "tasking.h"
-
-void
-task_perm_release(struct Task *task, size_t mask)
-{
- task->perm &= ~mask;
-}
diff --git a/usr/tasking.h b/usr/tasking.h
deleted file mode 100644
index 4b11999..0000000
--- a/usr/tasking.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef JOVE_TASKING_H
-#define JOVE_TASKING_H 1
-
-#include <stddef.h>
-#include <stdint.h>
-#include "sys/types.h"
-#include "mem/memory.h"
-
-struct Task
-{
- struct Task *next;
- tid_t id;
- uintptr_t kbp;
- size_t perm;
-
- page_directory_t *pd;
-};
-
-extern struct Task *task_current;
-
-void tasking_setup(void);
-
-struct Task *task_new(struct Task *parent);
-struct Task *task_get(tid_t id);
-
-void task_perm_release(struct Task *task, size_t mask);
-
-#endif
diff --git a/usr/umode.c b/usr/umode.c
deleted file mode 100644
index 1105d9e..0000000
--- a/usr/umode.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "umode.h"
-#include "elf.h"
-#include "boot/cmdline.h"
-#include "lib/jove.h"
-#include "ird/initrd.h"
-#include "mem/memory.h"
-
-void
-umode_setup(void)
-{
- extern void syscall_setup_syscall(void);
- syscall_setup_syscall();
-
- const char *init_path = cmdline_get("init");
- if(init_path == NULL)
- kpanic("Missing path to init ELF file / binary\n");
-
- struct InitrdFile *init_file = ird_getfile(init_path);
- if(init_file == NULL)
- kpanic("Missing init file %s in initrd\n", init_path);
-
- void (*entry_point)(void) = elf_load(init_file->data, init_file->size);
- if(entry_point == NULL)
- kpanic("Init file %s is incorrectly formatted (want ELF64)\n", init_path);
-
- void *user_stack = (void*)(0x00007FFFFFFFFFFF);
- mem_ensure_range(
- (uintptr_t)user_stack & ~0xFFF,
- (uintptr_t)user_stack,
- (page_flags_t) {
- .present = true,
- .writeable = true,
- .useraccess = true,
- .executable = false
- });
-
- klogf("User entry point %#016X\n", entry_point);
- umode_enter(entry_point, user_stack);
-}
diff --git a/usr/umode.h b/usr/umode.h
deleted file mode 100644
index 2755abe..0000000
--- a/usr/umode.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef JOVE_UMODE_H
-#define JOVE_UMODE_H 1
-
-void umode_setup(void);
-
-void umode_enter(void (*entry)(void), void *stack);
-
-#endif