No description
Find a file
plonky b06139adca Add reliable minimal Linux ISO builder with net, SSH, and hybrid UEFI.
Harden the Bash pipeline with SHA256 pins, fingerprints/stamps, build
summaries, and QEMU smoke tests; ship size-focused kernel and BusyBox
configs; enable virtio networking, optional Dropbear, and BIOS+UEFI
hybrid ISO generation documented for USB boot.
2026-07-27 15:04:55 +02:00
overlay Add reliable minimal Linux ISO builder with net, SSH, and hybrid UEFI. 2026-07-27 15:04:55 +02:00
.gitignore Add reliable minimal Linux ISO builder with net, SSH, and hybrid UEFI. 2026-07-27 15:04:55 +02:00
busybox.config Add reliable minimal Linux ISO builder with net, SSH, and hybrid UEFI. 2026-07-27 15:04:55 +02:00
checksums.sha256 Add reliable minimal Linux ISO builder with net, SSH, and hybrid UEFI. 2026-07-27 15:04:55 +02:00
config Add reliable minimal Linux ISO builder with net, SSH, and hybrid UEFI. 2026-07-27 15:04:55 +02:00
kernel.config Add reliable minimal Linux ISO builder with net, SSH, and hybrid UEFI. 2026-07-27 15:04:55 +02:00
ntmkstdlib.sh Add reliable minimal Linux ISO builder with net, SSH, and hybrid UEFI. 2026-07-27 15:04:55 +02:00
README.md Add reliable minimal Linux ISO builder with net, SSH, and hybrid UEFI. 2026-07-27 15:04:55 +02:00
script.sh Add reliable minimal Linux ISO builder with net, SSH, and hybrid UEFI. 2026-07-27 15:04:55 +02:00

makecore

makecore is a Bash-based build script that creates a tiny bootable Linux ISO for x86_64.

It automates:

  • Linux kernel download/build
  • Optional glibc build (for dynamic BusyBox)
  • BusyBox build (static by default)
  • Root filesystem + initramfs generation
  • Optional ./overlay/ merge into the rootfs
  • Bootable ISO creation with Syslinux/Isolinux
  • SHA256 verification of source archives
  • Build summary (stage times + artefact sizes)
  • Optional QEMU run and headless smoke test
  • Network (virtio-net + DHCP) and optional Dropbear SSH

Repository layout

Path Role
script.sh Main entry point
config Build configuration (URLs + options)
checksums.sha256 SHA256 pins for source archives
kernel.config Minimal kvm-oriented kernel config (Linux 6.12.x)
busybox.config Minimal static BusyBox config (versioned)
overlay/ Optional rootfs overlay (OVERLAY_TYPE=folder)
sources/ Optional local source archives (offline mode)
ntmkstdlib.sh Logging / error helpers

Prerequisites

  • bash, make, gcc, tar, cpio, gzip, sed, find, wget, sha256sum

  • One ISO tool: xorriso or mkisofs or genisoimage

  • qemu-system-x86_64 (for run and test)

  • Static C library for default static BusyBox: glibc-static (Fedora/RHEL) or libc6-dev with static libs (Debian/Ubuntu). Without it the build fails with a clear message; alternative: USE_GLIBC=true for a dynamic BusyBox. Notes:

  • USE_LOCAL_SOURCE=true looks for archives under sources/ first.

  • Exact basename from the URL is preferred; otherwise a component-*.tar.* match is used.

  • If nothing is local, the script downloads from the configured URL.

  • With VERIFY_CHECKSUMS=true, archives are checked against checksums.sha256.

Quick start

chmod +x script.sh
./script.sh all
./script.sh test    # headless QEMU smoke test

Outputs:

  • ISO: ~/work/tmp/out/minidistro.iso (override with WORK_DIR / ISO_NAME)
  • Summary: ~/work/tmp/out/build-summary.txt
  • Workspace: ~/work/tmp by default

Interactive QEMU (serial console; quit with Ctrl-A then X):

./script.sh run

Commands

