]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
IntelSiliconPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Gpt.c
CommitLineData
adbcbf8f 1/** @file\r
8a7d75b0 2 Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0\r
adbcbf8f 3 specification.\r
4\r
dc204d5a
JY
5 Caution: This file requires additional review when modified.\r
6 This driver will have external input - disk partition.\r
7 This external input must be validated carefully to avoid security issue like\r
8 buffer overflow, integer overflow.\r
9\r
10 PartitionInstallGptChildHandles() routine will read disk partition content and\r
11 do basic validation before PartitionInstallChildHandle().\r
12\r
13 PartitionValidGptTable(), PartitionCheckGptEntry() routine will accept disk\r
14 partition content and validate the GPT table and GPT entry.\r
15\r
709c9fd5 16Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.\r
fccdb880 17Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 18This program and the accompanying materials\r
f42be642 19are licensed and made available under the terms and conditions of the BSD License\r
20which accompanies this distribution. The full text of the license may be found at\r
21http://opensource.org/licenses/bsd-license.php\r
22\r
23THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
24WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
adbcbf8f 25\r
26**/\r
27\r
28\r
29#include "Partition.h"\r
30\r
a8d0c20e 31/**\r
32 Install child handles if the Handle supports GPT partition structure.\r
33\r
dc204d5a
JY
34 Caution: This function may receive untrusted input.\r
35 The GPT partition table header is external input, so this routine\r
36 will do basic validation for GPT partition table header before return.\r
37\r
490b5ea1 38 @param[in] BlockIo Parent BlockIo interface.\r
a8d0c20e 39 @param[in] DiskIo Disk Io protocol.\r
40 @param[in] Lba The starting Lba of the Partition Table\r
41 @param[out] PartHeader Stores the partition table that is read\r
42\r
43 @retval TRUE The partition table is valid\r
44 @retval FALSE The partition table is not valid\r
45\r
46**/\r
adbcbf8f 47BOOLEAN\r
48PartitionValidGptTable (\r
49 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
50 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
51 IN EFI_LBA Lba,\r
52 OUT EFI_PARTITION_TABLE_HEADER *PartHeader\r
53 );\r
54\r
a8d0c20e 55/**\r
56 Check if the CRC field in the Partition table header is valid\r
57 for Partition entry array.\r
58\r
59 @param[in] BlockIo Parent BlockIo interface\r
60 @param[in] DiskIo Disk Io Protocol.\r
61 @param[in] PartHeader Partition table header structure\r
62\r
63 @retval TRUE the CRC is valid\r
64 @retval FALSE the CRC is invalid\r
65\r
66**/\r
adbcbf8f 67BOOLEAN\r
68PartitionCheckGptEntryArrayCRC (\r
69 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
70 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
71 IN EFI_PARTITION_TABLE_HEADER *PartHeader\r
72 );\r
73\r
74\r
a8d0c20e 75/**\r
76 Restore Partition Table to its alternate place\r
490b5ea1 77 (Primary -> Backup or Backup -> Primary).\r
a8d0c20e 78\r
490b5ea1 79 @param[in] BlockIo Parent BlockIo interface.\r
a8d0c20e 80 @param[in] DiskIo Disk Io Protocol.\r
490b5ea1 81 @param[in] PartHeader Partition table header structure.\r
a8d0c20e 82\r
83 @retval TRUE Restoring succeeds\r
84 @retval FALSE Restoring failed\r
85\r
86**/\r
adbcbf8f 87BOOLEAN\r
88PartitionRestoreGptTable (\r
89 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
90 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
91 IN EFI_PARTITION_TABLE_HEADER *PartHeader\r
92 );\r
93\r
94\r
a8d0c20e 95/**\r
dc204d5a
JY
96 This routine will check GPT partition entry and return entry status.\r
97\r
98 Caution: This function may receive untrusted input.\r
99 The GPT partition entry is external input, so this routine\r
100 will do basic validation for GPT partition entry and report status.\r
a8d0c20e 101\r
102 @param[in] PartHeader Partition table header structure\r
103 @param[in] PartEntry The partition entry array\r
d1102dba 104 @param[out] PEntryStatus the partition entry status array\r
a8d0c20e 105 recording the status of each partition\r
106\r
107**/\r
adbcbf8f 108VOID\r
109PartitionCheckGptEntry (\r
110 IN EFI_PARTITION_TABLE_HEADER *PartHeader,\r
111 IN EFI_PARTITION_ENTRY *PartEntry,\r
112 OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus\r
113 );\r
114\r
115\r
a8d0c20e 116/**\r
ea7cb08c 117 Checks the CRC32 value in the table header.\r
a8d0c20e 118\r
119 @param MaxSize Max Size limit\r
120 @param Size The size of the table\r
121 @param Hdr Table to check\r
122\r
123 @return TRUE CRC Valid\r
124 @return FALSE CRC Invalid\r
125\r
126**/\r
adbcbf8f 127BOOLEAN\r
128PartitionCheckCrcAltSize (\r
129 IN UINTN MaxSize,\r
130 IN UINTN Size,\r
131 IN OUT EFI_TABLE_HEADER *Hdr\r
132 );\r
133\r
134\r
a8d0c20e 135/**\r
ea7cb08c 136 Checks the CRC32 value in the table header.\r
a8d0c20e 137\r
138 @param MaxSize Max Size limit\r
139 @param Hdr Table to check\r
140\r
141 @return TRUE CRC Valid\r
142 @return FALSE CRC Invalid\r
143\r
144**/\r
adbcbf8f 145BOOLEAN\r
146PartitionCheckCrc (\r
147 IN UINTN MaxSize,\r
148 IN OUT EFI_TABLE_HEADER *Hdr\r
149 );\r
150\r
151\r
a8d0c20e 152/**\r
ea7cb08c 153 Updates the CRC32 value in the table header.\r
a8d0c20e 154\r
155 @param Size The size of the table\r
156 @param Hdr Table to update\r
157\r
158**/\r
adbcbf8f 159VOID\r
160PartitionSetCrcAltSize (\r
161 IN UINTN Size,\r
162 IN OUT EFI_TABLE_HEADER *Hdr\r
163 );\r
164\r
165\r
a8d0c20e 166/**\r
ea7cb08c 167 Updates the CRC32 value in the table header.\r
a8d0c20e 168\r
169 @param Hdr Table to update\r
170\r
171**/\r
adbcbf8f 172VOID\r
173PartitionSetCrc (\r
174 IN OUT EFI_TABLE_HEADER *Hdr\r
175 );\r
176\r
177/**\r
178 Install child handles if the Handle supports GPT partition structure.\r
179\r
dc204d5a
JY
180 Caution: This function may receive untrusted input.\r
181 The GPT partition table is external input, so this routine\r
182 will do basic validation for GPT partition table before install\r
183 child handle for each GPT partition.\r
184\r
490b5ea1 185 @param[in] This Calling context.\r
186 @param[in] Handle Parent Handle.\r
187 @param[in] DiskIo Parent DiskIo interface.\r
493d8e3a 188 @param[in] DiskIo2 Parent DiskIo2 interface.\r
490b5ea1 189 @param[in] BlockIo Parent BlockIo interface.\r
190 @param[in] BlockIo2 Parent BlockIo2 interface.\r
191 @param[in] DevicePath Parent Device Path.\r
adbcbf8f 192\r
490b5ea1 193 @retval EFI_SUCCESS Valid GPT disk.\r
194 @retval EFI_MEDIA_CHANGED Media changed Detected.\r
195 @retval other Not a valid GPT disk.\r
adbcbf8f 196\r
197**/\r
198EFI_STATUS\r
199PartitionInstallGptChildHandles (\r
200 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
201 IN EFI_HANDLE Handle,\r
202 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
493d8e3a 203 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,\r
adbcbf8f 204 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
490b5ea1 205 IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,\r
adbcbf8f 206 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
207 )\r
208{\r
3a3d62d2
HW
209 EFI_STATUS Status;\r
210 UINT32 BlockSize;\r
211 EFI_LBA LastBlock;\r
212 MASTER_BOOT_RECORD *ProtectiveMbr;\r
213 EFI_PARTITION_TABLE_HEADER *PrimaryHeader;\r
214 EFI_PARTITION_TABLE_HEADER *BackupHeader;\r
215 EFI_PARTITION_ENTRY *PartEntry;\r
216 EFI_PARTITION_ENTRY *Entry;\r
217 EFI_PARTITION_ENTRY_STATUS *PEntryStatus;\r
218 UINTN Index;\r
219 EFI_STATUS GptValidStatus;\r
220 HARDDRIVE_DEVICE_PATH HdDev;\r
221 UINT32 MediaId;\r
222 EFI_PARTITION_INFO_PROTOCOL PartitionInfo;\r
adbcbf8f 223\r
224 ProtectiveMbr = NULL;\r
225 PrimaryHeader = NULL;\r
226 BackupHeader = NULL;\r
227 PartEntry = NULL;\r
228 PEntryStatus = NULL;\r
229\r
230 BlockSize = BlockIo->Media->BlockSize;\r
231 LastBlock = BlockIo->Media->LastBlock;\r
490b5ea1 232 MediaId = BlockIo->Media->MediaId;\r
adbcbf8f 233\r
234 DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize));\r
7df7393f 235 DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock));\r
adbcbf8f 236\r
ff61847d 237 GptValidStatus = EFI_NOT_FOUND;\r
adbcbf8f 238\r
fccdb880
HW
239 //\r
240 // Ensure the block size can hold the MBR\r
241 //\r
242 if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {\r
243 return EFI_NOT_FOUND;\r
244 }\r
245\r
adbcbf8f 246 //\r
247 // Allocate a buffer for the Protective MBR\r
248 //\r
249 ProtectiveMbr = AllocatePool (BlockSize);\r
250 if (ProtectiveMbr == NULL) {\r
251 return EFI_NOT_FOUND;\r
252 }\r
253\r
254 //\r
255 // Read the Protective MBR from LBA #0\r
256 //\r
96f99e1d 257 Status = DiskIo->ReadDisk (\r
258 DiskIo,\r
490b5ea1 259 MediaId,\r
96f99e1d 260 0,\r
490b5ea1 261 BlockSize,\r
96f99e1d 262 ProtectiveMbr\r
263 );\r
adbcbf8f 264 if (EFI_ERROR (Status)) {\r
ff61847d 265 GptValidStatus = Status;\r
adbcbf8f 266 goto Done;\r
267 }\r
490b5ea1 268\r
adbcbf8f 269 //\r
270 // Verify that the Protective MBR is valid\r
271 //\r
339c754a 272 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {\r
273 if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&\r
274 ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION &&\r
275 UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1\r
276 ) {\r
277 break;\r
278 }\r
279 }\r
280 if (Index == MAX_MBR_PARTITIONS) {\r
adbcbf8f 281 goto Done;\r
282 }\r
283\r
284 //\r
285 // Allocate the GPT structures\r
286 //\r
287 PrimaryHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));\r
288 if (PrimaryHeader == NULL) {\r
289 goto Done;\r
290 }\r
291\r
292 BackupHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));\r
adbcbf8f 293 if (BackupHeader == NULL) {\r
294 goto Done;\r
295 }\r
296\r
297 //\r
298 // Check primary and backup partition tables\r
299 //\r
300 if (!PartitionValidGptTable (BlockIo, DiskIo, PRIMARY_PART_HEADER_LBA, PrimaryHeader)) {\r
301 DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));\r
302\r
303 if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) {\r
304 DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));\r
305 goto Done;\r
306 } else {\r
307 DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));\r
308 DEBUG ((EFI_D_INFO, " Restore primary partition table by the backup\n"));\r
309 if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) {\r
310 DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));\r
311 }\r
312\r
313 if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) {\r
314 DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));\r
315 }\r
316 }\r
317 } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {\r
318 DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n"));\r
319 DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n"));\r
320 if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {\r
b4e027f1 321 DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));\r
adbcbf8f 322 }\r
323\r
324 if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {\r
325 DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));\r
326 }\r
327\r
328 }\r
329\r
330 DEBUG ((EFI_D_INFO, " Valid primary and Valid backup partition table\n"));\r
331\r
332 //\r
333 // Read the EFI Partition Entries\r
334 //\r
d0e9c3ca 335 PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);\r
adbcbf8f 336 if (PartEntry == NULL) {\r
337 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
338 goto Done;\r
339 }\r
340\r
341 Status = DiskIo->ReadDisk (\r
7059dad9 342 DiskIo,\r
490b5ea1 343 MediaId,\r
7059dad9 344 MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize),\r
345 PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),\r
346 PartEntry\r
347 );\r
adbcbf8f 348 if (EFI_ERROR (Status)) {\r
ff61847d 349 GptValidStatus = Status;\r
96f99e1d 350 DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));\r
adbcbf8f 351 goto Done;\r
352 }\r
353\r
354 DEBUG ((EFI_D_INFO, " Partition entries read block success\n"));\r
355\r
356 DEBUG ((EFI_D_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));\r
357\r
358 PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));\r
359 if (PEntryStatus == NULL) {\r
360 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
361 goto Done;\r
362 }\r
363\r
364 //\r
365 // Check the integrity of partition entries\r
366 //\r
367 PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);\r
368\r
369 //\r
370 // If we got this far the GPT layout of the disk is valid and we should return true\r
371 //\r
ff61847d 372 GptValidStatus = EFI_SUCCESS;\r
adbcbf8f 373\r
374 //\r
375 // Create child device handles\r
376 //\r
377 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
d0e9c3ca
RN
378 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);\r
379 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||\r
adbcbf8f 380 PEntryStatus[Index].OutOfRange ||\r
47e1a80b 381 PEntryStatus[Index].Overlap ||\r
382 PEntryStatus[Index].OsSpecific\r
adbcbf8f 383 ) {\r
384 //\r
47e1a80b 385 // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific\r
386 // partition Entries\r
adbcbf8f 387 //\r
388 continue;\r
389 }\r
390\r
391 ZeroMem (&HdDev, sizeof (HdDev));\r
3a3d62d2
HW
392 HdDev.Header.Type = MEDIA_DEVICE_PATH;\r
393 HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;\r
adbcbf8f 394 SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));\r
395\r
3a3d62d2
HW
396 HdDev.PartitionNumber = (UINT32) Index + 1;\r
397 HdDev.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;\r
398 HdDev.SignatureType = SIGNATURE_TYPE_GUID;\r
399 HdDev.PartitionStart = Entry->StartingLBA;\r
400 HdDev.PartitionSize = Entry->EndingLBA - Entry->StartingLBA + 1;\r
d0e9c3ca 401 CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));\r
adbcbf8f 402\r
3a3d62d2
HW
403 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));\r
404 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;\r
405 PartitionInfo.Type = PARTITION_TYPE_GPT;\r
406 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)) {\r
407 PartitionInfo.System = 1;\r
408 }\r
409 CopyMem (&PartitionInfo.Info.Gpt, Entry, sizeof (EFI_PARTITION_ENTRY));\r
410\r
ff61847d 411 DEBUG ((EFI_D_INFO, " Index : %d\n", (UINT32) Index));\r
412 DEBUG ((EFI_D_INFO, " Start LBA : %lx\n", (UINT64) HdDev.PartitionStart));\r
d0e9c3ca 413 DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA));\r
ff61847d 414 DEBUG ((EFI_D_INFO, " Partition size: %lx\n", (UINT64) HdDev.PartitionSize));\r
d0e9c3ca
RN
415 DEBUG ((EFI_D_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));\r
416 DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));\r
adbcbf8f 417\r
418 Status = PartitionInstallChildHandle (\r
490b5ea1 419 This,\r
420 Handle,\r
421 DiskIo,\r
493d8e3a 422 DiskIo2,\r
490b5ea1 423 BlockIo,\r
424 BlockIo2,\r
425 DevicePath,\r
426 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,\r
3a3d62d2 427 &PartitionInfo,\r
d0e9c3ca
RN
428 Entry->StartingLBA,\r
429 Entry->EndingLBA,\r
709c9fd5
JB
430 BlockSize,\r
431 &Entry->PartitionTypeGUID\r
490b5ea1 432 );\r
adbcbf8f 433 }\r
434\r
435 DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n"));\r
436\r
437Done:\r
438 if (ProtectiveMbr != NULL) {\r
439 FreePool (ProtectiveMbr);\r
440 }\r
441 if (PrimaryHeader != NULL) {\r
442 FreePool (PrimaryHeader);\r
443 }\r
444 if (BackupHeader != NULL) {\r
445 FreePool (BackupHeader);\r
446 }\r
447 if (PartEntry != NULL) {\r
448 FreePool (PartEntry);\r
449 }\r
450 if (PEntryStatus != NULL) {\r
451 FreePool (PEntryStatus);\r
452 }\r
453\r
ff61847d 454 return GptValidStatus;\r
adbcbf8f 455}\r
456\r
adbcbf8f 457/**\r
dc204d5a
JY
458 This routine will read GPT partition table header and return it.\r
459\r
460 Caution: This function may receive untrusted input.\r
461 The GPT partition table header is external input, so this routine\r
462 will do basic validation for GPT partition table header before return.\r
adbcbf8f 463\r
490b5ea1 464 @param[in] BlockIo Parent BlockIo interface.\r
adbcbf8f 465 @param[in] DiskIo Disk Io protocol.\r
466 @param[in] Lba The starting Lba of the Partition Table\r
a8d0c20e 467 @param[out] PartHeader Stores the partition table that is read\r
adbcbf8f 468\r
469 @retval TRUE The partition table is valid\r
470 @retval FALSE The partition table is not valid\r
471\r
472**/\r
473BOOLEAN\r
474PartitionValidGptTable (\r
475 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
476 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
477 IN EFI_LBA Lba,\r
478 OUT EFI_PARTITION_TABLE_HEADER *PartHeader\r
479 )\r
480{\r
481 EFI_STATUS Status;\r
482 UINT32 BlockSize;\r
483 EFI_PARTITION_TABLE_HEADER *PartHdr;\r
490b5ea1 484 UINT32 MediaId;\r
adbcbf8f 485\r
486 BlockSize = BlockIo->Media->BlockSize;\r
490b5ea1 487 MediaId = BlockIo->Media->MediaId;\r
adbcbf8f 488 PartHdr = AllocateZeroPool (BlockSize);\r
489\r
490 if (PartHdr == NULL) {\r
491 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
492 return FALSE;\r
493 }\r
494 //\r
495 // Read the EFI Partition Table Header\r
496 //\r
96f99e1d 497 Status = DiskIo->ReadDisk (\r
498 DiskIo,\r
490b5ea1 499 MediaId,\r
7059dad9 500 MultU64x32 (Lba, BlockSize),\r
96f99e1d 501 BlockSize,\r
502 PartHdr\r
503 );\r
adbcbf8f 504 if (EFI_ERROR (Status)) {\r
505 FreePool (PartHdr);\r
506 return FALSE;\r
507 }\r
508\r
cd2d8468 509 if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||\r
adbcbf8f 510 !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||\r
b4e027f1
SZ
511 PartHdr->MyLBA != Lba ||\r
512 (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))\r
adbcbf8f 513 ) {\r
ff61847d 514 DEBUG ((EFI_D_INFO, "Invalid efi partition table header\n"));\r
adbcbf8f 515 FreePool (PartHdr);\r
516 return FALSE;\r
517 }\r
518\r
b4e027f1
SZ
519 //\r
520 // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.\r
521 //\r
522 if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {\r
523 FreePool (PartHdr);\r
524 return FALSE;\r
525 }\r
526\r
adbcbf8f 527 CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));\r
528 if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {\r
529 FreePool (PartHdr);\r
530 return FALSE;\r
531 }\r
532\r
533 DEBUG ((EFI_D_INFO, " Valid efi partition table header\n"));\r
534 FreePool (PartHdr);\r
535 return TRUE;\r
536}\r
537\r
adbcbf8f 538/**\r
539 Check if the CRC field in the Partition table header is valid\r
540 for Partition entry array.\r
541\r
542 @param[in] BlockIo Parent BlockIo interface\r
543 @param[in] DiskIo Disk Io Protocol.\r
544 @param[in] PartHeader Partition table header structure\r
545\r
546 @retval TRUE the CRC is valid\r
547 @retval FALSE the CRC is invalid\r
548\r
549**/\r
550BOOLEAN\r
551PartitionCheckGptEntryArrayCRC (\r
552 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
553 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
554 IN EFI_PARTITION_TABLE_HEADER *PartHeader\r
555 )\r
556{\r
557 EFI_STATUS Status;\r
558 UINT8 *Ptr;\r
559 UINT32 Crc;\r
560 UINTN Size;\r
561\r
562 //\r
563 // Read the EFI Partition Entries\r
564 //\r
565 Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);\r
566 if (Ptr == NULL) {\r
567 DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));\r
568 return FALSE;\r
569 }\r
570\r
571 Status = DiskIo->ReadDisk (\r
572 DiskIo,\r
573 BlockIo->Media->MediaId,\r
574 MultU64x32(PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),\r
575 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,\r
576 Ptr\r
577 );\r
578 if (EFI_ERROR (Status)) {\r
579 FreePool (Ptr);\r
580 return FALSE;\r
581 }\r
582\r
583 Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;\r
584\r
585 Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);\r
586 if (EFI_ERROR (Status)) {\r
587 DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));\r
588 FreePool (Ptr);\r
589 return FALSE;\r
590 }\r
591\r
592 FreePool (Ptr);\r
593\r
594 return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc);\r
595}\r
596\r
597\r
598/**\r
599 Restore Partition Table to its alternate place\r
490b5ea1 600 (Primary -> Backup or Backup -> Primary).\r
adbcbf8f 601\r
490b5ea1 602 @param[in] BlockIo Parent BlockIo interface.\r
adbcbf8f 603 @param[in] DiskIo Disk Io Protocol.\r
490b5ea1 604 @param[in] PartHeader Partition table header structure.\r
adbcbf8f 605\r
606 @retval TRUE Restoring succeeds\r
607 @retval FALSE Restoring failed\r
608\r
609**/\r
610BOOLEAN\r
611PartitionRestoreGptTable (\r
612 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
613 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
614 IN EFI_PARTITION_TABLE_HEADER *PartHeader\r
615 )\r
616{\r
617 EFI_STATUS Status;\r
618 UINTN BlockSize;\r
619 EFI_PARTITION_TABLE_HEADER *PartHdr;\r
620 EFI_LBA PEntryLBA;\r
621 UINT8 *Ptr;\r
490b5ea1 622 UINT32 MediaId;\r
adbcbf8f 623\r
624 PartHdr = NULL;\r
625 Ptr = NULL;\r
626\r
627 BlockSize = BlockIo->Media->BlockSize;\r
490b5ea1 628 MediaId = BlockIo->Media->MediaId;\r
adbcbf8f 629\r
630 PartHdr = AllocateZeroPool (BlockSize);\r
631\r
632 if (PartHdr == NULL) {\r
633 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
634 return FALSE;\r
635 }\r
636\r
637 PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \\r
638 (PartHeader->LastUsableLBA + 1) : \\r
639 (PRIMARY_PART_HEADER_LBA + 1);\r
640\r
641 CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));\r
642\r
643 PartHdr->MyLBA = PartHeader->AlternateLBA;\r
644 PartHdr->AlternateLBA = PartHeader->MyLBA;\r
645 PartHdr->PartitionEntryLBA = PEntryLBA;\r
646 PartitionSetCrc ((EFI_TABLE_HEADER *) PartHdr);\r
647\r
071b7221 648 Status = DiskIo->WriteDisk (\r
649 DiskIo,\r
490b5ea1 650 MediaId,\r
651 MultU64x32 (PartHdr->MyLBA, (UINT32) BlockSize),\r
071b7221 652 BlockSize,\r
653 PartHdr\r
654 );\r
adbcbf8f 655 if (EFI_ERROR (Status)) {\r
656 goto Done;\r
657 }\r
658\r
659 Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);\r
660 if (Ptr == NULL) {\r
071b7221 661 DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));\r
adbcbf8f 662 Status = EFI_OUT_OF_RESOURCES;\r
663 goto Done;\r
664 }\r
665\r
666 Status = DiskIo->ReadDisk (\r
667 DiskIo,\r
490b5ea1 668 MediaId,\r
669 MultU64x32(PartHeader->PartitionEntryLBA, (UINT32) BlockSize),\r
adbcbf8f 670 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,\r
671 Ptr\r
672 );\r
673 if (EFI_ERROR (Status)) {\r
674 goto Done;\r
675 }\r
676\r
677 Status = DiskIo->WriteDisk (\r
678 DiskIo,\r
490b5ea1 679 MediaId,\r
680 MultU64x32(PEntryLBA, (UINT32) BlockSize),\r
adbcbf8f 681 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,\r
682 Ptr\r
683 );\r
684\r
685Done:\r
686 FreePool (PartHdr);\r
ff61847d 687\r
688 if (Ptr != NULL) {\r
689 FreePool (Ptr);\r
690 }\r
adbcbf8f 691\r
692 if (EFI_ERROR (Status)) {\r
693 return FALSE;\r
694 }\r
695\r
696 return TRUE;\r
697}\r
698\r
adbcbf8f 699/**\r
dc204d5a
JY
700 This routine will check GPT partition entry and return entry status.\r
701\r
702 Caution: This function may receive untrusted input.\r
703 The GPT partition entry is external input, so this routine\r
704 will do basic validation for GPT partition entry and report status.\r
adbcbf8f 705\r
706 @param[in] PartHeader Partition table header structure\r
707 @param[in] PartEntry The partition entry array\r
d1102dba 708 @param[out] PEntryStatus the partition entry status array\r
adbcbf8f 709 recording the status of each partition\r
a8d0c20e 710\r
adbcbf8f 711**/\r
712VOID\r
713PartitionCheckGptEntry (\r
714 IN EFI_PARTITION_TABLE_HEADER *PartHeader,\r
715 IN EFI_PARTITION_ENTRY *PartEntry,\r
716 OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus\r
717 )\r
718{\r
d0e9c3ca
RN
719 EFI_LBA StartingLBA;\r
720 EFI_LBA EndingLBA;\r
721 EFI_PARTITION_ENTRY *Entry;\r
722 UINTN Index1;\r
723 UINTN Index2;\r
adbcbf8f 724\r
725 DEBUG ((EFI_D_INFO, " start check partition entries\n"));\r
726 for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {\r
d0e9c3ca
RN
727 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);\r
728 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
adbcbf8f 729 continue;\r
730 }\r
731\r
d0e9c3ca
RN
732 StartingLBA = Entry->StartingLBA;\r
733 EndingLBA = Entry->EndingLBA;\r
adbcbf8f 734 if (StartingLBA > EndingLBA ||\r
735 StartingLBA < PartHeader->FirstUsableLBA ||\r
736 StartingLBA > PartHeader->LastUsableLBA ||\r
737 EndingLBA < PartHeader->FirstUsableLBA ||\r
738 EndingLBA > PartHeader->LastUsableLBA\r
739 ) {\r
740 PEntryStatus[Index1].OutOfRange = TRUE;\r
741 continue;\r
742 }\r
743\r
d0e9c3ca
RN
744 if ((Entry->Attributes & BIT1) != 0) {\r
745 //\r
d1102dba 746 // If Bit 1 is set, this indicate that this is an OS specific GUID partition.\r
d0e9c3ca
RN
747 //\r
748 PEntryStatus[Index1].OsSpecific = TRUE;\r
749 }\r
adbcbf8f 750\r
d0e9c3ca
RN
751 for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {\r
752 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);\r
753 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
adbcbf8f 754 continue;\r
755 }\r
756\r
d0e9c3ca 757 if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {\r
adbcbf8f 758 //\r
759 // This region overlaps with the Index1'th region\r
760 //\r
761 PEntryStatus[Index1].Overlap = TRUE;\r
762 PEntryStatus[Index2].Overlap = TRUE;\r
763 continue;\r
adbcbf8f 764 }\r
765 }\r
766 }\r
767\r
768 DEBUG ((EFI_D_INFO, " End check partition entries\n"));\r
769}\r
770\r
771\r
772/**\r
ea7cb08c 773 Updates the CRC32 value in the table header.\r
adbcbf8f 774\r
a8d0c20e 775 @param Hdr Table to update\r
adbcbf8f 776\r
777**/\r
778VOID\r
779PartitionSetCrc (\r
780 IN OUT EFI_TABLE_HEADER *Hdr\r
781 )\r
782{\r
783 PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);\r
784}\r
785\r
786\r
787/**\r
ea7cb08c 788 Updates the CRC32 value in the table header.\r
adbcbf8f 789\r
a8d0c20e 790 @param Size The size of the table\r
791 @param Hdr Table to update\r
adbcbf8f 792\r
793**/\r
794VOID\r
795PartitionSetCrcAltSize (\r
796 IN UINTN Size,\r
797 IN OUT EFI_TABLE_HEADER *Hdr\r
798 )\r
adbcbf8f 799{\r
800 UINT32 Crc;\r
801\r
802 Hdr->CRC32 = 0;\r
803 gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);\r
804 Hdr->CRC32 = Crc;\r
805}\r
806\r
807\r
808/**\r
ea7cb08c 809 Checks the CRC32 value in the table header.\r
adbcbf8f 810\r
a8d0c20e 811 @param MaxSize Max Size limit\r
812 @param Hdr Table to check\r
adbcbf8f 813\r
a8d0c20e 814 @return TRUE CRC Valid\r
815 @return FALSE CRC Invalid\r
adbcbf8f 816\r
817**/\r
818BOOLEAN\r
819PartitionCheckCrc (\r
820 IN UINTN MaxSize,\r
821 IN OUT EFI_TABLE_HEADER *Hdr\r
822 )\r
823{\r
824 return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);\r
825}\r
826\r
827\r
828/**\r
ea7cb08c 829 Checks the CRC32 value in the table header.\r
adbcbf8f 830\r
a8d0c20e 831 @param MaxSize Max Size limit\r
832 @param Size The size of the table\r
833 @param Hdr Table to check\r
adbcbf8f 834\r
835 @return TRUE CRC Valid\r
836 @return FALSE CRC Invalid\r
837\r
838**/\r
839BOOLEAN\r
840PartitionCheckCrcAltSize (\r
841 IN UINTN MaxSize,\r
842 IN UINTN Size,\r
843 IN OUT EFI_TABLE_HEADER *Hdr\r
844 )\r
845{\r
846 UINT32 Crc;\r
847 UINT32 OrgCrc;\r
848 EFI_STATUS Status;\r
849\r
850 Crc = 0;\r
851\r
852 if (Size == 0) {\r
853 //\r
854 // If header size is 0 CRC will pass so return FALSE here\r
855 //\r
856 return FALSE;\r
857 }\r
858\r
ea7cb08c 859 if ((MaxSize != 0) && (Size > MaxSize)) {\r
adbcbf8f 860 DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));\r
861 return FALSE;\r
862 }\r
863 //\r
864 // clear old crc from header\r
865 //\r
866 OrgCrc = Hdr->CRC32;\r
867 Hdr->CRC32 = 0;\r
868\r
869 Status = gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);\r
870 if (EFI_ERROR (Status)) {\r
871 DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));\r
872 return FALSE;\r
873 }\r
874 //\r
875 // set results\r
876 //\r
877 Hdr->CRC32 = Crc;\r
878\r
879 //\r
880 // return status\r
881 //\r
882 DEBUG_CODE_BEGIN ();\r
883 if (OrgCrc != Crc) {\r
884 DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));\r
885 }\r
886 DEBUG_CODE_END ();\r
887\r
888 return (BOOLEAN) (OrgCrc == Crc);\r
889}\r