| git.druid.rocks | index | druid520 | kaboom | src/ | kernel/ | kmain.nsc |
src/kernel/kmain.nsc
/*
* kernel entry point, called directly from boot.s's long_mode_entry
* once the cpu is actually in 64-bit mode with paging live. this file
* intentionally does no -s/freestanding-mode nscc tricks (see docs
* note below) -- it's just an ordinary function that boot.s calls.
*
* why not nscc's -s mode: -s hardcodes the entry function's name to
* "main" and emits a _start that ends in a real linux/netbsd exit
* syscall, which is meaningless with no os underneath. boot.s is the
* real entry point; this is just the first ordinary function it calls,
* same extern-linking pattern as everything else in this kernel.
*/
include "klog.nsh";
include "../fs/kfs.nsh";
include "exec.nsh";
include "vmm.nsh";
void gdt_init(void);
void idt_init(void);
void vga_init(void);
void vga_puts(ptr str);
void serial_init(void);
void serial_puts(ptr str);
void kbd_init(void);
void alloc_init(void);
void klog_init(void);
void halt(void);
void sti(void);
void vmm_init(void);
void vmm_e820_from_pvh(void);
u32 get_bios_boot_flag(void);
u32 get_bios_e820_ptr32(void);
u32 get_bios_e820_count32(void);
u64 get_cr3(void);
global void
kmain(void)
{
kernel_cr3 = get_cr3();
ptr argv0[1];
/* boot progress used to also go straight to vga+serial (every
* "kaboom: X ok" line, printed twice over -- once here via
* klog_write, once again by hand on the console) -- removed from
* the console specifically, not from the log: klog_write still
* records every line below exactly as before, so `klogs` shows
* the full boot sequence; the console itself now stays quiet until
* sh's own first "$ " prompt, or a genuine fatal halt below. */
klog_init();
klog_write("kaboom: boot start\n");
gdt_init();
klog_write("kaboom: gdt ok\n");
idt_init();
klog_write("kaboom: idt ok\n");
alloc_init();
klog_write("kaboom: alloc ok\n");
/* which boot path got us here, pvh (qemu -kernel) or real-bios
* (dynamite.s) -- dynamite sets an explicit, otherwise-impossible
* sentinel in %ebp right before jumping in (see its own comment),
* which boot.s's _start saves off before anything else can touch
* it; a genuine pvh boot never runs dynamite.s at all, so this flag
* reads as whatever qemu's own pvh loader happened to leave there,
* never this exact value. */
if((u64)get_bios_boot_flag() == (u64)0xb105b00b)
{
vmm_e820_from_bios((u64)get_bios_e820_ptr32(), (u64)get_bios_e820_count32());
}
else
{
vmm_e820_from_pvh();
}
vmm_init();
klog_write("kaboom: vmm ok\n");
serial_init();
vga_init();
kbd_init();
klog_write("kaboom: vga+kbd ok\n");
klog_write("kaboom: enabling interrupts\n");
/* everything up to here ran entirely with interrupts off (boot.s's
* initial cli, never re-enabled) -- irq1 (keyboard) is unmasked in
* the pic but the cpu's IF flag still has to actually be set or it
* never fires regardless. */
sti();
if(kfs_mount() == 0)
{
serial_puts("kaboom: no kfs filesystem on disk -- halting\n");
vga_puts("no filesystem -- halting\n");
while(1)
{
halt();
}
}
klog_write("kaboom: kfs mounted\n");
proc_init();
/* sh is init here, not a process something else launches -- if it
* ever returns (the user typed "exit"), respawn it rather than
* halt, the same way a real getty would. exec failing outright
* (sh missing from the disk entirely) is the only real halt path. */
while(1)
{
argv0[0] = "sh";
if(sys_exec("sh", (u64)2, (i64)1, (ptr)&argv0[0]) == (i64)(-1))
{
serial_puts("kaboom: exec sh failed -- halting\n");
vga_puts("exec sh failed -- halting\n");
while(1)
{
halt();
}
}
}
}