building the kernel
in 2019 we have nice things like docker, and alpine linux can build the kernel just fine with
make gcc libc-dev linux-headers bison flex bc xz. you'll also need
make menuconfig. create a barebones
make allnoconfig or
make tinyconfig, which, mostly transparent to our purposes, produces a config that results in even smaller kernels (< 1 MiB!)
the good thing about starting out with nothing in an exercise like this is that we get to add things only as we discover that they are needed, which is conducive to maximum learning. in particular, to meet our requirements, we'll need to enable:
- initramfs support (xz compression only)
- me from the future: i found that xz results in a better compression ratio than the popular gzip for the initramfs. the tinyconfig kernel is also xz-compressed, so i *think* this would just be reusing existing functionality.
- elf + shebang support
- me from the future: as you'll see later, our initramfs
initis a shell script. did you know shebang support is actually a configurable kernel feature?
- printk and 8250/16550 serial console (enable tty first to reveal this option)
- this is the magic that gives the kernel the ability to talk UART serial.
- tty/console also implies input, but honestly i don't know anything about hardware and have so many questions1.
booting the kernel
thankfully in 2019 there are nice things like qemu, so a total amateur like me doesn't have to worry about bootloader firmware, and hardware. at this point the kernel already boots:
qemu-system-x86_64 -kernel bzImage
but it will panic, because there isn't an initramfs providing a filesystem containing an init. preparing that will be the next step.
notes on qemu
i've seen some confusion online regarding qemu-emulated consoles and linux, so here is some demystification.
if linux doesn't get a
console= command-line, it will first look for a VGA display to
printk to, falling back to a serial port.
ttyS0 is the device for the first UART serial port recognized by linux. So with
-append "console=ttyS0" you tell linux to print to only UART serial.
qemu's default mode (graphical) emulates a VGA display on the default starting view, and the qemu monitor and serial console are available on other views. if you only add
-append "console=ttyS0", then you will see seabios output in VGA and linux output in the serial console.
i definitely remember being confused by that, when i wasn't aware you could switch views with ctrl-alt-number. "my kernel isn't printing stuff even though i compiled in printk support!" well, by additionally passing
-nographic, qemu will not emulate VGA and redirect the serial console to the tty or terminal emulator you started qemu with. in nographic mode, ctrl-a then c. in the monitor, type q/quit to exit.