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