Skip to content

Instantly share code, notes, and snippets.

@emneo-dev
Last active March 13, 2024 16:27
Show Gist options
  • Save emneo-dev/82f3073272e7b86710bda5925fcbac67 to your computer and use it in GitHub Desktop.
Save emneo-dev/82f3073272e7b86710bda5925fcbac67 to your computer and use it in GitHub Desktop.
Simple workshop subject about making your own bootable Linux system from scratch

Workshop - Creation of a Minimal Linux distribution

Disclaimer

Everything here where sudo is not written does not require sudo! Using sudo when you do not need to could break your installation, and I won't be helping you with that, you are warned!

Compile Linux

First we need to get an archive of Linux's code, so go to kernel.org to get it. You will then need to extract it and then compile it. There are three steps to that process:

  • Configuring the kernel using make menuconfig (You don't need to change anything, just to save the config)
  • Compiling the kernel in its compress form with make bzImage
  • Copying the resulting kernel to our project's root folder (Look in ./arch/x86/boot

Compile Busybox

After the kernel we need to build some utilities to make a usable system (Remember that the kernel by itself is useless, you need userspace programs). For that we will be using busybox because it is much much easier to compile and install than all the GNU utilities.

For that you will need to go to busybox's website (busybox.net) and like for the kernel get an archive of its code followed by its extraction to a folder of your choice.

Like the kernel there are multiple steps to it:

  • Configuring the utilities using make menuconfig (This time you will need to find the option to compile all the utilities statically, we do not want any dynamic linking as we will not have a dynamic linker).
  • Compiling the utilities using make
  • Installing busybox to an empty folder at the project's root make install (Watch out, you need to specificy a parameter to that command to install to a specific directory!)

Create an init program

Of course we need an initial program that the kernel will launch after booting, else it will just complain really hard.

Go to the folder where you installed busybox and delete the linuxrc file at the root.

Then create another one called init that is just a shell script launching /bin/sh (Yes we use sh to launch sh, yes that is the correct way to do it).

PS: Don't forget the shebang :)

Preparing the filesystem

Now that we have everything needed for the system it is time to prepare the boot image, so start by creating a 50MB file filed with zeroes (You can use the dd command to do so).

Then once the file has been created you will need to format it to a specific filesystem, here we will be using FAT32 as it is the simpliest solution (Remember the morpheus/my_web project on how to format a partition :3).

Creating the initramfs

Once that is done we need to prepare the Initial RAM Filesystem, or initramfs for short. for that you will need to use this command from inside the folder with the installed busybox:

find . | cpio -ov --format=newc > ../initramfs

This will create an archive of the filesystem inside that folder that the kernel can use while booting, it is also only filesystem you will have access to once your kernel boots!

Copy the kernel and initramfs to the end filesystem

Then you can mount the 50MB boot file that we prepared in an empty folder and copy the compressed kernel binary and your initramfs inside of it.

This is the only step that requires sudo!

Don't forget to unmount the boot file at the end of the steps else you risk having quite the problems while booting.

Install the bootloader to the filesystem

Now we have the kernel and the initramfs at the correct place, but we still need to find a way to boot to it. We therefore need a bootloader.

We will be using syslinux here as it is the simpliest bootloader for linux available out here.

To install syslinux to the final filesystem do this:

syslinux boot

Boot the system

Now we are done creating our linux install, just boot it using qemu using this command (Of course if you are on an ARM system you will need to change that line):

qemu-system-x86_64 -hda boot

Once syslinux has loaded and prompts you to give it something to boot type this:

bzImage -initrd=initramfs

It will tell syslinux to boot our compressed linux image with our custom made initramfs.

Bonuses

Congratulations, you got to the end of the start!

Now that you understand how a really basic Linux system works you can now add as much stuff as you'd like, for example:

  • Use grub instead of syslinux
  • Use a proper init system instead of just sh (Take a look at openrc, it is pretty cool)
  • Have working networking out of the box
  • Find out how to setup the hostname of the machine
  • Bundle the system into a .iso to be usable on more emulation platforms or even baremetal
  • Make a smaller but still usable Linux build (The base kernel has a lot of compiled code that you definetely do not need)
  • Try some different Linux kernels that change some stuff (Linux-zen, Linux-next, etc...)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment