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