The kernel now links at 0xFFFF_FFFF_8000_0000 (code_model .kernel) and
loads low via the linker script's AT() clauses (.text at 1 MiB). A new
asm _start installs a 64 KiB kernel-owned .bss stack — the loader stack
is a low address that goes away with the identity map — and calls the
Zig entry, which reaches boot_info through the physmap. The user-pf test
blob reads the LAPIC through the physmap window (still present|user, ec
0x5). The low identity map still coexists in the kernel's tables as the
safety net. Suite 27/27.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
paging.init now builds the physmap (physToVirt(phys)) alongside the low
identity map, so both addressing modes resolve during the transition.
tableAt (the page-table walk hinge), the pmm bitmap, the framebuffer,
LAPIC/IOAPIC/HPET/PM-timer/SPCR MMIO, the ACPI table walk, AML
OperationRegions, the ACPI power registers, the user-ELF frame fills,
and the AP trampoline arm/disarm all reach physical memory through the
physmap. Hal.mapMmio now maps into the physmap and returns the virtual
address, so the device layer never learns the layout. boot_info and its
pointees are converted at kmain entry. The kernel still links and runs
low; identity is the safety net until it's removed. Suite 27/27.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add the higher-half layout constants (physToVirt/virtToPhys, physmap
and kernel bases) to the danos handoff module, and KernelSegment.phys
so the loader records where it actually placed each segment.
The loader now builds its own page tables before ExitBootServices —
identity + a physmap of low RAM (2 MiB pages) plus 4 KiB mappings for
any higher-half kernel segment — and switches CR3, then calls the entry
with boot_info in RDI, interrupts off. The kernel still links and runs
low (identity), oblivious; this proves the CR3 dance in isolation.
Suite 27/27.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The self-hosted linker ignores parts of linker.ld (PHDRS, /DISCARD/,
section order). The higher-half move needs the script authoritative.
Suite 27/27 on the LLD build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ring 3 works: user GDT descriptors (sysret-ready layout), TSS.rsp0,
U/S-bit user mappings (W^X preserved), an int 0x80 syscall gate with a
mutable trap frame, and a setjmp-style enter/exit path. /sbin/init is a
real freestanding Zig binary built from sbin/, shipped on the ESP,
loaded by the bootloader (BootInfo.init_base/len), validated and mapped
by an in-kernel user-ELF loader, and run at CPL 3 — syscalls: exit,
ping, write. Tests: user, user-pf (U/S isolation proof, error code
0x5), init. Suite 27/27.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
max_cpus, max_tasks, kernel/IST stack sizes, and timer_hz move from scattered constants into one config module. root.zig goes back to being just the boot contract. Values unchanged; any can become a -D build option later.
Hoist max_cpus into danos (root.zig), raise it to 128, and stop reserving a static [max_cpus][16 KiB] IST array. Only the BSP's IST stack is static (needed before the allocator); each AP's is heap-allocated when it comes online. Shrinks the kernel from ~1.1 MB to ~139 KiB in ReleaseSmall.
fault-ap-df pins a #DF to an AP (its own IST must catch it); affinity checks a pinned task never migrates. onException now names the core, so an AP fault is attributed and shown contained. Both teeth-checked.
spawnOn(entry, priority, cpu) routes to a per-core pinned queue, merged with the global queue at O(1) selection. Falls back to unpinned for an offline/invalid core.
Add a discovery case (asserts stable ACPI/MADT/FADT/AML facts) and a wx case (audits R+X code vs NX data/rodata/heap/stack via arch.pageExecutable). Wire the existing poweroff/reboot cases into the harness. Suite: 18 -> 22.
Adds paging.isExecutable and arch.trampolinePage; the smp case now asserts the frame is zeroed and non-executable after bring-up. Teeth-checked against a no-op disarm.
Arm the low frame (copy blob, make executable) only while a core climbs, then zero it and restore RW+NX; the frame stays reserved so cores can be re-woken. startSecondary is one re-runnable attempt; boot retries a non-responding core 3x. Validated the retry path by forcing a first-attempt failure.