2 Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
5 Copyright (c) 2006 - 2009, Intel Corporation. <BR>
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "Partition.h"
21 Install child handles if the Handle supports GPT partition structure.
23 @param[in] BlockIo Parent BlockIo interface
24 @param[in] DiskIo Disk Io protocol.
25 @param[in] Lba The starting Lba of the Partition Table
26 @param[out] PartHeader Stores the partition table that is read
28 @retval TRUE The partition table is valid
29 @retval FALSE The partition table is not valid
33 PartitionValidGptTable (
34 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
35 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
37 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
42 Check if the CRC field in the Partition table header is valid
43 for Partition entry array.
45 @param[in] BlockIo Parent BlockIo interface
46 @param[in] DiskIo Disk Io Protocol.
47 @param[in] PartHeader Partition table header structure
49 @retval TRUE the CRC is valid
50 @retval FALSE the CRC is invalid
54 PartitionCheckGptEntryArrayCRC (
55 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
56 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
57 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
62 Restore Partition Table to its alternate place
63 (Primary -> Backup or Backup -> Primary)
65 @param[in] BlockIo Parent BlockIo interface
66 @param[in] DiskIo Disk Io Protocol.
67 @param[in] PartHeader Partition table header structure
69 @retval TRUE Restoring succeeds
70 @retval FALSE Restoring failed
74 PartitionRestoreGptTable (
75 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
76 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
77 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
82 Restore Partition Table to its alternate place.
83 (Primary -> Backup or Backup -> Primary)
85 @param[in] PartHeader Partition table header structure
86 @param[in] PartEntry The partition entry array
87 @param[out] PEntryStatus the partition entry status array
88 recording the status of each partition
92 PartitionCheckGptEntry (
93 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
94 IN EFI_PARTITION_ENTRY
*PartEntry
,
95 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
100 Checks the CRC32 value in the table header.
102 @param MaxSize Max Size limit
103 @param Size The size of the table
104 @param Hdr Table to check
106 @return TRUE CRC Valid
107 @return FALSE CRC Invalid
111 PartitionCheckCrcAltSize (
114 IN OUT EFI_TABLE_HEADER
*Hdr
119 Checks the CRC32 value in the table header.
121 @param MaxSize Max Size limit
122 @param Hdr Table to check
124 @return TRUE CRC Valid
125 @return FALSE CRC Invalid
131 IN OUT EFI_TABLE_HEADER
*Hdr
136 Updates the CRC32 value in the table header.
138 @param Size The size of the table
139 @param Hdr Table to update
143 PartitionSetCrcAltSize (
145 IN OUT EFI_TABLE_HEADER
*Hdr
150 Updates the CRC32 value in the table header.
152 @param Hdr Table to update
157 IN OUT EFI_TABLE_HEADER
*Hdr
161 Install child handles if the Handle supports GPT partition structure.
163 @param[in] This - Calling context.
164 @param[in] Handle - Parent Handle
165 @param[in] DiskIo - Parent DiskIo interface
166 @param[in] BlockIo - Parent BlockIo interface
167 @param[in] DevicePath - Parent Device Path
169 @retval EFI_SUCCESS Valid GPT disk
170 @retval EFI_MEDIA_CHANGED Media changed Detected
171 @retval other Not a valid GPT disk
175 PartitionInstallGptChildHandles (
176 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
177 IN EFI_HANDLE Handle
,
178 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
179 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
180 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
186 MASTER_BOOT_RECORD
*ProtectiveMbr
;
187 EFI_PARTITION_TABLE_HEADER
*PrimaryHeader
;
188 EFI_PARTITION_TABLE_HEADER
*BackupHeader
;
189 EFI_PARTITION_ENTRY
*PartEntry
;
190 EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
;
192 EFI_STATUS GptValidStatus
;
193 HARDDRIVE_DEVICE_PATH HdDev
;
195 ProtectiveMbr
= NULL
;
196 PrimaryHeader
= NULL
;
201 BlockSize
= BlockIo
->Media
->BlockSize
;
202 LastBlock
= BlockIo
->Media
->LastBlock
;
204 DEBUG ((EFI_D_INFO
, " BlockSize : %d \n", BlockSize
));
205 DEBUG ((EFI_D_INFO
, " LastBlock : %lx \n", LastBlock
));
207 GptValidStatus
= EFI_NOT_FOUND
;
210 // Allocate a buffer for the Protective MBR
212 ProtectiveMbr
= AllocatePool (BlockSize
);
213 if (ProtectiveMbr
== NULL
) {
214 return EFI_NOT_FOUND
;
218 // Read the Protective MBR from LBA #0
220 Status
= DiskIo
->ReadDisk (
222 BlockIo
->Media
->MediaId
,
224 BlockIo
->Media
->BlockSize
,
227 if (EFI_ERROR (Status
)) {
228 GptValidStatus
= Status
;
232 // Verify that the Protective MBR is valid
234 for (Index
= 0; Index
< MAX_MBR_PARTITIONS
; Index
++) {
235 if (ProtectiveMbr
->Partition
[Index
].BootIndicator
== 0x00 &&
236 ProtectiveMbr
->Partition
[Index
].OSIndicator
== PMBR_GPT_PARTITION
&&
237 UNPACK_UINT32 (ProtectiveMbr
->Partition
[Index
].StartingLBA
) == 1
242 if (Index
== MAX_MBR_PARTITIONS
) {
247 // Allocate the GPT structures
249 PrimaryHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
250 if (PrimaryHeader
== NULL
) {
254 BackupHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
255 if (BackupHeader
== NULL
) {
260 // Check primary and backup partition tables
262 if (!PartitionValidGptTable (BlockIo
, DiskIo
, PRIMARY_PART_HEADER_LBA
, PrimaryHeader
)) {
263 DEBUG ((EFI_D_INFO
, " Not Valid primary partition table\n"));
265 if (!PartitionValidGptTable (BlockIo
, DiskIo
, LastBlock
, BackupHeader
)) {
266 DEBUG ((EFI_D_INFO
, " Not Valid backup partition table\n"));
269 DEBUG ((EFI_D_INFO
, " Valid backup partition table\n"));
270 DEBUG ((EFI_D_INFO
, " Restore primary partition table by the backup\n"));
271 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, BackupHeader
)) {
272 DEBUG ((EFI_D_INFO
, " Restore primary partition table error\n"));
275 if (PartitionValidGptTable (BlockIo
, DiskIo
, BackupHeader
->AlternateLBA
, PrimaryHeader
)) {
276 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
279 } else if (!PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
280 DEBUG ((EFI_D_INFO
, " Valid primary and !Valid backup partition table\n"));
281 DEBUG ((EFI_D_INFO
, " Restore backup partition table by the primary\n"));
282 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, PrimaryHeader
)) {
283 DEBUG ((EFI_D_INFO
, " Restore backup partition table error\n"));
286 if (PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
287 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
292 DEBUG ((EFI_D_INFO
, " Valid primary and Valid backup partition table\n"));
295 // Read the EFI Partition Entries
297 PartEntry
= AllocatePool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY
));
298 if (PartEntry
== NULL
) {
299 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
303 Status
= DiskIo
->ReadDisk (
305 BlockIo
->Media
->MediaId
,
306 MultU64x32(PrimaryHeader
->PartitionEntryLBA
, BlockSize
),
307 PrimaryHeader
->NumberOfPartitionEntries
* (PrimaryHeader
->SizeOfPartitionEntry
),
310 if (EFI_ERROR (Status
)) {
311 GptValidStatus
= Status
;
312 DEBUG ((EFI_D_ERROR
, " Partition Entry ReadDisk error\n"));
316 DEBUG ((EFI_D_INFO
, " Partition entries read block success\n"));
318 DEBUG ((EFI_D_INFO
, " Number of partition entries: %d\n", PrimaryHeader
->NumberOfPartitionEntries
));
320 PEntryStatus
= AllocateZeroPool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY_STATUS
));
321 if (PEntryStatus
== NULL
) {
322 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
327 // Check the integrity of partition entries
329 PartitionCheckGptEntry (PrimaryHeader
, PartEntry
, PEntryStatus
);
332 // If we got this far the GPT layout of the disk is valid and we should return true
334 GptValidStatus
= EFI_SUCCESS
;
337 // Create child device handles
339 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
340 if (CompareGuid (&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
) ||
341 PEntryStatus
[Index
].OutOfRange
||
342 PEntryStatus
[Index
].Overlap
||
343 PEntryStatus
[Index
].OsSpecific
346 // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
352 ZeroMem (&HdDev
, sizeof (HdDev
));
353 HdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
354 HdDev
.Header
.SubType
= MEDIA_HARDDRIVE_DP
;
355 SetDevicePathNodeLength (&HdDev
.Header
, sizeof (HdDev
));
357 HdDev
.PartitionNumber
= (UINT32
) Index
+ 1;
358 HdDev
.MBRType
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
359 HdDev
.SignatureType
= SIGNATURE_TYPE_GUID
;
360 HdDev
.PartitionStart
= PartEntry
[Index
].StartingLBA
;
361 HdDev
.PartitionSize
= PartEntry
[Index
].EndingLBA
- PartEntry
[Index
].StartingLBA
+ 1;
362 CopyMem (HdDev
.Signature
, &PartEntry
[Index
].UniquePartitionGUID
, sizeof (EFI_GUID
));
364 DEBUG ((EFI_D_INFO
, " Index : %d\n", (UINT32
) Index
));
365 DEBUG ((EFI_D_INFO
, " Start LBA : %lx\n", (UINT64
) HdDev
.PartitionStart
));
366 DEBUG ((EFI_D_INFO
, " End LBA : %lx\n", (UINT64
) PartEntry
[Index
].EndingLBA
));
367 DEBUG ((EFI_D_INFO
, " Partition size: %lx\n", (UINT64
) HdDev
.PartitionSize
));
368 DEBUG ((EFI_D_INFO
, " Start : %lx", MultU64x32 (PartEntry
[Index
].StartingLBA
, BlockSize
)));
369 DEBUG ((EFI_D_INFO
, " End : %lx\n", MultU64x32 (PartEntry
[Index
].EndingLBA
, BlockSize
)));
371 Status
= PartitionInstallChildHandle (
377 (EFI_DEVICE_PATH_PROTOCOL
*) &HdDev
,
378 PartEntry
[Index
].StartingLBA
,
379 PartEntry
[Index
].EndingLBA
,
381 CompareGuid(&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeSystemPartGuid
)
385 DEBUG ((EFI_D_INFO
, "Prepare to Free Pool\n"));
388 if (ProtectiveMbr
!= NULL
) {
389 FreePool (ProtectiveMbr
);
391 if (PrimaryHeader
!= NULL
) {
392 FreePool (PrimaryHeader
);
394 if (BackupHeader
!= NULL
) {
395 FreePool (BackupHeader
);
397 if (PartEntry
!= NULL
) {
398 FreePool (PartEntry
);
400 if (PEntryStatus
!= NULL
) {
401 FreePool (PEntryStatus
);
404 return GptValidStatus
;
409 Install child handles if the Handle supports GPT partition structure.
411 @param[in] BlockIo Parent BlockIo interface
412 @param[in] DiskIo Disk Io protocol.
413 @param[in] Lba The starting Lba of the Partition Table
414 @param[out] PartHeader Stores the partition table that is read
416 @retval TRUE The partition table is valid
417 @retval FALSE The partition table is not valid
421 PartitionValidGptTable (
422 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
423 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
425 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
430 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
432 BlockSize
= BlockIo
->Media
->BlockSize
;
434 PartHdr
= AllocateZeroPool (BlockSize
);
436 if (PartHdr
== NULL
) {
437 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
441 // Read the EFI Partition Table Header
443 Status
= DiskIo
->ReadDisk (
445 BlockIo
->Media
->MediaId
,
446 MultU64x32 (Lba
, BlockSize
),
450 if (EFI_ERROR (Status
)) {
455 if ((PartHdr
->Header
.Signature
!= EFI_PTAB_HEADER_ID
) ||
456 !PartitionCheckCrc (BlockSize
, &PartHdr
->Header
) ||
457 PartHdr
->MyLBA
!= Lba
459 DEBUG ((EFI_D_INFO
, "Invalid efi partition table header\n"));
464 CopyMem (PartHeader
, PartHdr
, sizeof (EFI_PARTITION_TABLE_HEADER
));
465 if (!PartitionCheckGptEntryArrayCRC (BlockIo
, DiskIo
, PartHeader
)) {
470 DEBUG ((EFI_D_INFO
, " Valid efi partition table header\n"));
477 Check if the CRC field in the Partition table header is valid
478 for Partition entry array.
480 @param[in] BlockIo Parent BlockIo interface
481 @param[in] DiskIo Disk Io Protocol.
482 @param[in] PartHeader Partition table header structure
484 @retval TRUE the CRC is valid
485 @retval FALSE the CRC is invalid
489 PartitionCheckGptEntryArrayCRC (
490 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
491 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
492 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
501 // Read the EFI Partition Entries
503 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
505 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
509 Status
= DiskIo
->ReadDisk (
511 BlockIo
->Media
->MediaId
,
512 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
513 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
516 if (EFI_ERROR (Status
)) {
521 Size
= PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
;
523 Status
= gBS
->CalculateCrc32 (Ptr
, Size
, &Crc
);
524 if (EFI_ERROR (Status
)) {
525 DEBUG ((EFI_D_ERROR
, "CheckPEntryArrayCRC: Crc calculation failed\n"));
532 return (BOOLEAN
) (PartHeader
->PartitionEntryArrayCRC32
== Crc
);
537 Restore Partition Table to its alternate place
538 (Primary -> Backup or Backup -> Primary)
540 @param[in] BlockIo Parent BlockIo interface
541 @param[in] DiskIo Disk Io Protocol.
542 @param[in] PartHeader Partition table header structure
544 @retval TRUE Restoring succeeds
545 @retval FALSE Restoring failed
549 PartitionRestoreGptTable (
550 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
551 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
552 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
557 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
564 BlockSize
= BlockIo
->Media
->BlockSize
;
566 PartHdr
= AllocateZeroPool (BlockSize
);
568 if (PartHdr
== NULL
) {
569 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
573 PEntryLBA
= (PartHeader
->MyLBA
== PRIMARY_PART_HEADER_LBA
) ? \
574 (PartHeader
->LastUsableLBA
+ 1) : \
575 (PRIMARY_PART_HEADER_LBA
+ 1);
577 CopyMem (PartHdr
, PartHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
579 PartHdr
->MyLBA
= PartHeader
->AlternateLBA
;
580 PartHdr
->AlternateLBA
= PartHeader
->MyLBA
;
581 PartHdr
->PartitionEntryLBA
= PEntryLBA
;
582 PartitionSetCrc ((EFI_TABLE_HEADER
*) PartHdr
);
584 Status
= DiskIo
->WriteDisk (
586 BlockIo
->Media
->MediaId
,
587 MultU64x32 (PartHdr
->MyLBA
, BlockIo
->Media
->BlockSize
),
591 if (EFI_ERROR (Status
)) {
595 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
597 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
598 Status
= EFI_OUT_OF_RESOURCES
;
602 Status
= DiskIo
->ReadDisk (
604 BlockIo
->Media
->MediaId
,
605 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
606 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
609 if (EFI_ERROR (Status
)) {
613 Status
= DiskIo
->WriteDisk (
615 BlockIo
->Media
->MediaId
,
616 MultU64x32(PEntryLBA
, BlockIo
->Media
->BlockSize
),
617 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
628 if (EFI_ERROR (Status
)) {
637 Restore Partition Table to its alternate place.
638 (Primary -> Backup or Backup -> Primary)
640 @param[in] PartHeader Partition table header structure
641 @param[in] PartEntry The partition entry array
642 @param[out] PEntryStatus the partition entry status array
643 recording the status of each partition
647 PartitionCheckGptEntry (
648 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
649 IN EFI_PARTITION_ENTRY
*PartEntry
,
650 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
659 DEBUG ((EFI_D_INFO
, " start check partition entries\n"));
660 for (Index1
= 0; Index1
< PartHeader
->NumberOfPartitionEntries
; Index1
++) {
661 if (CompareGuid (&PartEntry
[Index1
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
665 StartingLBA
= PartEntry
[Index1
].StartingLBA
;
666 EndingLBA
= PartEntry
[Index1
].EndingLBA
;
667 if (StartingLBA
> EndingLBA
||
668 StartingLBA
< PartHeader
->FirstUsableLBA
||
669 StartingLBA
> PartHeader
->LastUsableLBA
||
670 EndingLBA
< PartHeader
->FirstUsableLBA
||
671 EndingLBA
> PartHeader
->LastUsableLBA
673 PEntryStatus
[Index1
].OutOfRange
= TRUE
;
677 for (Index2
= Index1
+ 1; Index2
< PartHeader
->NumberOfPartitionEntries
; Index2
++) {
679 if (CompareGuid (&PartEntry
[Index2
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
683 if (PartEntry
[Index2
].EndingLBA
>= StartingLBA
&& PartEntry
[Index2
].StartingLBA
<= EndingLBA
) {
685 // This region overlaps with the Index1'th region
687 PEntryStatus
[Index1
].Overlap
= TRUE
;
688 PEntryStatus
[Index2
].Overlap
= TRUE
;
694 Attributes
= PartEntry
[Index1
].Attributes
;
695 if ((Attributes
& BIT1
) != 0) {
697 // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
699 PEntryStatus
[Index1
].OsSpecific
= TRUE
;
703 DEBUG ((EFI_D_INFO
, " End check partition entries\n"));
708 Updates the CRC32 value in the table header.
710 @param Hdr Table to update
715 IN OUT EFI_TABLE_HEADER
*Hdr
718 PartitionSetCrcAltSize (Hdr
->HeaderSize
, Hdr
);
723 Updates the CRC32 value in the table header.
725 @param Size The size of the table
726 @param Hdr Table to update
730 PartitionSetCrcAltSize (
732 IN OUT EFI_TABLE_HEADER
*Hdr
738 gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
744 Checks the CRC32 value in the table header.
746 @param MaxSize Max Size limit
747 @param Hdr Table to check
749 @return TRUE CRC Valid
750 @return FALSE CRC Invalid
756 IN OUT EFI_TABLE_HEADER
*Hdr
759 return PartitionCheckCrcAltSize (MaxSize
, Hdr
->HeaderSize
, Hdr
);
764 Checks the CRC32 value in the table header.
766 @param MaxSize Max Size limit
767 @param Size The size of the table
768 @param Hdr Table to check
770 @return TRUE CRC Valid
771 @return FALSE CRC Invalid
775 PartitionCheckCrcAltSize (
778 IN OUT EFI_TABLE_HEADER
*Hdr
789 // If header size is 0 CRC will pass so return FALSE here
794 if ((MaxSize
!= 0) && (Size
> MaxSize
)) {
795 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Size > MaxSize\n"));
799 // clear old crc from header
804 Status
= gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
805 if (EFI_ERROR (Status
)) {
806 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc calculation failed\n"));
819 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc check failed\n"));
823 return (BOOLEAN
) (OrgCrc
== Crc
);