Build a Virtual Machine Guest

This is a step-by-step guide to building a bootable virtual machine image using the grub boot-loader. It is primarily aimed at quick testing of custom kernels when it isn’t necessary to test the kernel on physical hardware. The basic steps can be amended to suit.

# work as root sudo su # create a 2GB sparse disk image dd if=/dev/zero of=linux-2.6.25.img bs=1M count=0 seek=2048
# attach the image to a device losetup /dev/loop0 linux-2.6.25.img
# configure the disk with one partition fdisk /dev/loop0

Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel Building a new DOS disklabel with disk identifier 0x567b812e. Changes will remain in memory only, until you decide to write them. After that, of course, the previous content won’t be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)
Command (m for help): Command action e extended p primary partition (1-4) Partition number (1-4): First cylinder (1-261, default 1): Using default value 1 Last cylinder or +size or +sizeM or +sizeK (1-261, default 261): Using default value 261 Command (m for help): Selected partition 1 Hex code (type L to list codes): Command (m for help):
Disk /dev/loop0: 2147 MB, 2147483648 bytes 255 heads, 63 sectors/track, 261 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Disk identifier: 0x567b812e Device Boot Start End Blocks Id System /dev/loop0p1 1 261 2096451 83 Linux Command (m for help): The partition table has been altered! Calling ioctl() to re-read partition table. WARNING: Re-reading the partition table failed with error 22: Invalid argument. The kernel still uses the old table. The new table will be used at the next reboot. Syncing disks.

# refresh the view of the disk by disconnecting and reconnecting it losetup -d /dev/loop0 && losetup /dev/loop0 linux-2.6.25.img
# find out which sector the partition begins at and how large it is fdisk -ul /dev/loop0 Disk /dev/loop0: 2147 MB, 2147483648 bytes 255 heads, 63 sectors/track, 261 cylinders, total 4194304 sectors Units = sectors of 1 * 512 = 512 bytes Disk identifier: 0x567b812e Device Boot Start End Blocks Id System /dev/loop0p1 63 4192964 2096451 83 Linux

