Lately, I have been doing work with the Pistachio L4 microkernel as part of my research. This requires building various disk images, installing GRUB, and running them inside of a virtual machine. Initially, I was using Linux to do this, since it had all the tools ready to go and was what everyone else was using. However, I have a Mac, so I wanted to be able to use that, rather than SSHing into a server all the time. I didn’t think it would be a big deal, just install the same tools on my Mac, right? Wrong! What follows is the odyssey of what I’ve gone through to do this. Hopefully, it will help anyone else facing a similar circumstance.
The main problem I ran into with this task is that Mac’s do not have loop devices and the losetup program. On Linux, these let you mount a disk image, such as a CD ISO or a raw hard drive image, to a folder. You can then easily mount the image, copy files, then unmount the image and be done. Since Macs do not have these loopback devices, it wouldn’t be possible to just build the losetup program either.
On a Mac, you can play with ISOs and other images using Disk Utility. For a bootable hard drive image, there is no filesystem on the disk initially, so there is nothing for Mac to mount. Too bad.
However, there is a set of tools called mtools, which allow you to play with DOS formatted images, i.e. FAT, which will work for my needs. They are especially helpful on Linux systems, since you can use them without being a root user, unlike losetup. Luckily, they are GNU open source, so there was a glimmer of hope that these may work on Mac. I tried Homebrew and MacPorts, but neither worked. There was source available though, so I could try building them myself.
Normally, GNU software is easy to install. Just do ‘./configure; make; make install’ and that’s it on a Linux system. Macs are a little different from Linux though, so sometimes this doesn’t work. In this case, I kept getting compile errors when running make. Something to do with the iconv library and not linking properly. I suspect that is from Apple providing a slightly different version of the library. Fortunately, this was an optional library, so I simply excluded it from the rebuild and tried again. Voila, it built and I now have mtools.
The next step was to create a hard drive image. This sounds simple, but it takes some math to make one of the proper size. It is important that the disk has less than 1023 cylinders, or else GRUB will complain later on. I found a calculator online to help do this. For my needs, I only needed about a 10 MB disk, so I used the values: 4 heads, 500 cylinders, 10 sectors per track, and 512 per sector. This gives a 10.24 MB disk size. Great.
I made a raw file of the proper size with the command:
dd if=/dev/zero of=disk.img bs=512 count=20000
That command spits out disk.img, which will be the hard drive image we are working with. However, it is just filled with zeros right now, so mtools needed to format it. I pulled my hair out trying to figure out the right command line options for this. I kept confusing the -s flag for the number of sectors, but it’s actually number of sectors PER TRACK. That’s kind of a big deal. Anyways, here are the commands I used to get mtools to play nice:
echo 'drive a: file="disk.img"' > mtoolsrcMTOOLSRC=./mtoolsrc mformat -t 2000 -s 10 -h 4 a:
Now, the disk is formatted with a FAT filesystem (at least as far as I understand it). However, there are no files on it, so it’s pretty boring. First, we need to install GRUB, which is a bootloader, so that we can boot this stupid disk (At this point, I have done about 10 hours of Googling, compiling, and yelling). In the mtools package, there are two commands called ‘mmd’ and ‘mcopy’. These can make a directory and copy files for us. Exciting, I know. Here are the steps to copy GRUB (legacy) to the disk. Note that you must already have the files downloaded. You can grab them here. For grub.conf, you will have to play with that and make one yourself. There are tutorials, so I omit directions here.
MTOOLSRC=./mtoolsrc mmd a:/boot MTOOLSRC=./mtoolsrc mmd a:/boot/grub MTOOLSRC=./mtoolsrc mcopy stage1 a:/boot/grub MTOOLSRC=./mtoolsrc mcopy stage2 a:/boot/grub MTOOLSRC=./mtoolsrc mcopy grub.conf a:/boot/grub
Well, now we have a hard disk image with GRUB on it, we’re done right? WRONG. Grub is stored on the disk, but not installed on the disk. To actually install it, we have to boot the disk and run some GRUB commands.
But how can we boot the disk if GRUB isn’t installed? Point for you if you asked that. We now need to go grab a bootable GRUB floppy. We’re only interested in the GRUB command line, so any will do. There is one from here that will work.
Now that we have the disk with GRUB stored on it and a bootable floppy, let’s finally start the virtual machine and install GRUB. I’m going to use QEMU. If you’re using something else, QEMU commands won’t help you, so use QEMU instead. First, boot the disk and floppy with the command:
qemu -hda disk.img -fda /floppy.img -boot order=a
That will start QEMU with both the floppy and hard disk inserted and boot the floppy. When the floppy first boots up, hit ‘c’ on the keyboard to get a command line. That’s all we actually needed the floppy for. Now, on the command line, enter the commands:
root (hd0,0) setup (hd0,0)
Some text should fly by and if there are no errors, GRUB will now be installed. You can check by running QEMU again, but without the floppy disk and seeing what happens. Hopefully, you will get a boot screen, in which case you are done. You can now copy files as needed to the disk using ‘mcopy’ how we did before.
If you get errors about disk size and cylinders, use the command ‘geometry (hd0,0)’ to get some more information, when at the GRUB command line.
Well, I hope that helps someone else out there. I had no end of problems getting that to work. However, I can now use disk images so I can work on…. Well, I forgot what I was originally doing, it was so long ago!