Feat: userspace !!!!

This commit is contained in:
Keyboard Slayer 2023-12-20 12:06:07 +01:00 committed by keyboard-slayer
commit 1d80b23b7e
46 changed files with 3621 additions and 150 deletions

View file

@ -5,6 +5,11 @@ class Builder:
def __init__(self, args: cli.Args, arch: str = "x86_64"): def __init__(self, args: cli.Args, arch: str = "x86_64"):
self.__registry = model.Registry.use(args) self.__registry = model.Registry.use(args)
self.__kernel_scope = builder.TargetScope( self.__kernel_scope = builder.TargetScope(
self.__registry,
self.__registry.lookup(f"kernel-{arch}", model.Target),
)
self.__user_scope = builder.TargetScope(
self.__registry, self.__registry,
self.__registry.lookup(f"navy-{arch}", model.Target), self.__registry.lookup(f"navy-{arch}", model.Target),
) )
@ -14,6 +19,16 @@ class Builder:
product = builder.build(self.__kernel_scope, core_component)[0] product = builder.build(self.__kernel_scope, core_component)[0]
return Path(product.path).absolute() return Path(product.path).absolute()
def build_modules(self) -> list[Path]:
modules = dict(filter(lambda x: type(x[1]) is model.Component and \
x[1].type == model.Kind.EXE and x[0] != "core", self.__registry.manifests.items()))
products = []
for component in modules.values():
products.append(Path(builder.build(self.__user_scope, component)[0].path).absolute())
return products
@property @property
def arch(self) -> str: def arch(self) -> str:
return self.__kernel_scope.target.id.split("-")[1] return self.__kernel_scope.target.id.split("-")[1]

View file

@ -1,4 +1,5 @@
from cutekit import cli, model from cutekit import cli, model, shell
from pathlib import Path
from . import build from . import build
from . import image from . import image
@ -13,11 +14,14 @@ def _(args: cli.Args):
def _(args: cli.Args): def _(args: cli.Args):
qemu.Qemu( qemu.Qemu(
image.Image( image.Image(
build.Builder(args) build.Builder(args),
) ),
no_display=args.consumeOpt("no-display"),
soft_dbg=args.consumeOpt("soft-dbg")
).run() ).run()
@cli.command("B", "navy/build", "Build Navy") @cli.command("B", "navy/build", "Build Navy")
def _(args: cli.Args): def _(args: cli.Args):
build.Builder(args).build_core() build.Builder(args).build_core()
build.Builder(args).build_modules()

View file

