]>
code.delx.au - refind/blob - refind/gpt.c
3 * Functions related to GPT data structures
5 * Copyright (c) 2014-2015 Roderick W. Smith
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "../include/refit_call_wrapper.h"
28 #ifdef __MAKEWITH_TIANO
29 #define BlockIoProtocol gEfiBlockIoProtocolGuid
32 extern GPT_DATA
*gPartitions
;
34 // Allocate data for the main GPT_DATA structure, as well as the ProtectiveMBR
35 // and Header structures it contains. This function does *NOT*, however,
36 // allocate memory for the Entries data structure, since its size is variable
37 // and is determined by the contents of Header.
38 GPT_DATA
* AllocateGptData(VOID
) {
41 GptData
= AllocateZeroPool(sizeof(GPT_DATA
));
42 if (GptData
!= NULL
) {
43 GptData
->ProtectiveMBR
= AllocateZeroPool(sizeof(MBR_RECORD
));
44 GptData
->Header
= AllocateZeroPool(sizeof(GPT_HEADER
));
45 if ((GptData
->ProtectiveMBR
== NULL
) || (GptData
->Header
== NULL
)) {
46 MyFreePool(GptData
->ProtectiveMBR
);
47 MyFreePool(GptData
->Header
);
53 } // GPT_DATA * AllocateGptData()
55 // Unallocate a single GPT_DATA structure. This does NOT follow the
56 // linked list, though.
57 VOID
ClearGptData(GPT_DATA
*Data
) {
59 if (Data
->ProtectiveMBR
)
60 MyFreePool(Data
->ProtectiveMBR
);
62 MyFreePool(Data
->Header
);
64 MyFreePool(Data
->Entries
);
67 } // VOID ClearGptData()
69 // TODO: Make this work on big-endian systems; at the moment, it contains
70 // little-endian assumptions!
71 // Returns TRUE if the GPT protective MBR and header data appear valid,
73 static BOOLEAN
GptHeaderValid(GPT_DATA
*GptData
) {
75 UINT32 CrcValue
, StoredCrcValue
;
76 UINTN HeaderSize
= sizeof(GPT_HEADER
);
78 if ((GptData
== NULL
) || (GptData
->ProtectiveMBR
== NULL
) || (GptData
->Header
== NULL
))
81 IsValid
= (GptData
->ProtectiveMBR
->MBRSignature
== 0xAA55);
82 IsValid
= IsValid
&& ((GptData
->ProtectiveMBR
->partitions
[0].type
== 0xEE) ||
83 (GptData
->ProtectiveMBR
->partitions
[1].type
== 0xEE) ||
84 (GptData
->ProtectiveMBR
->partitions
[2].type
== 0xEE) ||
85 (GptData
->ProtectiveMBR
->partitions
[3].type
== 0xEE));
87 IsValid
= IsValid
&& ((GptData
->Header
->signature
== 0x5452415020494645ULL
) &&
88 (GptData
->Header
->spec_revision
== 0x00010000) &&
89 (GptData
->Header
->entry_size
== 128));
91 // Looks good so far; check CRC value....
93 if (GptData
->Header
->header_size
< HeaderSize
)
94 HeaderSize
= GptData
->Header
->header_size
;
95 StoredCrcValue
= GptData
->Header
->header_crc32
;
96 GptData
->Header
->header_crc32
= 0;
97 CrcValue
= crc32(0x0, GptData
->Header
, HeaderSize
);
98 if (CrcValue
!= StoredCrcValue
)
100 GptData
->Header
->header_crc32
= StoredCrcValue
;
104 } // BOOLEAN GptHeaderValid()
106 // Read GPT data from Volume and store it in *Data. Note that this function
107 // may be called on a Volume that is not in fact a GPT disk (an MBR disk,
108 // a partition, etc.), in which case it will return EFI_LOAD_ERROR or some
109 // other error condition. In this case, *Data will be left alone.
110 // Note also that this function checks CRCs and does other sanity checks
111 // on the input data, but does NOT resort to using the backup data if the
112 // primary data structures are damaged. The intent is that the function
113 // be very conservative about reading GPT data. Currently (version 0.7.10),
114 // rEFInd uses the data only to provide access to partition names. This is
115 // non-critical data, so it's OK to return nothing, but having the program
116 // hang on reading garbage or return nonsense could be very bad.
117 EFI_STATUS
ReadGptData(REFIT_VOLUME
*Volume
, GPT_DATA
**Data
) {
118 EFI_STATUS Status
= EFI_SUCCESS
;
121 GPT_DATA
*GptData
= NULL
; // Temporary holding storage; transferred to *Data later
123 if ((Volume
== NULL
) || (Data
== NULL
))
124 return EFI_INVALID_PARAMETER
;
127 if ((Status
== EFI_SUCCESS
) && (Volume
->BlockIO
== NULL
)) {
128 Status
= refit_call3_wrapper(BS
->HandleProtocol
, Volume
->DeviceHandle
, &BlockIoProtocol
, (VOID
**) &(Volume
->BlockIO
));
129 if (EFI_ERROR(Status
)) {
130 Volume
->BlockIO
= NULL
;
131 Print(L
"Warning: Can't get BlockIO protocol in ReadGptData().\n");
132 Status
= EFI_NOT_READY
;
136 if ((Status
== EFI_SUCCESS
) && ((!Volume
->BlockIO
->Media
->MediaPresent
) || (Volume
->BlockIO
->Media
->LogicalPartition
)))
137 Status
= EFI_NO_MEDIA
;
139 if (Status
== EFI_SUCCESS
) {
140 GptData
= AllocateGptData(); // Note: All but GptData->Entries
141 if (GptData
== NULL
) {
142 Status
= EFI_OUT_OF_RESOURCES
;
146 // Read the MBR and store it in GptData->ProtectiveMBR.
147 if (Status
== EFI_SUCCESS
) {
148 Status
= refit_call5_wrapper(Volume
->BlockIO
->ReadBlocks
, Volume
->BlockIO
, Volume
->BlockIO
->Media
->MediaId
,
149 0, sizeof(MBR_RECORD
), (VOID
*) GptData
->ProtectiveMBR
);
152 // Read the GPT header and store it in GptData->Header.
153 if (Status
== EFI_SUCCESS
) {
154 Status
= refit_call5_wrapper(Volume
->BlockIO
->ReadBlocks
, Volume
->BlockIO
, Volume
->BlockIO
->Media
->MediaId
,
155 1, sizeof(GPT_HEADER
), GptData
->Header
);
158 // If it looks like a valid protective MBR & GPT header, try to do more with it....
159 if (Status
== EFI_SUCCESS
) {
160 if (GptHeaderValid(GptData
)) {
161 // Load actual GPT table....
162 BufferSize
= GptData
->Header
->entry_count
* 128;
163 GptData
->Entries
= AllocatePool(BufferSize
);
164 if (GptData
->Entries
== NULL
)
165 Status
= EFI_OUT_OF_RESOURCES
;
167 if (Status
== EFI_SUCCESS
)
168 Status
= refit_call5_wrapper(Volume
->BlockIO
->ReadBlocks
, Volume
->BlockIO
, Volume
->BlockIO
->Media
->MediaId
,
169 GptData
->Header
->entry_lba
, BufferSize
, GptData
->Entries
);
171 // Check CRC status of table
172 if ((Status
== EFI_SUCCESS
) && (crc32(0x0, GptData
->Entries
, BufferSize
) != GptData
->Header
->entry_crc32
))
173 Status
= EFI_CRC_ERROR
;
175 // Now, ensure that every name is null-terminated....
176 if (Status
== EFI_SUCCESS
) {
177 for (i
= 0; i
< GptData
->Header
->entry_count
; i
++)
178 GptData
->Entries
[i
].name
[35] = '\0';
181 Status
= EFI_UNSUPPORTED
;
182 } // if/else valid header
183 } // if header read OK
185 if (Status
== EFI_SUCCESS
) {
186 // Everything looks OK, so copy it over
190 ClearGptData(GptData
);
194 } // EFI_STATUS ReadGptData()
196 // Look in gPartitions for a partition with the specified Guid. If found, return
197 // a pointer to that partition's data. If not found, return a NULL pointer.
198 // The calling function is responsible for freeing the returned memory.
199 GPT_ENTRY
* FindPartWithGuid(EFI_GUID
*Guid
) {
201 GPT_ENTRY
*Found
= NULL
;
204 if ((Guid
== NULL
) || (gPartitions
== NULL
))
207 GptData
= gPartitions
;
208 while ((GptData
!= NULL
) && (!Found
)) {
210 while ((i
< GptData
->Header
->entry_count
) && (!Found
)) {
211 if (GuidsAreEqual((EFI_GUID
*) &(GptData
->Entries
[i
].partition_guid
), Guid
)) {
212 Found
= AllocateZeroPool(sizeof(GPT_ENTRY
));
213 CopyMem(Found
, &GptData
->Entries
[i
], sizeof(GPT_ENTRY
));
217 } // while(scanning entries)
218 GptData
= GptData
->NextEntry
;
219 } // while(scanning GPTs)
221 } // GPT_ENTRY * FindPartWithGuid()
223 // Erase the gPartitions linked-list data structure
224 VOID
ForgetPartitionTables(VOID
) {
227 while (gPartitions
!= NULL
) {
228 Next
= gPartitions
->NextEntry
;
229 ClearGptData(gPartitions
);
232 } // VOID ForgetPartitionTables()
234 // If Volume points to a whole disk with a GPT, add it to the gPartitions
235 // linked list of GPTs.
236 VOID
AddPartitionTable(REFIT_VOLUME
*Volume
) {
237 GPT_DATA
*GptData
= NULL
, *GptList
;
241 Status
= ReadGptData(Volume
, &GptData
);
242 if (Status
== EFI_SUCCESS
) {
243 if (gPartitions
== NULL
) {
244 gPartitions
= GptData
;
246 GptList
= gPartitions
;
247 while (GptList
->NextEntry
!= NULL
) {
248 GptList
= GptList
->NextEntry
;
251 GptList
->NextEntry
= GptData
;
254 } else if (GptData
!= NULL
) {
255 ClearGptData(GptData
);
258 } // VOID AddPartitionTable()