PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
part_driver_gpt.c
1#include "part_driver.h"
2#include <errno.h>
3#include <stdio.h>
4#include <string.h>
5#include <sysmem.h>
6
7#include <bdm.h>
8#include "gpt_types.h"
9
10#include "module_debug.h"
11
12void GetGPTPartitionNameAscii(gpt_partition_table_entry* pPartition, char* pAsciiBuffer)
13{
14 // Loop and perform the world's worst unicode -> ascii string conversion.
15 for (int i = 0; i < sizeof(pPartition->partition_name) / sizeof(u16); i++)
16 pAsciiBuffer[i] = (char)pPartition->partition_name[i];
17}
18
19int part_connect_gpt(struct block_device *bd)
20{
21 int ret;
22 void* buffer = NULL;
23 gpt_partition_table_header* pGptHeader;
24 gpt_partition_table_entry* pGptPartitionEntry;
25 int entriesPerSector;
26 int endOfTable = 0;
27 char partName[37] = { 0 };
28 int partIndex;
29 int mountCount = 0;
30
31 M_DEBUG("%s\n", __func__);
32
33 // Allocate scratch memory for parsing the partition table.
34 buffer = AllocSysMemory(ALLOC_FIRST, 512 * 2, NULL);
35 if (buffer == NULL)
36 {
37 M_DEBUG("Failed to allocate memory\n");
38 return 0;
39 }
40
41 pGptHeader = (gpt_partition_table_header*)buffer;
42 pGptPartitionEntry = (gpt_partition_table_entry*)((u8*)buffer + 512);
43
44 // Read the GPT partition table header from the block device.
45 ret = bd->read(bd, 1, pGptHeader, 1);
46 if (ret < 0)
47 {
48 // Failed to read gpt partition table header.
49 M_DEBUG("Failed to read GPT partition table header %d\n", ret);
50 FreeSysMemory(buffer);
51 return -1;
52 }
53
54 // Check the partition table header signature.
55 if (memcmp(pGptHeader->signature, EFI_PARTITION_SIGNATURE, sizeof(EFI_PARTITION_SIGNATURE)) != 0)
56 {
57 // GPT partition table header signature is invalid.
58 M_DEBUG("GPT partition table header signature is invalid: %s\n", pGptHeader->signature);
59 FreeSysMemory(buffer);
60 return -1;
61 }
62
63 // TODO: we might want to check the header revision and size for compatibility for newer/older GPT layouts. There's
64 // also a few CRC checksums in the header that may be useful to validate, but is probably not needed.
65
66 // Calculate how many partition entries there are per sector.
67 entriesPerSector = bd->sectorSize / sizeof(gpt_partition_table_entry);
68
69 // Loop through all the partition table entries and attempt to mount each one.
70 printf("Found GPT disk '%08x...'\n", *(u32*)&pGptHeader->disk_guid);
71 for (int i = 0; i < pGptHeader->partition_count && endOfTable == 0; )
72 {
73 // Check if we need to buffer more data, GPT usually uses LBA 2-33 for partition table entries. Typically there will
74 // only be a couple partitions at most, so we buffer one sector at a time to avoid making needless allocations for all sectors at once.
75 if (i % entriesPerSector == 0)
76 {
77 // Read the next sector from the block device.
78 ret = bd->read(bd, pGptHeader->partition_table_lba + (i / entriesPerSector), pGptPartitionEntry, 1);
79 if (ret < 0)
80 {
81 // Failed to read the next sector from the drive.
82#ifdef DEBUG
83 u64 lba = pGptHeader->partition_table_lba + (i / entriesPerSector);
84 DEBUG_U64_2XU32(lba);
85 M_DEBUG("Failed to read next partition table entry sector lba=0x%08x%08x\n", lba_u32[1], lba_u32[0]);
86#endif
87 FreeSysMemory(buffer);
88 return -1;
89 }
90
91 // Parse the two partition table entries in the structure.
92 for (int x = 0; x < entriesPerSector; x++, i++)
93 {
94 // Check if the partition type guid is valid, the header will list the maximum number of partitions that can fit into the table, so
95 // we need to check if the entries are actually valid.
96 if (memcmp(pGptPartitionEntry[x].partition_type_guid, NULL_GUID, sizeof(NULL_GUID)) == 0)
97 {
98 // Stop scanning for partitions.
99 endOfTable = 1;
100 break;
101 }
102
103 // Perform some sanity checks on the partition.
104 if (pGptPartitionEntry[x].first_lba < pGptHeader->first_lba || pGptPartitionEntry[x].last_lba > pGptHeader->last_lba)
105 {
106 // Partition entry data appears to be corrupt.
107 M_DEBUG("Partition entry %d appears to be corrupt (lba bounds incorrect)\n", i);
108 continue;
109 }
110
111 // Print the partition info and create a pseudo block device for it.
112 GetGPTPartitionNameAscii(&pGptPartitionEntry[x], partName);
113 u64 first_lba = pGptPartitionEntry[x].first_lba;
114 u64 last_lba = pGptPartitionEntry[x].last_lba;
115 u64 attribute_flags = pGptPartitionEntry[x].attribute_flags;
116 U64_2XU32(first_lba);
117 U64_2XU32(last_lba);
118 U64_2XU32(attribute_flags);
119 M_PRINTF("Found partition '%s' type=%08x unique=%08x start=0x%08x%08x end=0x%08x%08x attr=0x%08x%08x\n", partName, *(u32*)&pGptPartitionEntry[x].partition_type_guid,
120 *(u32*)&pGptPartitionEntry[x].partition_unique_guid, first_lba_u32[1], first_lba_u32[0], last_lba_u32[1], last_lba_u32[0], attribute_flags_u32[1], attribute_flags_u32[0]);
121
122 // Check for specific GPT partition types we should ignore.
123 if (memcmp(pGptPartitionEntry[x].partition_type_guid, MS_RESERVED_PARTITION_GUID, sizeof(MS_RESERVED_PARTITION_GUID)) == 0 ||
124 memcmp(pGptPartitionEntry[x].partition_type_guid, EFI_SYSTEM_PARTITION, sizeof(EFI_SYSTEM_PARTITION)) == 0)
125 continue;
126
127 // Check if the partition should be ignored.
128 if ((pGptPartitionEntry[x].attribute_flags & GPT_PART_ATTR_IGNORE) != 0)
129 continue;
130
131 // TODO: Check type specific partition flags: read-only, hidden, etc.
132
133 if ((partIndex = GetNextFreePartitionIndex()) == -1)
134 {
135 // No more free partition slots.
136 printf("Can't mount partition, no more free partition slots!\n");
137 continue;
138 }
139
140 // Create the pseudo block device for the partition.
141 g_part[partIndex].bd = bd;
142 g_part_bd[partIndex].name = bd->name;
143 g_part_bd[partIndex].devNr = bd->devNr;
144 g_part_bd[partIndex].parNr = i + 1;
145 g_part_bd[partIndex].parId = 0;
146 g_part_bd[partIndex].sectorSize = bd->sectorSize;
147 g_part_bd[partIndex].sectorOffset = bd->sectorOffset + pGptPartitionEntry[x].first_lba;
148 g_part_bd[partIndex].sectorCount = pGptPartitionEntry[x].last_lba - pGptPartitionEntry[x].first_lba;
149 bdm_connect_bd(&g_part_bd[partIndex]);
150 mountCount++;
151 }
152 }
153 }
154
155 // Free our scratch buffer.
156 FreeSysMemory(buffer);
157 return mountCount > 0 ? 0 : -1;
158}