feature: boot.mgr replace hardcoded init sequence with dependency-driven boot manager

Introduce boot.mgr - a self-registering, dependency-ordered boot
initialization framework with barrier-based phasing and glob pattern
matching. Units now declare their own init procedures and dependencies
via registerBoot()/registerBarrier() in their initialization sections,
boot.mgr.run() topologically sorts and executes them.

- Add src/boot/boot.mgr.pas with topoSort, glob matching, barrier
  two-pass algorithm, and boot tree printer
- Gut src/asuro.pas (kmain): now just stores multiboot info, calls
  System.init(), boot.mgr.run, and yield()
- Add initialization sections with registerBoot() to 53 existing units
- Add new units: core.pas, test.pas, driver.storage.boot.pas,
  app.wasm.pas, app.bsod.pas (factored out of asuro.pas)
- Define 9 barrier phases: immediate -> early -> middle -> storage ->
  bus -> device -> bus.late -> late -> final
- Fix xHCI ISR: exclude PRC/WRC from PORTSC change bit clearing to
  prevent race with port reset busy-wait
- Fix driver.bus.usb.core fire_completion_hooks: guard against uint32
  underflow when CompletionHookCount = 0
- Move auto_mount_volumes from device barrier to late barrier so it
  runs after PCI scan discovers storage controllers
- Add toolchain/compile_initcalls.sh for boot entry extraction
- Add Boot Registration sections to all 51 doc files; create 4 new
  doc files; rewrite boot.mgr.md; update mkdocs.yml nav
This commit is contained in:
t3hn3rd committed 2026-03-13 15:37:43 +00:00
1 parent dd56ffbcb4
commit 2d190c221a
116 files changed
+1922 -465

No files matched your search