./script.sh all              # kernel → (glibc) → busybox → initramfs → ISO + summary
./script.sh kernel           # kernel only
./script.sh glibc            # glibc only (needs USE_GLIBC=true)
./script.sh busybox          # BusyBox only
./script.sh initramfs        # rootfs + initramfs only
./script.sh iso              # ISO stage (needs kernel + initramfs)
./script.sh dropbear         # Dropbear only (ENABLE_DROPBEAR=true)
./script.sh menuconfig       # interactive kernel config → kernel.config
./script.sh busybox-config   # interactive BusyBox config → busybox.config
./script.sh run              # QEMU BIOS + virtio-net (+ SSH hostfwd)
./script.sh run-uefi         # QEMU UEFI (OVMF)
./script.sh test             # BIOS smoke (MAKECORE_BOOT_OK)
./script.sh test-net         # BIOS + DHCP (MAKECORE_NET_OK)
./script.sh test-uefi        # UEFI smoke (OVMF)
./script.sh test-uefi-net    # UEFI + DHCP
./script.sh summary          # print last build sizes / stage times
./script.sh clean            # remove WORK_DIR
./script.sh help

Options:

./script.sh --force all       # ignore stamps, rebuild
./script.sh -f busybox        # force BusyBox rebuild only

Phase D: UEFI hybrid boot

The ISO is BIOS + UEFI hybrid:

Mode Bootloader How
BIOS Isolinux El Torito + isohybrid MBR
UEFI GRUB BOOTX64.EFI El Torito ESP (EFI/efiboot.img) + GPT basdat

Kernel has CONFIG_EFI + CONFIG_EFI_STUB (+ ACPI). The ESP embeds kernel+initrd so UEFI does not depend on ISO9660 path search.

./script.sh all
./script.sh test          # BIOS
./script.sh test-uefi     # OVMF UEFI
./script.sh run-uefi      # interactive UEFI

Host packages for UEFI build/test: xorriso, grub2-efi-x64-modules, grub2-tools, mtools, dosfstools, edk2-ovmf (or ovmf).

Write to USB (hybrid ISO)

# CAUTION: destroys all data on the target device
sudo dd if=~/work/tmp/out/minidistro.iso of=/dev/sdX bs=4M status=progress oflag=sync
# or:
sudo cp ~/work/tmp/out/minidistro.iso /dev/sdX && sync

Then boot the USB stick in either legacy BIOS or UEFI mode (disable Secure Boot if GRUB is unsigned — this image is not signed).

Variable Default Meaning
ENABLE_UEFI true Build hybrid BIOS+UEFI ISO
UEFI_ESP_SIZE_KB auto (≥8MiB) Minimum ESP size override
OVMF_CODE / OVMF_VARS auto QEMU firmware paths
TEST_UEFI_TIMEOUT 240 UEFI smoke timeout (s)

Phase C: network & services

Feature How
Virtio-net in QEMU ./script.sh run / test attach -device virtio-net-pci + user net
DHCP /init runs udhcpc → marker MAKECORE_NET_OK
Dropbear SSH Static build; host keys baked at build; password from ROOT_PASSWORD
Overlay examples overlay/etc/motd, issue, root/.profile, …
./script.sh all && ./script.sh test-net
./script.sh run
# other terminal:
ssh -p 2222 root@127.0.0.1   # password: makecore (default)
Variable Default Meaning
ENABLE_NETWORK true Bring up lo + first NIC
ENABLE_DHCP true udhcpc on that NIC
ENABLE_DROPBEAR true Build/install dropbear
ROOT_PASSWORD makecore root shadow password
QEMU_SSH_PORT 2222 Host port → guest :22
DROPBEAR_SOURCE_URL dropbear-2025.88 Source tarball

Disable SSH to shrink the image: ENABLE_DROPBEAR=false then rebuild.

Phase B: minimalism

Versioned configs tuned for a small QEMU-friendly image:

Artefact Phase A (defconfig-ish) Phase B (minimal)
Kernel bzImage ~14M ~2.7M
BusyBox ~2.4M ~2.0M
Initramfs ~1.3M ~1.0M
ISO ~16M ~4.2M
Full build (16 cores) ~5+ min ~2.5 min
  • kernel.config: allnoconfig base + initrd, serial, virtio, networking, ext4/squashfs/overlay; CONFIG_CC_OPTIMIZE_FOR_SIZE, no modules.
  • busybox.config: static, ash, coreutils, mount, ip/udhcpc/wget, vi/awk — servers and niche applets off.
  • USE_PREDEFINED_BUSYBOX_CONFIG=true by default.
  • Iterate configs: ./script.sh menuconfig / ./script.sh busybox-config, then ./script.sh --force all && ./script.sh test.

