Add DiskIo2 protocol definition to MdePkg.
[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
493d8e3a 187 @param[in] DiskIo2 Parent DiskIo2 interface.\r
490b5ea1 188 @param[in] BlockIo Parent BlockIo interface.\r
189 @param[in] BlockIo2 Parent BlockIo2 interface.\r
190 @param[in] DevicePath Parent Device Path.\r
adbcbf8f 191\r
490b5ea1 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
adbcbf8f 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
493d8e3a 202 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,\r
adbcbf8f 203 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
490b5ea1 204 IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,\r
adbcbf8f 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
d0e9c3ca 215 EFI_PARTITION_ENTRY *Entry;\r
adbcbf8f 216 EFI_PARTITION_ENTRY_STATUS *PEntryStatus;\r
217 UINTN Index;\r
ff61847d 218 EFI_STATUS GptValidStatus;\r
adbcbf8f 219 HARDDRIVE_DEVICE_PATH HdDev;\r
490b5ea1 220 UINT32 MediaId;\r
adbcbf8f 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
490b5ea1 230 MediaId = BlockIo->Media->MediaId;\r
adbcbf8f 231\r
232 DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize));\r
7df7393f 233 DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock));\r
adbcbf8f 234\r
ff61847d 235 GptValidStatus = EFI_NOT_FOUND;\r
adbcbf8f 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
96f99e1d 248 Status = DiskIo->ReadDisk (\r
249 DiskIo,\r
490b5ea1 250 MediaId,\r
96f99e1d 251 0,\r
490b5ea1 252 BlockSize,\r
96f99e1d 253 ProtectiveMbr\r
254 );\r
adbcbf8f 255 if (EFI_ERROR (Status)) {\r
ff61847d 256 GptValidStatus = Status;\r
adbcbf8f 257 goto Done;\r
258 }\r
490b5ea1 259\r
adbcbf8f 260 //\r
261 // Verify that the Protective MBR is valid\r
262 //\r
339c754a 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
adbcbf8f 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
adbcbf8f 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
b4e027f1 312 DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));\r
adbcbf8f 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
d0e9c3ca 326 PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);\r
adbcbf8f 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
7059dad9 333 DiskIo,\r
490b5ea1 334 MediaId,\r
7059dad9 335 MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize),\r
336 PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),\r
337 PartEntry\r
338 );\r
adbcbf8f 339 if (EFI_ERROR (Status)) {\r
ff61847d 340 GptValidStatus = Status;\r
96f99e1d 341 DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));\r
adbcbf8f 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
ff61847d 363 GptValidStatus = EFI_SUCCESS;\r
adbcbf8f 364\r
365 //\r
366 // Create child device handles\r
367 //\r
368 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
d0e9c3ca
RN
369 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);\r
370 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||\r
adbcbf8f 371 PEntryStatus[Index].OutOfRange ||\r
47e1a80b 372 PEntryStatus[Index].Overlap ||\r
373 PEntryStatus[Index].OsSpecific\r
adbcbf8f 374 ) {\r
375 //\r
47e1a80b 376 // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific\r
377 // partition Entries\r
adbcbf8f 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
d0e9c3ca
RN
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
adbcbf8f 393\r
ff61847d 394 DEBUG ((EFI_D_INFO, " Index : %d\n", (UINT32) Index));\r
395 DEBUG ((EFI_D_INFO, " Start LBA : %lx\n", (UINT64) HdDev.PartitionStart));\r
d0e9c3ca 396 DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA));\r
ff61847d 397 DEBUG ((EFI_D_INFO, " Partition size: %lx\n", (UINT64) HdDev.PartitionSize));\r
d0e9c3ca
RN
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
adbcbf8f 400\r
401 Status = PartitionInstallChildHandle (\r
490b5ea1 402 This,\r
403 Handle,\r
404 DiskIo,\r
493d8e3a 405 DiskIo2,\r
490b5ea1 406 BlockIo,\r
407 BlockIo2,\r
408 DevicePath,\r
409 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,\r
d0e9c3ca
RN
410 Entry->StartingLBA,\r
411 Entry->EndingLBA,\r
490b5ea1 412 BlockSize,\r
d0e9c3ca 413 CompareGuid(&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)\r
490b5ea1 414 );\r
adbcbf8f 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
ff61847d 436 return GptValidStatus;\r
adbcbf8f 437}\r
438\r
adbcbf8f 439/**\r
dc204d5a
JY
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
adbcbf8f 445\r
490b5ea1 446 @param[in] BlockIo Parent BlockIo interface.\r
adbcbf8f 447 @param[in] DiskIo Disk Io protocol.\r
448 @param[in] Lba The starting Lba of the Partition Table\r
a8d0c20e 449 @param[out] PartHeader Stores the partition table that is read\r
adbcbf8f 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
490b5ea1 466 UINT32 MediaId;\r
adbcbf8f 467\r
468 BlockSize = BlockIo->Media->BlockSize;\r
490b5ea1 469 MediaId = BlockIo->Media->MediaId;\r
adbcbf8f 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
96f99e1d 479 Status = DiskIo->ReadDisk (\r
480 DiskIo,\r
490b5ea1 481 MediaId,\r
7059dad9 482 MultU64x32 (Lba, BlockSize),\r
96f99e1d 483 BlockSize,\r
484 PartHdr\r
485 );\r
adbcbf8f 486 if (EFI_ERROR (Status)) {\r
487 FreePool (PartHdr);\r
488 return FALSE;\r
489 }\r
490\r
cd2d8468 491 if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||\r
adbcbf8f 492 !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||\r
b4e027f1
SZ
493 PartHdr->MyLBA != Lba ||\r
494 (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))\r
adbcbf8f 495 ) {\r
ff61847d 496 DEBUG ((EFI_D_INFO, "Invalid efi partition table header\n"));\r
adbcbf8f 497 FreePool (PartHdr);\r
498 return FALSE;\r
499 }\r
500\r
b4e027f1
SZ
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
adbcbf8f 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
adbcbf8f 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
490b5ea1 582 (Primary -> Backup or Backup -> Primary).\r
adbcbf8f 583\r
490b5ea1 584 @param[in] BlockIo Parent BlockIo interface.\r
adbcbf8f 585 @param[in] DiskIo Disk Io Protocol.\r
490b5ea1 586 @param[in] PartHeader Partition table header structure.\r
adbcbf8f 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
490b5ea1 604 UINT32 MediaId;\r
adbcbf8f 605\r
606 PartHdr = NULL;\r
607 Ptr = NULL;\r
608\r
609 BlockSize = BlockIo->Media->BlockSize;\r
490b5ea1 610 MediaId = BlockIo->Media->MediaId;\r
adbcbf8f 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
071b7221 630 Status = DiskIo->WriteDisk (\r
631 DiskIo,\r
490b5ea1 632 MediaId,\r
633 MultU64x32 (PartHdr->MyLBA, (UINT32) BlockSize),\r
071b7221 634 BlockSize,\r
635 PartHdr\r
636 );\r
adbcbf8f 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
071b7221 643 DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));\r
adbcbf8f 644 Status = EFI_OUT_OF_RESOURCES;\r
645 goto Done;\r
646 }\r
647\r
648 Status = DiskIo->ReadDisk (\r
649 DiskIo,\r
490b5ea1 650 MediaId,\r
651 MultU64x32(PartHeader->PartitionEntryLBA, (UINT32) BlockSize),\r
adbcbf8f 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
490b5ea1 661 MediaId,\r
662 MultU64x32(PEntryLBA, (UINT32) BlockSize),\r
adbcbf8f 663 PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,\r
664 Ptr\r
665 );\r
666\r
667Done:\r
668 FreePool (PartHdr);\r
ff61847d 669\r
670 if (Ptr != NULL) {\r
671 FreePool (Ptr);\r
672 }\r
adbcbf8f 673\r
674 if (EFI_ERROR (Status)) {\r
675 return FALSE;\r
676 }\r
677\r
678 return TRUE;\r
679}\r
680\r
adbcbf8f 681/**\r
dc204d5a
JY
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
adbcbf8f 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
a8d0c20e 692\r
adbcbf8f 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
d0e9c3ca
RN
701 EFI_LBA StartingLBA;\r
702 EFI_LBA EndingLBA;\r
703 EFI_PARTITION_ENTRY *Entry;\r
704 UINTN Index1;\r
705 UINTN Index2;\r
adbcbf8f 706\r
707 DEBUG ((EFI_D_INFO, " start check partition entries\n"));\r
708 for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {\r
d0e9c3ca
RN
709 Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);\r
710 if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {\r
adbcbf8f 711 continue;\r
712 }\r
713\r
d0e9c3ca
RN
714 StartingLBA = Entry->StartingLBA;\r
715 EndingLBA = Entry->EndingLBA;\r
adbcbf8f 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
d0e9c3ca
RN
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
adbcbf8f 732\r
d0e9c3ca
RN
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
adbcbf8f 736 continue;\r
737 }\r
738\r
d0e9c3ca 739 if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {\r
adbcbf8f 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
adbcbf8f 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
ea7cb08c 755 Updates the CRC32 value in the table header.\r
adbcbf8f 756\r
a8d0c20e 757 @param Hdr Table to update\r
adbcbf8f 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
ea7cb08c 770 Updates the CRC32 value in the table header.\r
adbcbf8f 771\r
a8d0c20e 772 @param Size The size of the table\r
773 @param Hdr Table to update\r
adbcbf8f 774\r
775**/\r
776VOID\r
777PartitionSetCrcAltSize (\r
778 IN UINTN Size,\r
779 IN OUT EFI_TABLE_HEADER *Hdr\r
780 )\r
adbcbf8f 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
ea7cb08c 791 Checks the CRC32 value in the table header.\r
adbcbf8f 792\r
a8d0c20e 793 @param MaxSize Max Size limit\r
794 @param Hdr Table to check\r
adbcbf8f 795\r
a8d0c20e 796 @return TRUE CRC Valid\r
797 @return FALSE CRC Invalid\r
adbcbf8f 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
ea7cb08c 811 Checks the CRC32 value in the table header.\r
adbcbf8f 812\r
a8d0c20e 813 @param MaxSize Max Size limit\r
814 @param Size The size of the table\r
815 @param Hdr Table to check\r
adbcbf8f 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
ea7cb08c 841 if ((MaxSize != 0) && (Size > MaxSize)) {\r
adbcbf8f 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