From 607566531dd8537143bf1b31e28b19244e9632ae Mon Sep 17 00:00:00 2001 From: Matheus Date: Thu, 14 Aug 2025 20:25:43 -0300 Subject: [PATCH] kernel: rework init --- kernel-src/arch/x86-64/apic.c | 7 +- kernel-src/arch/x86-64/cpu.c | 25 ++++- kernel-src/arch/x86-64/e9.c | 12 ++- kernel-src/arch/x86-64/kernel.ld | 7 ++ kernel-src/arch/x86-64/main.c | 138 ------------------------- kernel-src/arch/x86-64/mmu.c | 3 + kernel-src/arch/x86-64/ps2.c | 3 + kernel-src/arch/x86-64/smp.c | 16 +-- kernel-src/fs/devfs.c | 3 + kernel-src/fs/ext2.c | 3 + kernel-src/fs/pipefs.c | 3 + kernel-src/fs/sockfs.c | 3 + kernel-src/fs/tmpfs.c | 3 + kernel-src/fs/vfs.c | 11 +- kernel-src/include/kernel/init.h | 80 ++++++++++++++ kernel-src/include/kernel/timekeeper.h | 2 +- kernel-src/include/logging.h | 1 + kernel-src/include/x86-64/arch/cpu.h | 2 +- kernel-src/io/acpi/acpi.c | 5 + kernel-src/io/block/nvme.c | 3 + kernel-src/io/console.c | 3 + kernel-src/io/fb.c | 3 + kernel-src/io/keyboard.c | 3 + kernel-src/io/net/arp.c | 3 + kernel-src/io/net/ipv4.c | 3 + kernel-src/io/net/loopback.c | 3 + kernel-src/io/net/tcp.c | 3 + kernel-src/io/pci.c | 3 + kernel-src/io/pseudodevices.c | 3 + kernel-src/io/pty.c | 3 + kernel-src/io/term.c | 3 + kernel-src/io/tty.c | 3 + kernel-src/io/virtio.c | 3 + kernel-src/mm/alloc.c | 3 + kernel-src/mm/pmm.c | 6 ++ kernel-src/mm/vmm.c | 3 + kernel-src/mm/vmmcache.c | 3 + kernel-src/sys/defaultauth.c | 3 + kernel-src/sys/init.c | 27 +++++ kernel-src/sys/scheduler/scheduler.c | 5 + kernel-src/sys/timekeeper.c | 13 ++- 41 files changed, 268 insertions(+), 164 deletions(-) delete mode 100644 kernel-src/arch/x86-64/main.c create mode 100644 kernel-src/include/kernel/init.h create mode 100644 kernel-src/sys/init.c diff --git a/kernel-src/arch/x86-64/apic.c b/kernel-src/arch/x86-64/apic.c index 43d17b69..1e941e97 100644 --- a/kernel-src/arch/x86-64/apic.c +++ b/kernel-src/arch/x86-64/apic.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -240,6 +241,8 @@ void arch_apic_timerinit() { __assert(current_cpu()->timer); } +INIT_ROUTINE_DEFINE(arch_timer, INIT_ROUTINE_FLAGS_NONE, arch_apic_timerinit, timekeeper_early); + void arch_apic_sendipi(uint8_t cpu, uint8_t vec, uint8_t dest, uint8_t mode, uint8_t level) { writelapic(APIC_REG_ICR_HI, (uint32_t)cpu << 24); writelapic(APIC_REG_ICR_LO, vec | (level << 8) | (mode << 11) | (dest << 18) | (1 << 14)); @@ -263,7 +266,7 @@ void arch_apic_init() { // map LAPIC to virtual memory - void *paddr = (void *) rdmsr(MSR_IA32APICBASE); + void *paddr = (void *) rdmsr(MSR_IA32APICBASE); lapic_address = vmm_map(NULL, PAGE_SIZE, VMM_FLAGS_PHYSICAL, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, paddr); __assert(lapic_address); @@ -289,3 +292,5 @@ void arch_apic_init() { // FIXME limine does this already but just in case the PIC should be masked } + +INIT_ROUTINE_DEFINE(arch_irq, INIT_ROUTINE_FLAGS_NONE, arch_apic_init, acpi_early); diff --git a/kernel-src/arch/x86-64/cpu.c b/kernel-src/arch/x86-64/cpu.c index 6c8848d7..687b5d5a 100644 --- a/kernel-src/arch/x86-64/cpu.c +++ b/kernel-src/arch/x86-64/cpu.c @@ -4,6 +4,10 @@ #include #include #include +#include +#include +#include +#include #define EFER_SYSCALLENABLE 1 @@ -145,9 +149,7 @@ static void get_topology(long *topology_ids, long *topology_types) { } } -void cpu_initstate() { - arch_apic_initap(); - +void arch_cpu_init() { // syscall instruction unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0; __get_cpuid(0x80000001, &eax, &ebx, &ecx, &edx); @@ -224,3 +226,20 @@ void cpu_initstate() { topology_insert(topology_nodes[i], i == 0 ? topology_get_root() : topology_nodes[i - 1], TOPOLOGY_MAKE_ID(topology_types[i], topology_ids[i]), current_cpu()); } } + +INIT_ROUTINE_DEFINE(cpu, INIT_ROUTINE_FLAGS_NONE, arch_cpu_init, acpi_early); + +static void infinite_loop(void) { + asm volatile("cli"); + for (;;) asm volatile(""); +} + +static void arch_early(void) { + arch_gdt_reload(); + arch_idt_setup(); + arch_idt_reload(); + interrupt_register(0xfd, (void *)infinite_loop, NULL, IPL_IGNORE); + dpc_init(); +} + +INIT_ROUTINE_DEFINE(arch_early, INIT_ROUTINE_FLAGS_NONE, arch_early) diff --git a/kernel-src/arch/x86-64/e9.c b/kernel-src/arch/x86-64/e9.c index 4043b0d0..a7ff69ad 100644 --- a/kernel-src/arch/x86-64/e9.c +++ b/kernel-src/arch/x86-64/e9.c @@ -2,6 +2,7 @@ #include #include #include +#include void arch_e9_putc(char c) { #ifdef X86_64_ENABLE_E9 @@ -9,6 +10,11 @@ void arch_e9_putc(char c) { #endif } +void arch_early_log(char c) { + arch_e9_putc(c); +} + + void arch_e9_puts(char *c) { #ifdef X86_64_ENABLE_E9 while (*c) { @@ -35,10 +41,10 @@ static int devwrite(int minor, iovec_iterator_t *iovec_iterator, size_t count, u static devops_t devops = { .write = devwrite }; -#endif void arch_e9_initdev() { -#ifdef X86_64_ENABLE_E9 __assert(devfs_register(&devops, "e9", V_TYPE_CHDEV, DEV_MAJOR_E9, 0, 0666, NULL) == 0); -#endif } + +INIT_ROUTINE_DEFINE(e9, INIT_ROUTINE_FLAGS_NONE, arch_e9_initdev, devfs); +#endif diff --git a/kernel-src/arch/x86-64/kernel.ld b/kernel-src/arch/x86-64/kernel.ld index 28043a36..b119c07e 100644 --- a/kernel-src/arch/x86-64/kernel.ld +++ b/kernel-src/arch/x86-64/kernel.ld @@ -32,6 +32,13 @@ SECTIONS *(.timekeeper_sources); timekeeper_sources_end = .; } :rodata + + . = ALIGN(8); + .init_routines : { + init_routines = .; + *(.init_routines); + init_routines_end = .; + } :rodata . = ALIGN(4K); _rodata_end = .; diff --git a/kernel-src/arch/x86-64/main.c b/kernel-src/arch/x86-64/main.c deleted file mode 100644 index 8e9fbc5b..00000000 --- a/kernel-src/arch/x86-64/main.c +++ /dev/null @@ -1,138 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static cpu_t bsp_cpu; - -void kernel_entry() { - cpu_set(&bsp_cpu); - logging_sethook(arch_e9_putc); - - arch_gdt_reload(); - arch_idt_setup(); - arch_idt_reload(); - dpc_init(); - pmm_init(); - term_init(); - logging_sethook(term_putchar); - arch_mmu_init(); - vmm_init(); - alloc_init(); - cmdline_parse(); - acpi_early_init(); - arch_apic_init(); - - timekeeper_early_init(0); - - cpu_initstate(); - - arch_apic_timerinit(); - - sched_init(); - - timekeeper_init(); - - arch_smp_wakeup(); - - timekeeper_sync(); - - pci_init(); - - acpi_init(); - - vmmcache_init(); - - vfs_init(); - tmpfs_init(); - devfs_init(); - pipefs_init(); - sockfs_init(); - ext2_init(); - - acpi_initdevice(); - - tty_init(); - pty_init(); - - loopback_init(); - arp_init(); - ipv4_init(); - tcp_init(); - - pseudodevices_init(); - arch_e9_initdev(); - keyboard_init(); - arch_ps2_init(); - fb_init(); - nvme_init(); - virtio_init(); - console_init(); - logging_sethook(console_putc); - - char *root = cmdline_get("root"); - char *rootfs = cmdline_get("rootfs"); - - printf("entry: mounting %s (%s) on /\n", root == NULL ? "none" : root, rootfs); - - vnode_t *backing; - if (root) { - __assert(devfs_getbyname(root, &backing) == 0); - } else { - backing = NULL; - } - - __assert(vfs_mount(backing, vfsroot, "/", rootfs, NULL) == 0); - - if (backing) { - VOP_RELEASE(backing); - } - - if (cmdline_get("initrd")) - initrd_unpack(); - - defaultauth_init(); - proc_run_init(); - sched_threadexit(); -} - -cpu_t *get_bsp(void) { - return &bsp_cpu; -} diff --git a/kernel-src/arch/x86-64/mmu.c b/kernel-src/arch/x86-64/mmu.c index c8237aeb..ab9533f2 100644 --- a/kernel-src/arch/x86-64/mmu.c +++ b/kernel-src/arch/x86-64/mmu.c @@ -7,6 +7,7 @@ #include #include #include +#include #define ADDRMASK (uint64_t)0x7ffffffffffff000 #define PTMASK (uint64_t)0b111111111000000000000 @@ -381,6 +382,8 @@ void arch_mmu_init() { arch_mmu_apswitch(); } +INIT_ROUTINE_DEFINE(mmu, INIT_ROUTINE_FLAGS_NONE, arch_mmu_init, pmm); + void arch_mmu_apswitch() { arch_mmu_switch(FROM_HHDM(template)); interrupt_register(13, gpfisr, NULL, IPL_IGNORE); diff --git a/kernel-src/arch/x86-64/ps2.c b/kernel-src/arch/x86-64/ps2.c index 222f99e8..62ccbded 100644 --- a/kernel-src/arch/x86-64/ps2.c +++ b/kernel-src/arch/x86-64/ps2.c @@ -2,6 +2,7 @@ #include #include #include +#include static void ps2_disablescanning(int port) { ps2_device_command(port, PS2_DEVICE_CMD_DISABLESCANNING); @@ -275,3 +276,5 @@ void arch_ps2_init() { ps2_write_command(PS2_CTLR_CMD_WRITECFG); ps2_write_data(control); } + +INIT_ROUTINE_DEFINE(ps2, INIT_ROUTINE_FLAGS_NONE, arch_ps2_init, acpi, keyboard); diff --git a/kernel-src/arch/x86-64/smp.c b/kernel-src/arch/x86-64/smp.c index f7c7b3bd..abe840b9 100644 --- a/kernel-src/arch/x86-64/smp.c +++ b/kernel-src/arch/x86-64/smp.c @@ -7,6 +7,7 @@ #include #include #include +#include static volatile struct limine_smp_request smprequest = { .id = LIMINE_SMP_REQUEST @@ -21,8 +22,6 @@ static void cpuwakeuphalt(struct limine_smp_info *info) { for (;;) CPU_HALT(); } -static time_t us_offset; - static void cpuwakeup(struct limine_smp_info *info) { cpu_set((cpu_t *)info->extra_argument); @@ -33,11 +32,13 @@ static void cpuwakeup(struct limine_smp_info *info) { arch_mmu_apswitch(); vmm_apinit(); - timekeeper_early_init(us_offset); + arch_apic_initap(); - cpu_initstate(); + timekeeper_early_init(); + + arch_cpu_init(); arch_apic_timerinit(); - + timekeeper_init(); __atomic_add_fetch(&arch_smp_cpusawake, 1, __ATOMIC_SEQ_CST); @@ -55,7 +56,6 @@ void arch_smp_haltallothers() { cpu_t **smp_cpus; void arch_smp_wakeup() { - interrupt_register(0xfd, (void *)cpuwakeuphalt, NULL, IPL_IGNORE); struct limine_smp_response *response = smprequest.response; if (response == NULL) { // TODO try to detect the other processors manually @@ -77,8 +77,6 @@ void arch_smp_wakeup() { void (*wakeupfn)(struct limine_smp_info *) = cmdline_get("nosmp") ? cpuwakeuphalt : cpuwakeup; - us_offset = timespec_us(timekeeper_timefromboot()); - // make the other processors jump to cpuwakeup() for (int i = 0; i < response->cpu_count; ++i) { // skip the bootstrap processor @@ -99,3 +97,5 @@ void arch_smp_wakeup() { printf("smp: awoke other processors\n"); } + +INIT_ROUTINE_DEFINE(smp, INIT_ROUTINE_FLAGS_NONE, arch_smp_wakeup, scheduler); diff --git a/kernel-src/fs/devfs.c b/kernel-src/fs/devfs.c index 8c917436..ef1b9496 100644 --- a/kernel-src/fs/devfs.c +++ b/kernel-src/fs/devfs.c @@ -9,6 +9,7 @@ #include #include #include +#include static devnode_t *devfsroot; @@ -498,6 +499,8 @@ void devfs_init() { __assert(hashtable_set(&devfsroot->children, devfsroot, ".", 1, true) == 0); } +INIT_ROUTINE_DEFINE(devfs, INIT_ROUTINE_FLAGS_NONE, devfs_init, vfs); + int devfs_getbyname(char *name, vnode_t **ret) { int error = vfs_lookup(ret, (vnode_t *)devfsroot, name, NULL, 0); if (error) diff --git a/kernel-src/fs/ext2.c b/kernel-src/fs/ext2.c index 24b4f2c0..42fc8fda 100644 --- a/kernel-src/fs/ext2.c +++ b/kernel-src/fs/ext2.c @@ -12,6 +12,7 @@ #include #include #include +#include #define INODE_ROOT 2 @@ -2010,3 +2011,5 @@ void ext2_init() { nodecache = slab_newcache(sizeof(ext2node_t), 0, NULL, NULL); __assert(nodecache); } + +INIT_ROUTINE_DEFINE(ext2, INIT_ROUTINE_FLAGS_NONE, ext2_init, vfs); diff --git a/kernel-src/fs/pipefs.c b/kernel-src/fs/pipefs.c index 7bb140d1..72d59c15 100644 --- a/kernel-src/fs/pipefs.c +++ b/kernel-src/fs/pipefs.c @@ -8,6 +8,7 @@ #include #include #include +#include #define BUFFER_SIZE 16 * PAGE_SIZE #define PIPE_ATOMIC_SIZE 4096 @@ -403,6 +404,8 @@ void pipefs_init() { __assert(nodecache); } +INIT_ROUTINE_DEFINE(pipefs, INIT_ROUTINE_FLAGS_NONE, pipefs_init, bsp_early); + int pipefs_newpipe(vnode_t **nodep) { vnode_t *vnode = slab_allocate(nodecache); pipenode_t *node = (pipenode_t *)vnode; diff --git a/kernel-src/fs/sockfs.c b/kernel-src/fs/sockfs.c index 8d7b752d..2064e93b 100644 --- a/kernel-src/fs/sockfs.c +++ b/kernel-src/fs/sockfs.c @@ -9,6 +9,7 @@ #include #include #include +#include static scache_t *nodecache; static uintmax_t currentinode; @@ -267,6 +268,8 @@ void sockfs_init() { __assert(nodecache); } +INIT_ROUTINE_DEFINE(sockfs, INIT_ROUTINE_FLAGS_NONE, sockfs_init, bsp_early); + int sockfs_newsocket(vnode_t **nodep, socket_t *socket) { vnode_t *vnode = slab_allocate(nodecache); socketnode_t *node = (socketnode_t *)vnode; diff --git a/kernel-src/fs/tmpfs.c b/kernel-src/fs/tmpfs.c index 1fbc48a8..7481086a 100644 --- a/kernel-src/fs/tmpfs.c +++ b/kernel-src/fs/tmpfs.c @@ -15,6 +15,7 @@ #include #include #include +#include static scache_t *nodecache; static tmpfsnode_t *newnode(vfs_t *vfs, int type); @@ -598,3 +599,5 @@ void tmpfs_init() { nodecache = slab_newcache(sizeof(tmpfsnode_t), 0, NULL, NULL); __assert(nodecache); } + +INIT_ROUTINE_DEFINE(tmpfs, INIT_ROUTINE_FLAGS_NONE, tmpfs_init, vfs); diff --git a/kernel-src/fs/vfs.c b/kernel-src/fs/vfs.c index e74eec38..c9637b10 100644 --- a/kernel-src/fs/vfs.c +++ b/kernel-src/fs/vfs.c @@ -11,6 +11,7 @@ #include #include #include +#include #define PATHNAME_MAX 512 #define MAXLINKDEPTH 64 @@ -18,7 +19,7 @@ static hashtable_t fstable; vnode_t *vfsroot; -static spinlock_t listlock; +static mutex_t listlock; static vfs_t *vfslist; static cred_t *getcred() { @@ -53,12 +54,14 @@ void vfs_init() { __assert(hashtable_init(&fstable, 20) == 0); vfsroot = alloc(sizeof(vnode_t)); __assert(vfsroot); - SPINLOCK_INIT(listlock); + MUTEX_INIT(&listlock); vfsroot->type = V_TYPE_DIR; vfsroot->refcount = 1; vfsroot->ops = &vnops; } +INIT_ROUTINE_DEFINE(vfs, INIT_ROUTINE_FLAGS_NONE, vfs_init, bsp_early); + int vfs_register(vfsops_t *ops, char *name) { return hashtable_set(&fstable, ops, name, strlen(name), true); } @@ -111,12 +114,12 @@ int vfs_mount(vnode_t *backing, vnode_t *pathref, char *path, char *name, void * return err; } - spinlock_acquire(&listlock); + MUTEX_ACQUIRE(&listlock); vfs->next = vfslist; vfslist = vfs; - spinlock_release(&listlock); + MUTEX_RELEASE(&listlock); mounton->vfsmounted = vfs; vfs->nodecovered = mounton; diff --git a/kernel-src/include/kernel/init.h b/kernel-src/include/kernel/init.h new file mode 100644 index 00000000..f56dd3eb --- /dev/null +++ b/kernel-src/include/kernel/init.h @@ -0,0 +1,80 @@ +#ifndef _INIT_H +#define _INIT_H + +#include + +#define INIT_ROUTINE_FLAGS_NONE 0 +#define INIT_ROUTINE_FLAGS_ALREADY_DONE 1 +#define INIT_ROUTINE_FLAGS_QUIET 2 +#define INIT_ROUTINE_FLAGS_PHONY 4 + +typedef struct init_routine_t { + const char *name; + int flags; + void (*fn)(void); + struct init_routine_t ***dependencies; + size_t dependency_count; +} init_routine_t; + +// tasty tasty macro soup! +// this will make it cleaner overall and keep the ugly here +// if any routine has more than 10 deps add more here +#define INIT_MACRO_ARG_COUNT_(n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n, ...) n +#define INIT_MACRO_ARG_COUNT(...) INIT_MACRO_ARG_COUNT_(0, ## __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#define INIT_CONCAT_(a, b) a##b +#define INIT_CONCAT(a, b) INIT_CONCAT_(a, b) + + +#define INIT_GET_DEP_NAME(x) init_routine_ ## x + +#define INIT_DEFINE_EXTERN(x) extern init_routine_t * INIT_GET_DEP_NAME(x) +#define INIT_DEFINE_EXTERN_0(...) +#define INIT_DEFINE_EXTERN_1(x) INIT_DEFINE_EXTERN(x) +#define INIT_DEFINE_EXTERN_2(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_1(__VA_ARGS__) +#define INIT_DEFINE_EXTERN_3(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_2(__VA_ARGS__) +#define INIT_DEFINE_EXTERN_4(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_3(__VA_ARGS__) +#define INIT_DEFINE_EXTERN_5(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_4(__VA_ARGS__) +#define INIT_DEFINE_EXTERN_6(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_5(__VA_ARGS__) +#define INIT_DEFINE_EXTERN_7(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_6(__VA_ARGS__) +#define INIT_DEFINE_EXTERN_8(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_7(__VA_ARGS__) +#define INIT_DEFINE_EXTERN_9(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_8(__VA_ARGS__) +#define INIT_DEFINE_EXTERN_10(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_9(__VA_ARGS__) + +#define INIT_GET_DEP_0(...) +#define INIT_GET_DEP_1(x) &INIT_GET_DEP_NAME(x) +#define INIT_GET_DEP_2(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_1(__VA_ARGS__) +#define INIT_GET_DEP_3(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_2(__VA_ARGS__) +#define INIT_GET_DEP_4(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_3(__VA_ARGS__) +#define INIT_GET_DEP_5(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_4(__VA_ARGS__) +#define INIT_GET_DEP_6(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_5(__VA_ARGS__) +#define INIT_GET_DEP_7(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_6(__VA_ARGS__) +#define INIT_GET_DEP_8(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_7(__VA_ARGS__) +#define INIT_GET_DEP_9(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_8(__VA_ARGS__) +#define INIT_GET_DEP_10(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_9(__VA_ARGS__) + +#define INIT_GET_ROUTINE(name) init_routine_##name + +// ... is deps +#define INIT_ROUTINE_DEFINE(name_, flags_, fn_, ...) \ + /* first define all dependencies as extern. if none, then it will not define any + * but since it will not be used, then there is no harm done. */ \ + INIT_CONCAT(INIT_DEFINE_EXTERN_, INIT_MACRO_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__); \ + /* then, create the array of the dependencies for the use in the main struct. + * if none, then it will just be empty */ \ + static init_routine_t **init_routine_deps_##name_ [] = { \ + INIT_CONCAT(INIT_GET_DEP_, INIT_MACRO_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__) \ + }; \ + /* finally, define the init routine struct and keep a pointer to it in the special section */ \ + static init_routine_t struct_init_routine_##name_ = { \ + .name = #name_, \ + .flags = flags_, \ + .fn = fn_, \ + .dependencies = init_routine_deps_##name_, \ + .dependency_count = INIT_MACRO_ARG_COUNT(__VA_ARGS__) \ + }; \ + __attribute__((section(".init_routines"), used)) init_routine_t *init_routine_##name_ = &struct_init_routine_##name_; + +void init_run_routine(init_routine_t *routine); +void init_run_all_routines(void); + +#endif diff --git a/kernel-src/include/kernel/timekeeper.h b/kernel-src/include/kernel/timekeeper.h index 3d4e09ae..76274731 100644 --- a/kernel-src/include/kernel/timekeeper.h +++ b/kernel-src/include/kernel/timekeeper.h @@ -21,7 +21,7 @@ typedef struct { } timekeeper_source_t; // initializes the highest priority source that can be used as an early timer and switches the cpu to use it -void timekeeper_early_init(time_t us_offset); +void timekeeper_early_init(void); // initializes the highest priority source and switches the cpu to use it. uses the early timer for calibration if nescessary void timekeeper_init(void); diff --git a/kernel-src/include/logging.h b/kernel-src/include/logging.h index 9a8407df..e06c67b2 100644 --- a/kernel-src/include/logging.h +++ b/kernel-src/include/logging.h @@ -7,6 +7,7 @@ #include #include +void arch_early_log(char c); void _putchar(char c); void logging_sethook(void (*fun)(char)); void logging_init(); diff --git a/kernel-src/include/x86-64/arch/cpu.h b/kernel-src/include/x86-64/arch/cpu.h index 4ebc3af3..50c576a8 100644 --- a/kernel-src/include/x86-64/arch/cpu.h +++ b/kernel-src/include/x86-64/arch/cpu.h @@ -117,6 +117,6 @@ static inline void cpu_set(cpu_t *ptr) { wrmsr(MSR_GSBASE, (uint64_t)ptr); } -void cpu_initstate(); +void arch_cpu_init(); #endif diff --git a/kernel-src/io/acpi/acpi.c b/kernel-src/io/acpi/acpi.c index fde9f228..cb610e53 100644 --- a/kernel-src/io/acpi/acpi.c +++ b/kernel-src/io/acpi/acpi.c @@ -7,12 +7,15 @@ #include #include #include +#include #include void acpi_early_init(void) { __assert(uacpi_initialize(0) == UACPI_STATUS_OK); } +INIT_ROUTINE_DEFINE(acpi_early, INIT_ROUTINE_FLAGS_NONE, acpi_early_init, alloc); + void acpi_dopoweroff(uacpi_handle ctx) { (void)ctx; acpi_signaldevice('p'); @@ -37,6 +40,8 @@ void acpi_init(void) { uacpi_install_fixed_event_handler(UACPI_FIXED_EVENT_POWER_BUTTON, handle_pwrbtn, UACPI_NULL); } +INIT_ROUTINE_DEFINE(acpi, INIT_ROUTINE_FLAGS_NONE, acpi_init, pci, devfs, scheduler); + int acpi_poweroff(void) { uacpi_status ret = uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S5); if (uacpi_unlikely_error(ret)) { diff --git a/kernel-src/io/block/nvme.c b/kernel-src/io/block/nvme.c index 675496ca..c67a42a3 100644 --- a/kernel-src/io/block/nvme.c +++ b/kernel-src/io/block/nvme.c @@ -10,6 +10,7 @@ #include #include #include +#include #define CC_ENABLE(cc) cc = (cc) | 1 #define CC_DISABLE(cc) cc = (cc) & ~1 @@ -788,3 +789,5 @@ void nvme_init() { initcontroller(e); } } + +INIT_ROUTINE_DEFINE(nvme, INIT_ROUTINE_FLAGS_NONE, nvme_init, acpi); diff --git a/kernel-src/io/console.c b/kernel-src/io/console.c index 8368509c..a06ba384 100644 --- a/kernel-src/io/console.c +++ b/kernel-src/io/console.c @@ -9,6 +9,7 @@ #include #include #include +#include static mutex_t writemutex; static thread_t *thread; @@ -124,3 +125,5 @@ void console_init() { tty->winsize.ws_xpixel = fbx; tty->winsize.ws_ypixel = fby; } + +INIT_ROUTINE_DEFINE(console, INIT_ROUTINE_FLAGS_NONE, console_init, scheduler, keyboard); diff --git a/kernel-src/io/fb.c b/kernel-src/io/fb.c index 0cdb018d..7f96be0e 100644 --- a/kernel-src/io/fb.c +++ b/kernel-src/io/fb.c @@ -7,6 +7,7 @@ #include #include #include +#include typedef struct bitfield_t { uint32_t offset; @@ -256,3 +257,5 @@ void fb_init() { printf("%s: %dx%d %d bpp\n", name, fb->width, fb->height, fb->bpp); } } + +INIT_ROUTINE_DEFINE(fb, INIT_ROUTINE_FLAGS_NONE, fb_init, devfs); diff --git a/kernel-src/io/keyboard.c b/kernel-src/io/keyboard.c index 4660c8d4..d0f4decf 100644 --- a/kernel-src/io/keyboard.c +++ b/kernel-src/io/keyboard.c @@ -6,6 +6,7 @@ #include #include #include +#include #define BUFFER_PACKET_CAPACITY 100 #define BUFFER_SIZE (BUFFER_PACKET_CAPACITY * sizeof(kbpacket_t)) @@ -252,3 +253,5 @@ void keyboard_init() { __assert(keyboard_console); __assert(hashtable_init(&kbtable, 20) == 0); } + +INIT_ROUTINE_DEFINE(keyboard, INIT_ROUTINE_FLAGS_NONE, keyboard_init, bsp_early); diff --git a/kernel-src/io/net/arp.c b/kernel-src/io/net/arp.c index 3cffb0ca..fcaa9916 100644 --- a/kernel-src/io/net/arp.c +++ b/kernel-src/io/net/arp.c @@ -7,6 +7,7 @@ #include #include #include +#include #define CACHE_TIMEOUT_SEC 300 #define CACHE_TIMEOUT_MS (CACHE_TIMEOUT_SEC * 1000) @@ -315,3 +316,5 @@ void arp_init() { sched_queue(handlerthread); sched_queue(cleanupthread); } + +INIT_ROUTINE_DEFINE(arp, INIT_ROUTINE_FLAGS_NONE, arp_init, scheduler); diff --git a/kernel-src/io/net/ipv4.c b/kernel-src/io/net/ipv4.c index 7267682a..2e134ba2 100644 --- a/kernel-src/io/net/ipv4.c +++ b/kernel-src/io/net/ipv4.c @@ -5,6 +5,7 @@ #include #include #include +#include typedef struct { netdev_t *netdev; @@ -229,3 +230,5 @@ void ipv4_init() { __assert(routingtable); __assert(ipv4_addroute(loopback_device(), 0x7f000001, 0, 0xff000000, 10000) == 0); } + +INIT_ROUTINE_DEFINE(ipv4, INIT_ROUTINE_FLAGS_NONE, ipv4_init, devfs) diff --git a/kernel-src/io/net/loopback.c b/kernel-src/io/net/loopback.c index d7a9f5a7..7086170f 100644 --- a/kernel-src/io/net/loopback.c +++ b/kernel-src/io/net/loopback.c @@ -5,6 +5,7 @@ #include #include #include +#include static netdev_t loopbacknetdev; @@ -64,3 +65,5 @@ void loopback_init() { __assert(netdev_register(&loopbacknetdev, "lo") == 0); } + +INIT_ROUTINE_DEFINE(loopback, INIT_ROUTINE_FLAGS_NONE, loopback_init, devfs); diff --git a/kernel-src/io/net/tcp.c b/kernel-src/io/net/tcp.c index 168f25aa..ee47c38a 100644 --- a/kernel-src/io/net/tcp.c +++ b/kernel-src/io/net/tcp.c @@ -5,6 +5,7 @@ #include #include #include +#include #define WORKER_COUNT 12 #define WORKER_BUFFER_SIZE (64 * 1024) @@ -1879,3 +1880,5 @@ void tcp_init() { sched_queue(thread); } } + +INIT_ROUTINE_DEFINE(tcp, INIT_ROUTINE_FLAGS_NONE, tcp_init, ipv4, scheduler); diff --git a/kernel-src/io/pci.c b/kernel-src/io/pci.c index 50a3869e..d836caeb 100644 --- a/kernel-src/io/pci.c +++ b/kernel-src/io/pci.c @@ -3,6 +3,7 @@ #include #include #include +#include uint8_t pci_read8(int bus, int device, int function, uint32_t offset) { return (pci_archread32(bus, device, function, offset) >> ((offset & 0b11) * 8)) & 0xff; @@ -279,3 +280,5 @@ void pci_init() { } } } + +INIT_ROUTINE_DEFINE(pci, INIT_ROUTINE_FLAGS_NONE, pci_init, scheduler); diff --git a/kernel-src/io/pseudodevices.c b/kernel-src/io/pseudodevices.c index 382ce858..f43c3b5f 100644 --- a/kernel-src/io/pseudodevices.c +++ b/kernel-src/io/pseudodevices.c @@ -3,6 +3,7 @@ #include #include #include +#include static int null_write(int minor, iovec_iterator_t *iovec_iterator, size_t count, uintmax_t offset, int flags, size_t *wcount) { *wcount = count; @@ -77,3 +78,5 @@ void pseudodevices_init() { __assert(devfs_register(&zeroops, "zero", V_TYPE_CHDEV, DEV_MAJOR_ZERO, 0, 0666, NULL) == 0); __assert(devfs_register(&urandomops, "urandom", V_TYPE_CHDEV, DEV_MAJOR_URANDOM, 0, 0666, NULL) == 0); } + +INIT_ROUTINE_DEFINE(pseudo_devices, INIT_ROUTINE_FLAGS_NONE, pseudodevices_init, devfs); diff --git a/kernel-src/io/pty.c b/kernel-src/io/pty.c index 987856f2..003b2b93 100644 --- a/kernel-src/io/pty.c +++ b/kernel-src/io/pty.c @@ -4,6 +4,7 @@ #include #include #include +#include #define PTY_BUFFER 4096 #define PTY_MAX 1024 @@ -285,3 +286,5 @@ void pty_init() { __assert(devfs_createdir("pts") == 0); SPINLOCK_INIT(listlock); } + +INIT_ROUTINE_DEFINE(pty, INIT_ROUTINE_FLAGS_NONE, pty_init, tty); diff --git a/kernel-src/io/term.c b/kernel-src/io/term.c index aa51d32a..1691389b 100644 --- a/kernel-src/io/term.c +++ b/kernel-src/io/term.c @@ -8,6 +8,7 @@ #include #include #include +#include extern volatile struct limine_framebuffer_request fb_liminereq; static size_t xs, ys, fbxs, fbys; @@ -66,3 +67,5 @@ void term_init() { MUTEX_INIT(&term_mutex); } + +INIT_ROUTINE_DEFINE(term, INIT_ROUTINE_FLAGS_NONE, term_init, pmm); diff --git a/kernel-src/io/tty.c b/kernel-src/io/tty.c index 007c2f99..07b459a2 100644 --- a/kernel-src/io/tty.c +++ b/kernel-src/io/tty.c @@ -4,6 +4,7 @@ #include #include #include +#include #define TTY_MAX_COUNT 4096 #define CONTROLLING_TTY_MINOR TTY_MAX_COUNT @@ -552,3 +553,5 @@ void tty_init() { __assert(devfs_register(&devops, "tty", V_TYPE_CHDEV, DEV_MAJOR_TTY, CONTROLLING_TTY_MINOR, 0666, NULL) == 0); MUTEX_INIT(&listmutex); } + +INIT_ROUTINE_DEFINE(tty, INIT_ROUTINE_FLAGS_NONE, tty_init, devfs); diff --git a/kernel-src/io/virtio.c b/kernel-src/io/virtio.c index 6e395c44..befac83f 100644 --- a/kernel-src/io/virtio.c +++ b/kernel-src/io/virtio.c @@ -3,6 +3,7 @@ #include #include #include +#include #define VIRTIO_VENDOR 0x1af4 #define VIRTIO_DEVICE_MIN 0x1000 @@ -176,3 +177,5 @@ void virtio_init() { } } } + +INIT_ROUTINE_DEFINE(virtio, INIT_ROUTINE_FLAGS_NONE, virtio_init, acpi); diff --git a/kernel-src/mm/alloc.c b/kernel-src/mm/alloc.c index f803b83e..877679c8 100644 --- a/kernel-src/mm/alloc.c +++ b/kernel-src/mm/alloc.c @@ -2,6 +2,7 @@ #include #include #include +#include // each allocation has the following structure: // ptr: data capacity (allocsizes size) @@ -96,3 +97,5 @@ void alloc_init() { for (int i = 0; i < 5; ++i) caches[i] = caches[5]; } + +INIT_ROUTINE_DEFINE(alloc, INIT_ROUTINE_FLAGS_NONE, alloc_init, vmm); diff --git a/kernel-src/mm/pmm.c b/kernel-src/mm/pmm.c index df715550..9d6ac48b 100644 --- a/kernel-src/mm/pmm.c +++ b/kernel-src/mm/pmm.c @@ -6,6 +6,7 @@ #include #include #include +#include uintptr_t hhdmbase; static size_t memorysize; @@ -266,6 +267,11 @@ void pmm_init() { MUTEX_INIT(&freelistmutex); } +INIT_ROUTINE_DEFINE(pmm, + INIT_ROUTINE_FLAGS_NONE, + pmm_init, + arch_early); + // XXX pmm_alloc won't be able to take pages from the page cache when the allocation size is over 1 page void *pmm_alloc(size_t size, int section) { diff --git a/kernel-src/mm/vmm.c b/kernel-src/mm/vmm.c index 21cee500..b0a9ec6c 100644 --- a/kernel-src/mm/vmm.c +++ b/kernel-src/mm/vmm.c @@ -7,6 +7,7 @@ #include #include #include +#include #define RANGE_TOP(x) (void *)((uintptr_t)x->start + x->size) @@ -962,6 +963,8 @@ void vmm_init() { printspace(&kernelspace); } +INIT_ROUTINE_DEFINE(vmm, INIT_ROUTINE_FLAGS_NONE, vmm_init, mmu); + void vmm_apinit() { vmm_switchcontext(&vmm_kernelctx); } diff --git a/kernel-src/mm/vmmcache.c b/kernel-src/mm/vmmcache.c index f9ab2c25..6c041497 100644 --- a/kernel-src/mm/vmmcache.c +++ b/kernel-src/mm/vmmcache.c @@ -4,6 +4,7 @@ #include #include #include +#include #define TABLE_SIZE 4096 #define WRITER_TICK_SECONDS 15 @@ -475,3 +476,5 @@ void vmmcache_init() { EVENT_INITHEADER(&syncevent); EVENT_INITHEADER(&pagereadyevent); } + +INIT_ROUTINE_DEFINE(vmm_cache, INIT_ROUTINE_FLAGS_NONE, vmmcache_init, scheduler); diff --git a/kernel-src/sys/defaultauth.c b/kernel-src/sys/defaultauth.c index e6e49a65..33f1650f 100644 --- a/kernel-src/sys/defaultauth.c +++ b/kernel-src/sys/defaultauth.c @@ -1,5 +1,6 @@ #include #include +#include // default listeners for auth @@ -285,3 +286,5 @@ void defaultauth_init() { auth_registerlistener(AUTH_SCOPE_PROCESS, process); auth_registerlistener(AUTH_SCOPE_NETWORK, network); } + +INIT_ROUTINE_DEFINE(default_auth, INIT_ROUTINE_FLAGS_NONE, defaultauth_init, bsp_early); diff --git a/kernel-src/sys/init.c b/kernel-src/sys/init.c new file mode 100644 index 00000000..ef1d0f8a --- /dev/null +++ b/kernel-src/sys/init.c @@ -0,0 +1,27 @@ +#include +#include +#include + +void init_run_routine(init_routine_t *routine) { + if (routine->flags & INIT_ROUTINE_FLAGS_ALREADY_DONE) + return; + + for (int i = 0; i < routine->dependency_count; ++i) + init_run_routine(*routine->dependencies[i]); + + if ((routine->flags & INIT_ROUTINE_FLAGS_QUIET) == 0) + printf("kernel_init: running routine %s\n", routine->name); + + if ((routine->flags & INIT_ROUTINE_FLAGS_PHONY) == 0) + routine->fn(); + + routine->flags |= INIT_ROUTINE_FLAGS_ALREADY_DONE; +} + +extern init_routine_t *init_routines; +extern init_routine_t *init_routines_end; + +void init_run_all_routines(void) { + for (init_routine_t **routine_ptr = &init_routines; routine_ptr < &init_routines_end; ++routine_ptr) + init_run_routine(*routine_ptr); +} diff --git a/kernel-src/sys/scheduler/scheduler.c b/kernel-src/sys/scheduler/scheduler.c index c779d504..96391bca 100644 --- a/kernel-src/sys/scheduler/scheduler.c +++ b/kernel-src/sys/scheduler/scheduler.c @@ -13,6 +13,7 @@ #include #include #include +#include #define QUANTUM_US 100000 #define SCHEDULER_STACK_SIZE PAGE_SIZE * 16 @@ -458,7 +459,11 @@ void sched_init() { current_cpu()->reschedule_isr = interrupt_allocate(reschedule_ipi, ARCH_EOI, IPL_MAX); __assert(current_cpu()->reschedule_isr); + sched_target_cpu(current_cpu()); + timer_insert(current_cpu()->timer, ¤t_cpu()->schedtimerentry, reschedule_timer_dpc, NULL, QUANTUM_US, true); // XXX move this resume to a more appropriate place timer_resume(current_cpu()->timer); } + +INIT_ROUTINE_DEFINE(scheduler, INIT_ROUTINE_FLAGS_NONE, sched_init, arch_timer); diff --git a/kernel-src/sys/timekeeper.c b/kernel-src/sys/timekeeper.c index 42a7823d..c57e28c4 100644 --- a/kernel-src/sys/timekeeper.c +++ b/kernel-src/sys/timekeeper.c @@ -4,6 +4,7 @@ #include #include #include +#include static volatile struct limine_boot_time_request timereq = { .id = LIMINE_BOOT_TIME_REQUEST, @@ -106,6 +107,8 @@ void timekeeper_sync(void) { MUTEX_RELEASE(&sync_mutex); } +INIT_ROUTINE_DEFINE(sync_cpu_time, INIT_ROUTINE_FLAGS_NONE, timekeeper_sync, smp, timekeeper); + extern timekeeper_source_t *timekeeper_sources; extern timekeeper_source_t *timekeeper_sources_end; @@ -130,7 +133,7 @@ void timekeeper_wait_us(time_t us) { CPU_PAUSE(); } -void timekeeper_early_init(time_t us_offset) { +void timekeeper_early_init(void) { __assert(timereq.response); boot_unix = timereq.response->boot_time; @@ -151,14 +154,12 @@ void timekeeper_early_init(time_t us_offset) { current_cpu()->timekeeper_source_info = early_source_info; current_cpu()->timekeeper_source = early_source; - // this tick offset is to account for any possible time before early_init. - // for example, on SMP init the early init will have the time passed on the ap as an offset - current_cpu()->timekeeper_source_tick_offset = us_offset * early_source_info->hz / 1000000; - printf("cpu%d: timekeeper: \"%s\" selected as early source. %lu ticks at early init (%lu hz)\n", current_cpu_id(), early_source->name, current_cpu()->timekeeper_source_base_ticks, early_source_info->hz); } +INIT_ROUTINE_DEFINE(timekeeper_early, INIT_ROUTINE_FLAGS_NONE, timekeeper_early_init, arch_irq); + // this will do a re-init per cpu // the initialization threads will not switch cpus so we dont have to worry about it here void timekeeper_init(void) { @@ -197,3 +198,5 @@ void timekeeper_init(void) { printf("cpu%d: timekeeper: \"%s\" selected as main source. %lu ticks at init (%lu hz)\n", current_cpu_id(), new_source->name, current_cpu()->timekeeper_source_base_ticks, new_source_info->hz); } + +INIT_ROUTINE_DEFINE(timekeeper, INIT_ROUTINE_FLAGS_NONE, timekeeper_init, scheduler);