-
-
Save jclulow/2b1cc7a41437cb0690b7e605560cdee1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
First, grab the MBR: | |
dd \ | |
if=/dev/zvol/rdsk/zones/ce799de5-247d-4e6d-878c-de074ef35c15-disk1 \ | |
of=/tmp/fromdisk \ | |
bs=512 count=32 skip=0 | |
Inspect with MDB: | |
mdb -V ia16 /tmp/fromdisk | |
Check that it's a valid MBR by looking at the signature: | |
> 1fe/BB | |
0x1fe: 55 aa | |
The signature is intact. Look at partition 1: | |
> 1be/BnBBBnBnBBBnDnD | |
0x1be: 0 | |
ff ff ff | |
ee | |
ff ff ff | |
1 | |
461373439 | |
Type is 0xEE (the GPT protective MBR), and the partition ranges from LBA 1 | |
to LBA 461373439, which seems right for this disk. | |
The BIOS will load the MBR into memory at 0x7C00 and then jump there. Check | |
the disassembly: | |
> 0::dis -n 1 | |
0: jmp +0x3c <0x3e> | |
2: nop | |
Step forward to the jump offset: | |
> 3e::dis -n 0t16 | |
0x3e: cld | |
0x3f: xorw %ax,%ax | |
0x41: movw %ax,%es | |
0x43: movw %ax,%ds | |
0x45: movw %ax,%ss | |
0x47: movw $0xe00,%sp | |
0x4a: movw $0x7c58,%si | |
0x4d: movw $0x658,%di | |
0x50: movw $0x1a8,%cx | |
0x53: repz movsb (%si),(%di) | |
Note that this is code from "sys/boot/i386/pmbr/pmbr.s". There are some | |
fixed offsets into this sector, which we can get from "installboot.h": | |
#define STAGE1_STAGE2_SIZE (0xfc) /* 16bits */ | |
#define STAGE1_STAGE2_LBA (0xfe) /* 64bits */ | |
Looking at those values in the MBR: | |
> fc/d | |
0xfc: 1 | |
> fe/E | |
0xfe: 524544 | |
So the MBR code will load 1 sector from LBA 524544 into memory at 0x7C00 | |
and then jump there (mimicking the BIOS). Let's grab that sector now: | |
dd \ | |
if=/dev/zvol/rdsk/zones/ce799de5-247d-4e6d-878c-de074ef35c15-disk1 \ | |
of=/tmp/fromdisk \ | |
bs=512 count=1 skip=524544 | |
Using ::dis we can see that this block looks substantially the same as the MBR, | |
which comments in "installboot.c" confirm. Looking, then, at the offsets in | |
_this_ block: | |
> fc/d | |
0xfc: 332 | |
> fe/E | |
0xfe: 525568 | |
i.e., we'll load 332 sectors from LBA 525568. Let's get that from the disk: | |
dd \ | |
if=/dev/zvol/rdsk/zones/ce799de5-247d-4e6d-878c-de074ef35c15-disk1 \ | |
of=/tmp/fromdisk \ | |
bs=512 count=332 skip=525568 | |
On a _working_ system we would expect to see instructions from | |
"sys/boot/i386/gptzfsboot/gptldr.S"; e.g., starting with "xor %cx, %cx". | |
On _this_ system, we see what does not really appear to be useful | |
program text: | |
> 0::dis | |
0: orb $0xb1,%al | |
2: movw $0x0,%dx | |
5: addb %al,(%bx,%si) | |
7: addb %cl,0x13(%bx,%si) | |
0xb: addb %al,(%bx,%si) | |
... | |
Dumping the actual bytes: | |
> 0::dump -g 1 -l 32 | |
\/ 1 2 3 4 5 6 7 8 9 a b c d e f v123456789abcdef | |
00: 0c b1 ba 00 00 00 00 00 88 13 00 00 00 00 00 00 ................ | |
10: be 81 0a 00 00 00 00 00 d9 89 a8 50 45 6d 25 c2 ...........PEm%. | |
20: 06 f2 87 5c 00 00 00 00 01 00 00 00 00 00 00 00 ...\............ | |
30: bc e3 40 0b 00 00 00 00 01 00 00 00 00 00 00 00 ..@............. | |
Indeed, if we look at offset 0xB0, adjusting for endianness we see MMP_MAGIC: | |
> 0b0::dump -g 4 -e | |
b0: a11cea11 00000000 00000000 00000000 | |
This is LBA 525568 + byte offset 176 (0xB0). | |
To fix this, we'll need a pristine copy of the "gptzfsboot" loader image. I | |
grabbed the one from boot environment we're trying to rescue in the pool: | |
# wc -c /var/tmp/gptzfsboot | |
169984 /var/tmp/gptzfsboot | |
The loader image is patched by installboot(1M) to include the LBA of the | |
beginning of the partition, misusing a field of the fake multiboot header that | |
appears in the image. The 64-bit LBA value is written starting at the address | |
of the "bss_end_addr" member in the multiboot header. Make a copy of the | |
"gptzfsboot" file and locate the multiboot header within: | |
# cp /var/tmp/gptzfsboot /tmp/edited | |
# mdb -V ia16 /tmp/edited | |
> 0,1000::dump -e -g 4 -u ! grep -A1 -i 1BADB002 | |
7a0: 1badb002 00010000 e4514ffe 00000000 | |
7b0: 00000000 000290d4 00000000 00000000 | |
Note that the multiboot magic (0x1BADB002) appears at the top of the | |
multiboot header, and the "bss_end_addr" is the seventh uint32_t-sized | |
member. By default the value is zero: | |
> 7b8/E | |
0x7b8: 0 | |
Replace it with the LBA of the start of the partition as a 64-bit value: | |
> $W | |
> 7b8/Z 0t524544 | |
0x7b8: 0 = 0x80100 | |
Now, write the patched boot block to the disk in the appropriate place: | |
dd \ | |
if=/tmp/edited \ | |
of=/dev/zvol/rdsk/zones/ce799de5-247d-4e6d-878c-de074ef35c15-disk1 \ | |
bs=512 count=332 oseek=525568 | |
The machine will now boot! | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment