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