diff --git a/system/services/volume-manager/partition.zig b/system/services/volume-manager/partition.zig index 6a72a68..eada032 100644 --- a/system/services/volume-manager/partition.zig +++ b/system/services/volume-manager/partition.zig @@ -351,9 +351,9 @@ fn gptEntry(type_nonzero: bool, unique_guid: u128, start: u64, end: u64) [128]u8 return e; } -/// Lay out a 4-sector disk: protective MBR (LBA 0), GPT header with a correct -/// CRC (LBA 1), and the entry array (LBA 2). -fn buildGptDisk(disk: []u8, entries: []const [128]u8) void { +/// Lay out a disk with `entry_size`-spaced GPT entries: protective MBR (LBA 0), +/// GPT header with a correct CRC (LBA 1), the entry array (LBA 2+). +fn buildGptDiskSized(disk: []u8, entries: []const [128]u8, entry_size: u32) void { @memset(disk, 0); disk[510] = 0x55; disk[511] = 0xAA; @@ -365,16 +365,22 @@ fn buildGptDisk(disk: []u8, entries: []const [128]u8) void { std.mem.writeInt(u32, h[12..16], 92, .little); // header_size std.mem.writeInt(u64, h[72..80], 2, .little); // partition_entry_lba std.mem.writeInt(u32, h[80..84], @intCast(entries.len), .little); - std.mem.writeInt(u32, h[84..88], 128, .little); // size_of_partition_entry + std.mem.writeInt(u32, h[84..88], entry_size, .little); // size_of_partition_entry @memset(h[16..20], 0); std.mem.writeInt(u32, h[16..20], crc32(h[0..92]), .little); - const ea = disk[2 * sector_bytes ..][0..sector_bytes]; + const step: usize = @intCast(entry_size); var i: usize = 0; - while (i < entries.len and i < 4) : (i += 1) { - @memcpy(ea[i * 128 ..][0..128], &entries[i]); + while (i < entries.len) : (i += 1) { + const abs = 2 * sector_bytes + i * step; + @memcpy(disk[abs..][0..128], &entries[i]); } } +/// The common 128-byte-entry case. +fn buildGptDisk(disk: []u8, entries: []const [128]u8) void { + buildGptDiskSized(disk, entries, 128); +} + test "a GPT disk yields the partition GUID as the identity id" { var disk = [_]u8{0} ** (4 * sector_bytes); const guid: u128 = 0x112233445566778899AABBCCDDEEFF00; @@ -468,3 +474,20 @@ test "an MBR FAT partition prefers the volume serial; a non-FAT partition keeps try std.testing.expectEqual(Rung.mbr_index, v2.identity.rung); try std.testing.expectEqual((@as(u128, 0xDEADBEEF) << 8) | 0, v2.identity.key); } + +test "GPT with 256-byte entries reads the non-128 offset arithmetic correctly" { + // With entry_size 256, entry 1 lands at offset 256 of the same sector (LBA 2). + // Put the only valid entry at index 1 so the off = (i*entry_size) % 512 path + // (256, not 0) is exercised — the sharp edge the 128-byte tests never hit. + var disk = [_]u8{0} ** (5 * sector_bytes); + const entries = [_][128]u8{ + gptEntry(false, 0, 0, 0), // index 0: unused (type GUID zero) + gptEntry(true, 0xF00D, 4096, 8191), // index 1: at offset 256 + }; + buildGptDiskSized(&disk, &entries, 256); + const rd = RamDisk{ .sectors = &disk }; + const v = firstVolume(rd.reader(), 200000).?; + try std.testing.expectEqual(@as(u64, 4096), v.base_lba); + try std.testing.expectEqual(Rung.gpt_guid, v.identity.rung); + try std.testing.expectEqual(@as(u128, 0xF00D), v.identity.key); +}