Troubleshooting - KekkoTech-Softwares/K-ernel GitHub Wiki

Troubleshooting

Ordered by how likely you are to hit it, not by how interesting it is.

docker: Cannot connect to the Docker daemon

The Docker CLI is useless without a running daemon; on macOS that means Docker Desktop must be open, with the whale in the menu bar. docker/run.sh tries to start it for you (open -a Docker) and waits up to 90 seconds, then gives up with a message. On Linux it refuses outright: start the daemon and retry.

Corollary that costs real time: quitting Docker Desktop kills whatever is running inside it. If you close it during the first image build, the GCC compile stops where it is. Layer caching means a restart resumes from the last completed step rather than from zero, but the step in progress is lost.

A warning scrolled past and I ignored it

Do not. In a freestanding kernel a warning is usually a bug that still links and still boots. The build compiles with -Wall -Wextra and nothing else is assumed: GCC will happily produce a working ISO out of code that returns a value from a void function, or indents a statement outside the if that was supposed to guard it. "It compiled and it booted" is not evidence.

What makes this nasty is that the build is incremental: a warning is printed by the compiler only when that file is actually recompiled. Run make twice and the second run is silent — the warning has not been fixed, it has been cached away. So:

make clean && make

is the only run whose output you can trust. Do it before you conclude the tree is clean, and before you report that it is not.

make: Nothing to be done for 'all', and then you boot a stale ISO

make decides what to rebuild by comparing modification times, and here those timestamps are written by your editor on the host and read by make through a bind mount inside an emulated container. When the two disagree — a file saved with an older mtime, a clock that drifted, an editor that writes atomically through a rename — make concludes there is nothing to do and keeps the objects it already has.

The failure mode is not an error message. It is QEMU booting the previous build/k-ernel.iso while you watch for a change you just made and wonder why it had no effect, or why a bug you fixed is still there.

Check before you debug:

ls -l build/kernel.bin build/k-ernel.iso

If those are older than the source you edited, you are testing the past. Force the point with touch on the file, or settle it with make clean && make iso. Any time a result surprises you, a clean rebuild is the first thing to rule out, not the last.

The QEMU monitor tells me the kernel installed nothing

Reading the hardware state back is the right instinct — it is how the GDT and IDT self tests work. But the monitor answers about the machine as it is right now, and if you ask too early "right now" is the reset state, or the firmware, or GRUB: a GDT limit of 0xffff, cs=0xf000, no TSS. Nothing is wrong; your kernel simply has not run yet.

No make target attaches a monitor, so when you want one, run QEMU by hand inside the container and keep the serial port out of the way:

qemu-system-i386 -cdrom build/k-ernel.iso -display none \
    -monitor stdio -serial file:build/serial.log

Then wait: query only after build/serial.log shows the self-test verdict, which means the kernel has reached its halt loop. info registers at that point reports what the kernel really loaded. Asking at the (qemu) prompt the instant it appears reports what the BIOS left behind.

My editor is full of errors the build does not have

A language server on the host (clangd and friends) analyses this code with the host's own compiler and target — on an Apple Silicon machine, an arm64 clang with a hosted standard library. This code is i686, freestanding, built with a cross compiler that has no target OS and no libc, and some of it is i686 inline assembly and __attribute__((packed)) structs.

So the editor invents errors: unknown register names, unresolved <stdint.h>, complaints about freestanding constructs, wrong sizeof reasoning. None of them are real. The container build is the truth; the editor index is a convenience. Note that compile_commands.json is git-ignored precisely because it describes one machine's idea of the build, not the build.

QEMU runs but I see no serial output

With make run-vga that is the design: the terminal is showing the VGA screen, and the serial log is in build/serial.log (tail -f it from a second shell). With make run the serial output is the terminal, so silence means the kernel produced none — see below.

The machine reboots in a loop, or prints nothing at all

An unhandled CPU exception is supposed to be loud: the kernel prints --- EXCEPTION <n>: <mnemonic> ---, dumps every register including eip and the error code, and halts. A divide by zero stops with an explanation; it does not reset.

A silent reset therefore means the fault happened somewhere that path could not cover:

  • before output was initialised at all (very early in boot.s, or a bad Multiboot handover);
  • a double fault, which currently has no handler of its own — a stack overflow reboots without a message (issue #2);
  • an NMI, which has a gate but no handler (issue #1).

Both are known and tracked. To find out where, make debug and attach GDB (the README has the invocation): a breakpoint on kernel_main tells you immediately whether you are even getting that far.

⚠️ **GitHub.com Fallback** ⚠️