]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
IntelSiliconPkg: Clean up source files
[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) 2018 Qualcomm Datacenter Technologies, Inc.\r
17Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
18This program and the accompanying materials\r
19are licensed and made available under the terms and conditions of the BSD License\r
20which accompanies this distribution. The full text of the license may be found at\r
21http://opensource.org/licenses/bsd-license.php\r
22\r
23THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
24WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
25\r
26**/\r
27\r
28\r
29#include "Partition.h"\r
30\r
31/**\r
32 Install child handles if the Handle supports GPT partition structure.\r
33\r
34 Caution: This function may receive untrusted input.\r
35 The GPT partition table header is external input, so this routine\r
36 will do basic validation for GPT partition table header before return.\r
37\r
38 @param[in] BlockIo Parent BlockIo interface.\r
39 @param[in] DiskIo Disk Io protocol.\r
40 @param[in] Lba The starting Lba of the Partition Table\r
41 @param[out] PartHeader Stores the partition table that is read\r
42\r
43 @retval TRUE The partition table is valid\r
44 @retval FALSE The partition table is not valid\r
45\r
46**/\r
47BOOLEAN\r
48PartitionValidGptTable (\r
49 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
50 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
51 IN EFI_LBA Lba,\r
52 OUT EFI_PARTITION_TABLE_HEADER *PartHeader\r
53 );\r
54\r
55/**\r
56 Check if the CRC field in the Partition table header is valid\r
57 for Partition entry array.\r
58\r
59 @param[in] BlockIo Parent BlockIo interface\r
60 @param[in] DiskIo Disk Io Protocol.\r
61 @param[in] PartHeader Partition table header structure\r
62\r
63 @retval TRUE the CRC is valid\r
64 @retval FALSE the CRC is invalid\r
65\r
66**/\r
67BOOLEAN\r
68PartitionCheckGptEntryArrayCRC (\r
69 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
70 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
71 IN EFI_PARTITION_TABLE_HEADER *PartHeader\r
72 );\r
73\r
74\r
75/**\r
76 Restore Partition Table to its alternate place\r
77 (Primary -> Backup or Backup -> Primary).\r
78\r
79 @param[in] BlockIo Parent BlockIo interface.\r
80 @param[in] DiskIo Disk Io Protocol.\r
81 @param[in] PartHeader Partition table header structure.\r
82\r
83 @retval TRUE Restoring succeeds\r
84 @retval FALSE Restoring failed\r
85\r
86**/\r
87BOOLEAN\r
88PartitionRestoreGptTable (\r
89 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
90 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
91 IN EFI_PARTITION_TABLE_HEADER *PartHeader\r
92 );\r
93\r
94\r
95/**\r
96 This routine will check GPT partition entry and return entry status.\r
97\r
98 Caution: This function may receive untrusted input.\r
99 The GPT partition entry is external input, so this routine\r
100 will do basic validation for GPT partition entry and report status.\r
101\r
102 @param[in] PartHeader Partition table header structure\r
103 @param[in] PartEntry The partition entry array\r
104 @param[out] PEntryStatus the partition entry status array \r
105 recording the status of each partition\r
106\r
107**/\r
108VOID\r
109PartitionCheckGptEntry (\r
110 IN EFI_PARTITION_TABLE_HEADER *PartHeader,\r
111 IN EFI_PARTITION_ENTRY *PartEntry,\r
112 OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus\r
113 );\r
114\r
115\r
116/**\r
117 Checks the CRC32 value in the table header.\r
118\r
119 @param MaxSize Max Size limit\r
120 @param Size The size of the table\r
121 @param Hdr Table to check\r
122\r
123 @return TRUE CRC Valid\r
124 @return FALSE CRC Invalid\r
125\r
126**/\r
127BOOLEAN\r
128PartitionCheckCrcAltSize (\r
129 IN UINTN MaxSize,\r
130 IN UINTN Size,\r
131 IN OUT EFI_TABLE_HEADER *Hdr\r
132 );\r
133\r
134\r
135/**\r
136 Checks the CRC32 value in the table header.\r
137\r
138 @param MaxSize Max Size limit\r
139 @param Hdr Table to check\r
140\r
141 @return TRUE CRC Valid\r
142 @return FALSE CRC Invalid\r
143\r
144**/\r
145BOOLEAN\r
146PartitionCheckCrc (\r
147 IN UINTN MaxSize,\r
148 IN OUT EFI_TABLE_HEADER *Hdr\r
149 );\r
150\r
151\r
152/**\r
153 Updates the CRC32 value in the table header.\r
154\r
155 @param Size The size of the table\r
156 @param Hdr Table to update\r
157\r
158**/\r
159VOID\r
160PartitionSetCrcAltSize (\r
161 IN UINTN Size,\r
162 IN OUT EFI_TABLE_HEADER *Hdr\r
163 );\r
164\r
165\r
166/**\r
167 Updates the CRC32 value in the table header.\r
168\r
169 @param Hdr Table to update\r
170\r
171**/\r
172VOID\r
173PartitionSetCrc (\r
174 IN OUT EFI_TABLE_HEADER *Hdr\r
175 );\r
176\r
177/**\r
178 Install child handles if the Handle supports GPT partition structure.\r
179\r
180 Caution: This function may receive untrusted input.\r
181 The GPT partition table is external input, so this routine\r
182 will do basic validation for GPT partition table before install\r
183 child handle for each GPT partition.\r
184\r
185 @param[in] This Calling context.\r
186 @param[in] Handle Parent Handle.\r
187 @param[in] DiskIo Parent DiskIo interface.\r
188 @param[in] DiskIo2 Parent DiskIo2 interface.\r
189 @param[in] BlockIo Parent BlockIo interface.\r
190 @param[in] BlockIo2 Parent BlockIo2 interface.\r
191 @param[in] DevicePath Parent Device Path.\r
192\r
193 @retval EFI_SUCCESS Valid GPT disk.\r
194 @retval EFI_MEDIA_CHANGED Media changed Detected.\r
195 @retval other Not a valid GPT disk.\r
196\r
197**/\r
198EFI_STATUS\r
199PartitionInstallGptChildHandles (\r
200 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
201 IN EFI_HANDLE Handle,\r
202 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
203 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,\r
204 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
205 IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,\r
206 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
207 )\r
208{\r
209 EFI_STATUS Status;\r
210 UINT32 BlockSize;\r
211 EFI_LBA LastBlock;\r
212 MASTER_BOOT_RECORD *ProtectiveMbr;\r
213 EFI_PARTITION_TABLE_HEADER *PrimaryHeader;\r
214 EFI_PARTITION_TABLE_HEADER *BackupHeader;\r
215 EFI_PARTITION_ENTRY *PartEntry;\r
216 EFI_PARTITION_ENTRY *Entry;\r
217 EFI_PARTITION_ENTRY_STATUS *PEntryStatus;\r
218 UINTN Index;\r
219 EFI_STATUS GptValidStatus;\r
220 HARDDRIVE_DEVICE_PATH HdDev;\r
221 UINT32 MediaId;\r
222 EFI_PARTITION_INFO_PROTOCOL PartitionInfo;\r
223\r
224 ProtectiveMbr = NULL;\r
225 PrimaryHeader = NULL;\r
226 BackupHeader = NULL;\r
227 PartEntry = NULL;\r
228 PEntryStatus = NULL;\r
229\r
230 BlockSize = BlockIo->Media->BlockSize;\r
231 LastBlock = BlockIo->Media->LastBlock;\r
232 MediaId = BlockIo->Media->MediaId;\r
233\r
234 DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize));\r
235 DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock));\r
236\r
237 GptValidStatus = EFI_NOT_FOUND;\r
238\r
239 //\r
240 // Allocate a buffer for the Protective MBR\r
241 //\r
242 ProtectiveMbr = AllocatePool (BlockSize);\r
243 if (ProtectiveMbr == NULL) {\r
244 return EFI_NOT_FOUND;\r
245 }\r
246\r
247 //\r
248 // Read the Protective MBR from LBA #0\r
249 //\r
250 Status = DiskIo->ReadDisk (\r
251 DiskIo,\r
252 MediaId,\r
253 0,\r
254 BlockSize,\r
255 ProtectiveMbr\r
256 );\r
257 if (EFI_ERROR (Status)) {\r
258 GptValidStatus = Status;\r
259 goto Done;\r
260 }\r
261\r
262 //\r
263 // Verify that the Protective MBR is valid\r
264 //\r
265 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {\r
266 if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&\r
267 ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION &&\r
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
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
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
294 DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));\r
295\r
296 if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) {\r
297 DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));\r
298 goto Done;\r
299 } else {\r
300 DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));\r
301 DEBUG ((EFI_D_INFO, " Restore primary partition table by the backup\n"));\r
302 if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) {\r
303 DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));\r
304 }\r
305\r
306 if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) {\r
307 DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));\r
308 }\r
309 }\r
310 } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {\r
311 DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n"));\r
312 DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n"));\r
313 if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {\r
314 DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));\r
315 }\r
316\r
317 if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {\r
318 DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));\r
319 }\r
320\r
321 }\r
322\r
323 DEBUG ((EFI_D_INFO, " Valid primary and Valid backup partition table\n"));\r
324\r
325 //\r
326 // Read the EFI Partition Entries\r
327 //\r
328 PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);\r
329 if (PartEntry == NULL) {\r
330 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
331 goto Done;\r
332 }\r
333\r
334 Status = DiskIo->ReadDisk (\r
335 DiskIo,\r
336 MediaId,\r
337 MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize),\r
338 PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),\r
339 PartEntry\r
340 );\r
341 if (EFI_ERROR (Status)) {\r
342 GptValidStatus = Status;\r
343 DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));\r
344 goto Done;\r
345 }\r
346\r
347 DEBUG ((EFI_D_INFO, " Partition entries read block success\n"));\r
348\r
349 DEBUG ((EFI_D_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));\r
350\r
351 PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));\r
352 if (PEntryStatus == NULL) {\r
353 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
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
365 GptValidStatus = EFI_SUCCESS;\r
366\r
367 //\r
368 // Create child device handles\r
369 //\r
370 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
371 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);\r
372 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||\r
373 PEntryStatus[Index].OutOfRange ||\r
374 PEntryStatus[Index].Overlap ||\r
375 PEntryStatus[Index].OsSpecific\r
376 ) {\r
377 //\r
378 // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific\r
379 // partition Entries\r
380 //\r
381 continue;\r
382 }\r
383\r
384 ZeroMem (&HdDev, sizeof (HdDev));\r
385 HdDev.Header.Type = MEDIA_DEVICE_PATH;\r
386 HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;\r
387 SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));\r
388\r
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
394 CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));\r
395\r
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
404 DEBUG ((EFI_D_INFO, " Index : %d\n", (UINT32) Index));\r
405 DEBUG ((EFI_D_INFO, " Start LBA : %lx\n", (UINT64) HdDev.PartitionStart));\r
406 DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA));\r
407 DEBUG ((EFI_D_INFO, " Partition size: %lx\n", (UINT64) HdDev.PartitionSize));\r
408 DEBUG ((EFI_D_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));\r
409 DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));\r
410\r
411 Status = PartitionInstallChildHandle (\r
412 This,\r
413 Handle,\r
414 DiskIo,\r
415 DiskIo2,\r
416 BlockIo,\r
417 BlockIo2,\r
418 DevicePath,\r
419 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,\r
420 &PartitionInfo,\r
421 Entry->StartingLBA,\r
422 Entry->EndingLBA,\r
423 BlockSize,\r
424 &Entry->PartitionTypeGUID\r
425 );\r
426 }\r
427\r
428 DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n"));\r
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
447 return GptValidStatus;\r
448}\r
449\r
450/**\r
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
456\r
457 @param[in] BlockIo Parent BlockIo interface.\r
458 @param[in] DiskIo Disk Io protocol.\r
459 @param[in] Lba The starting Lba of the Partition Table\r
460 @param[out] PartHeader Stores the partition table that is read\r
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
477 UINT32 MediaId;\r
478\r
479 BlockSize = BlockIo->Media->BlockSize;\r
480 MediaId = BlockIo->Media->MediaId;\r
481 PartHdr = AllocateZeroPool (BlockSize);\r
482\r
483 if (PartHdr == NULL) {\r
484 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
485 return FALSE;\r
486 }\r
487 //\r
488 // Read the EFI Partition Table Header\r
489 //\r
490 Status = DiskIo->ReadDisk (\r
491 DiskIo,\r
492 MediaId,\r
493 MultU64x32 (Lba, BlockSize),\r
494 BlockSize,\r
495 PartHdr\r
496 );\r
497 if (EFI_ERROR (Status)) {\r
498 FreePool (PartHdr);\r
499 return FALSE;\r
500 }\r
501\r
502 if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||\r
503 !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||\r
504 PartHdr->MyLBA != Lba ||\r
505 (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))\r
506 ) {\r
507 DEBUG ((EFI_D_INFO, "Invalid efi partition table header\n"));\r
508 FreePool (PartHdr);\r
509 return FALSE;\r
510 }\r
511\r
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
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
526 DEBUG ((EFI_D_INFO, " Valid efi partition table header\n"));\r
527 FreePool (PartHdr);\r
528 return TRUE;\r
529}\r
530\r
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
560 DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));\r
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
580 DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));\r
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
593 (Primary -> Backup or Backup -> Primary).\r
594\r
595 @param[in] BlockIo Parent BlockIo interface.\r
596 @param[in] DiskIo Disk Io Protocol.\r
597 @param[in] PartHeader Partition table header structure.\r
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
615 UINT32 MediaId;\r
616\r
617 PartHdr = NULL;\r
618 Ptr = NULL;\r
619\r
620 BlockSize = BlockIo->Media->BlockSize;\r
621 MediaId = BlockIo->Media->MediaId;\r
622\r
623 PartHdr = AllocateZeroPool (BlockSize);\r
624\r
625 if (PartHdr == NULL) {\r
626 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
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
641 Status = DiskIo->WriteDisk (\r
642 DiskIo,\r
643 MediaId,\r
644 MultU64x32 (PartHdr->MyLBA, (UINT32) BlockSize),\r
645 BlockSize,\r
646 PartHdr\r
647 );\r
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
654 DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));\r
655 Status = EFI_OUT_OF_RESOURCES;\r
656 goto Done;\r
657 }\r
658\r
659 Status = DiskIo->ReadDisk (\r
660 DiskIo,\r
661 MediaId,\r
662 MultU64x32(PartHeader->PartitionEntryLBA, (UINT32) BlockSize),\r
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
672 MediaId,\r
673 MultU64x32(PEntryLBA, (UINT32) BlockSize),\r
674 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,\r
675 Ptr\r
676 );\r
677\r
678Done:\r
679 FreePool (PartHdr);\r
680\r
681 if (Ptr != NULL) {\r
682 FreePool (Ptr);\r
683 }\r
684\r
685 if (EFI_ERROR (Status)) {\r
686 return FALSE;\r
687 }\r
688\r
689 return TRUE;\r
690}\r
691\r
692/**\r
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
698\r
699 @param[in] PartHeader Partition table header structure\r
700 @param[in] PartEntry The partition entry array\r
701 @param[out] PEntryStatus the partition entry status array \r
702 recording the status of each partition\r
703\r
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
712 EFI_LBA StartingLBA;\r
713 EFI_LBA EndingLBA;\r
714 EFI_PARTITION_ENTRY *Entry;\r
715 UINTN Index1;\r
716 UINTN Index2;\r
717\r
718 DEBUG ((EFI_D_INFO, " start check partition entries\n"));\r
719 for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {\r
720 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);\r
721 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
722 continue;\r
723 }\r
724\r
725 StartingLBA = Entry->StartingLBA;\r
726 EndingLBA = Entry->EndingLBA;\r
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
737 if ((Entry->Attributes & BIT1) != 0) {\r
738 //\r
739 // If Bit 1 is set, this indicate that this is an OS specific GUID partition. \r
740 //\r
741 PEntryStatus[Index1].OsSpecific = TRUE;\r
742 }\r
743\r
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
747 continue;\r
748 }\r
749\r
750 if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {\r
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
757 }\r
758 }\r
759 }\r
760\r
761 DEBUG ((EFI_D_INFO, " End check partition entries\n"));\r
762}\r
763\r
764\r
765/**\r
766 Updates the CRC32 value in the table header.\r
767\r
768 @param Hdr Table to update\r
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
781 Updates the CRC32 value in the table header.\r
782\r
783 @param Size The size of the table\r
784 @param Hdr Table to update\r
785\r
786**/\r
787VOID\r
788PartitionSetCrcAltSize (\r
789 IN UINTN Size,\r
790 IN OUT EFI_TABLE_HEADER *Hdr\r
791 )\r
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
802 Checks the CRC32 value in the table header.\r
803\r
804 @param MaxSize Max Size limit\r
805 @param Hdr Table to check\r
806\r
807 @return TRUE CRC Valid\r
808 @return FALSE CRC Invalid\r
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
822 Checks the CRC32 value in the table header.\r
823\r
824 @param MaxSize Max Size limit\r
825 @param Size The size of the table\r
826 @param Hdr Table to check\r
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
852 if ((MaxSize != 0) && (Size > MaxSize)) {\r
853 DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));\r
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
864 DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));\r
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
877 DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));\r
878 }\r
879 DEBUG_CODE_END ();\r
880\r
881 return (BOOLEAN) (OrgCrc == Crc);\r
882}\r