User:Graham/Making a GRUB2 image

From OSDev.wiki
Revision as of 21:07, 22 January 2011 by Graham (talk | contribs) (→‎Automatically updating the image)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Introduction

This guide uses the latest GRUB2 (1.98+20100804-5ubuntu3) from the Ubuntu repositories (at the time of writing). I have not tested it with anything else but I don't see any reason why it shouldn't work.

GRUB2 is a bit more problematic to set up compared to the legacy version because you need some sort of partition table. Also, it is based around modules and you need to specify the minimum modules you need to be able to load all the other modules - this caused quite a headache for me when I tried using the grub-install command without specifying them.

I'm using an MS-DOS partition table with an ext2 filesystem in this tutorial. GRUB is also configured to read the disks with the BIOS functions. All of this is easily customizable however the combination I've used here seems to be chosen by most hobby developers.

Making the image

Create an empty image file and set up a loop device for it:

 dd if=/dev/zero of=disk.img bs=512 count=32130
 sudo losetup /dev/loop0 disk.img

Create an MS-DOS partition table with fdisk:

 sudo fdisk /dev/loop0

Within the fdisk prompt type "o" to create a partition table, then "n" to create a new partition. Type "p" to create a primary partition and make it the first partition with "1". I left all the other settings as their defaults by hitting enter. Finally, use "w" to save the changes.

Find the first sector of the partition with fdisk:

 sudo fdisk -lu /dev/loop0

You need to multiply the number under "Start" by 512. For me, this was 63 * 512 = 32256. Now create a loop device for this partition (like how /dev/sda and /dev/sda0 would work on your normal system):

 sudo losetup -o 32256 /dev/loop1 /dev/loop0

Format this as ext2 and mount it to a temporary location:

 sudo mke2fs /dev/loop1
 mkdir temp
 sudo mount /dev/loop1 ./temp

Install GRUB:

 sudo grub-install --root-directory=./temp --disk-module=biosdisk --modules="ext2 part_msdos" /dev/loop0

Now unmount the partition and remove the loop devices:

 sudo umount ./temp
 sudo losetup -d /dev/loop1
 sudo losetup -d /dev/loop0
 rmdir ./temp

And test it:

 qemu -hda disk.img

If you get a GRUB prompt then it worked!

Automatically updating the image

I use this shell script to automatically update my image with the latest kernel binary and grub configuration as part of the build process:

 #!/bin/sh -e
 mkdir -p ./mnt
 sudo mount -o loop,offset=32256 disk.img ./mnt
 sudo cp kernel ./mnt
 sudo cp grub.cfg ./mnt/boot/grub
 sync
 sudo umount ./mnt

You'll need to change the offset value to the one used above. What is nice about mounting and unmounting only with the mount/umount commands is that we do not need to mess around with the /dev/loopX devices directly which can be problematic if you forget to delete one after using it.