# Start is sector 63 so, in bytes, the partition starts at: 512 bytes-per-sector x 63 sectors = 32256 bytes
# create a device for the partition starting at offset 32,256 bytes, so it can be formatted losetup -o 32256 /dev/loop1 linux-2.6.25.img
# fdisk will have reserved some free space at the end of the ‘drive’ but mkfs.ext won’t
# be aware of it. Therefore, specifically set the file-system size to match the partition size. # In the fdisk report above it shows the number of 1024-byte blocks used by the partition: 2096451
# That is used, with some added calculation, to correct the file-system: mkfs.ext3 -b 4096 /dev/loop1 $(fdisk -lu /dev/loop0 | awk ‘$1 ~ /^\/dev\/loop0p1.*/ {print ($4 * 1024/4096)-1;}’) e2fsck -f /dev/loop1
# At this point the file-system should be consistent with the partition table
# somewhere to mount the new file system mkdir linux mount /dev/loop1 linux
# install a basic system, enough to get started sudo debootstrap –variant=buildd –components=”main,universe” –include=”language-pack-en-base” \ hardy linux/
# configure some essential system settings echo “LANG=en_GB” >> linux/etc/environment rm linux/etc/localtime ln -s /usr/share/zoneinfo/Europe/London linux/etc/localtime ls -l linux/etc/localtime echo -e “auto lo eth0\niface lo inet loopback\niface eth0 inet dhcp\n” > linux/etc/network/interfaces # name server should match the local address dnsmasq is listening on, that is attached to the host interface kvm0 # kvm0 is the dedicated interface for hosting all virtual machines and is set up separately echo -e “nameserver\n” > linux/etc/resolv.conf echo -e “test-vm\n” > linux/etc/hostname # prepare to use it as a chroot mount -o bind /proc linux/proc mount -o bind /dev linux/dev
# now install a base distro chroot linux /bin/bash -c “apt-get -y –force-yes install ubuntu-minimal”
# configure the file system table export UUID=$(vol_id –uuid /dev/loop1); echo “proc /proc proc defaults 0 0” > linux/etc/fstab echo “UUID=${UUID} / ext3 defaults,errors=remount-ro 0 1” >> linux/etc/fstab
# copy the built kernel image and supporting files into place
# these could come from the kernel build directory cp /home/all/SourceCode/linux/builds/linux-2.6/arch/x86/boot/bzImage linux/boot/vmlinuz-2.6.25 cp /home/all/SourceCode/linux/builds/linux-2.6/ /boot/ cp /home/all/SourceCode/linux/builds/linux-2.6/.config /boot/config-2.6.25 # install the kernel modules
# note -C causes make to change to the kernel source directory, and the O= causes the kernel Makefile
# to use an out-of-tree build directory as the source of the binary modules sudo make -C /home/all/SourceCode/linux/linux-2.6 O=../builds/linux-2.6 \ INSTALL_MOD_PATH=/home/all/VirtualMachines/linux modules_install
# update (create) the initial ram disk image chroot linux /bin/bash -c “update-initramfs -c -k 2.6.25”
# you should see: update-initramfs: Generating /boot/initrd.img-2.6.25 # it needs to be bootable so install grub chroot linux /bin/bash -c “apt-get install grub” chroot linux /bin/bash -c “mkdir -p /boot/grub”
# copy grub boot loader files into the correct location chroot linux /bin/bash -c “cp linux/usr/lib/grub/x86_64-pc/{,e2fs_}stage* linux/boot/grub/”
# now we have to use a trick to install grub stage1 to the master boot record on /dev/loop0 # first, create a grub bootable image cat linux/boot/grub/stage1 linux/boot/grub/stage2 >grub-boot.img
# now boot it in a virtual machine and use it to install grub to the disk image kvm -boot a -fda grub-boot.img -hda /dev/loop0
# In the Virtual Machine, at the grub prompt do: grub> root (hd0,0) grub> find /boot/grub/stage2 (hd0,0) grub> setup (hd0) Checking if “/boot/grub/stage1” exists… yes Checking if “/boot/grub/stage2” exists… yes Checking if “/boot/grub/e2fs_stage1_5” exists… yes Running “embed /boot/grub/e2fs_stage1_5 (hd0)”… 16 sectors are embedded. succeeded Running “install /boot/grub/stage1 (hd0) (hd0)1+16 p (hd0,0)/boot/grub/stage2 /boot/grub/menu.lst”… succeeded Done. grub> halt
# The VM should have halted and quit at that point chroot linux /bin/bash -c “update-grub” Searching for GRUB installation directory … found: /boot/grub Cannot determine root device. Assuming /dev/hda1 This error is probably caused by an invalid /etc/fstab Searching for default file … Generating /boot/grub/default file and setting the default boot entry to 0 Searching for GRUB installation directory … found: /boot/grub Testing for an existing GRUB menu.lst file … Could not find /boot/grub/menu.lst file. Would you like /boot/grub/menu.lst generated for you? (y/N) y Searching for splash image … none found, skipping … Found kernel: /boot/vmlinuz-2.6.25 Updating /boot/grub/menu.lst … done
# mostly done – detach ready for use chroot linux /bin/bash -c “/etc/init.d/sysklogd stop” chroot linux /bin/bash -c “/etc/init.d/klogd stop” umount linux/dev umount linux/proc umount linux
# ensure the loop devices are disconnected losetup -sa /dev/loop0: [0808]:12140623 (linux-2.6.25.img) /dev/loop1: [0808]:12140623 (linux-2.6.25.img), offset 32256 losetup -d /dev/loop1 losetup -d /dev/loop0 losetup -sa
# finally, time to use it in the Virtual Machine! kvm -boot c -hda linux-2.6.25.img -m 512 -k en-gb

From now on only the revised kernel image needs to be updated:
losetup -o 32256 /dev/loop1 linux-2.6.25.img mount /dev/loop1 linux cp /home/all/SourceCode/linux/builds/linux-2.6/arch/x86/boot/bzImage linux/boot/vmlinuz-2.6.25 cp /home/all/SourceCode/linux/builds/linux-2.6/ /boot/ cp /home/all/SourceCode/linux/builds/linux-2.6/.config /boot/config-2.6.25 # might not need to reinstall the modules if only the kernel image was updated sudo make -C /home/all/SourceCode/linux/linux-2.6 O=../builds/linux-2.6 \ INSTALL_MOD_PATH=/home/all/VirtualMachines/linux modules_install chroot linux /bin/bash -c “update-initramfs -c -k 2.6.25” # ready to try again umount /dev/loop1 losetup -d /dev/loop1

This entry was posted in Virtualisation. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s