]>
code.delx.au - refind/blob - refind/gpt.c
eb106b7960efa21141ac1a0d9343cbeb9b32712e
3 * Functions related to GPT data structures
5 * Copyright (c) 2014 Roderick W. Smith
8 * This program is distributed under the terms of the GNU General Public
9 * License (GPL) version 3 (GPLv3), a copy of which must be distributed
10 * with this source code or binaries made from it.
18 #include "../include/refit_call_wrapper.h"
20 #ifdef __MAKEWITH_TIANO
21 #define BlockIoProtocol gEfiBlockIoProtocolGuid
24 extern GPT_DATA
*gPartitions
;
26 // Allocate data for the main GPT_DATA structure, as well as the ProtectiveMBR
27 // and Header structures it contains. This function does *NOT*, however,
28 // allocate memory for the Entries data structure, since its size is variable
29 // and is determined by the contents of Header.
30 GPT_DATA
* AllocateGptData(VOID
) {
33 GptData
= AllocateZeroPool(sizeof(GPT_DATA
));
34 if (GptData
!= NULL
) {
35 GptData
->ProtectiveMBR
= AllocateZeroPool(sizeof(MBR_RECORD
));
36 GptData
->Header
= AllocateZeroPool(sizeof(GPT_HEADER
));
37 if ((GptData
->ProtectiveMBR
== NULL
) || (GptData
->Header
== NULL
)) {
38 MyFreePool(GptData
->ProtectiveMBR
);
39 MyFreePool(GptData
->Header
);
45 } // GPT_DATA * AllocateGptData()
47 // Unallocate a single GPT_DATA structure. This does NOT follow the
48 // linked list, though.
49 VOID
ClearGptData(GPT_DATA
*Data
) {
51 if (Data
->ProtectiveMBR
)
52 MyFreePool(Data
->ProtectiveMBR
);
54 MyFreePool(Data
->Header
);
56 MyFreePool(Data
->Entries
);
59 } // VOID ClearGptData()
61 // TODO: Make this work on big-endian systems; at the moment, it contains
62 // little-endian assumptions!
63 // Returns TRUE if the GPT header data appear valid, FALSE otherwise.
64 static BOOLEAN
GptHeaderValid(GPT_DATA
*GptData
) {
66 UINT32 CrcValue
, StoredCrcValue
;
67 UINTN HeaderSize
= sizeof(GPT_HEADER
);
69 IsValid
= ((GptData
!= NULL
) && (GptData
->ProtectiveMBR
!= NULL
) && (GptData
->Header
!= NULL
));
70 IsValid
= IsValid
&& (GptData
->ProtectiveMBR
->MBRSignature
== 0xAA55);
71 IsValid
= IsValid
&& ((GptData
->ProtectiveMBR
->partitions
[0].type
== 0xEE) ||
72 (GptData
->ProtectiveMBR
->partitions
[1].type
== 0xEE) ||
73 (GptData
->ProtectiveMBR
->partitions
[2].type
== 0xEE) ||
74 (GptData
->ProtectiveMBR
->partitions
[3].type
== 0xEE));
75 IsValid
= IsValid
&& (GptData
->Header
->signature
== 0x5452415020494645ULL
);
77 // Looks good so far; check CRC value....
79 if (GptData
->Header
->header_size
< HeaderSize
)
80 HeaderSize
= GptData
->Header
->header_size
;
81 StoredCrcValue
= GptData
->Header
->header_crc32
;
82 GptData
->Header
->header_crc32
= 0;
83 CrcValue
= crc32(0x0, GptData
->Header
, HeaderSize
);
84 if (CrcValue
!= StoredCrcValue
)
86 GptData
->Header
->header_crc32
= StoredCrcValue
;
90 } // BOOLEAN GptHeaderValid()
92 // Read GPT data from Volume and store it in Data. Note that this function
93 // may be called on a Volume that is not in fact a GPT disk (an MBR disk,
94 // a partition, etc.), in which case it will return EFI_LOAD_ERROR or some
95 // other error condition. In this case, *Data will be left alone.
96 // Note also that this function checks CRCs and does other sanity checks
97 // on the input data, but does NOT resort to using the backup data if the
98 // primary data structures are damaged.
99 EFI_STATUS
ReadGptData(REFIT_VOLUME
*Volume
, GPT_DATA
**Data
) {
100 EFI_STATUS Status
= EFI_SUCCESS
;
104 GPT_DATA
*GptData
; // Temporary holding storage; transferred to *Data later
106 if ((Volume
== NULL
) || (Data
== NULL
))
107 Status
= EFI_INVALID_PARAMETER
;
110 if ((Status
== EFI_SUCCESS
) && (Volume
->BlockIO
== NULL
)) {
111 Status
= refit_call3_wrapper(BS
->HandleProtocol
, Volume
->DeviceHandle
, &BlockIoProtocol
, (VOID
**) &(Volume
->BlockIO
));
112 if (EFI_ERROR(Status
)) {
113 Volume
->BlockIO
= NULL
;
114 Print(L
"Warning: Can't get BlockIO protocol.\n");
115 Status
= EFI_NOT_READY
;
119 if ((Status
== EFI_SUCCESS
) && ((!Volume
->BlockIO
->Media
->MediaPresent
) || (Volume
->BlockIO
->Media
->LogicalPartition
)))
120 Status
= EFI_NO_MEDIA
;
122 if (Status
== EFI_SUCCESS
) {
123 GptData
= AllocateGptData(); // Note: All but GptData->Entries
124 if (GptData
== NULL
) {
125 Status
= EFI_OUT_OF_RESOURCES
;
129 // Read the MBR and store it in GptData->ProtectiveMBR.
130 if (Status
== EFI_SUCCESS
) {
131 Status
= refit_call5_wrapper(Volume
->BlockIO
->ReadBlocks
, Volume
->BlockIO
, Volume
->BlockIO
->Media
->MediaId
,
132 0, 512, (VOID
*) GptData
->ProtectiveMBR
);
135 // Read the GPT header and store it in GptData->Header.
136 if (Status
== EFI_SUCCESS
) {
137 Status
= refit_call5_wrapper(Volume
->BlockIO
->ReadBlocks
, Volume
->BlockIO
, Volume
->BlockIO
->Media
->MediaId
,
138 1, sizeof(GPT_HEADER
), GptData
->Header
);
141 // If it looks like a valid protective MBR, try to do more with it....
142 if (Status
== EFI_SUCCESS
) {
143 if (GptHeaderValid(GptData
)) {
144 // Load actual GPT table....
145 BufferSize
= GptData
->Header
->entry_count
* 128;
146 if (GptData
->Entries
!= NULL
)
147 MyFreePool(GptData
->Entries
);
148 GptData
->Entries
= AllocatePool(BufferSize
);
149 if (GptData
->Entries
== NULL
) {
150 Status
= EFI_OUT_OF_RESOURCES
;
153 if (Status
== EFI_SUCCESS
) {
154 Status
= refit_call5_wrapper(Volume
->BlockIO
->ReadBlocks
, Volume
->BlockIO
, Volume
->BlockIO
->Media
->MediaId
,
155 GptData
->Header
->entry_lba
, BufferSize
, GptData
->Entries
);
158 // Check CRC status of table
159 if (Status
== EFI_SUCCESS
) {
160 TableCrc
= crc32(0x0, GptData
->Entries
, BufferSize
);
161 if (TableCrc
!= GptData
->Header
->entry_crc32
)
162 Status
= EFI_CRC_ERROR
;
165 // Now, ensure that every name is null-terminated....
166 if (Status
== EFI_SUCCESS
) {
167 for (i
= 0; i
< GptData
->Header
->entry_count
; i
++)
168 GptData
->Entries
[i
].name
[35] = '\0';
171 Status
= EFI_UNSUPPORTED
;
172 } // if/else valid header
173 } // if header read OK
175 if (Status
== EFI_SUCCESS
) {
176 // Everything looks OK, so copy it over
180 ClearGptData(GptData
);
184 } // EFI_STATUS ReadGptData()
186 // Look in gPartitions for a partition with the specified Guid. If found, return
187 // a pointer to that partition's name string. If not found, return a NULL pointer.
188 // The calling function is responsible for freeing the returned memory.
189 CHAR16
* PartNameFromGuid(EFI_GUID
*Guid
) {
191 CHAR16
*Found
= NULL
;
194 if ((Guid
== NULL
) || (gPartitions
== NULL
))
197 GptData
= gPartitions
;
198 while ((GptData
!= NULL
) && (!Found
)) {
200 while ((i
< GptData
->Header
->entry_count
) && (!Found
)) {
201 if (GuidsAreEqual((EFI_GUID
*) &(GptData
->Entries
[i
].partition_guid
), Guid
))
202 Found
= StrDuplicate(GptData
->Entries
[i
].name
);
205 } // while(scanning entries)
206 GptData
= GptData
->NextEntry
;
207 } // while(scanning GPTs)
209 } // CHAR16 * PartNameFromGuid()
211 // Erase the gPartitions linked-list data structure
212 VOID
ForgetPartitionTables(VOID
) {
215 while (gPartitions
!= NULL
) {
216 Next
= gPartitions
->NextEntry
;
217 ClearGptData(gPartitions
);
220 } // VOID ForgetPartitionTables()
222 // If Volume points to a whole disk with a GPT, add it to the gPartitions
223 // linked list of GPTs.
224 VOID
AddPartitionTable(REFIT_VOLUME
*Volume
) {
225 GPT_DATA
*GptData
= NULL
, *GptList
;
229 Status
= ReadGptData(Volume
, &GptData
);
230 if (Status
== EFI_SUCCESS
) {
231 if (gPartitions
== NULL
) {
232 gPartitions
= GptData
;
234 GptList
= gPartitions
;
235 while (GptList
->NextEntry
!= NULL
) {
236 GptList
= GptList
->NextEntry
;
239 GptList
->NextEntry
= GptData
;
242 } else if (GptData
!= NULL
) {
243 ClearGptData(GptData
);
246 Print(L
"In AddPartitionTable(), total number of tables is %d\n", NumTables
);
248 } // VOID AddPartitionTable()