In another episode of my experimentation, I was back again tinkering with my X230. This time I tried out Buildroot.

Buildroot is a set of tools to build a tiny complete Linux system from scratch. From the tarball, you can create a bzImage with integrated initramfs that has everything you want to include (even the X server if you want to).

At the heart of Buildroot is the Linux kernel itself, the C library of choice (of which I picked musl), as well as busybox -- an all-in-one command-line utilities that includes the shell.

If you happen to be running OpenWRT on some ouf your routers, the OpenWRT is actually based on Buildroot. This is how they're able to create system small enough to fit that router ROM with only megabytes in size.

Preparation

I was building it on my Debian system I've been using in my previous articles.

For the Buildroot package, I was using the version 2022.02.6.

To ensure I got all the necessary build requirements, I ran:

$ apt install libssl-dev libelf-dev pahole

Configuration

I first configured it by running make menuconfig. I was then presented by this menu.

buildroot-menuconfig

These are the configurations I did:

  • "Target options" menu:
    • set "Target architecture" to x86_64
    • set "Target Architecture Variant" to sandybridge
  • "Toolchain" menu
    • set "C library" to musl.
  • "Kernel" menu
    • ticked "Linux Kernel"
    • set "Kernel configuration" to "Using a custom (def)config file"
    • set "Configuration file path" to config-linux
    • ticked the options for OpenSSL, libelf, and pahole
  • "Target packages" menu
    • set "BusyBox configuration file to use?" to config-busybox

buildroot-menuconfig-kernel

Linux kernel

To prompt the menuconfig for Linux kernel, I ran make linux-menuconfig. But before I was able to run it, I needed the file config-linux (the file name was determined by the buildroot makeconfig). So I created an empty file by running touch config-linux.

After I was happy with the Linux kernel configuration, I ran make linux-update-config to update the config-linux file.

Busybox

Same goes with the Linux kernel, I needed the config file before I ran the menuconfig.

$ touch config-busybox
$ make busybox-menuconfig
$ make busybox-update-config

Build process

After configuring, the Buildroot was ready to build a bootable image. I ran make -j8 and waited for a bit.

I was building the whole thing on the X230 itself, with its i7-3520M. While there are much faster machines out there, this one is quite fast for this purpose. At least with this, I didn't have to wait a long time.

The resulting image is on output/images/bzImage.

Testing

To test that it's usable, I simply booted from it using GRUB2, which I already have.

I only needed to have the bzImage under /boot and have it listed on the /boot/grub/grub.cfg.

First the bzImage was copied into the /boot directory by running sudo cp output/images/bzImage /boot/.

Then the grub.cfg was updated accordingly -- I wouldn't do it manually as it would get overwritten on each update.

GRUB2 config

The clean way of doing it was thru /etc/grub.d/40_custom. So I opened up that file (as root) and added:

menuentry 'Buildroot testing' {
  set gfxmode=1280x1024
  load_video
  insmod gfxterm
  set root='hd0,msdos1'
  echo    'Loading Linux'
  linux   /bzImage quiet
}

This way, the custom entry would always be there on the boot menu.

Finally, to update the grub.cfg, I ran sudo update-grub2.

Modifications

I ended up making several attempts of adjustments in order to include the features I wanted while keeping the size down. For that, I reran the menuconfig commands, backing up the config, config-linux, and config-busybox files each time (and then updating them, of course).

Running make clean is important before rebuilding to ensure a clean build each time. Do note that the all the build stuff will get removed, including the toolchain. So if you run the clean and you wanna configure the Linux kernel, the toolchain is gonna have to be rebuilt first.

Sometimes, nuking everything by running make distclean is necessary. Just got to ensure the configs are backed-up, especially the busybox config, which gets removed everytime this command runs.

You should also backup the dl folder before make distclean to save time. That way, there's no need to download the packages on each build. Just make sure to copy the folder back afterwards.

After each build process I simply copied the resulting bzImage to /boot without doing anything to the GRUB as it's already pointing there. Occasionally, I'd backup the old bzImage (and its corresponding configs) when I feel like it's a good build (i.e. able to access the shell with it).

Closing

Simply running the above commands seem quite simple, but getting the configs to fit the need is definitely not for the faint of hearts. The sight of menuconfig screen can definitely be daunting, especially for the uninitiated.

I happened to have some experience configuring and building my own kernel. Even for myself, it's not always easy to get everything right.

The buildroot config itself is just a matter of what extra features to include (aside from the ones covered above, at least). The busybox config The Linux kernel config, on the other hand, can be quite tricky at times.

This is especially true for the device drivers. Missing some drivers can yield inoperable system such as not being able to use the keyboard, having blank screen. Missing some others can hinder certain functionalities that can render the system useless depending on the context (e.g. networking, ACPI, disk access, audio).

While the default configuration can be said to work, it is rarely optimal. So more often than not, you may find yourself tweaking it here and there. The difficulty level would rise when you want a minimum build, as removing certain parts always have potential in breaking the system.

With that said, I've included the config files below: