Making an ISO

Now that we have our kernel.bin, the next step is to make an ISO. Remember compact discs? Well, by making an ISO file, we can both test our Hello World kernel in QEMU, as well as running it on actual hardware!

To do this, we’re going to use a GRUB tool called grub-mkrescue. We have to create a certain structure of files on disk, run the tool, and we’ll get an os.iso file at the end.

Doing so is not very much work, but we need to make the files in the right places. First, we need to make three directories:

$ mkdir -p isofiles/boot/grub

The -p flag to mkdir will make the directory we specify, as well as any ‘parent’ directories, hence the p. In other words, this will make an isofiles directory, with a boot directory inside, and a grub directory inside of that.

Next, create a grub.cfg file inside of that isofiles/boot/grub directory, and put this in it:

set timeout=0
set default=0

menuentry "intermezzOS" {
    multiboot2 /boot/kernel.bin
    boot
}

This file configures GRUB. Let’s talk about the menuentry block first. GRUB lets us load up multiple different operating systems, and it usually does this by displaying a menu of OS choices to the user when the machine boots. Each menuentry section corresponds to one of these. We give it a name, in this case, intermezzOS, and then a little script to tell it what to do. First, we use the multiboot2 command to point at our kernel file. In this case, that location is /boot/kernel.bin. Remember how we made a boot directory inside of isofiles? Since we’re making the ISO out of the isofiles directory, everything inside of it is at the root of our ISO. Hence /boot.

Let’s copy our kernel.bin file there now:

$ cp kernel.bin isofiles/boot/

Finally, the boot command says “that’s all the configuration we need to do, boot it up.“

But what about those timeout and default settings? Well, the default setting controls which menuentry we want to be the default. The numbers start at zero, and since we only have that one, we set it as the default. When GRUB starts, it will wait for timeout seconds, and then choose the default option if the user didn’t pick a different one. Since we only have one option here, we just set it to zero, so it will start up right away.

The final layout should look like this:

isofiles/
└── boot
    ├── grub
    │   └── grub.cfg
    └── kernel.bin

Using grub-mkrescue is easy. We run this command:

$ grub-mkrescue -o os.iso isofiles

The -o flag controls the output filename, which we choose to be os.iso. And then we pass it the directory to make the ISO out of, which is the isofiles directory we just set up.

After this, you have an os.iso file with our teeny kernel on it. You could burn this to a USB stick or CD and run it on an actual computer if you wanted to! But doing so would be really annoying during development. So in the next section, we’ll use an emulator, QEMU, to run the ISO file on our development machine.