|  | make-bootable-grub-hdd.txt | 
|  | Barret Rhoden | 
|  | 2013-02-22 | 
|  |  | 
|  | This document explains how to make a hard disk image file, install grub on the | 
|  | image, and load your kernel (Akaros in the examples). | 
|  |  | 
|  |  | 
|  | Initial Setup: | 
|  | -------------------------- | 
|  | Commands that begin with # need root access.  Commands beginning with $ should | 
|  | be done as your development user. | 
|  |  | 
|  | You need the loop module loaded with max_part=10 (or something more than the | 
|  | number of partions you are making on an image file). | 
|  |  | 
|  | # modprobe loop max_part=10 | 
|  |  | 
|  | If your loop device is compiled into the kernel, add the kernel parameter "loop.max_part=10" | 
|  |  | 
|  | For example, once you partition an image file and connect it to a loopback | 
|  | device (e.g., loop1), you will see the following devices: | 
|  |  | 
|  | /dev/loop1 | 
|  | /dev/loop1p1 | 
|  | /dev/loop1p2 | 
|  | ..etc | 
|  |  | 
|  |  | 
|  | Build your Image File: | 
|  | -------------------------- | 
|  | This makes an image of size 268MB, which is 256MiB): | 
|  |  | 
|  | $ dd if=/dev/zero of=mnt/hdd.img bs=512 count=1 seek=524287 | 
|  |  | 
|  | Connect to the image via a loopback device: | 
|  |  | 
|  | # losetup /dev/loop0 mnt/hdd.img | 
|  |  | 
|  | Fdisk the device: | 
|  |  | 
|  | # fdisk /dev/loop0 | 
|  | Create a new linux partition | 
|  | Note it has 524288 sectors (1 + the seek offset) | 
|  | Also note the partition begins at 2048, not 512 like it used to (changes | 
|  | to fdisk, probably to get away from 512 byte alignments) | 
|  |  | 
|  | Disconnect and reconnect the loopback device, so we now can see the | 
|  | partitions: | 
|  |  | 
|  | # losetup -d /dev/loop0 | 
|  | # losetup /dev/loop0 mnt/hdd.img | 
|  | # ls /dev/loop0* | 
|  | /dev/loop0  /dev/loop0p1 | 
|  |  | 
|  | Make the filesystem: | 
|  |  | 
|  | # mkfs /dev/loop0p1 | 
|  |  | 
|  | Create a mount point for your image file (as your user); | 
|  |  | 
|  | $ mkdir mnt/hdd/ | 
|  |  | 
|  | Mount and chown.  The chown only needs to be done the first time you mount the | 
|  | device. | 
|  |  | 
|  | # mount /dev/loop0p1 mnt/hdd/ | 
|  | # chown -R brho:brho mnt/hdd/ | 
|  |  | 
|  |  | 
|  | Install Grub on the Image file: | 
|  | -------------------------- | 
|  |  | 
|  | This assumes legacy grub:  for gentoo, emerge sys-boot/grub-static to get the | 
|  | legacy grub.  I glanced at grub2, but don't particularly want to mess with | 
|  | that. | 
|  |  | 
|  | Set up the grub1 files and directories (assuming you still have the image | 
|  | mounted and have access to stage1 and stage2 files). | 
|  |  | 
|  | $ mkdir -p mnt/hdd/boot/grub | 
|  | $ cp /boot/grub/stage1 /boot/grub/stage2 /boot/grub/menu.lst mnt/hdd/boot/grub/ | 
|  |  | 
|  | Edit menu.lst.  Here's one similar to mine that works with Akaros: | 
|  | default 0 | 
|  | timeout 5 | 
|  | serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1 | 
|  | terminal --timeout=5 serial console | 
|  |  | 
|  | title=Akaros | 
|  | root (hd0,0) | 
|  | kernel /kernel | 
|  |  | 
|  | Now put the kernel on the mounted image.  You can do this whenever, btw, and | 
|  | you'll do this whenever you want to update the kernel (my Makelocal has a | 
|  | target that does this).  So feel free to do this later. | 
|  |  | 
|  | $ cp obj/kern/kernel mnt/hdd/kernel | 
|  |  | 
|  | Actually install grub on the device.  Do this as a regular user (not root), to | 
|  | limit damage in case you mess up (e.g., accidentally write to /dev/sda instead | 
|  | of your image file) | 
|  |  | 
|  | $ /sbin/grub --device-map=/dev/null | 
|  |  | 
|  | Enter the commands at the grub> prompt.  I've included the output you | 
|  | should see if things are going well: | 
|  |  | 
|  | grub> device (hd0) mnt/hdd.img | 
|  | device (hd0) mnt/hdd.img | 
|  |  | 
|  | grub> root (hd0,0) | 
|  | root (hd0,0) | 
|  | Filesystem type is ext2fs, partition type 0x83 | 
|  |  | 
|  | grub> setup (hd0) | 
|  | setup (hd0) | 
|  | Checking if "/boot/grub/stage1" exists... yes | 
|  | Checking if "/boot/grub/stage2" exists... yes | 
|  | Checking if "/boot/grub/e2fs_stage1_5" exists... no | 
|  | Running "install /boot/grub/stage1 (hd0) /boot/grub/stage2 p /boot/grub/menu.lst "... succeeded | 
|  | Done. | 
|  |  | 
|  | grub> quit | 
|  | quit | 
|  |  | 
|  |  | 
|  | That's it.  Whenever you reboot, you'll need to recreate the loopback device | 
|  | and remount the image at mnt/hdd/.  Check out my "kvm-up.sh" script for how I | 
|  | do this (it's basically just losetup, sleep, and mount). | 
|  |  | 
|  | Whenever you update the kernel, cp it into mnt/hdd/kernel, and sync.  The sync | 
|  | is necessary so the image file / backing store gets updated right away.  If | 
|  | you don't do this, your VM might see the old version of kernel if you run the | 
|  | VM right away (before the FS naturally syncs).  Check out my Makelocal target | 
|  | for kvm for how to do this. | 
|  |  | 
|  |  | 
|  | Old Stuff: | 
|  | -------------------------- | 
|  | I originally wrote this back in 2009.  It works for older versions of fdisk | 
|  | and has some acrobatics with loopback devices that will help if you can't use | 
|  | the max_part parameter to the loop module.  Also, it has some examples with | 
|  | using bochs | 
|  |  | 
|  |  | 
|  | # make a 8MB image.  picked these values so there is 1 cyl (minimum, it seems) | 
|  | dd if=/dev/zero of=mnt/hdd.img bs=512 count=16065 | 
|  | losetup /dev/loop1 mnt/hdd.img | 
|  | fdisk /dev/loop1 | 
|  | # determine the offset, in sectors | 
|  | fdisk -ul /dev/loop1 | 
|  | # mult the sector offset by 512, since losetup offsets by bytes | 
|  | # this will have us point loop2 to the partition on the disk | 
|  | losetup -o 32256 /dev/loop2 /dev/loop1 | 
|  | mkfs /dev/loop2 | 
|  | mount /dev/loop2 mnt/hdd/ | 
|  | # copy over grub info | 
|  | mkdir -p mnt/hdd/boot/grub | 
|  | cp -r /boot/grub/stage1 /boot/grub/stage2 /boot/grub/menu.lst mnt/hdd/boot/grub | 
|  | cp -r the_kernel mnt/hdd/ | 
|  | # edit accordingly | 
|  | vi mnt/hdd/boot/grub/menu.lst | 
|  | grub --device-map=/dev/null | 
|  | # in here: | 
|  | # important to not use the /dev/loop1, since there is a bug in grub | 
|  | # use the image instead, since it bypasses whatever checks fail later | 
|  | device (hd0) mnt/hdd.img | 
|  | root (hd0,0) | 
|  | setup (hd0) # make sure you don't do (hd0,0).  it'll still work, but not the way you want | 
|  | kvm mnt/hdd.img | 
|  | # or | 
|  | bochs -q 'ata0-master: type=disk, mode=flat, path="./mnt/hdd.img", cylinders=1, heads=255, spt=63' | 
|  | # to use a floppy image (made similarly) | 
|  | bochs -q 'floppya: 1_44=mnt/floppy.img, status=inserted' 'boot:a' | 
|  |  | 
|  | # to easily edit, keep the hdd image mounted and just copy in your kernel or | 
|  | # whatever | 
|  | # list the loops, delete them with -d to keep things nice and clean | 
|  | losetup -a | 
|  | losetup -o 32256 /dev/loop0 mnt/hdd.img | 
|  | mount /dev/loop0 mnt/hdd | 
|  | chown -R brho:brho mnt/hdd | 
|  |  | 
|  | # you'll need to make sure changes to the mnt/hdd take effect immediately | 
|  | # if you want to run a VM right away with the .img | 
|  | sync | 
|  |  | 
|  |  | 
|  | Notes: | 
|  | -------------------------- | 
|  | http://www.linuxjournal.com/article/4622 | 
|  | http://sig9.com/bochs-grub | 
|  | http://web2.clarkson.edu/projects/itl/honeypot/ddtutorial.txt | 
|  | http://www.mail-archive.com/bug-grub@gnu.org/msg09648.html | 
|  | http://www.omninerd.com/articles/Installing_GRUB_on_a_Hard_Disk_Image_File |