]>
code.delx.au - refind/blob - refind/gpt.c
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.
17 #include "../include/refit_call_wrapper.h"
19 #ifdef __MAKEWITH_TIANO
20 #define BlockIoProtocol gEfiBlockIoProtocolGuid
23 extern GPT_DATA
*gPartitions
;
25 GPT_DATA
* AllocateGptData(VOID
) {
28 GptData
= AllocateZeroPool(sizeof(GPT_DATA
));
29 if (GptData
!= NULL
) {
30 GptData
->ProtectiveMBR
= AllocateZeroPool(sizeof(MBR_RECORD
));
31 GptData
->Header
= AllocateZeroPool(sizeof(GPT_HEADER
));
32 if ((GptData
->ProtectiveMBR
== NULL
) || (GptData
->Header
== NULL
)) {
33 MyFreePool(GptData
->ProtectiveMBR
);
34 MyFreePool(GptData
->Header
);
40 } // GPT_DATA * AllocateGptData()
42 VOID
ClearGptData(GPT_DATA
*Data
) {
44 if (Data
->ProtectiveMBR
)
45 MyFreePool(Data
->ProtectiveMBR
);
47 MyFreePool(Data
->Header
);
49 MyFreePool(Data
->Entries
);
52 } // VOID ClearGptData()
54 // TODO: Add more tests, like a CRC check.
55 // Returns TRUE if the GPT header data appear valid, FALSE otherwise.
56 static BOOLEAN
GptHeaderValid(GPT_HEADER
*Header
) {
57 BOOLEAN IsValid
= TRUE
;
59 if ((Header
->signature
!= 0x5452415020494645ULL
) || (Header
->entry_count
> 2048))
63 } // BOOLEAN GptHeaderValid
65 // Read GPT data from Volume and store it in Data. Note that this function
66 // may be called on a Volume that is not in fact the protective MBR of a GPT
67 // disk, in which case it will return EFI_LOAD_ERROR or some other error
68 // condition. In this case, *Data will be left alone.
69 EFI_STATUS
ReadGptData(REFIT_VOLUME
*Volume
, GPT_DATA
**Data
) {
70 EFI_STATUS Status
= EFI_SUCCESS
;
72 GPT_DATA
*GptData
; // Temporary holding storage; transferred to *Data later
74 if ((Volume
== NULL
) || (Data
== NULL
))
75 Status
= EFI_INVALID_PARAMETER
;
78 if ((Status
== EFI_SUCCESS
) && (Volume
->BlockIO
== NULL
)) {
79 Status
= refit_call3_wrapper(BS
->HandleProtocol
, Volume
->DeviceHandle
, &BlockIoProtocol
, (VOID
**) &(Volume
->BlockIO
));
80 if (EFI_ERROR(Status
)) {
81 Volume
->BlockIO
= NULL
;
82 Print(L
"Warning: Can't get BlockIO protocol.\n");
83 Status
= EFI_INVALID_PARAMETER
;
87 if ((Status
== EFI_SUCCESS
) && ((!Volume
->BlockIO
->Media
->MediaPresent
) || (Volume
->BlockIO
->Media
->LogicalPartition
)))
88 Status
= EFI_NO_MEDIA
;
90 if (Status
== EFI_SUCCESS
) {
91 GptData
= AllocateGptData();
92 if (GptData
== NULL
) {
93 Status
= EFI_OUT_OF_RESOURCES
;
97 // Read the MBR and store it in GptData->ProtectiveMBR.
98 if (Status
== EFI_SUCCESS
) {
99 Status
= refit_call5_wrapper(Volume
->BlockIO
->ReadBlocks
, Volume
->BlockIO
, Volume
->BlockIO
->Media
->MediaId
,
100 0, 512, (VOID
*) GptData
->ProtectiveMBR
);
103 // If it looks like a valid protective MBR, try to do more with it....
104 if ((Status
== EFI_SUCCESS
) && (GptData
->ProtectiveMBR
->MBRSignature
== 0xAA55) &&
105 ((GptData
->ProtectiveMBR
->partitions
[0].type
== 0xEE) || (GptData
->ProtectiveMBR
->partitions
[1].type
== 0xEE) ||
106 (GptData
->ProtectiveMBR
->partitions
[2].type
= 0xEE) || (GptData
->ProtectiveMBR
->partitions
[3].type
== 0xEE))) {
107 Status
= refit_call5_wrapper(Volume
->BlockIO
->ReadBlocks
, Volume
->BlockIO
, Volume
->BlockIO
->Media
->MediaId
,
108 1, sizeof(GPT_HEADER
), GptData
->Header
);
110 // Do basic sanity check on GPT header.
111 if ((Status
== EFI_SUCCESS
) && !GptHeaderValid(GptData
->Header
)) {
112 Status
= EFI_UNSUPPORTED
;
115 // Load actual GPT table....
116 if (Status
== EFI_SUCCESS
) {
117 BufferSize
= GptData
->Header
->entry_count
* 128;
118 if (GptData
->Entries
!= NULL
)
119 MyFreePool(GptData
->Entries
);
120 GptData
->Entries
= AllocatePool(BufferSize
);
121 if (GptData
->Entries
== NULL
) {
122 Status
= EFI_OUT_OF_RESOURCES
;
126 if (Status
== EFI_SUCCESS
) {
127 Status
= refit_call5_wrapper(Volume
->BlockIO
->ReadBlocks
, Volume
->BlockIO
, Volume
->BlockIO
->Media
->MediaId
,
128 GptData
->Header
->header_lba
, BufferSize
, GptData
->Entries
);
132 Status
= EFI_LOAD_ERROR
;
135 if (Status
== EFI_SUCCESS
) {
136 // Everything looks OK, so copy it over
140 ClearGptData(GptData
);
144 } // EFI_STATUS ReadGptData()
146 // Look in gPartitions for a partition with the specified Guid. If found, return
147 // a pointer to that partition's name string. If not found, return a NULL pointer.
148 // The calling function is responsible for freeing the returned memory.
149 CHAR16
* PartNameFromGuid(EFI_GUID
*Guid
) {
151 CHAR16
*Found
= NULL
;
154 if ((Guid
== NULL
) || (gPartitions
== NULL
))
157 GptData
= gPartitions
;
158 while ((GptData
!= NULL
) && (!Found
)) {
160 while ((i
< GptData
->Header
->entry_count
) && (!Found
)) {
161 if (GuidsAreEqual((EFI_GUID
*) &(GptData
->Entries
[i
].partition_guid
), Guid
))
162 Found
= StrDuplicate(GptData
->Entries
[i
].name
);
165 } // while(scanning entries)
166 GptData
= GptData
->NextEntry
;
167 } // while(scanning GPTs)
169 } // CHAR16 * PartNameFromGuid()
171 // Erase the gPartitions linked-list data structure
172 VOID
ForgetPartitionTables(VOID
) {
175 while (gPartitions
!= NULL
) {
176 Next
= gPartitions
->NextEntry
;
177 ClearGptData(gPartitions
);
180 } // VOID ForgetPartitionTables()
182 // If Volume points to a whole disk with a GPT, add it to the gPartitions
183 // linked list of GPTs.
184 VOID
AddPartitionTable(REFIT_VOLUME
*Volume
) {
185 GPT_DATA
*GptData
= NULL
, *GptList
;
188 Status
= ReadGptData(Volume
, &GptData
);
189 if (Status
== EFI_SUCCESS
) {
190 if (gPartitions
== NULL
) {
191 gPartitions
= GptData
;
193 GptList
= gPartitions
;
194 while (GptList
->NextEntry
!= NULL
) {
195 GptList
= GptList
->NextEntry
;
197 GptList
->NextEntry
= GptData
;
199 } else if (GptData
!= NULL
) {
200 ClearGptData(GptData
);
202 } // VOID AddPartitionTable()