@ -25,14 +25,20 @@ class Image:
boot_dir = self.path / "boot" boot_dir = self.path / "boot"
boot_dir.mkdir(parents=True, exist_ok=True) boot_dir.mkdir(parents=True, exist_ok=True)
bin_dir = self.path / "bin"
bin_dir.mkdir(parents=True, exist_ok=True)
return { return {
"efi_boot": efi_boot, "efi_boot": efi_boot,
"boot_dir": boot_dir, "boot_dir": boot_dir,
"bin_dir": bin_dir,
} }
def efi_x86_64(self): def efi_x86_64(self):
kernel_path = self.builder.build_core() kernel_path = self.builder.build_core()
modules = self.builder.build_modules()
paths = self.__efi_common() paths = self.__efi_common()
cfg = [ cfg = [
@ -43,6 +49,14 @@ class Image:
"KERNEL_PATH=boot:///boot/kernel.elf", "KERNEL_PATH=boot:///boot/kernel.elf",
] ]
for mod in modules:
name = mod.name.split(".")[0]
cfg.append(f"MODULE_PATH=boot:///bin/{name}")
shell.cp(
str(mod),
str(paths["bin_dir"] / name)
)
shell.wget( shell.wget(
"https://github.com/limine-bootloader/limine/raw/v6.x-branch-binary/BOOTX64.EFI", "https://github.com/limine-bootloader/limine/raw/v6.x-branch-binary/BOOTX64.EFI",
str(paths["efi_boot"] / "BOOTX64.EFI"), str(paths["efi_boot"] / "BOOTX64.EFI"),

View file

@ -5,8 +5,8 @@ from cutekit import shell
from .image import Image from .image import Image
class Qemu: class Qemu:
def __init__(self, img: Image, no_reboot: bool = True, nographics: bool = False, def __init__(self, img: Image, no_reboot: bool = True, no_display: bool = False,
no_shutdown: bool = True, efi: bool = True, memory: str = "4G", debug: bool = False): no_shutdown: bool = True, efi: bool = True, memory: str = "4G", debug: bool = False, soft_dbg: bool = False):
self.__img = img self.__img = img
self.__binary = None self.__binary = None
self.__efi = efi self.__efi = efi
@ -26,12 +26,15 @@ class Qemu:
if no_shutdown: if no_shutdown:
self.__args.append("-no-shutdown") self.__args.append("-no-shutdown")
if nographics: if no_display:
self.__args.append("-nographic") self.__args += ["-display", "none"]
if self.iskvmAvailable(): if self.iskvmAvailable():
self.__args += ["-enable-kvm", "-cpu", "host"] self.__args += ["-enable-kvm", "-cpu", "host"]
if soft_dbg:
self.__args += ["-d", "int"]
try: try:
getattr(self, f"arch_{img.builder.arch}")() getattr(self, f"arch_{img.builder.arch}")()
except AttributeError: except AttributeError:

View file

@ -0,0 +1,99 @@
{
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.target.v1",
"id": "kernel-x86_64",
"type": "target",
"props": {
"toolchain": "clang",
"arch": "x86_64",
"bits": "64",
"sys": "kernel",
"loader": "limine",
"abi": "sysv",
"encoding": "utf8",
"freestanding": true,
"host": false
},
"tools": {
"cc": {
"cmd": [
"@latest",
"clang"
],
"args": [
"-target",
"x86_64-none-elf",
"-ffreestanding",
"-fno-stack-protector",
"-mno-80387",
"-mno-mmx",
"-mno-3dnow",
"-mno-sse",
"-mno-sse2",
"-mno-red-zone",
"-mcmodel=kernel",
"-Dauto=__auto_type",
"-g"
]
},
"cxx": {
"cmd": [
"@latest",
"clang++"
],
"args": [
"-target",
"x86_64-none-elf",
"-ffreestanding",
"-fno-stack-protector",
"-mno-80387",
"-mno-mmx",
"-mno-3dnow",
"-mno-sse",
"-mno-sse2",
"-mno-red-zone",
"-mcmodel=kernel"
]
},
"ld": {
"cmd": [
"@latest",
"ld.lld"
],
"args": [
"-m",
"elf_x86_64",
"-T",
[
"@abspath",
"kernel-x86_64.ld"
],
"-z",
"max-page-size=0x1000"
],
"files": [
"meta/targets/kernel-x86_64.ld"
]
},
"ar": {
"cmd": [
"@latest",
"llvm-ar"
],
"args": [
"rcs"
]
},
"as": {
"cmd": [
"@latest",
"clang"
],
"args": [
"-target",
"x86_64-none-elf",
"-c",
"-g"
]
}
}
}

View file

@ -0,0 +1,67 @@
/* Tell the linker that we want an x86_64 ELF64 output file */
OUTPUT_FORMAT(elf64-x86-64)
OUTPUT_ARCH(i386:x86-64)
/* We want the symbol _start to be our entry point */
ENTRY(_start)
/* Define the program headers we want so the bootloader gives us the right */
/* MMU permissions */
PHDRS
{
text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */
rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */
data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */
}
SECTIONS
{
/* We wanna be placed in the topmost 2GiB of the address space, for optimisations */
/* and because that is what the Limine spec mandates. */
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
/* that is the beginning of the region. */
. = 0xffffffff80000000;
text_start_addr = .;
.text : {
*(.text .text.*)
} :text
text_end_addr = .;
/* Move to the next memory page for .rodata */
. += CONSTANT(MAXPAGESIZE);
rodata_start_addr = .;
PROVIDE(symbol_table = 1);
.rodata : {
*(.rodata .rodata.*)
} :rodata
rodata_end_addr = .;
/* Move to the next memory page for .data */
. += CONSTANT(MAXPAGESIZE);
data_start_addr = .;
.data : {
*(.data .data.*)
} :data
.bss : {
*(COMMON)
*(.bss .bss.*)
} :data
data_end_addr = .;
/* Discard .note.* and .eh_frame since they may cause issues on some hosts. */
/DISCARD/ : {
*(.eh_frame)
*(.note .note.*)
}
}

View file

@ -1,5 +1,5 @@
{ {
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.target.v1", "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"id": "navy-x86_64", "id": "navy-x86_64",
"type": "target", "type": "target",
"props": { "props": {
@ -7,10 +7,9 @@
"arch": "x86_64", "arch": "x86_64",
"bits": "64", "bits": "64",
"sys": "navy", "sys": "navy",
"loader": "limine",
"abi": "sysv", "abi": "sysv",
"encoding": "utf8", "encoding": "utf8",
"freestanding": true, "freestanding": false,
"host": false "host": false
}, },
"tools": { "tools": {
@ -23,15 +22,11 @@
"-target", "-target",
"x86_64-none-elf", "x86_64-none-elf",
"-ffreestanding", "-ffreestanding",
"-fno-stack-protector",
"-mno-80387", "-mno-80387",
"-mno-mmx", "-mno-mmx",
"-mno-3dnow", "-mno-3dnow",
"-mno-sse", "-mno-sse",
"-mno-sse2", "-mno-sse2"
"-mno-red-zone",
"-mcmodel=kernel",
"-Dauto=__auto_type"
] ]
}, },
"cxx": { "cxx": {
@ -43,14 +38,11 @@
"-target", "-target",
"x86_64-none-elf", "x86_64-none-elf",
"-ffreestanding", "-ffreestanding",
"-fno-stack-protector",
"-mno-80387", "-mno-80387",
"-mno-mmx", "-mno-mmx",
"-mno-3dnow", "-mno-3dnow",
"-mno-sse", "-mno-sse",
"-mno-sse2", "-mno-sse2"
"-mno-red-zone",
"-mcmodel=kernel"
] ]
}, },
"ld": { "ld": {
@ -64,13 +56,10 @@
"-T", "-T",
[ [
"@abspath", "@abspath",
"kernel-x86_64.ld" "navy-x86_64.ld"
], ],
"-z", "-z",
"max-page-size=0x1000" "max-page-size=0x1000"
],
"files": [
"meta/targets/kernel-x86_64.ld"
] ]
}, },
"ar": { "ar": {
@ -83,15 +72,11 @@
] ]
}, },
"as": { "as": {
"cmd": [ "cmd": "clang",
"@latest",
"clang"
],
"args": [ "args": [
"-target", "-target",
"x86_64-none-elf", "x86_64-none-elf",
"-c", "-c"
"-g"
] ]
} }
} }

