]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
Add DiskIo2 protocol definition to MdePkg.
[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 - 2013, 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\r
222 ProtectiveMbr = NULL;\r
223 PrimaryHeader = NULL;\r
224 BackupHeader = NULL;\r
225 PartEntry = NULL;\r
226 PEntryStatus = NULL;\r
227\r
228 BlockSize = BlockIo->Media->BlockSize;\r
229 LastBlock = BlockIo->Media->LastBlock;\r
230 MediaId = BlockIo->Media->MediaId;\r
231\r
232 DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize));\r
233 DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock));\r
234\r
235 GptValidStatus = EFI_NOT_FOUND;\r
236\r
237 //\r
238 // Allocate a buffer for the Protective MBR\r
239 //\r
240 ProtectiveMbr = AllocatePool (BlockSize);\r
241 if (ProtectiveMbr == NULL) {\r
242 return EFI_NOT_FOUND;\r
243 }\r
244\r
245 //\r
246 // Read the Protective MBR from LBA #0\r
247 //\r
248 Status = DiskIo->ReadDisk (\r
249 DiskIo,\r
250 MediaId,\r
251 0,\r
252 BlockSize,\r
253 ProtectiveMbr\r
254 );\r
255 if (EFI_ERROR (Status)) {\r
256 GptValidStatus = Status;\r
257 goto Done;\r
258 }\r
259\r
260 //\r
261 // Verify that the Protective MBR is valid\r
262 //\r
263 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {\r
264 if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&\r
265 ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION &&\r
266 UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1\r
267 ) {\r
268 break;\r
269 }\r
270 }\r
271 if (Index == MAX_MBR_PARTITIONS) {\r
272 goto Done;\r
273 }\r
274\r
275 //\r
276 // Allocate the GPT structures\r
277 //\r
278 PrimaryHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));\r
279 if (PrimaryHeader == NULL) {\r
280 goto Done;\r
281 }\r
282\r
283 BackupHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));\r
284 if (BackupHeader == NULL) {\r
285 goto Done;\r
286 }\r
287\r
288 //\r
289 // Check primary and backup partition tables\r
290 //\r
291 if (!PartitionValidGptTable (BlockIo, DiskIo, PRIMARY_PART_HEADER_LBA, PrimaryHeader)) {\r
292 DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));\r
293\r
294 if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) {\r
295 DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));\r
296 goto Done;\r
297 } else {\r
298 DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));\r
299 DEBUG ((EFI_D_INFO, " Restore primary partition table by the backup\n"));\r
300 if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) {\r
301 DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));\r
302 }\r
303\r
304 if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) {\r
305 DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));\r
306 }\r
307 }\r
308 } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {\r
309 DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n"));\r
310 DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n"));\r
311 if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {\r
312 DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));\r
313 }\r
314\r
315 if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {\r
316 DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));\r
317 }\r
318\r
319 }\r
320\r
321 DEBUG ((EFI_D_INFO, " Valid primary and Valid backup partition table\n"));\r
322\r
323 //\r
324 // Read the EFI Partition Entries\r
325 //\r
326 PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);\r
327 if (PartEntry == NULL) {\r
328 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
329 goto Done;\r
330 }\r
331\r
332 Status = DiskIo->ReadDisk (\r
333 DiskIo,\r
334 MediaId,\r
335 MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize),\r
336 PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),\r
337 PartEntry\r
338 );\r
339 if (EFI_ERROR (Status)) {\r
340 GptValidStatus = Status;\r
341 DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));\r
342 goto Done;\r
343 }\r
344\r
345 DEBUG ((EFI_D_INFO, " Partition entries read block success\n"));\r
346\r
347 DEBUG ((EFI_D_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));\r
348\r
349 PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));\r
350 if (PEntryStatus == NULL) {\r
351 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
352 goto Done;\r
353 }\r
354\r
355 //\r
356 // Check the integrity of partition entries\r
357 //\r
358 PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);\r
359\r
360 //\r
361 // If we got this far the GPT layout of the disk is valid and we should return true\r
362 //\r
363 GptValidStatus = EFI_SUCCESS;\r
364\r
365 //\r
366 // Create child device handles\r
367 //\r
368 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
369 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);\r
370 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||\r
371 PEntryStatus[Index].OutOfRange ||\r
372 PEntryStatus[Index].Overlap ||\r
373 PEntryStatus[Index].OsSpecific\r
374 ) {\r
375 //\r
376 // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific\r
377 // partition Entries\r
378 //\r
379 continue;\r
380 }\r
381\r
382 ZeroMem (&HdDev, sizeof (HdDev));\r
383 HdDev.Header.Type = MEDIA_DEVICE_PATH;\r
384 HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;\r
385 SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));\r
386\r
387 HdDev.PartitionNumber = (UINT32) Index + 1;\r
388 HdDev.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;\r
389 HdDev.SignatureType = SIGNATURE_TYPE_GUID;\r
390 HdDev.PartitionStart = Entry->StartingLBA;\r
391 HdDev.PartitionSize = Entry->EndingLBA - Entry->StartingLBA + 1;\r
392 CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));\r
393\r
394 DEBUG ((EFI_D_INFO, " Index : %d\n", (UINT32) Index));\r
395 DEBUG ((EFI_D_INFO, " Start LBA : %lx\n", (UINT64) HdDev.PartitionStart));\r
396 DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA));\r
397 DEBUG ((EFI_D_INFO, " Partition size: %lx\n", (UINT64) HdDev.PartitionSize));\r
398 DEBUG ((EFI_D_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));\r
399 DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));\r
400\r
401 Status = PartitionInstallChildHandle (\r
402 This,\r
403 Handle,\r
404 DiskIo,\r
405 DiskIo2,\r
406 BlockIo,\r
407 BlockIo2,\r
408 DevicePath,\r
409 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,\r
410 Entry->StartingLBA,\r
411 Entry->EndingLBA,\r
412 BlockSize,\r
413 CompareGuid(&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)\r
414 );\r
415 }\r
416\r
417 DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n"));\r
418\r
419Done:\r
420 if (ProtectiveMbr != NULL) {\r
421 FreePool (ProtectiveMbr);\r
422 }\r
423 if (PrimaryHeader != NULL) {\r
424 FreePool (PrimaryHeader);\r
425 }\r
426 if (BackupHeader != NULL) {\r
427 FreePool (BackupHeader);\r
428 }\r
429 if (PartEntry != NULL) {\r
430 FreePool (PartEntry);\r
431 }\r
432 if (PEntryStatus != NULL) {\r
433 FreePool (PEntryStatus);\r
434 }\r
435\r
436 return GptValidStatus;\r
437}\r
438\r
439/**\r
440 This routine will read GPT partition table header and return it.\r
441\r
442 Caution: This function may receive untrusted input.\r
443 The GPT partition table header is external input, so this routine\r
444 will do basic validation for GPT partition table header before return.\r
445\r
446 @param[in] BlockIo Parent BlockIo interface.\r
447 @param[in] DiskIo Disk Io protocol.\r
448 @param[in] Lba The starting Lba of the Partition Table\r
449 @param[out] PartHeader Stores the partition table that is read\r
450\r
451 @retval TRUE The partition table is valid\r
452 @retval FALSE The partition table is not valid\r
453\r
454**/\r
455BOOLEAN\r
456PartitionValidGptTable (\r
457 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
458 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
459 IN EFI_LBA Lba,\r
460 OUT EFI_PARTITION_TABLE_HEADER *PartHeader\r
461 )\r
462{\r
463 EFI_STATUS Status;\r
464 UINT32 BlockSize;\r
465 EFI_PARTITION_TABLE_HEADER *PartHdr;\r
466 UINT32 MediaId;\r
467\r
468 BlockSize = BlockIo->Media->BlockSize;\r
469 MediaId = BlockIo->Media->MediaId;\r
470 PartHdr = AllocateZeroPool (BlockSize);\r
471\r
472 if (PartHdr == NULL) {\r
473 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
474 return FALSE;\r
475 }\r
476 //\r
477 // Read the EFI Partition Table Header\r
478 //\r
479 Status = DiskIo->ReadDisk (\r
480 DiskIo,\r
481 MediaId,\r
482 MultU64x32 (Lba, BlockSize),\r
483 BlockSize,\r
484 PartHdr\r
485 );\r
486 if (EFI_ERROR (Status)) {\r
487 FreePool (PartHdr);\r
488 return FALSE;\r
489 }\r
490\r
491 if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||\r
492 !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||\r
493 PartHdr->MyLBA != Lba ||\r
494 (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))\r
495 ) {\r
496 DEBUG ((EFI_D_INFO, "Invalid efi partition table header\n"));\r
497 FreePool (PartHdr);\r
498 return FALSE;\r
499 }\r
500\r
501 //\r
502 // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.\r
503 //\r
504 if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {\r
505 FreePool (PartHdr);\r
506 return FALSE;\r
507 }\r
508\r
509 CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));\r
510 if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {\r
511 FreePool (PartHdr);\r
512 return FALSE;\r
513 }\r
514\r
515 DEBUG ((EFI_D_INFO, " Valid efi partition table header\n"));\r
516 FreePool (PartHdr);\r
517 return TRUE;\r
518}\r
519\r
520/**\r
521 Check if the CRC field in the Partition table header is valid\r
522 for Partition entry array.\r
523\r
524 @param[in] BlockIo Parent BlockIo interface\r
525 @param[in] DiskIo Disk Io Protocol.\r
526 @param[in] PartHeader Partition table header structure\r
527\r
528 @retval TRUE the CRC is valid\r
529 @retval FALSE the CRC is invalid\r
530\r
531**/\r
532BOOLEAN\r
533PartitionCheckGptEntryArrayCRC (\r
534 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
535 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
536 IN EFI_PARTITION_TABLE_HEADER *PartHeader\r
537 )\r
538{\r
539 EFI_STATUS Status;\r
540 UINT8 *Ptr;\r
541 UINT32 Crc;\r
542 UINTN Size;\r
543\r
544 //\r
545 // Read the EFI Partition Entries\r
546 //\r
547 Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);\r
548 if (Ptr == NULL) {\r
549 DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));\r
550 return FALSE;\r
551 }\r
552\r
553 Status = DiskIo->ReadDisk (\r
554 DiskIo,\r
555 BlockIo->Media->MediaId,\r
556 MultU64x32(PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),\r
557 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,\r
558 Ptr\r
559 );\r
560 if (EFI_ERROR (Status)) {\r
561 FreePool (Ptr);\r
562 return FALSE;\r
563 }\r
564\r
565 Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;\r
566\r
567 Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);\r
568 if (EFI_ERROR (Status)) {\r
569 DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));\r
570 FreePool (Ptr);\r
571 return FALSE;\r
572 }\r
573\r
574 FreePool (Ptr);\r
575\r
576 return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc);\r
577}\r
578\r
579\r
580/**\r
581 Restore Partition Table to its alternate place\r
582 (Primary -> Backup or Backup -> Primary).\r
583\r
584 @param[in] BlockIo Parent BlockIo interface.\r
585 @param[in] DiskIo Disk Io Protocol.\r
586 @param[in] PartHeader Partition table header structure.\r
587\r
588 @retval TRUE Restoring succeeds\r
589 @retval FALSE Restoring failed\r
590\r
591**/\r
592BOOLEAN\r
593PartitionRestoreGptTable (\r
594 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
595 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
596 IN EFI_PARTITION_TABLE_HEADER *PartHeader\r
597 )\r
598{\r
599 EFI_STATUS Status;\r
600 UINTN BlockSize;\r
601 EFI_PARTITION_TABLE_HEADER *PartHdr;\r
602 EFI_LBA PEntryLBA;\r
603 UINT8 *Ptr;\r
604 UINT32 MediaId;\r
605\r
606 PartHdr = NULL;\r
607 Ptr = NULL;\r
608\r
609 BlockSize = BlockIo->Media->BlockSize;\r
610 MediaId = BlockIo->Media->MediaId;\r
611\r
612 PartHdr = AllocateZeroPool (BlockSize);\r
613\r
614 if (PartHdr == NULL) {\r
615 DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));\r
616 return FALSE;\r
617 }\r
618\r
619 PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \\r
620 (PartHeader->LastUsableLBA + 1) : \\r
621 (PRIMARY_PART_HEADER_LBA + 1);\r
622\r
623 CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));\r
624\r
625 PartHdr->MyLBA = PartHeader->AlternateLBA;\r
626 PartHdr->AlternateLBA = PartHeader->MyLBA;\r
627 PartHdr->PartitionEntryLBA = PEntryLBA;\r
628 PartitionSetCrc ((EFI_TABLE_HEADER *) PartHdr);\r
629\r
630 Status = DiskIo->WriteDisk (\r
631 DiskIo,\r
632 MediaId,\r
633 MultU64x32 (PartHdr->MyLBA, (UINT32) BlockSize),\r
634 BlockSize,\r
635 PartHdr\r
636 );\r
637 if (EFI_ERROR (Status)) {\r
638 goto Done;\r
639 }\r
640\r
641 Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);\r
642 if (Ptr == NULL) {\r
643 DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));\r
644 Status = EFI_OUT_OF_RESOURCES;\r
645 goto Done;\r
646 }\r
647\r
648 Status = DiskIo->ReadDisk (\r
649 DiskIo,\r
650 MediaId,\r
651 MultU64x32(PartHeader->PartitionEntryLBA, (UINT32) BlockSize),\r
652 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,\r
653 Ptr\r
654 );\r
655 if (EFI_ERROR (Status)) {\r
656 goto Done;\r
657 }\r
658\r
659 Status = DiskIo->WriteDisk (\r
660 DiskIo,\r
661 MediaId,\r
662 MultU64x32(PEntryLBA, (UINT32) BlockSize),\r
663 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,\r
664 Ptr\r
665 );\r
666\r
667Done:\r
668 FreePool (PartHdr);\r
669\r
670 if (Ptr != NULL) {\r
671 FreePool (Ptr);\r
672 }\r
673\r
674 if (EFI_ERROR (Status)) {\r
675 return FALSE;\r
676 }\r
677\r
678 return TRUE;\r
679}\r
680\r
681/**\r
682 This routine will check GPT partition entry and return entry status.\r
683\r
684 Caution: This function may receive untrusted input.\r
685 The GPT partition entry is external input, so this routine\r
686 will do basic validation for GPT partition entry and report status.\r
687\r
688 @param[in] PartHeader Partition table header structure\r
689 @param[in] PartEntry The partition entry array\r
690 @param[out] PEntryStatus the partition entry status array \r
691 recording the status of each partition\r
692\r
693**/\r
694VOID\r
695PartitionCheckGptEntry (\r
696 IN EFI_PARTITION_TABLE_HEADER *PartHeader,\r
697 IN EFI_PARTITION_ENTRY *PartEntry,\r
698 OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus\r
699 )\r
700{\r
701 EFI_LBA StartingLBA;\r
702 EFI_LBA EndingLBA;\r
703 EFI_PARTITION_ENTRY *Entry;\r
704 UINTN Index1;\r
705 UINTN Index2;\r
706\r
707 DEBUG ((EFI_D_INFO, " start check partition entries\n"));\r
708 for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {\r
709 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);\r
710 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
711 continue;\r
712 }\r
713\r
714 StartingLBA = Entry->StartingLBA;\r
715 EndingLBA = Entry->EndingLBA;\r
716 if (StartingLBA > EndingLBA ||\r
717 StartingLBA < PartHeader->FirstUsableLBA ||\r
718 StartingLBA > PartHeader->LastUsableLBA ||\r
719 EndingLBA < PartHeader->FirstUsableLBA ||\r
720 EndingLBA > PartHeader->LastUsableLBA\r
721 ) {\r
722 PEntryStatus[Index1].OutOfRange = TRUE;\r
723 continue;\r
724 }\r
725\r
726 if ((Entry->Attributes & BIT1) != 0) {\r
727 //\r
728 // If Bit 1 is set, this indicate that this is an OS specific GUID partition. \r
729 //\r
730 PEntryStatus[Index1].OsSpecific = TRUE;\r
731 }\r
732\r
733 for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {\r
734 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);\r
735 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
736 continue;\r
737 }\r
738\r
739 if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {\r
740 //\r
741 // This region overlaps with the Index1'th region\r
742 //\r
743 PEntryStatus[Index1].Overlap = TRUE;\r
744 PEntryStatus[Index2].Overlap = TRUE;\r
745 continue;\r
746 }\r
747 }\r
748 }\r
749\r
750 DEBUG ((EFI_D_INFO, " End check partition entries\n"));\r
751}\r
752\r
753\r
754/**\r
755 Updates the CRC32 value in the table header.\r
756\r
757 @param Hdr Table to update\r
758\r
759**/\r
760VOID\r
761PartitionSetCrc (\r
762 IN OUT EFI_TABLE_HEADER *Hdr\r
763 )\r
764{\r
765 PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);\r
766}\r
767\r
768\r
769/**\r
770 Updates the CRC32 value in the table header.\r
771\r
772 @param Size The size of the table\r
773 @param Hdr Table to update\r
774\r
775**/\r
776VOID\r
777PartitionSetCrcAltSize (\r
778 IN UINTN Size,\r
779 IN OUT EFI_TABLE_HEADER *Hdr\r
780 )\r
781{\r
782 UINT32 Crc;\r
783\r
784 Hdr->CRC32 = 0;\r
785 gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);\r
786 Hdr->CRC32 = Crc;\r
787}\r
788\r
789\r
790/**\r
791 Checks the CRC32 value in the table header.\r
792\r
793 @param MaxSize Max Size limit\r
794 @param Hdr Table to check\r
795\r
796 @return TRUE CRC Valid\r
797 @return FALSE CRC Invalid\r
798\r
799**/\r
800BOOLEAN\r
801PartitionCheckCrc (\r
802 IN UINTN MaxSize,\r
803 IN OUT EFI_TABLE_HEADER *Hdr\r
804 )\r
805{\r
806 return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);\r
807}\r
808\r
809\r
810/**\r
811 Checks the CRC32 value in the table header.\r
812\r
813 @param MaxSize Max Size limit\r
814 @param Size The size of the table\r
815 @param Hdr Table to check\r
816\r
817 @return TRUE CRC Valid\r
818 @return FALSE CRC Invalid\r
819\r
820**/\r
821BOOLEAN\r
822PartitionCheckCrcAltSize (\r
823 IN UINTN MaxSize,\r
824 IN UINTN Size,\r
825 IN OUT EFI_TABLE_HEADER *Hdr\r
826 )\r
827{\r
828 UINT32 Crc;\r
829 UINT32 OrgCrc;\r
830 EFI_STATUS Status;\r
831\r
832 Crc = 0;\r
833\r
834 if (Size == 0) {\r
835 //\r
836 // If header size is 0 CRC will pass so return FALSE here\r
837 //\r
838 return FALSE;\r
839 }\r
840\r
841 if ((MaxSize != 0) && (Size > MaxSize)) {\r
842 DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));\r
843 return FALSE;\r
844 }\r
845 //\r
846 // clear old crc from header\r
847 //\r
848 OrgCrc = Hdr->CRC32;\r
849 Hdr->CRC32 = 0;\r
850\r
851 Status = gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);\r
852 if (EFI_ERROR (Status)) {\r
853 DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));\r
854 return FALSE;\r
855 }\r
856 //\r
857 // set results\r
858 //\r
859 Hdr->CRC32 = Crc;\r
860\r
861 //\r
862 // return status\r
863 //\r
864 DEBUG_CODE_BEGIN ();\r
865 if (OrgCrc != Crc) {\r
866 DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));\r
867 }\r
868 DEBUG_CODE_END ();\r
869\r
870 return (BOOLEAN) (OrgCrc == Crc);\r
871}\r