Friday, September 25, 2009

Boot PC from Floppy Image w/ GRUB2 and MEMDISK

[The stuff below is outdated - see the updated howto]

I've already described how I installed GRUB2 on my Live HDD, under the false impression that it would allow me to chainload and boot from a WinPE ISO image.

While I searched for more info about this subject I hit upon MEMDISK, which is part of SYSLINUX - a boot loader for the Linux operating system which operates off an MS-DOS/Windows FAT file-system. MEMDISK is an auxiliary module of SYSLINUX that simulates a disk whose contents resides in a disk image file. This allows the bootloader to boot from that disk image.

MEMDISK can be used to boot from floppy disk images and (I haven't tried this myself) from hard disk images. It seems that the next major release (v4.0) will allow it to actually boot from ISO images, but at the moment Debian has v3.82 available.

Some popular utilities (like MHDD) are distributed as floppy disk images, and it seemed like a useful tool to have. It took some time to put the pieces of the puzzle together, but I finally managed to get it working on my Live HDD:
  1. install syslinux:
    aptitude install syslinux
  2. copy (as root) /usr/lib/syslinux/memdisk to /boot
  3. create a directory /boot/images to hold all the floppy disk images
  4. get some floppy disk images, e.g. like this:
    • download SystemRescueCD
    • loop mount the downloaded ISO image:
      mount -o loop systemrescuecd-x86-1.3.0.iso /mnt/iso
    • copy any disk images that you need from /mnt/iso/bootdisk/*.img (which include MHDD and a few others) to /boot/images
  5. replace the contents of /etc/grub.d/40_custom with the script below
  6. run update-grub - if all goes well, it should create an entry in the GRUB2 boot menu for each floppy image that you copied over to /boot/images
Note that on some machines, and with some floppy images, the MEMDISK hack won't work (hint: you may want to replace bigraw in the script with another command line option). YMMV.

And here's the script:

#!/bin/sh
set -e

IMAGES=/boot/images
. /usr/lib/grub/grub-mkconfig_lib
if test -e /boot/memdisk ; then
MEMDISKPATH=$( make_system_path_relative_to_its_root "/boot/memdisk" )
echo "Found memdisk: $MEMDISKPATH" >&2
find $IMAGES -name "*.img" | sort | 
while read image ; do
IMAGEPATH=$( make_system_path_relative_to_its_root "$image" )
echo "Found floppy image: $IMAGEPATH" >&2
cat << EOF
menuentry "Bootable floppy: $(basename $IMAGEPATH | sed s/.img//)" {
EOF
prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/"
cat << EOF
linux16 $MEMDISKPATH bigraw
initrd16 $IMAGEPATH
}
EOF
done
fi

14 comments:

  1. In Ubuntu 10.04, the 40_custom template has a line "exec tail -n +3 $0"
    The script tells me to not remove this line.
    However your script is missing it. Will this cause any problems?

    ReplyDelete
  2. It the same in Debian/testing.

    The original 40_custom lets you write custom boot menu entries there and have them appear verbatim in the resulting grub2 boot menu.

    If you want to keep this behavior, then just save my script with a different name (e.g. 50_memdisk - the number sets the order of the resulting boot menu entries), and then run

    chmod +x /etc/grub.d/50_memdisk
    update-grub

    It should work (TM), but I haven't tested it.

    ReplyDelete
  3. Bless you, sir!

    That script was a big help! It worked well, and I've been searching for this solution for about a day!

    ReplyDelete
  4. Brilliant...worked a treat. Thanks a bunch.

    ReplyDelete
  5. Thanks for making this guide! Golden stuff!

    Do you think it would be possible to boot an image file of a Windows XP installation using this technique? I'd love to be able to have a Windows installation residing in a file on an ext4 partition on my drive, in all those cases where some Windows-only, hardware-dependent program is needed (like abit uGuru, GPU-Z etc.).

    ReplyDelete
  6. It wasn't possible when I wrote this, two years ago.

    But since then, memdisk has apparently acquired the capability of direct booting an ISO image [1]. So booting from a custom WinPE ISO image may very well just work.

    As for a WinXP installation media - I guess you'll have to try for yourself...

    Good luck!

    [1] http://reboot.pro/8258/

    ReplyDelete
  7. I just tried using this script:
    http://michael-prokop.at/blog/2011/01/07/booting-iso-images-from-within-grub2/
    ie. combining memdisk with GRUB2. The iso boots fine, but when I choose BartPE and the Windows XP logo appears and loads a bit, I see a BSOD (STOP) error of 7B (inaccessible boot device). I've tried setting the SATA controller to IDE mode (which I know is the only thing Win XP supports), but no luck).
    I'll keep trying and post here if I get lucky.

    ReplyDelete
  8. worked great.. I changed it a bit to include iso

    - find $IMAGES -name "*.img" | sort |
    + find $IMAGES -iregex ".*\(img\|iso\)" | sort |

    you might want to use -iname so its not case sensitive.

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. I was getting an initramfs error saying "Unable to find a medium containing a live file system" using the above script (with "Anonumous"'s modification). I've created a script that is able to boot at least ubuntu-12.10-desktop-amd64.iso and probably other Ubuntu ISOs as well, but perhaps not other distributions (I suspect).

    Pasting the following into /etc/grub.d/60_isoboot does the trick (remember chmod +x)


    #!/bin/sh
    set -e

    IMAGES=/boot/images
    . /usr/lib/grub/grub-mkconfig_lib
    find $IMAGES -name "*.iso" | sort |
    while read image ; do
    IMAGEPATH=$( make_system_path_relative_to_its_root "$image" )
    echo "Found ISO image: $IMAGEPATH" >&2
    cat << EOF
    menuentry "Bootable ISO: $(basename $IMAGEPATH | sed s/.iso//)" {
    loopback loop $image
    set gfxpayload=keep
    linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=$image noeject noprompt --
    initrd (loop)/casper/initrd.lz
    }
    EOF
    done

    ReplyDelete
  11. Here's the updated version of the script. This version depends on "isoinfo" to find out what the name of the "initrd" image is. This also works with Rebecca Black OS (if you want to test out Wayland):

    #!/bin/sh
    set -e

    IMAGES=/boot/images
    . /usr/lib/grub/grub-mkconfig_lib
    find $IMAGES -name "*.iso" | sort |
    while read image ; do
    IMAGEPATH=$( make_system_path_relative_to_its_root "$image" )
    echo "Found ISO image: $IMAGEPATH" >&2
    #now we need to find out what the initrd file is called
    INITRD="$(isoinfo -l -i "$IMAGEPATH" | egrep -o INITRD*.* | sed 's/;1 $//' | tr '[A-Z]' '[a-z]' )"

    cat << EOF
    menuentry "Bootable ISO: $(basename $IMAGEPATH | sed s/.iso//)" {
    loopback loop $image
    set gfxpayload=keep
    linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=$image noeject noprompt --
    initrd (loop)/casper/$INITRD
    }
    EOF
    done

    ReplyDelete