Linux – How to install grub into an .img file

grublinux

I did the following:

  1. created an empty .img file with dd
  2. associated it to /dev/loop0 with losetup
  3. created a partition in it with fdisk
  4. formatted such partition with mke2fs
  5. copied a custom GNU/Linux system into that partition

Now I'd like to make the .img file bootable by installing grub into its MBR and /boot directory. My goal is to load the .img file with qemu. It would be better if grub2 is used instead of grub legacy.

Thanks.

Best Answer

This is with grub-pc version 1.98+20100804-5ubuntu3 (Maverick Meerkat).

The grub2 installer can install to loopback devices, but if you mount using the device mapper it will get confused and believe that you have an LVM scheme, failing mysteriously with a complaint about a missing abstraction.

Instead, you should setup the loopback device for the partition yourself, with a name that must match the pattern "/dev/loop[0-9]", i.e. without any partition designator at the end:

kpartx -v -a /dev/loop0
losetup /dev/loop1 /dev/mapper/loop0p1
mount /dev/loop1 /mnt

(Note that if you want grub-mkconfig/update-grub to operate on this volume, then the partition loopback must be connected to the disk loopback under /dev, and not directly to the image file).

Since you used fdisk to partition the image, you have an msdos-style partition table (aka label), and boot using a BIOS. In addition to putting the stage1/boot.img in the MBR, the stage1.5/core.img will be put in an embedding area in unpartitioned space (!) following right after, and there must be space for this.

The trick is now to tell the grub2 installer through a device map how your loopback setup will map to BIOS drives in the virtual machine. (In grub1 legacy this was done directly in the shell). You are probably planning to boot this image as the first disk, so I guess the appropriate mapping would be:

mkdir -p /mnt/boot/grub
cat > /mnt/boot/grub/device.map <<EOF
(hd0)   /dev/loop0
(hd0,1) /dev/loop1
EOF

Here I have put the device map inside the guest disk image, so that you can generate the boot configuration file grub.cfg:

mount --bind /dev /mnt/dev
chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg

(Beware that the post-installer of the grub-pc package will run a probe that overwrites the device map(!), so you'll have to write it after installation and run grub-mkconfig/update-grub yourself).

Now run the installer from the host, pointing to the guest installation:

grub-install --no-floppy --grub-mkdevicemap=/mnt/boot/grub/device.map --root-directory=/mnt /dev/loop0

Finally, unmount everything set up here before starting qemu on your image:

umount /mnt/dev
umount /mnt
losetup -d /dev/loop1
kpartx -v -d /dev/loop0
Related Question