+9
View File
@@ -22,6 +22,7 @@ unit arch.x86.cpu;
interface
uses
boot.mgr,
core.util, arch.x86.util, driver.timer.rtc, io.stdio;
type
@@ -117,6 +118,9 @@ procedure Terminal_Command_CPU(Params : PParamList; stdin_buf, stdout_buf, stder
implementation
uses
io.syslog;
procedure getCPUIdentifier;
var
id0, id1, id2 : uint32;
@@ -323,6 +327,7 @@ end;
procedure init();
begin
io.syslog.logln('CPU', 'Init begin');
CPUID.Capabilities0:= PCapabilities_Old(@CAP_OLD);
CPUID.Capabilities1:= PCapabilities_New(@CAP_NEW);
getCPUIdentifier;
@@ -330,6 +335,10 @@ begin
getCPUClockSpeed;
enableSSE;
enableAVX;
io.syslog.logln('CPU', 'Init end');
end;
initialization
boot.mgr.registerBoot('arch.x86.cpu', @init, 'x86 CPU Initialization', BOOT_MGR_BARRIER_EARLY);
end.
+26 -3
View File
@@ -22,7 +22,7 @@ unit arch.x86.gdt;
interface
uses
io.syslog;
io.syslog, core.panic;
type
TGDT_Entry = packed record
@@ -51,6 +51,9 @@ procedure reload;
implementation
uses
boot.mgr;
procedure flush_gdt(gdt_pointer : uint32); assembler; nostackframe;
asm
MOV EAX, gdt_pointer
@@ -105,9 +108,8 @@ begin
io.syslog.writestringln(' SET.');
end;
procedure init();
procedure initializeBaseGTD();
begin
io.syslog.logln('GDT','INIT START.');
gdt_pointer.limit:= 0;
gdt_pointer.base := uint32(@gdt_entries);
set_gate($00, $00, $00, $00, $00); //OFFSET: 0
@@ -116,7 +118,28 @@ begin
set_gate($03, $00, $FFFFFFFF, $FA, $CF); //OFFSET: 24
set_gate($04, $00, $FFFFFFFF, $F2, $CF); //OFFSET: 32
flush;
end;
procedure init();
var
dds : uint16;
begin
io.syslog.logln('GDT','INIT START.');
initializeBaseGTD();
asm
MOV dds, CS
end;
if dds = $08 then begin
io.syslog.logln('KERNEL', 'GDT: LOAD SUCCESS.');
end else begin
io.syslog.logln('KERNEL', 'GDT: LOAD FAIL.');
io.syslog.logln('KERNEL', 'HALTING.');
core.panic.panic('GDT', 'Failed to load the GDT correctly.', nil);
end;
io.syslog.logln('GDT','INIT END.');
end;
initialization
boot.mgr.registerBoot('arch.x86.gdt', @init, 'Global Descriptor Table', BOOT_MGR_BARRIER_EARLY);
end.
+4
View File
@@ -22,6 +22,7 @@ unit arch.x86.idt;
interface
uses
boot.mgr,
core.util, arch.x86.util, io.syslog;
const
@@ -86,4 +87,7 @@ begin
io.syslog.logln('IDT','INIT END.');
end;
initialization
boot.mgr.registerBoot('arch.x86.idt', @init, 'Interrupt Descriptor Table', 'arch.x86.gdt');
end.
+6 -1
View File
@@ -21,7 +21,9 @@ unit arch.x86.irq;
interface
uses core.util, arch.x86.util, io.syslog;
uses
boot.mgr,
core.util, arch.x86.util, io.syslog;
procedure init();
@@ -53,4 +55,7 @@ begin
io.syslog.logln('IRQ','INIT END.');
end;
initialization
boot.mgr.registerBoot('arch.x86.irq', @init, 'Interrupt Request Line', 'arch.x86.idt');
end.
+11 -1
View File
@@ -21,13 +21,23 @@ unit arch.x86.isr;
interface
uses
boot.mgr;
procedure init();
implementation
uses
arch.x86.util, arch.x86.isr.tmr0, arch.x86.bda;
procedure init();
begin
STI;
arch.x86.isr.tmr0.hook(uint32(@arch.x86.bda.tick_update));
end;
Initialization
boot.mgr.registerBoot('asuro.x86.isr', @init, 'Enable Interrupts and Timer', 'driver.storage.*.mgr');
end.
+9 -3
View File
@@ -12,7 +12,9 @@ unit arch.x86.panic;
interface
uses
core.panic;
boot.mgr,
core.panic,
io.syslog;
{ Register the x86 halt procedure with core.panic. Call after LVGL init. }
procedure init;
@@ -74,11 +76,15 @@ end;
procedure init;
begin
io.syslog.logln('PANIC', 'Initializing x86 Panic Handler.');
{ Register x86 halt as the panic halt procedure }
core.panic.registerHaltProc(@arch.x86.util.halt_and_catch_fire);
{ Initialize the BSOD LVGL screen }
core.panic.init;
io.syslog.logln('PANIC', 'Initialization complete.');
end;
initialization
boot.mgr.registerBoot('arch.x86.panic', @init, 'Panic Screen', 'driver.video*');
end.
+4
View File
@@ -20,6 +20,7 @@ unit arch.x86.v86;
interface
uses
boot.mgr,
core.util, arch.x86.util, core.panic, io.syslog, debug.tracer, arch.x86.memory.virtual, arch.x86.gdt, arch.x86.idt, arch.x86.isr.types;
const
@@ -771,4 +772,7 @@ begin
pop_trace;
end;
initialization
boot.mgr.registerBoot('arch.x86.v86', @init, 'V86 Mode Initialization', BOOT_MGR_BARRIER_EARLY);
end.
+1 -1
View File
@@ -49,7 +49,7 @@ MULTIBOOT_HEADER_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEA
;
; Kernel stack size
;
KERNEL_STACKSIZE equ 0x4000
KERNEL_STACKSIZE equ 0x4000
KERNEL_VIRTUAL_BASE equ 0xC0000000
KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22)
+4
View File
@@ -22,6 +22,7 @@ unit arch.x86.fault;
interface
uses
boot.mgr,
arch.x86.fault.ace, arch.x86.fault.bpe, arch.x86.fault.btsse, arch.x86.fault.cfe, arch.x86.fault.csoe, arch.x86.fault.dbge, arch.x86.fault.dbz, arch.x86.fault.dfe, arch.x86.fault.gpf, arch.x86.fault.idoe, arch.x86.fault.iope, arch.x86.fault.mce,
arch.x86.fault.nce, arch.x86.fault.nmie, arch.x86.fault.oobe, arch.x86.fault.pf, arch.x86.fault.sfe, arch.x86.fault.snpe, arch.x86.fault.uie;
@@ -52,4 +53,7 @@ begin
arch.x86.fault.uie.register();
end;
initialization
boot.mgr.registerBoot('arch.x86.fault', @init, 'Faults', 'arch.x86.isr.mgr');
end.
+5
View File
@@ -22,6 +22,7 @@ unit arch.x86.isr.mgr;
interface
uses
boot.mgr,
arch.x86.isr, arch.x86.idt, arch.x86.isr.types, core.util, arch.x86.util;
type
@@ -2402,4 +2403,8 @@ begin
arch.x86.idt.set_gate(255, uint32(@ISR_255), $08, ISR_RING_0);
end;
initialization
boot.mgr.registerBoot('arch.x86.isr.mgr', @init, 'Interrupt Request Manager', 'arch.x86.irq');
end.
@@ -30,6 +30,7 @@ unit arch.x86.memory.physical;
interface
uses
boot.mgr,
arch.x86.multiboot,
io.syslog,
debug.tracer,
@@ -346,4 +347,7 @@ begin
pmm_total_blocks := nPresent;
end;
initialization
boot.mgr.registerBoot('arch.x86.memory.physical', @init, 'Physical Memory Manager', 'arch.x86.idt');
end.
@@ -23,6 +23,7 @@ unit arch.x86.memory.virtual;
interface
uses
boot.mgr,
core.util, arch.x86.util,
arch.x86.memory.physical,
io.syslog,
@@ -292,4 +293,7 @@ begin
pop_trace;
end;
initialization
boot.mgr.registerBoot('arch.x86.memory.virtual', @init, 'Virtual Memory Manager', 'arch.x86.memory.physical');
end.
+47 -1
View File
@@ -210,7 +210,27 @@ type
end;
PTextRec = ^TextRec;
{ FPC 3.2.2 INITFINAL table — compiler-generated unit init/finalize table.
Each unit with an initialization or finalization section gets an entry.
The table is emitted by the compiler under the symbol 'INITFINAL'. }
TInitFinalRec = packed record
InitProc : CodePointer;
FinalProc: CodePointer;
end;
TInitFinalTable = packed record
TableCount : longint;
Procs : array[1..1] of TInitFinalRec; { open array, actual size = TableCount }
end;
PInitFinalTable = ^TInitFinalTable;
{ Procedure type for calling initialization procs from the INITFINAL table }
TProcedure = procedure;
var
{ Compiler-generated INITFINAL table — contains init/finalize procs for
all units that have initialization or finalization sections }
InitFinalTable : TInitFinalTable; external name 'INITFINAL';
AK_START : uint32; external name 'kernel_start';
AK_END : uint32; external name 'kernel_end';
ASURO_KERNEL_START : uint32;
@@ -353,8 +373,19 @@ begin
end;
procedure fpc_initializeunits; [public, alias: 'FPC_INITIALIZEUNITS']; compilerproc;
var
i : longint;
proc : CodePointer;
begin
{ Unit initialization is handled by the core.version boot sequence }
{ Walk the compiler-generated INITFINAL table and call each unit's
initialization procedure (if non-nil). This runs before kmain, so
initialization sections must only do trivial work — write to static
globals, register boot entries, etc. No I/O or heap allocation. }
for i := 1 to InitFinalTable.TableCount do begin
proc := InitFinalTable.Procs[i].InitProc;
if proc <> nil then
TProcedure(proc)();
end;
end;
procedure fpc_do_exit; [public, alias: 'FPC_DO_EXIT']; compilerproc;
@@ -774,6 +805,9 @@ begin
end;
procedure init();
var
i : longint;
proc : CodePointer;
begin
ASURO_KERNEL_START := uint32(@AK_START);
ASURO_KERNEL_END := uint32(@AK_END);
@@ -783,6 +817,18 @@ begin
ErrorCode := 0;
ExitCode := 0;
ExitProc := nil;
{ Walk the INITFINAL table generated by compile_initcalls.sh and call
each unit's initialization section. FPC with -n does not insert this
call automatically, so we do it explicitly here — after basic system
globals are set up but before kmain proceeds.
Note: we inline the walk rather than calling fpc_initializeunits
because compilerproc procedures cannot be called from Pascal code. }
for i := 1 to InitFinalTable.TableCount do begin
proc := InitFinalTable.Procs[i].InitProc;
if proc <> nil then
TProcedure(proc)();
end;
end;
end.