Rebuilding the kernel inside Makar

Makar can recompile its own kernel from source using the shipped TinyCC (/apps/tcc.elf), then boot the new image without leaving QEMU. This is the “self-host” milestone (v0.9): the bootable Multiboot 2 ELF you just booted is the same artifact you can produce by running TCC from the live shell.

There are two surfaces:

Surface What it builds with When to use
./build-kernel-tcc.sh (host) Your host’s TCC build out of vendor/tinycc/ Sanity-check the recipe + regenerate src/userspace/rebuild-kernel.sh
/apps/rebuild-kernel.sh (in-OS) The shipped /apps/tcc.elf inside a running Makar Actually rebuild the kernel while booted

Both share a single source-file list, generated by build-kernel-tcc.sh.

Prerequisites inside Makar

The default ISO already ships everything the in-OS build needs:

You also need ~64 MiB of RAM (qemu -m 64) and the test ISO booted with a writable /tmp overlay (the default).

The quick path

From any shell prompt inside Makar:

./apps/rebuild-kernel.sh

or, if you’re not in /apps:

sh /apps/rebuild-kernel.sh

What it does, step by step (the script itself is regenerated, so don’t hand-edit src/userspace/rebuild-kernel.sh — edit build-kernel-tcc.sh and re-run it):

  1. mkdir /bin/ktcc — scratch dir for the .o files. /bin lives on the rootfs (the installer creates it; tmpfs is flat so /tmp can’t hold the per-source tree). On a CD-ROM-only live boot the rootfs is read-only ISO9660 and this step will fail — run from an installed HDD boot instead.
  2. tcc -c /apps/kend.S -o /tmp/ktcc/kend.o — the _kernel_end sentinel.
  3. For each source file (boot.S, build_origin.c, the i386 core/mm/ drivers/fs/proc/shell/debug/display modules, kernel.c, libc/string/, libc/stdio/) it runs:
    tcc -ffreestanding -D__is_kernel -DDEV_BUILD -DMAKAR_IN_OS_BUILD=1 \
        -I/usr/include/kernel-build -c <src> -o /tmp/ktcc/NNN.o
    

    MAKAR_IN_OS_BUILD=1 is the build-origin marker (see src/kernel/arch/i386/boot/build_origin.c) so the boot banner of the resulting kernel prints “Self-hosted kernel (built in Makar)” instead of “Self-hosted kernel (built on host with TCC)” or “Host-built kernel”. All three origins boot identically; only the banner string differs.

  4. Link with tcc -static -nostdlib -Wl,-Ttext=0x100000 ... into /bin/makar.kernel.tcc — a valid Multiboot 2 ELF that GRUB will load like the original.
  5. Print the final marker:

Each tcc -c runs as its own ring-3 task (you can watch them tick by in maktop). The driver also writes a rebuild-kernel: cc <file> serial line per source so a headless capture (-serial file:...) gives a complete build log.

The script does not copy the kernel into /boot automatically. That’s a manual step so you can decide whether to keep the GCC kernel around to fall back to.

Installing the freshly built kernel

On a live boot (CD-ROM or HDD install) you have two options.

HDD install

If you booted from a writable HDD partition (/boot mirrors the FAT32 boot partition), copy and reboot:

cp /bin/makar.kernel.tcc /boot/makar.kernel
reboot

reboot is a shell builtin that triggers ACPI shutdown (port 0x604). GRUB picks the kernel back up from /boot/makar.kernel on the next boot. If the boot fails or panics, drop into a known-good ISO and overwrite /boot/makar.kernel with the original.

Live CD boot

The CD-ROM is read-only, so you can’t write /boot/makar.kernel back. What you can do:

For a turn-key “boot the freshly-built kernel without leaving QEMU,” either work off an HDD image (./run.sh hdd boot) so /boot is writable, or run the same recipe on the host with ./build-kernel-tcc.sh and rebuild a fresh ISO.

Running it from the host

If you want to confirm the recipe works without booting Makar at all:

./build-kernel-tcc.sh

This drives the host TCC (vendor/tinycc/i386-tcc) against the same source list and writes build/ktcc/makar.kernel.tcc. You can then:

qemu-system-i386 -kernel build/ktcc/makar.kernel.tcc -m 64

…or roll it into an ISO yourself and verify the boot banner reads “Self-hosted kernel (built on host with TCC)” (the MAKAR_IN_OS_BUILD=1 define is only set by the in-OS driver).

Verifying which kernel you booted

The boot banner is the easiest tell. Right after the “Initializing X… [OK]” sequence the kernel prints one of:

Banner Built by
Host-built kernel i686-elf-gcc (the normal CI build)
Self-hosted kernel (built on host with TCC) ./build-kernel-tcc.sh
Self-hosted kernel (built in Makar) /apps/rebuild-kernel.sh

The string comes from MAKAR_BUILD_ORIGIN in src/kernel/arch/i386/boot/build_origin.c, selected at compile time via __TINYC__ + MAKAR_IN_OS_BUILD.

Regression coverage

The end-to-end in-OS rebuild is opt-in (slow under TCG ≈ 10 min):

TEST_CMDLINE='test_mode test=rebuild-kernel' CFLAGS='-O0 -g3' TEST_ISO=1 \
    bash iso.sh
qemu-system-i386 -cdrom makar-test.iso -serial file:/tmp/rk.log \
    -display none -no-reboot -m 64 \
    -device isa-debug-exit,iobase=0xf4,iosize=0x04

Then grep /tmp/rk.log for REBUILD-KERNEL: ALL PASS.

For a faster smoke that the in-OS TCC asm path still works (the strtoull/(null):3811692 regression that bit kend.S compilation), the regular LIBC-TCC suite now includes a compile-kend-S probe. Run it via:

./run.sh iso test

— LIBC-TCC’s ALL PASS line guarantees that bare 0 literals in in-OS asm still parse, without paying for the full rebuild-kernel run.

See also