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