View file

@ -1,67 +1,27 @@
/* Tell the linker that we want an x86_64 ELF64 output file */
OUTPUT_FORMAT(elf64-x86-64)
OUTPUT_ARCH(i386:x86-64)
/* We want the symbol _start to be our entry point */
ENTRY(_start) ENTRY(_start)
/* Define the program headers we want so the bootloader gives us the right */
/* MMU permissions */
PHDRS
{
text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */
rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */
data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */
}
SECTIONS SECTIONS
{ {
/* We wanna be placed in the topmost 2GiB of the address space, for optimisations */ . = 4M;
/* and because that is what the Limine spec mandates. */
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
/* that is the beginning of the region. */
. = 0xffffffff80000000;
text_start_addr = .; .text : ALIGN(4K)
{
*(.text)
}
.text : { .rodata : ALIGN(4K)
*(.text .text.*) {
} :text *(.rodata)
}
text_end_addr = .; .data : ALIGN(4K)
{
*(.data)
}
/* Move to the next memory page for .rodata */ .bss : ALIGN(4K)
. += CONSTANT(MAXPAGESIZE); {
rodata_start_addr = .;
PROVIDE(symbol_table = 1);
.rodata : {
*(.rodata .rodata.*)
} :rodata
rodata_end_addr = .;
/* Move to the next memory page for .data */
. += CONSTANT(MAXPAGESIZE);
data_start_addr = .;
.data : {
*(.data .data.*)
} :data
.bss : {
*(COMMON) *(COMMON)
*(.bss .bss.*) *(.bss)
} :data
data_end_addr = .;
/* Discard .note.* and .eh_frame since they may cause issues on some hosts. */
/DISCARD/ : {
*(.eh_frame)
*(.note .note.*)
} }
} }

View file

@ -1,8 +1,15 @@
#pragma once #pragma once
#include <io/stream.h> #include <io/stream.h>
#include <navy/api.h>
#include <stdint.h> #include <stdint.h>
#ifdef __ck_arch_x86_64__
# include <x86_64/acpi.h>
# include <x86_64/ctx.h>
# include <x86_64/regs.h>
#endif
Res hal_setup(void); Res hal_setup(void);
/* --- Structs ------------------------------------------------------------ */ /* --- Structs ------------------------------------------------------------ */
@ -45,11 +52,24 @@ Res hal_space_map(HalPage *space, uintptr_t virt, uintptr_t phys, size_t len, ui
void hal_space_apply(HalPage *space); void hal_space_apply(HalPage *space);
Res hal_space_create(HalPage **self);
/* --- Arch Specific ------------------------------------------------------- */ /* --- Arch Specific ------------------------------------------------------- */
#ifdef __ck_arch_x86_64__ #ifdef __ck_arch_x86_64__
# include <x86_64/acpi.h>
Rsdp *hal_acpi_rsdp(void); Rsdp *hal_acpi_rsdp(void);
#endif #endif
typedef struct _HalContext HalContext;
Res hal_context_create(void);
Res hal_context_start(HalContext *self, uintptr_t ip, uintptr_t sp, SysArgs args);
void hal_context_destroy(HalContext *self);
void hal_context_save(HalContext *self, HalRegs *regs);
void hal_context_restore(HalContext *self, HalRegs *regs);
void hal_regs_dump(HalRegs const *regs);

View file

@ -0,0 +1,68 @@
#include <dbg/log.h>
#include <hal.h>
#include <kmalloc/kmalloc.h>
#include <navy/api.h>
#include "x86_64/ctx.h"
#include "../../core/pmm.h"
#include "cpu.h"
#include "gdt.h"
#include "simd.h"
#include "syscall.h"
Res hal_context_create(void)
{
Alloc alloc = kmalloc_acquire();
HalContext *self = (HalContext *)try$(alloc.calloc(1, sizeof(HalContext) + simd_context_size()));
simd_context_init(self);
return uok$((uintptr_t)self);
}
void hal_context_destroy(HalContext *self)
{
Alloc alloc = kmalloc_acquire();
alloc.free(self);
}
Res hal_context_start(HalContext *self, uintptr_t ip, uintptr_t sp, SysArgs args)
{
self->regs.rip = ip;
self->regs.rflags = RFLAGS_INTERRUPT_ENABLE | RFLAGS_RESERVED1;
self->regs.rdi = args.arg1;
self->regs.rsi = args.arg2;
self->regs.rdx = args.arg3;
self->regs.rcx = args.arg4;
self->regs.r8 = args.arg5;
self->regs.cs = (GDT_USER_CODE * 8) | 3;
self->regs.ss = (GDT_USER_DATA * 8) | 3;
self->regs.rsp = sp + STACK_SIZE;
self->regs.rbp = sp;
PmmObj kStackObj = pmm_alloc(align_up$(STACK_SIZE, PMM_PAGE_SIZE) / PMM_PAGE_SIZE);
if (kStackObj.base == 0)
{
return err$(RES_NOMEM);
}
self->syscall_kernel_stack = hal_mmap_l2h(kStackObj.base) + KERNEL_STACK_SIZE;
memset((void *)self->syscall_kernel_stack, 0, KERNEL_STACK_SIZE);
return ok$();
}
void hal_context_save(HalContext *self, HalRegs *regs)
{
simd_context_save(self->simd);
self->regs = *regs;
}
void hal_context_restore(HalContext *self, HalRegs *regs)
{
*regs = self->regs;
simd_context_load(self->simd);
syscall_set_gs((uintptr_t)self);
}

View file

@ -0,0 +1,18 @@
#pragma once
#include <stdint.h>
#include "regs.h"
#define STACK_SIZE (kib$(4))
#define KERNEL_STACK_SIZE (0x1000)
#define USER_STACK_BASE (0xff0000000)
struct _HalContext
{
uintptr_t syscall_kernel_stack;
uintptr_t syscall_user_stack;
struct _HalRegs regs;
_Alignas(64) uint8_t simd[];
};

View file

@ -1,11 +1,14 @@
#include <dbg/log.h> #include <dbg/log.h>
#include <hal.h> #include <hal.h>
#include <kmalloc/kmalloc.h>
#include <string.h> #include <string.h>
#include <sync/spinlock.h> #include <sync/spinlock.h>
#include "ctx.h"
#include "gdt.h" #include "gdt.h"
static Gdt gdt = {0}; static Gdt gdt = {0};
static Tss tss = {0};
static Spinlock lock = SPINLOCK_INIT; static Spinlock lock = SPINLOCK_INIT;
@ -79,3 +82,17 @@ void gdt_init(void)
tss_flush(); tss_flush();
log$("TSS loaded"); log$("TSS loaded");
} }
Res gdt_init_tss(void)
{
Alloc heap = kmalloc_acquire();
tss.ist[1] = (uintptr_t)(try$(heap.malloc(KERNEL_STACK_SIZE)) + KERNEL_STACK_SIZE);
tss.ist[0] = (uintptr_t)(try$(heap.malloc(KERNEL_STACK_SIZE)) + KERNEL_STACK_SIZE);
tss.rsp[0] = (uintptr_t)(try$(heap.malloc(KERNEL_STACK_SIZE)) + KERNEL_STACK_SIZE);
log$("TSS initialized");
gdt_load_tss(&tss);
tss_flush();
return ok$();
}

