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