DF-2744 / mkimages.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | #!/usr/bin/env python3 # Craft GPT disk images for DF-2741 / DF-2742 / DF-2744 verification. # # gpt.img : 64 MiB GPT disk with 128 entries -> dss_nslices = 130 # mbr.img : 8 MiB MBR disk, 1 DFLYBSD slice, no label (race victim / clean disk) # lbl64.img : 4 MiB MBR disk, 1 DFLYBSD slice (1024 sectors) containing a # disklabel64 whose d_bbase is 32 GiB -> ds_reserved >> ds_size # # All on-disk structures follow sys/sys/{gpt.h,diskmbr.h,disklabel64.h}. import struct, zlib, sys def crc(b): return zlib.crc32(b) & 0xffffffff SECT = 512 # ---------------- gpt.img ---------------- def make_gpt(path, nsec=131072, nent=128): img = bytearray(nsec * SECT) # protective MBR at LBA0 img[446+0] = 0x00 # status img[446+4] = 0xEE # DOSPTYP_PMBR img[446+8:446+12] = struct.pack('<I', 1) img[446+12:446+16] = struct.pack('<I', nsec - 1) img[510:512] = b'\x55\xaa' # partition entries at LBA2 entsz = 128 table = bytearray() for i in range(nent): start = 34 + i * 512 end = start + 511 assert end < nsec # ent_type: recognizable 16-byte pattern "DF2741" + index t = b'DF2741T' + bytes([i & 0xff, (i >> 8) & 0xff]) + b'0123456' u = b'DF2741U' + bytes([i & 0xff, (i >> 8) & 0xff]) + b'0123456' table += t + u + struct.pack('<QQQ', start, end, 0) + b'\x00' * 72 assert len(table) == (i + 1) * entsz tbl_lba = 2 tbl_blocks = (nent * entsz + SECT - 1) // SECT img[tbl_lba * SECT:(tbl_lba + tbl_blocks) * SECT] = table # GPT header at LBA1 (92 valid bytes) hdr = struct.pack('<8sIIIIQQQQ16sQIII', b'EFI PART', 0x00010000, 92, 0, 0, 1, nsec - 1, 34, nsec - 2, b'\x11' * 16, tbl_lba, nent, entsz, crc(table)) assert len(hdr) == 92 hdr = hdr[:16] + struct.pack('<I', crc(hdr)) + hdr[20:] img[SECT:SECT + 92] = hdr open(path, 'wb').write(img) print(f"gpt: {nent} entries, nslices will be {2 + min(nent,128)}, " f"table_blocks={tbl_blocks}") # ---------------- mbr.img ---------------- def make_mbr(path, nsec=16384, start=63): img = bytearray(nsec * SECT) size = nsec - start - 1 img[446+0] = 0x00 img[446+4] = 0x6C # DOSPTYP_DFLYBSD img[446+8:446+12] = struct.pack('<I', start) img[446+12:446+16] = struct.pack('<I', size) img[510:512] = b'\x55\xaa' open(path, 'wb').write(img) print(f"mbr: slice at {start} size {size}") # ---------------- lbl64.img ---------------- # MBR slice at LBA 128, 1024 sectors. disklabel64 at slice-relative offset 0 # (magic at byte 512 of the slice per sys/disklabel64.h). def make_lbl64(path, nsec=8192, sl_start=128, sl_size=1024, bbase=32 * 1024**3): img = bytearray(nsec * SECT) img[446+0] = 0x00 img[446+4] = 0x6C img[446+8:446+12] = struct.pack('<I', sl_start) img[446+12:446+16] = struct.pack('<I', sl_size) img[510:512] = b'\x55\xaa' # disklabel64 inside slice sl_bytes = sl_size * SECT nparts = 16 # struct disklabel64 up to d_partitions[]: # 512 reserved | magic I | crc I | align I | nparts I | stor_uuid 16 | # total_size Q | bbase Q | pbase Q | pstop Q | abase Q | packname 64 | # reserved 64 | partitions[] (each 64 bytes: Q Q BBBB IIII uuid16 uuid16) PSIZE = 64 lab = bytearray(512) lab += struct.pack('<IIII', 0xc4464c59, 0, 512, nparts) lab += b'\x22' * 16 # d_stor_uuid lab += struct.pack('<QQQQQ', sl_bytes, bbase, 4096, sl_bytes - 4096, 0) lab += b'poc2744' + b'\x00' * 57 # packname lab += b'\x00' * 64 # reserved for i in range(nparts): lab += struct.pack('<QQBBBBIII', 0, 0, 0, 0, 0, 0, 0, 0, 0) + b'\x00' * 32 assert len(lab) == 512 + 16 + 16 + 40 + 128 + 64 * nparts, len(lab) # crc over d_magic .. d_partitions[nparts] off_magic = 512 off_end = 512 + 16 + 16 + 40 + 128 + 64 * nparts c = crc(lab[off_magic:off_end]) lab[off_magic + 4:off_magic + 8] = struct.pack('<I', c) base = sl_start * SECT img[base:base + len(lab)] = lab open(path, 'wb').write(img) print(f"lbl64: slice {sl_start}/{sl_size} sectors, d_bbase={bbase} " f"-> ds_reserved={bbase // SECT} sectors (u32 ok: {bbase // SECT < 2**32})") if __name__ == '__main__': d = sys.argv[1] if len(sys.argv) > 1 else '.' make_gpt(f'{d}/gpt.img') make_mbr(f'{d}/mbr.img') make_lbl64(f'{d}/lbl64.img') |