View file

@ -85,6 +85,7 @@ typedef struct [[gnu::packed]]
void gdt_init(void); void gdt_init(void);
void gdt_load_tss(Tss *self); void gdt_load_tss(Tss *self);
Res gdt_init_tss(void);
uintptr_t gdt_descriptor(void); uintptr_t gdt_descriptor(void);
extern void gdt_flush(uintptr_t); extern void gdt_flush(uintptr_t);

View file

@ -2,6 +2,8 @@
#include <hal.h> #include <hal.h>
#include <sync/spinlock.h> #include <sync/spinlock.h>
#include "../core/pre-sched.h"
#include "apic.h"
#include "asm.h" #include "asm.h"
#include "regs.h" #include "regs.h"
@ -68,6 +70,7 @@ static void dump_backtrace(uintptr_t rbp)
static void kpanic(HalRegs const regs[static 1]) static void kpanic(HalRegs const regs[static 1])
{ {
spinlock_acquire(&lock); spinlock_acquire(&lock);
uint64_t cr0, cr2, cr3, cr4; uint64_t cr0, cr2, cr3, cr4;
asm_read_cr(0, cr0); asm_read_cr(0, cr0);
@ -107,6 +110,11 @@ uintptr_t interrupt_handler(uintptr_t rsp)
hal_pause(); hal_pause();
} }
} }
else if (regs->intno == IRQ0)
{
switch_to_scheduler(regs);
}
lapic_eoi();
return rsp; return rsp;
} }

View file

@ -111,3 +111,30 @@ __interrupts_vector:
idt_flush: idt_flush:
lidt (%rdi) lidt (%rdi)
ret ret
.extern syscall_handler
.globl syscall_handle
syscall_handle:
swapgs
mov %rsp, %gs:0x8
mov %gs:0x0, %rsp
pushq $0x1b
pushq %gs:0x8
push %r11
pushq $0x23
push %rcx
cld
__pusha
mov %rsp, %rdi
movl $0, %ebp
call syscall_handler
__popa
mov %gs:0x8, %rsp
swapgs
sysretq

View file

@ -5,12 +5,17 @@
"enableIf": { "enableIf": {
"arch": [ "arch": [
"x86_64" "x86_64"
],
"sys": [
"kernel"
] ]
}, },
"provides": [ "provides": [
"arch" "arch"
], ],
"requires": [ "requires": [
"io",
"stdc-shim",
"dbg" "dbg"
] ]
} }

View file

