fix(kernel-bootstrap): restore kexec-fiwix baseline and move post-fiwix distfiles into raw payload import path

The instability was not caused by kexec-fiwix logic itself but by oversized early-stage payload pressure in kernel-bootstrap mode.
When too many distfiles are injected before the Fiwix handoff, the early memory/file-table assumptions become fragile and KVM can fail during transition.
This change restores kexec-fiwix.c to the known baseline (matching commit 984b8322...) and fixes the actual failure mode by moving non-early distfiles out of the initial image.

What changed:
- Keep only bootstrap-required distfiles in early init image.
- Generate a separate raw payload image (LBPAYLD1 format) for the remaining distfiles.
- Attach payload image as an extra disk in QEMU/bare-metal kernel-bootstrap flow.
- Add a dedicated C89/tcc-compatible importer (payload-import) that scans payload disks and copies files into /external/distfiles after jump: fiwix.
- Insert improve: import_payload immediately after jump: fiwix so the full distfile set is restored before heavy build steps continue.
- Add PAYLOAD_REQUIRED config gating so this behavior is active only in kernel-bootstrap paths that need it.

Why this design:
- Preserves minimal early environment assumptions (no dependency on full shell utilities for the copy operation itself).
- Avoids adding filesystem-construction toolchain dependencies for the payload container by using a simple length-prefixed raw format.
- Keeps bare-metal and QEMU behavior aligned: both can carry full build artifacts without overloading the early handoff stage.
- Leaves kexec-fiwix behavior deterministic and auditable by reverting to a known-good baseline implementation.
This commit is contained in:
vxtls 2026-03-01 13:45:16 -05:00
parent 11c4dd8c01
commit f30c20b7be
8 changed files with 441 additions and 52 deletions

View file

@ -127,6 +127,10 @@ def create_configuration_file(args):
"""
config_path = os.path.join('steps', 'bootstrap.cfg')
with open(config_path, "w", encoding="utf_8") as config:
payload_required = ((args.bare_metal or args.qemu)
and not args.kernel
and not args.repo
and not args.external_sources)
config.write(f"ARCH={args.arch}\n")
config.write(f"ARCH_DIR={stage0_arch_map.get(args.arch, args.arch)}\n")
config.write(f"FORCE_TIMESTAMPS={args.force_timestamps}\n")
@ -137,6 +141,7 @@ def create_configuration_file(args):
config.write(f"FINAL_JOBS={args.cores}\n")
config.write(f"INTERNAL_CI={args.internal_ci or False}\n")
config.write(f"INTERACTIVE={args.interactive}\n")
config.write(f"PAYLOAD_REQUIRED={payload_required}\n")
config.write(f"QEMU={args.qemu}\n")
config.write(f"BARE_METAL={args.bare_metal or (args.qemu and args.interactive)}\n")
config.write(f"BUILD_GUIX_ALSO={args.build_guix_also}\n")
@ -407,6 +412,11 @@ print(shutil.which('chroot'))
path = os.path.join(args.target, os.path.relpath(generator.target_dir, args.target))
print("Please:")
print(f" 1. Take {path}.img and write it to a boot drive and then boot it.")
payload_disk = target.get_disk("payload")
if payload_disk is not None:
payload_path = os.path.join(args.target, os.path.relpath(payload_disk, args.target))
print(" 2. Take " +
f"{payload_path} and attach it as a second raw disk (/dev/sdb preferred).")
else:
if args.stage0_image:
@ -460,6 +470,10 @@ print(shutil.which('chroot'))
arg_list += [
'-drive', 'file=' + target.get_disk("external") + ',format=raw',
]
if target.get_disk("payload") is not None:
arg_list += [
'-drive', 'file=' + target.get_disk("payload") + ',format=raw',
]
arg_list += [
'-machine', 'kernel-irqchip=split',
'-nic', 'user,ipv6=off,model=e1000'