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