@ -2,13 +2,14 @@
#include <io/stream.h> #include <io/stream.h>
#include <res.h> #include <res.h>
#include "apic.h"
#include "e9.h" #include "e9.h"
#include "gdt.h" #include "gdt.h"
#include "hpet.h"
#include "idt.h" #include "idt.h"
#include "paging.h" #include "paging.h"
#include "hpet.h"
#include "apic.h"
#include "simd.h" #include "simd.h"
#include "syscall.h"
Stream hal_dbg_stream(void) Stream hal_dbg_stream(void)
{ {
@ -22,6 +23,8 @@ Res hal_setup(void)
gdt_init(); gdt_init();
idt_init(); idt_init();
try$(paging_init()); try$(paging_init());
try$(gdt_init_tss());
syscall_init();
acpi_init(); acpi_init();
try$(hpet_init()); try$(hpet_init());
try$(apic_init()); try$(apic_init());

View file

@ -68,8 +68,8 @@ static Res paging_get_pml_alloc(uintptr_t *pml, size_t index, bool alloc)
else if (alloc) else if (alloc)
{ {
PmmObj obj = pmm_alloc(1); PmmObj obj = pmm_alloc(1);
memset((void *)obj.base, 0, obj.len);
uintptr_t ptr_hddm = hal_mmap_l2h(obj.base); uintptr_t ptr_hddm = hal_mmap_l2h(obj.base);
memset((void *)ptr_hddm, 0, obj.len);
pml[index] = obj.base | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER; pml[index] = obj.base | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
@ -158,11 +158,11 @@ Res paging_init(void)
return err$(RES_NOMEM); return err$(RES_NOMEM);
} }
memset((void *)obj.base, 0, obj.len);
log$("PML4: 0x%p", obj.base); log$("PML4: 0x%p", obj.base);
pml4 = (uintptr_t *)hal_mmap_l2h((uintptr_t)obj.base); pml4 = (uintptr_t *)hal_mmap_l2h((uintptr_t)obj.base);
memset((void *)pml4, 0, obj.len);
if (cpuid_has_1gb_pages()) if (cpuid_has_1gb_pages())
{ {
log$("1GB pages are supported"); log$("1GB pages are supported");
@ -220,14 +220,14 @@ Res hal_space_create(HalPage **self)
{ {
PmmObj obj = pmm_alloc(1); PmmObj obj = pmm_alloc(1);
memset((void *)obj.base, 0, obj.len); uintptr_t *space = (uintptr_t *)hal_mmap_l2h(obj.base);
memset((void *)space, 0, obj.len);
if (obj.base == 0) if (obj.base == 0)
{ {
return err$(RES_NOMEM); return err$(RES_NOMEM);
} }
uintptr_t *space = (uintptr_t *)hal_mmap_l2h(obj.base);
memset((void *)space, 0, PMM_PAGE_SIZE); memset((void *)space, 0, PMM_PAGE_SIZE);
for (size_t i = 255; i < 512; i++) for (size_t i = 255; i < 512; i++)

View file

@ -0,0 +1,25 @@
#include <dbg/log.h>
#include <hal.h>
#include "asm.h"
void hal_regs_dump(HalRegs const *regs)
{
uint64_t cr0, cr2, cr3, cr4;
asm_read_cr(0, cr0);
asm_read_cr(2, cr2);
asm_read_cr(3, cr3);
asm_read_cr(4, cr4);
log$("=== Registers Dump ============================================");
log$("interrupt: %x, err: %x", regs->intno, regs->err);
log$("RAX %p RBX %p RCX %p RDX %p", regs->rax, regs->rbx, regs->rcx, regs->rdx);
log$("RSI %p RDI %p RBP %p RSP %p", regs->rsi, regs->rdi, regs->rbp, regs->rsp);
log$("R8 %p R9 %p R10 %p R11 %p", regs->r8, regs->r9, regs->r10, regs->r11);
log$("R12 %p R13 %p R14 %p R15 %p", regs->r12, regs->r13, regs->r14, regs->r15);
log$("CR0 %p CR2 %p CR3 %p CR4 %p", cr0, cr2, cr3, cr4);
log$("CS %p SS %p FLG %p", regs->cs, regs->ss, regs->rflags);
log$("RIP \033[7m%p\033[0m", regs->rip);
log$("==============================================================");
}

View file

@ -0,0 +1,25 @@
#include <dbg/log.h>
#include <hal.h>
#include "asm.h"
#include "gdt.h"
#include "syscall.h"
void syscall_init(void)
{
asm_write_msr(MSR_EFER, asm_read_msr(MSR_EFER) | 1);
asm_write_msr(MSR_STAR, ((uint64_t)(GDT_KERNEL_CODE * 8) << STAR_KCODE_OFFSET) | ((uint64_t)(((GDT_USER_DATA - 1) * 8) | 3) << STAR_UCODE_OFFSET));
asm_write_msr(MSR_LSTAR, (uint64_t)syscall_handle);
asm_write_msr(MSR_SYSCALL_FLAG_MASK, 0xfffffffe);
}
void syscall_set_gs(uintptr_t addr)
{
asm_write_msr(MSR_GS_BASE, addr);
asm_write_msr(MSR_KERN_GS_BASE, addr);
}
int64_t syscall_handler(HalRegs *regs)
{
return _syscall_handler(regs->rax, (SysArgs){regs->rdi, regs->rsi, regs->rdx, regs->r8, regs->r9, regs->r10}).type;
}

View file

@ -0,0 +1,9 @@
#pragma once
#include <stdint.h>
void syscall_handle(void);
void syscall_set_gs(uintptr_t addr);
void syscall_init(void);

View file

@ -2,11 +2,33 @@
#include <hal.h> #include <hal.h>
#include "pmm.h" #include "pmm.h"
#include "pre-sched.h"
_Noreturn int _start() _Noreturn int _start()
{ {
pmm_init(); Res pmm = pmm_init();
hal_setup(); if (pmm.type != RES_OK)
{
error$("%s at %s (%s:%d) - Couldn't initialize PMM",
res_to_str(pmm), pmm.loc.func, pmm.loc.file, pmm.loc.line);
hal_panic();
}
Res hal = hal_setup();
if (hal.type != RES_OK)
{
error$("%s at %s (%s:%d) - Couldn't initialize HAL",
res_to_str(hal), hal.loc.func, hal.loc.file, hal.loc.line);
hal_panic();
}
Res sched = load_scheduler();
if (sched.type != RES_OK)
{
error$("%s at %s (%s:%d) - Couldn't initialize scheduler",
res_to_str(sched), sched.loc.func, sched.loc.file, sched.loc.line);
hal_panic();
}
for (;;) for (;;)
; ;

View file

@ -6,7 +6,8 @@
"arch", "arch",
"dbg", "dbg",
"stdc-shim", "stdc-shim",
"loader" "loader",
"kmalloc"
], ],
"tools": { "tools": {
"cc": { "cc": {

View file

@ -0,0 +1,99 @@
#include <dbg/log.h>
#include <loader.h>
#include <specs/elf.h>
#include <string.h>
#include "hal.h"
#include "pmm.h"
#include "pre-sched.h"
#ifdef __ck_bits_64__
# define Elf_Ehdr Elf64_Ehdr
# define ELFCLASS ELFCLASS64
# define Elf_Phdr Elf64_Phdr
#else
# define Elf_Ehdr Elf32_Ehdr
# define ELFCLASS ELFCLASS32
# define Elf_Phdr Elf32_Phdr
#endif
static HalPage *sched_vspace;
static HalContext *sched_ctx;
static HalContext *kernel_ctx;
static bool need_switch = false;
Res load_scheduler(void)
{
Module sched = loader_get_module("/bin/sched");
if (sched.len == 0)
{
return err$(RES_NOENT);
}
try$(hal_space_create(&sched_vspace));
Elf_Ehdr *hdr = (Elf_Ehdr *)sched.base;
if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0)
{
return err$(RES_INVAL);
}
if (hdr->e_ident[EI_CLASS] != ELFCLASS)
{
return err$(RES_INVAL);
}
for (size_t i = 0; i < hdr->e_phnum; i++)
{
Elf_Phdr *phdr = (Elf_Phdr *)(sched.base + hdr->e_phoff + i * hdr->e_phentsize);
if (phdr->p_type == PT_LOAD)
{
log$("Mapping scheduler segment 0x%x -> 0x%x (len: %x)",
phdr->p_vaddr, phdr->p_vaddr + phdr->p_memsz, phdr->p_memsz);
PmmObj paddr = pmm_alloc(align_up$(phdr->p_memsz, PMM_PAGE_SIZE));
if (paddr.len == 0)
{
return err$(RES_NOMEM);
}
log$("Scheduler segment mapped to 0x%x", paddr.base);
try$(hal_space_map(sched_vspace, phdr->p_vaddr, paddr.base, align_up$(phdr->p_memsz, PMM_PAGE_SIZE), HAL_MEM_READ | HAL_MEM_WRITE | HAL_MEM_USER | HAL_MEM_EXEC));
memcpy((void *)hal_mmap_l2h(paddr.base), (void *)sched.base + phdr->p_offset, phdr->p_filesz);
memset((void *)hal_mmap_l2h(paddr.base + phdr->p_filesz), 0, phdr->p_memsz - phdr->p_filesz);
}
}
sched_ctx = (HalContext *)try$(hal_context_create());
kernel_ctx = (HalContext *)try$(hal_context_create());
PmmObj sched_stack_obj = pmm_alloc(align_up$(STACK_SIZE, PMM_PAGE_SIZE) / PMM_PAGE_SIZE);
if (sched_stack_obj.len == 0)
{
return err$(RES_NOMEM);
}
hal_space_map(sched_vspace, USER_STACK_BASE, sched_stack_obj.base, STACK_SIZE, HAL_MEM_READ | HAL_MEM_WRITE | HAL_MEM_USER);
hal_context_start(sched_ctx, hdr->e_entry, USER_STACK_BASE, (SysArgs){0, 0, 0, 0, 0, 0});
need_switch = true;
return ok$();
}
void switch_to_scheduler(HalRegs *regs)
{
if (need_switch)
{
hal_context_save(kernel_ctx, regs);
hal_space_apply((HalPage *)sched_vspace);
hal_context_restore(sched_ctx, regs);
need_switch = false;
return;
}
}

View file

@ -0,0 +1,8 @@
#pragma once
#include <hal.h>
#include <res.h>
Res load_scheduler(void);
void switch_to_scheduler(HalRegs *regs);

View file

@ -0,0 +1,26 @@
#include <dbg/log.h>
#include <navy/api.h>
#include <res.h>
#include "hal.h"
typedef Res Handler(SysArg arg1, SysArg arg2, SysArg arg3, SysArg arg4, SysArg arg5, SysArg arg6);
static Res _sys_log(char const *s, size_t len)
{
return hal_dbg_stream().write(len, s);
}
static Handler *handlers[__SYSCALL_LENGTH] = {
[SYS_LOG] = (Handler *)_sys_log,
};
Res _syscall_handler(Syscalls no, SysArgs args)
{
if (no >= __SYSCALL_LENGTH)
{
return err$(RES_BADSYSCALL);
}
return handlers[no](args.arg1, args.arg2, args.arg3, args.arg4, args.arg5, args.arg6);
}

View file

@ -1,28 +1,11 @@
#include <dbg/log.h>
#include <fmt/fmt.h> #include <fmt/fmt.h>
#include <hal.h> #include <hal.h>
#include <stdarg.h> #include <stdarg.h>
#include <sync/spinlock.h> #include <sync/spinlock.h>
#include "log.h"
static Spinlock _lock = SPINLOCK_INIT; static Spinlock _lock = SPINLOCK_INIT;
static char const *level_names[LOG_EVENT_LENGTH] = {
[LOG_NONE] = "",
[LOG_INFO] = "INFO",
[LOG_WARN] = "WARN",
[LOG_ERROR] = "ERROR",
[LOG_CRIT] = "CRITIC",
};
static char const *level_colors[LOG_EVENT_LENGTH] = {
[LOG_NONE] = "",
[LOG_INFO] = "\e[1;34m",
[LOG_WARN] = "\e[1;33m",
[LOG_ERROR] = "\e[1;31m",
[LOG_CRIT] = "\e[1;35m",
};
void _log(LogEvent event, Loc loc, char const *format, ...) void _log(LogEvent event, Loc loc, char const *format, ...)
{ {
spinlock_acquire(&_lock); spinlock_acquire(&_lock);

View file

@ -1,12 +1,15 @@
{ {
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"type": "lib", "type": "lib",
"id": "dbg", "id": "dbg-kernel",
"enableIf": { "enableIf": {
"freestanding": [ "sys": [
true "kernel"
] ]
}, },
"provides": [
"dbg"
],
"requires": [ "requires": [
"sync", "sync",
"fmt" "fmt"

View file

@ -0,0 +1,13 @@
{
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"type": "lib",
"id": "kmalloc",
"requires": [
"libheap"
],
"enableIf": {
"sys": [
"kernel"
]
}
}

View file

@ -1,9 +1,10 @@
#include <dbg/log.h> #include <dbg/log.h>
#include <hal.h> #include <hal.h>
#include <loader.h>
#include <stddef.h> #include <stddef.h>
#include <string.h>
#include "limine.h" #include "limine.h"
#include "loader.h"
static Mmap mmap = {0}; static Mmap mmap = {0};
@ -33,10 +34,10 @@ static volatile struct limine_rsdp_request rsdp_req = {
.response = NULL, .response = NULL,
}; };
static volatile struct limine_smp_request smp_req = { volatile struct limine_module_request module_request = {
.id = LIMINE_SMP_REQUEST, .id = LIMINE_MODULE_REQUEST,
.response = 0,
.revision = 0, .revision = 0,
.response = NULL,
}; };
/* --- Loader functions ---------------------------------------------------- */ /* --- Loader functions ---------------------------------------------------- */
@ -172,27 +173,27 @@ Rsdp *hal_acpi_rsdp(void)
return (Rsdp *)rsdp_req.response->address; return (Rsdp *)rsdp_req.response->address;
} }
size_t cpu_count(void) Module loader_get_module(char const *path)
{ {
if (smp_req.response == NULL) if (module_request.response == NULL)
{ {
error$("Couldn't retrieve SMP info from Limine"); return (Module){0};
hal_panic();
} }
return smp_req.response->cpu_count; for (size_t i = 0; i < module_request.response->module_count; i++)
} {
if (memcmp(path, module_request.response->modules[i]->path, strlen(path)) == 0)
void hal_smp_boot(void (*entry)(void)) {
{ Module mod = {
if (smp_req.response == NULL) .base = (uintptr_t)module_request.response->modules[i]->address,
{ .len = module_request.response->modules[i]->size,
error$("Couldn't retrieve SMP info from Limine"); };
hal_panic();
} memcpy(mod.name, module_request.response->modules[i]->path, strlen(path));
for (size_t i = 0; i < smp_req.response->cpu_count; i++) return mod;
{ }
smp_req.response->cpus[i]->goto_address = (limine_goto_address)entry; }
}
return (Module){0};
} }

View file

@ -8,9 +8,16 @@
], ],
"arch": [ "arch": [
"x86_64" "x86_64"
],
"sys": [
"kernel"
] ]
}, },
"provides": [ "provides": [
"loader" "loader"
],
"requires": [
"stdc-shim",
"dbg"
] ]
} }

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <res.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -37,6 +38,17 @@ typedef struct
Mmap loader_get_mmap(void); Mmap loader_get_mmap(void);
/* --- Modules -------------------------------------------------------------- */
typedef struct
{
uintptr_t base;
size_t len;
char name[64];
} Module;
Module loader_get_module(char const *path);
/* --- Misc ---------------------------------------------------------------- */ /* --- Misc ---------------------------------------------------------------- */
KernelMmap loader_get_kernel_mmap(void); KernelMmap loader_get_kernel_mmap(void);

View file

@ -1,13 +1,16 @@
{ {
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"type": "lib", "type": "lib",
"id": "stdc-shim", "id": "stdc-shim-kernel",
"props": { "props": {
"cpp-root-include": true "cpp-root-include": true
}, },
"enableIf": { "enableIf": {
"freestanding": [ "sys": [
true "kernel"
]
},
"provides": [
"stdc-shim"
] ]
}
} }

View file

@ -3,8 +3,8 @@
"type": "lib", "type": "lib",
"id": "sync", "id": "sync",
"enableIf": { "enableIf": {
"freestanding": [ "sys": [
true "kernel"
] ]
} }
} }

39
src/libs/dbg/log.c Normal file
View file

@ -0,0 +1,39 @@
#include <fmt/fmt.h>
#include <navy/api.h>
#include <stdarg.h>
#include "log.h"
/* --- Define sys_log as a stream ------------------------------------------- */
static Res stream_write(size_t n, char const buf[static n])
{
try$(sys_log(buf, n));
return uok$(n);
}
static Stream _stream = {
.write = stream_write,
};
/* --- Define log functions -------------------------------------------------- */
void _log(LogEvent event, Loc loc, char const *format, ...)
{
va_list args;
va_start(args, format);
if (event != LOG_NONE)
{
fmt(_stream, "%s%s\e[0m %s:%d ", level_colors[event], level_names[event], loc.file, loc.line);
}
vfmt(_stream, format, args);
if (event != LOG_NONE)
{
_stream.write(1, "\n");
}
va_end(args);
}

View file

@ -21,4 +21,20 @@ typedef enum
#define critical$(...) _log(LOG_CRIT, loc$(), __VA_ARGS__) #define critical$(...) _log(LOG_CRIT, loc$(), __VA_ARGS__)
#define print$(...) _log(LOG_NONE, (Loc){}, __VA_ARGS__) #define print$(...) _log(LOG_NONE, (Loc){}, __VA_ARGS__)
static char const *level_names[LOG_EVENT_LENGTH] = {
[LOG_NONE] = "",
[LOG_INFO] = "INFO",
[LOG_WARN] = "WARN",
[LOG_ERROR] = "ERROR",
[LOG_CRIT] = "CRITIC",
};
static char const *level_colors[LOG_EVENT_LENGTH] = {
[LOG_NONE] = "",
[LOG_INFO] = "\e[1;34m",
[LOG_WARN] = "\e[1;33m",
[LOG_ERROR] = "\e[1;31m",
[LOG_CRIT] = "\e[1;35m",
};
void _log(LogEvent event, Loc loc, char const *format, ...); void _log(LogEvent event, Loc loc, char const *format, ...);

View file

@ -0,0 +1,18 @@
{
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"type": "lib",
"id": "dbg-user",
"enableIf": {
"sys": [
"navy"
]
},
"provides": [
"dbg"
],
"requires": [
"fmt",
"stdc-shim",
"io"
]
}

View file

@ -1,5 +1,8 @@
{ {
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"type": "lib", "type": "lib",
"id": "fmt" "id": "fmt",
"requires": [
"stdc-shim"
]
} }

65
src/libs/navy/api.h Normal file
View file

@ -0,0 +1,65 @@
#pragma once
#include <res.h>
#include <stddef.h>
#include <stdint.h>
/* --- Types --------------------------------------------------------------- */
typedef uintptr_t SysArg;
typedef enum : size_t
{
SYS_LOG,
__SYSCALL_LENGTH
} Syscalls;
typedef struct
{
SysArg arg1;
SysArg arg2;
SysArg arg3;
SysArg arg4;
SysArg arg5;
SysArg arg6;
} SysArgs;
/* --- Syscall ------------------------------------------------------------- */
#ifdef __ck_arch_x86_64__
static inline Res __syscall_impl(Syscalls s, SysArg arg1, SysArg arg2, SysArg arg3, SysArg arg4, SysArg arg5, SysArg arg6)
{
enum res_type res;
// s : rax, arg1 : rdi, arg2 : rsi, arg3 : rdx, arg4 : r10, arg5 : r8, arg6 : r9
__asm__ volatile(
"syscall"
: "=a"(res)
: "a"(s), "D"(arg1), "S"(arg2), "d"(arg3), "r"(arg4), "r"(arg5), "r"(arg6)
: "rcx", "r11", "memory");
return (Res){
.type = res,
.uvalue = 0,
.loc = loc$(),
};
}
#else
# error "Unsupported architecture"
#endif
#define __syscall(id, a1, a2, a3, a4, a5, a6, ...) __syscall_impl(id, a1, a2, a3, a4, a5, a6)
#define syscall(...) __syscall(__VA_ARGS__, 0, 0, 0, 0, 0, 0)
Res _syscall_handler(Syscalls no, SysArgs args);
/* --- Syscalls ------------------------------------------------------------- */
static inline Res sys_log(char const *str, size_t len)
{
return syscall(SYS_LOG, (SysArg)str, (SysArg)len);
}

View file

@ -10,7 +10,8 @@
F(RES_INVAL) \ F(RES_INVAL) \
F(RES_NOMEM) \ F(RES_NOMEM) \
F(RES_BADALIGN) \ F(RES_BADALIGN) \
F(RES_NOENT) F(RES_NOENT) \
F(RES_BADSYSCALL)
enum res_type enum res_type
{ {

2719
src/libs/specs/elf.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
{
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"type": "lib",
"id": "stdc-shim-user",
"props": {
"cpp-root-include": true
},
"enableIf": {
"sys": [
"navy"
]
},
"provides": [
"stdc-shim"
]
}

View file

@ -0,0 +1,9 @@
#include "string.h"
size_t strlen(const char *s)
{
size_t i;
for (i = 0; s[i] != '\0'; i++)
;
return i;
}

View file

@ -0,0 +1,13 @@
#pragma once
#include <stddef.h>
/**
* @brief The strlen function computes the length of the string pointed to by s.
* @cite ISO/IEC 9899:2023 - 7.26.6.4 The strlen function
*
* @arg s - pointer to the string to be examined
* @return - the number of characters that precede the terminating null character
**/
size_t strlen(const char *s);

8
src/srvs/sched/main.c Normal file
View file

@ -0,0 +1,8 @@
#include <dbg/log.h>
_Noreturn int _start()
{
log$("Hello, world!");
for (;;)
;
}

View file

@ -0,0 +1,13 @@
{
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"type": "exe",
"id": "sched",
"requires": [
"dbg"
],
"enableIf": {
"sys": [
"navy"
]
}
}