Phase A: reliability features

Checksums

Pinned SHA256 digests live in checksums.sha256 (standard sha256sum format).

Variable Default Meaning
VERIFY_CHECKSUMS true Hash each archive after resolve/download
CHECKSUMS_REQUIRED false If true, fail when an archive has no entry
CHECKSUMS_FILE checksums.sha256 Path to the pin file

Manual check:

cd sources && sha256sum -c ../checksums.sha256

Build summary

After all (and several single stages), the script prints and saves:

  • Per-stage durations (kernel, glibc, busybox, initramfs, iso)
  • Artefact sizes (kernel, busybox, initramfs, ISO)

File: $WORK_DIR/out/build-summary.txt — also via ./script.sh summary.

Smoke test

./script.sh test

Boots the ISO headless in QEMU (-display none -serial file:…), waits for the marker string emitted by /init:

MAKECORE_BOOT_OK
Variable Default Meaning
TEST_TIMEOUT 180 Seconds before failure
TEST_MARKER MAKECORE_BOOT_OK Success string on serial
QEMU_MEM 256 Guest RAM (MiB)

Logs: $WORK_DIR/test/serial.log, last-result.txt, qemu.stderr.
Uses KVM when /dev/kvm is available.

Configuration (config)

Variable Meaning
KERNEL_SOURCE_URL Linux kernel tarball URL
GLIBC_SOURCE_URL glibc tarball URL
BUSYBOX_SOURCE_URL BusyBox tarball URL
SYSLINUX_SOURCE_URL Syslinux tarball URL
WORK_DIR Build workspace (default ~/work/tmp)
ISO_NAME Output ISO filename
USE_PREDEFINED_KERNEL_CONFIG true → use kernel.config, else x86_64_defconfig
USE_PREDEFINED_BUSYBOX_CONFIG true → use busybox.config if present
USE_GLIBC Dynamic BusyBox + glibc runtime in rootfs
USE_LOCAL_SOURCE Prefer ./sources/ archives
OVERLAY_TYPE none or folder (copy ./overlay/)
JOB_FACTOR jobs = cores * JOB_FACTOR
CFLAGS BusyBox compile flags
KERNEL_CMDLINE Appended by isolinux (default dual console)
QEMU_MEM RAM in MiB for run / test
VERIFY_CHECKSUMS Enable SHA256 checks
CHECKSUMS_REQUIRED Fail on missing checksum entries
CHECKSUMS_FILE Checksums path
TEST_TIMEOUT Smoke test timeout (s)
TEST_MARKER Smoke test success string

Incremental builds (stamps)

Each stage writes a stamp under $WORK_DIR/stamps/ that embeds a fingerprint of its inputs. Changing those inputs invalidates the stamp. Downstream stages are also invalidated when an upstream stage is rebuilt. Use --force to rebuild regardless.

Overlay

  1. Put files under overlay/ mirroring the rootfs tree.
  2. Set OVERLAY_TYPE=folder in config.
  3. Rebuild initramfs / all.

Boot behaviour

The initramfs /init mounts proc, sys, dev, tmp, run, sets hostname, prints a banner, emits MAKECORE_BOOT_OK, then starts a shell.

Default kernel cmdline includes serial + VGA (console=tty0 console=ttyS0).

Troubleshooting

Problem What to try
iso fails (missing kernel/initramfs) Run ./script.sh all first
ISO tool missing Install xorriso, mkisofs, or genisoimage
Download fails / offline Put archives in sources/ or set USE_LOCAL_SOURCE=false
SHA256 mismatch Re-download archive or update checksums.sha256
Smoke test timeout Raise TEST_TIMEOUT; inspect $WORK_DIR/test/serial.log
Smoke test: QEMU dies early Check qemu.stderr; ensure ISO boots under BIOS
Slow build Raise JOB_FACTOR
Stamp seems stuck ./script.sh --force <stage> or ./script.sh clean