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