Saturday, February 7, 2015

Installing LFS with QEMU

I traditionally start my Operating Systems course with an assignment that requires students to install Linux From Scratch. They need to hand in a disk image of a 32-bit x86 LFS that can be booted with QEMU, but how they go about making that image is up to them.

A common side-effect of this first assignment is that 20% of students drop the course in frustration. The complaint I hear most often is that they "learn nothing" because "it's just a long series of boring instructions and a tiny mistake in an early step can ruin the entire install 4 hours later". And they are correct (with the latter part anyway): That's exactly what this assignment is.

However, I vehemently disagree with the notion that there's no learning taking place here. Patience is a virtue. Persistence is as well. Working carefully should be one. And so on.

A few years ago I pretty much took the stance that if you're not able to do this, you're not going to be a good computer scientist: It's not just about coming up with new and shiny ideas and hacks, it's also about being able to do semi-boring detail-oriented work with lots and lots of care.

Nowadays I can appreciate that some students simply get too frustrated with this kind of work, especially if they also have to deal with unfamiliar tools and are not really sure how to start. So in an effort to help out a little bit, I've put together the following to show students how to get started (and finished!) with their LFS install using nothing but QEMU.

Note that the last time I actually tested these instructions was in February 2015 with QEMU 2.1.2 and LFS 7.6!

First install the current version of QEMU for your operating system, preferably through your package manager.

Then download and decompress the following disk image. It provides a basic install of Arch Linux that can be used to build LFS.

arch-based-lfs-install-i686.img.xz (483 MB)
(md5sum is 7ae93112f07d8662944a0d4ab0b1fa4d)

Note that this is a raw image that expands into a 4 GB file. You can check that everything is alright by starting QEMU and booting the image:

qemu-system-i386 -enable-kvm -m 256 -hda arch-based-lfs-install-i686.img -redir tcp:2222::22

If your host machine doesn't support KVM, things are going to be a lot slower for you; it's in your best interest to use on a host machine that supports KVM. The last option above instructs QEMU to forward port 2222 of the host machine to port 22 of the virtual machine. This is useful because it allows you to use SSH to do your work:

ssh -p 2222 root@localhost

That way you won't have to worry about QEMU's strange behavior when it comes to copying and pasting things, you can just use your regular terminal application.

Login as user root with password lfs and take a look around if you wish. The home directory of root will contain a bunch of LFS-related files from LFS 7.6. If you're working on a later version of LFS, you'll need to get updated copies of those files (as explained in the LFS book itself).

Finally you may want to run pacman -Syu to bring the system up-to-date before you continue. However, performing such an update is not without risks, especially if gcc gets updated to a version that can no longer compile some of the packages your LFS version depends on. So update with care!

Next run the scripts that check if all the required tools are installed and what versions you have compared to what's needed for LFS:

sh version-check.sh
sh library-check.sh

Again, if you are using an LFS version greater than 7.6 you need to get yourself the updated versions of those files. Read through the output of the scripts and carefully compare against the versions listed in the LFS book. If a package is missing, you can (in most cases) install it as follows:

pacman -S whateverpackagename

Once you are sure that you have all the correct tools, use the following command to shut down the virtual machine:

shutdown -h now

You have now confirmed that you have a VM that can be used to install LFS. The next step is to make a separate disk image file for LFS:

qemu-img create lfs-target-disk.img 4G

This will create another 4 GB file that QEMU will use to simulate a second disk attached to the virtual machine. Restart QEMU as follows:

qemu-system-i386 -enable-kvm -m 256 -hda arch-based-lfs-install-i686.img -hdb lfs-target-disk.img -redir tcp:2222::22

Once again QEMU will boot into the Arch Linux installation we'll use to create the LFS system. Login again and then run the command

lsblk

to display the disks attached to QEMU. You should see /dev/sda with two partitions /dev/sda1 and /dev/sda2 as well as a new disk /dev/sdb. The former refers to the Arch Linux image, the latter to the LFS target image we just created. You now need to follow the instructions from the LFS book for creating partitions and filesystems on the LFS disk. I'd suggest that you create two partitions: First create a 3.5 GB partition for the root filesystem, then use the remaining space on /dev/sdb as a swap partition. Incidentily, that's exactly the partition layout I used for the Arch Linux image:

[root@arch4lfs ~]# fdisk -l /dev/sda

Disk /dev/sda: 4 GiB, 4294967296 bytes, 8388608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x08659cdb

Device     Boot   Start     End Sectors  Size Id Type
/dev/sda1  *       2048 7317503 7315456  3.5G 83 Linux
/dev/sda2       7317504 8388607 1071104  523M 82 Linux swap / Solaris

Don't forget to mark /dev/sdb1 as bootable! Then create an EXT4 filesystem in /dev/sdb1 and a swap partition on /dev/sdb2 following the instructions from the LFS book.

Now you're set to perform the actual LFS install, so we'll skip ahead to the very end (hours later!) when you need to install the GRUB bootloader on /dev/sdb and create /etc/fstab in the LFS root filesystem.

The important thing to realize here is that when you boot your LFS disk image by itself, it will be considered /dev/sda by QEMU! Think about it, that's exactly what's been happening so far with the Arch Linux image. We handed it to QEMU using the -hda command line option, which told QEMU to consider it the first hard disk and boot from it. That's exactly what your LFS disk will be when it boots by itself.

Therefore, while you will install GRUB into the MBR of /dev/sdb as long as the Arch Linux image is /dev/sda, the configuration in /boot/grub.cfg as well as in /etc/fstab must be written with /dev/sda in mind. Proceed accordingly!

When you're done with all of that, follow the LFS book and leave the chroot, unmount all the LFS filesystems, and finally shut down the VM as before. Now you're ready to boot LFS:

qemu-system-i386 -enable-kvm -m 256 -hda lfs-target-disk.img

And there you go! Hopefully the boot process goes smoothly and you're looking at your brand-new LFS login prompt.

Credits: Thanks to Ruben Fiszel for taking Operating Systems as a graduate independent study course this semester, forcing me to double-check how all this LFS stuff really worked.

2 comments:

  1. Why is arch required for building LFS? Quemu is Linux specific so any distro with a working compiler should suffice IMUO (U stands for uniformed:) )

    ReplyDelete
    Replies
    1. Arch is not required, you just need *some* existing Linux install that has all the right tools for LFS. All I am saying here is that the Arch system I posted is such an install. You can use it to install LFS. But you don't have to. Take your pick of Linux distros, make sure you have all the right tools installed, and then build LFS following the handbook. Nothing is stopping you! I just tried to make it easier.

      Delete