2

I'm trying to get grub1 working with GPT. Currently on a virtual machine, as a test step before migrating a real one.

I've created a partition for /boot, and a different one where I'd like to embed grub stage1.5. This is what gdisk displays for the GPT partition table:

Number  Start (sector)    End (sector) Size        Code  Name
   1             2048           104447 50.0 MiB    8300  boot
   2           104448           206847 50.0 MiB    EF00  EFI
   3           206848         16984063 8.0 GiB     8E00  
   4             1024             2047 512.0 KiB   EF02  GRUB1

Don't bother with the EFI partition, it's not used in this scenario. It's just that I intend to later upgrade the system to UEFI (I know, saying goodbye to grub1), and want to create the partition earlier.

Now, as grub1 does not understand GPT, I've created a hybrid MBR, consiting of 1st and 4th partitions. This is what gdisk says about the hybrid MBR:

   Number  Boot  Start Sector   End Sector   Status      Code
   1                        1         1023   primary     0xEE
   2         *           2048       104447   primary     0x83
   3                     1024         2047   primary     0xEF
   4                   104448     20971519   primary     0xEE

My intention is to put stage1.5 on the small partition below 1MB and have real boot partition (with stage2, grub configuration and kernel image) at the boot partition (GPT 1/MBR 2). However I cannot get grub to install the stage.

When running grub the command find /grub/menu.lst shows me (hd0,0), so it looks like it's using the running kernels partition layout, where the embed partition would be (hd0,3). However giving root (hd0,3) gives me

Filesystem type unknown, partition type 0x83

The filesystem type is not a surprise, as the partition is empty, but I've set the the partition type and it's not visible.

When I try to embed the stage1.5 in the partition (using embed (hd0,0)/grub/e2fs_stage1_5 (hd0,3) I get an error:

Error 17: Cannot mount selected partition

I've tried creating reiserfs3 on that partition (as reiserfs3 has 16KB of space for embedding bootloader), but the error is identical. However the FS I've created is a nonstandard one, with journal on a separate device, as 512KB is not enough to create a normal one.

I've checked that (hd0,3) is the correct drive, as writing something to the first sector of the partition and running cat (hd0,3)+1 in grub shell gives me expected output.

Any other options on how to get this running? I'm thinking of manually embedding stage1.5 into the selected partition (cat /boot/grub/e2fs_stage1_5 > /dev/sda4), modifying it properly (I guess it's only the blocklist in first sector and stage2 location in 2nd sector), and going from there, but I'd like to make it work correctly.

The version I'm using is sys-boot/grub-0.97-r18 from Gentoo.

1 Answers1

2

Turned out to be both easier and harder than anticipated.

First, Gentoo (as well as many other distros as far as I know), has patched Grub to be able to read GPT, thus the whole hassle with hybrid MBR is not needed, it works with pure GPT.

It's easier, because standard setup (hd0,0) does work, as in 'makes a bootable system'. However the system is not robust enough by my standards - because setup can't embed the stage1.5 nowhere, it resorts to patching stage2 and including it's location on disk in MBR. So if anything moves stage2 around, altering the blocks where it was previously, I get an unbootable system. What's worse, I might not notice it first - an upgrade moves stage2 to a different location, but the old one stays intact. System still boots, I notice nothing. But since the code used during boot is now free space from filesystem's POV, something later overwrites it randomly and boom.

So I resorted to steps outlined at end of my question, manually embedding stage1.5.

First, make a copy of appropriate stage1.5 file, and fire up a hex editor on that copy. In case you don't have one handy, I've had success with vim and xxd - edit file, type :!xxd<enter> edit the file as hex, type :!xxd -r<enter> and save. The file gets an extra linefeed at end, but it's harmless. Note that in this case the ASCII part at right is completely ignored, only the hex digits are used. You need to edit 3 things in this file:

  • Put the block number of second block where stage1.5 will be embedded, at offset 0xf8. Note that it's little-endian, and relative to start of disk. Since the BIOS boot partition starts at sector 1024 this is 1025, or 0x0401 or (in little-endian) bytes 0104.
  • Put the number of 512-byte sectors of stage1.5, minus one, at offset 0x1fc. As my stage1.5 is 9908 bytes (9909 with the extra newline), it's 20 sectors (as 19 sectors is 19*512=9728 and 20 sectors is 10240 bytes, so I need to put 19, or hex 13 in there.
  • Change ff at offset 219 to 00. Don't touch the ff's nearby.

Here's a diff of hexdump's of original and modified files:

-000001f0  00 00 00 00 00 00 00 00  02 00 00 00 00 00 20 02  |.............. .|
+000001f0  00 00 00 00 00 00 00 00  01 04 00 00 13 00 20 02  |.............. .|
 00000200  ea 70 22 00 00 00 03 02  ff ff ff 00 00 00 00 00  |.p".............|
-00000210  02 00 30 2e 39 37 00 ff  ff ff ff 2f 62 6f 6f 74  |..0.97...../boot|
+00000210  02 00 30 2e 39 37 00 ff  ff 00 ff 2f 62 6f 6f 74  |..0.97...../boot|

The way this works is that first sector of stage1.5 reads the numbers from near it's end, and reads that many sectors, starting from specified one from start of disk. This loads the remaining sectors of stage1.5 to memory, and later executes them. The third part is actually a location of stage2 on disk, where grub needs to find the correct partition. The relevant code, in case one is interested, is in stage2/disk_io.c in grub's sources, just keep in mind that you use the part in #ifdef STAGE1_5, and the first sector, that loads the rest is in stage2/start.S. It's probably possible to have stage1.5 in several noncontinuous parts, but I haven't tried it.

After writing the modified stage1.5 simply copy it to target partition (the 4th one in my example), using either cat or dd, at your preference.

Finally, in grub shell execute

install /boot/grub/stage1 (hd0) (hd0)1024+20

with (hd0) being the grub name of the device you're using, 1024 is the start of embedded stage1.5 (incidentally, start of BIOS boot partition), and 20 is the size of stage1.5 in blocks. This completes the procedure.