diff --git a/.github/workflows/ci_pr.yml b/.github/workflows/ci_pr.yml index b3cf340..0c01bac 100644 --- a/.github/workflows/ci_pr.yml +++ b/.github/workflows/ci_pr.yml @@ -118,8 +118,8 @@ jobs: # available at this stage covers that much. Plain TCG, so no KVM and # no privileged container are required. # - # x86_64 is absent on purpose: q35 has no bare-ELF equivalent of - # -kernel, so that path needs a UEFI stub before it can boot at all. + # x86_64 is absent on purpose: QEMU's -kernel loads a 64-bit ELF only + # with a Xen PVH note, and the image has neither that nor a UEFI stub. # `cargo xtask boot-test --arch x86_64` says so explicitly rather # than failing obscurely. # Two boots: the ordinary path must greet, and the provoked path diff --git a/CHANGELOG.md b/CHANGELOG.md index 2af6a76..dad2a76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -165,6 +165,13 @@ Release codenames follow the six Noongar seasons — Birak, Bunuru, Djeran, Maku ### Fixed +- **The x86_64 docs no longer say `q35` has no bare-ELF `-kernel`.** `CLAUDE.md`, the README, the + x86_64 module, `xtask`'s refusal and a CI comment all claimed it. QEMU's x86 loader does take a + 64-bit ELF through `-kernel` when it carries a Xen PVH note (`XEN_ELFNOTE_PHYS32_ENTRY`, + `hw/i386/x86-common.c`), and refuses this image only because it has none — reproduced on the + pinned QEMU 11.0.3, which reports "Error loading uncompressed kernel without PVH ELF Note". The + corrected text states the fact and leaves the choice between PVH and a UEFI stub to the x86_64 + boot RFC. - **xtask validates its workspace root at the source.** CodeQL's one open alert flagged the image path as depending on a user-provided value (`CARGO_MANIFEST_DIR`). There is no privilege boundary in xtask for a hostile value to cross — cargo sets the variable, and the tool runs with the diff --git a/CLAUDE.md b/CLAUDE.md index e58c265..983787a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -65,11 +65,13 @@ Independently of that, a microkernel must not touch registers it would have to save and restore on every context switch: FP/SIMD belongs to userspace, enabled per process and saved lazily, once there is a userspace. -aarch64 boots. x86_64 compiles and links but does not boot: `q35` has no -bare-ELF equivalent of `-kernel`, so it needs a UEFI stub first. Its entry point +aarch64 boots. x86_64 compiles and links but does not boot. QEMU's x86 `-kernel` +loads a 64-bit ELF only if it carries a Xen PVH note +(`XEN_ELFNOTE_PHYS32_ENTRY`), which this image does not; whether x86_64 enters +through PVH, a UEFI stub or both is a decision for its boot RFC. Its entry point nevertheless calls straight through into the kernel proper, deliberately — an -entry that merely halted would leave everything above `arch` as dead code on that -target, and the second Tier-1 build would then prove nothing. +entry that merely halted would leave everything above `arch` as dead code on +that target, and the second Tier-1 build would then prove nothing. ## Building diff --git a/README.md b/README.md index 341bf82..f7cd866 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ rests on: link script, boot stub, stack, `.bss`, the hardware-abstraction boundary, and the console. x86_64 compiles and links against the same architecture-independent kernel, which -is what keeps the hardware-abstraction boundary honest, but it does not boot yet — -`q35` needs a UEFI stub first. +is what keeps the hardware-abstraction boundary honest, but it does not boot yet: +the image carries neither the Xen PVH note QEMU's `-kernel` needs nor a UEFI stub. ## Building diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index ed36d9c..af96a98 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -10,8 +10,10 @@ //! //! What is missing, in the order it will be needed: //! -//! - A UEFI entry path. `q35` has no equivalent of `-kernel` for a bare ELF, so -//! this needs a proper PE/COFF stub or a bootloader shim plus an ESP image. +//! - An entry path. QEMU's x86 `-kernel` loads a 64-bit ELF only if it carries +//! a Xen PVH note (`XEN_ELFNOTE_PHYS32_ENTRY`), entering it in 32-bit protected +//! mode; real hardware needs a UEFI stub. Which this target gets first is a +//! decision for its boot RFC. //! - A console. The 16550 UART at `0x3f8` is the counterpart of the PL011, and //! is where the console will land; the UEFI GOP framebuffer comes later. //! - GDT and IDT, neither of which AArch64 needs before its first print, and a @@ -22,9 +24,9 @@ /// The ELF entry point. /// -/// **This image cannot boot.** There is no UEFI stub, no multiboot header, no -/// descriptor tables and no stack of our own, so nothing will ever transfer -/// control here in practice. +/// **This image cannot boot.** There is no PVH note, no UEFI stub, no multiboot +/// header, no descriptor tables and no stack of our own, so nothing will ever +/// transfer control here in practice. /// /// It nevertheless calls straight through to the kernel proper, and that is the /// point: it makes the architecture-independent kernel genuinely compile and link diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 06483f4..50ea8dc 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -273,10 +273,12 @@ fn build(arch: Arch, release: bool, features: Option<&str>) -> Result { /// Rejects architectures whose boot path is not implemented yet. fn require_bootable(arch: Arch) -> Result<()> { if arch == Arch::X86_64 { - return Err("the x86_64 boot path is not implemented yet — \ - q35 has no bare-ELF equivalent of -kernel, so this needs a \ - UEFI stub and an ESP image first (see kernel/src/arch/x86_64/mod.rs)" - .into()); + return Err( + "the x86_64 boot path is not implemented yet — the image has \ + neither the Xen PVH note QEMU's -kernel needs for a 64-bit ELF \ + nor a UEFI stub (see kernel/src/arch/x86_64/mod.rs)" + .into(), + ); } Ok(()) }