]> code.delx.au - refind/blob - refind/gpt.c
New files required for reading and parsing GPT data.
[refind] / refind / gpt.c
1 /*
2 * refind/gpt.c
3 * Functions related to GPT data structures
4 *
5 * Copyright (c) 2014 Roderick W. Smith
6 * All rights reserved.
7 *
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.
11 *
12 */
13
14 #include "gpt.h"
15 #include "lib.h"
16 #include "screen.h"
17 #include "../include/refit_call_wrapper.h"
18
19 #ifdef __MAKEWITH_TIANO
20 #define BlockIoProtocol gEfiBlockIoProtocolGuid
21 #endif
22
23 extern GPT_DATA *gPartitions;
24
25 GPT_DATA * AllocateGptData(VOID) {
26 GPT_DATA *GptData;
27
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);
35 MyFreePool(GptData);
36 GptData = NULL;
37 } // if
38 } // if
39 return GptData;
40 } // GPT_DATA * AllocateGptData()
41
42 VOID ClearGptData(GPT_DATA *Data) {
43 if (Data) {
44 if (Data->ProtectiveMBR)
45 MyFreePool(Data->ProtectiveMBR);
46 if (Data->Header)
47 MyFreePool(Data->Header);
48 if (Data->Entries)
49 MyFreePool(Data->Entries);
50 MyFreePool(Data);
51 } // if
52 } // VOID ClearGptData()
53
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;
58
59 if ((Header->signature != 0x5452415020494645ULL) || (Header->entry_count > 2048))
60 IsValid = FALSE;
61
62 return IsValid;
63 } // BOOLEAN GptHeaderValid
64
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;
71 UINT64 BufferSize;
72 GPT_DATA *GptData; // Temporary holding storage; transferred to *Data later
73
74 if ((Volume == NULL) || (Data == NULL))
75 Status = EFI_INVALID_PARAMETER;
76
77 // get block i/o
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;
84 }
85 } // if
86
87 if ((Status == EFI_SUCCESS) && ((!Volume->BlockIO->Media->MediaPresent) || (Volume->BlockIO->Media->LogicalPartition)))
88 Status = EFI_NO_MEDIA;
89
90 if (Status == EFI_SUCCESS) {
91 GptData = AllocateGptData();
92 if (GptData == NULL) {
93 Status = EFI_OUT_OF_RESOURCES;
94 } // if
95 } // if
96
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);
101 }
102
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);
109
110 // Do basic sanity check on GPT header.
111 if ((Status == EFI_SUCCESS) && !GptHeaderValid(GptData->Header)) {
112 Status = EFI_UNSUPPORTED;
113 }
114
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;
123 } // if
124 } // if
125
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);
129 } // if
130
131 } else {
132 Status = EFI_LOAD_ERROR;
133 } // if/else
134
135 if (Status == EFI_SUCCESS) {
136 // Everything looks OK, so copy it over
137 ClearGptData(*Data);
138 *Data = GptData;
139 } else {
140 ClearGptData(GptData);
141 } // if/else
142
143 return Status;
144 } // EFI_STATUS ReadGptData()
145
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) {
150 UINTN i;
151 CHAR16 *Found = NULL;
152 GPT_DATA *GptData;
153
154 if ((Guid == NULL) || (gPartitions == NULL))
155 return NULL;
156
157 GptData = gPartitions;
158 while ((GptData != NULL) && (!Found)) {
159 i = 0;
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);
163 else
164 i++;
165 } // while(scanning entries)
166 GptData = GptData->NextEntry;
167 } // while(scanning GPTs)
168 return Found;
169 } // CHAR16 * PartNameFromGuid()
170
171 // Erase the gPartitions linked-list data structure
172 VOID ForgetPartitionTables(VOID) {
173 GPT_DATA *Next;
174
175 while (gPartitions != NULL) {
176 Next = gPartitions->NextEntry;
177 ClearGptData(gPartitions);
178 gPartitions = Next;
179 } // while
180 } // VOID ForgetPartitionTables()
181
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;
186 EFI_STATUS Status;
187
188 Status = ReadGptData(Volume, &GptData);
189 if (Status == EFI_SUCCESS) {
190 if (gPartitions == NULL) {
191 gPartitions = GptData;
192 } else {
193 GptList = gPartitions;
194 while (GptList->NextEntry != NULL) {
195 GptList = GptList->NextEntry;
196 } // while
197 GptList->NextEntry = GptData;
198 } // if/else
199 } else if (GptData != NULL) {
200 ClearGptData(GptData);
201 } // if/else
202 } // VOID AddPartitionTable()
203