2 Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
5 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
6 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"
20 Install child handles if the Handle supports GPT partition structure.
22 @param[in] BlockIo Parent BlockIo interface.
23 @param[in] DiskIo Disk Io protocol.
24 @param[in] Lba The starting Lba of the Partition Table
25 @param[out] PartHeader Stores the partition table that is read
27 @retval TRUE The partition table is valid
28 @retval FALSE The partition table is not valid
32 PartitionValidGptTable (
33 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
34 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
36 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
40 Check if the CRC field in the Partition table header is valid
41 for Partition entry array.
43 @param[in] BlockIo Parent BlockIo interface
44 @param[in] DiskIo Disk Io Protocol.
45 @param[in] PartHeader Partition table header structure
47 @retval TRUE the CRC is valid
48 @retval FALSE the CRC is invalid
52 PartitionCheckGptEntryArrayCRC (
53 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
54 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
55 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
60 Restore Partition Table to its alternate place
61 (Primary -> Backup or Backup -> Primary).
63 @param[in] BlockIo Parent BlockIo interface.
64 @param[in] DiskIo Disk Io Protocol.
65 @param[in] PartHeader Partition table header structure.
67 @retval TRUE Restoring succeeds
68 @retval FALSE Restoring failed
72 PartitionRestoreGptTable (
73 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
74 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
75 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
80 Restore Partition Table to its alternate place.
81 (Primary -> Backup or Backup -> Primary)
83 @param[in] PartHeader Partition table header structure
84 @param[in] PartEntry The partition entry array
85 @param[out] PEntryStatus the partition entry status array
86 recording the status of each partition
90 PartitionCheckGptEntry (
91 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
92 IN EFI_PARTITION_ENTRY
*PartEntry
,
93 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
98 Checks the CRC32 value in the table header.
100 @param MaxSize Max Size limit
101 @param Size The size of the table
102 @param Hdr Table to check
104 @return TRUE CRC Valid
105 @return FALSE CRC Invalid
109 PartitionCheckCrcAltSize (
112 IN OUT EFI_TABLE_HEADER
*Hdr
117 Checks the CRC32 value in the table header.
119 @param MaxSize Max Size limit
120 @param Hdr Table to check
122 @return TRUE CRC Valid
123 @return FALSE CRC Invalid
129 IN OUT EFI_TABLE_HEADER
*Hdr
134 Updates the CRC32 value in the table header.
136 @param Size The size of the table
137 @param Hdr Table to update
141 PartitionSetCrcAltSize (
143 IN OUT EFI_TABLE_HEADER
*Hdr
148 Updates the CRC32 value in the table header.
150 @param Hdr Table to update
155 IN OUT EFI_TABLE_HEADER
*Hdr
159 Install child handles if the Handle supports GPT partition structure.
161 @param[in] This Calling context.
162 @param[in] Handle Parent Handle.
163 @param[in] DiskIo Parent DiskIo interface.
164 @param[in] BlockIo Parent BlockIo interface.
165 @param[in] BlockIo2 Parent BlockIo2 interface.
166 @param[in] DevicePath Parent Device Path.
168 @retval EFI_SUCCESS Valid GPT disk.
169 @retval EFI_MEDIA_CHANGED Media changed Detected.
170 @retval other Not a valid GPT disk.
174 PartitionInstallGptChildHandles (
175 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
176 IN EFI_HANDLE Handle
,
177 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
178 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
179 IN EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
,
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
;
196 ProtectiveMbr
= NULL
;
197 PrimaryHeader
= NULL
;
202 BlockSize
= BlockIo
->Media
->BlockSize
;
203 LastBlock
= BlockIo
->Media
->LastBlock
;
204 MediaId
= BlockIo
->Media
->MediaId
;
206 DEBUG ((EFI_D_INFO
, " BlockSize : %d \n", BlockSize
));
207 DEBUG ((EFI_D_INFO
, " LastBlock : %lx \n", LastBlock
));
209 GptValidStatus
= EFI_NOT_FOUND
;
212 // Allocate a buffer for the Protective MBR
214 ProtectiveMbr
= AllocatePool (BlockSize
);
215 if (ProtectiveMbr
== NULL
) {
216 return EFI_NOT_FOUND
;
220 // Read the Protective MBR from LBA #0
222 Status
= DiskIo
->ReadDisk (
229 if (EFI_ERROR (Status
)) {
230 GptValidStatus
= Status
;
235 // Verify that the Protective MBR is valid
237 for (Index
= 0; Index
< MAX_MBR_PARTITIONS
; Index
++) {
238 if (ProtectiveMbr
->Partition
[Index
].BootIndicator
== 0x00 &&
239 ProtectiveMbr
->Partition
[Index
].OSIndicator
== PMBR_GPT_PARTITION
&&
240 UNPACK_UINT32 (ProtectiveMbr
->Partition
[Index
].StartingLBA
) == 1
245 if (Index
== MAX_MBR_PARTITIONS
) {
250 // Allocate the GPT structures
252 PrimaryHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
253 if (PrimaryHeader
== NULL
) {
257 BackupHeader
= AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER
));
258 if (BackupHeader
== NULL
) {
263 // Check primary and backup partition tables
265 if (!PartitionValidGptTable (BlockIo
, DiskIo
, PRIMARY_PART_HEADER_LBA
, PrimaryHeader
)) {
266 DEBUG ((EFI_D_INFO
, " Not Valid primary partition table\n"));
268 if (!PartitionValidGptTable (BlockIo
, DiskIo
, LastBlock
, BackupHeader
)) {
269 DEBUG ((EFI_D_INFO
, " Not Valid backup partition table\n"));
272 DEBUG ((EFI_D_INFO
, " Valid backup partition table\n"));
273 DEBUG ((EFI_D_INFO
, " Restore primary partition table by the backup\n"));
274 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, BackupHeader
)) {
275 DEBUG ((EFI_D_INFO
, " Restore primary partition table error\n"));
278 if (PartitionValidGptTable (BlockIo
, DiskIo
, BackupHeader
->AlternateLBA
, PrimaryHeader
)) {
279 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
282 } else if (!PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
283 DEBUG ((EFI_D_INFO
, " Valid primary and !Valid backup partition table\n"));
284 DEBUG ((EFI_D_INFO
, " Restore backup partition table by the primary\n"));
285 if (!PartitionRestoreGptTable (BlockIo
, DiskIo
, PrimaryHeader
)) {
286 DEBUG ((EFI_D_INFO
, " Restore backup partition table error\n"));
289 if (PartitionValidGptTable (BlockIo
, DiskIo
, PrimaryHeader
->AlternateLBA
, BackupHeader
)) {
290 DEBUG ((EFI_D_INFO
, " Restore backup partition table success\n"));
295 DEBUG ((EFI_D_INFO
, " Valid primary and Valid backup partition table\n"));
298 // Read the EFI Partition Entries
300 PartEntry
= AllocatePool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY
));
301 if (PartEntry
== NULL
) {
302 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
306 Status
= DiskIo
->ReadDisk (
309 MultU64x32(PrimaryHeader
->PartitionEntryLBA
, BlockSize
),
310 PrimaryHeader
->NumberOfPartitionEntries
* (PrimaryHeader
->SizeOfPartitionEntry
),
313 if (EFI_ERROR (Status
)) {
314 GptValidStatus
= Status
;
315 DEBUG ((EFI_D_ERROR
, " Partition Entry ReadDisk error\n"));
319 DEBUG ((EFI_D_INFO
, " Partition entries read block success\n"));
321 DEBUG ((EFI_D_INFO
, " Number of partition entries: %d\n", PrimaryHeader
->NumberOfPartitionEntries
));
323 PEntryStatus
= AllocateZeroPool (PrimaryHeader
->NumberOfPartitionEntries
* sizeof (EFI_PARTITION_ENTRY_STATUS
));
324 if (PEntryStatus
== NULL
) {
325 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
330 // Check the integrity of partition entries
332 PartitionCheckGptEntry (PrimaryHeader
, PartEntry
, PEntryStatus
);
335 // If we got this far the GPT layout of the disk is valid and we should return true
337 GptValidStatus
= EFI_SUCCESS
;
340 // Create child device handles
342 for (Index
= 0; Index
< PrimaryHeader
->NumberOfPartitionEntries
; Index
++) {
343 if (CompareGuid (&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
) ||
344 PEntryStatus
[Index
].OutOfRange
||
345 PEntryStatus
[Index
].Overlap
||
346 PEntryStatus
[Index
].OsSpecific
349 // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
355 ZeroMem (&HdDev
, sizeof (HdDev
));
356 HdDev
.Header
.Type
= MEDIA_DEVICE_PATH
;
357 HdDev
.Header
.SubType
= MEDIA_HARDDRIVE_DP
;
358 SetDevicePathNodeLength (&HdDev
.Header
, sizeof (HdDev
));
360 HdDev
.PartitionNumber
= (UINT32
) Index
+ 1;
361 HdDev
.MBRType
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
362 HdDev
.SignatureType
= SIGNATURE_TYPE_GUID
;
363 HdDev
.PartitionStart
= PartEntry
[Index
].StartingLBA
;
364 HdDev
.PartitionSize
= PartEntry
[Index
].EndingLBA
- PartEntry
[Index
].StartingLBA
+ 1;
365 CopyMem (HdDev
.Signature
, &PartEntry
[Index
].UniquePartitionGUID
, sizeof (EFI_GUID
));
367 DEBUG ((EFI_D_INFO
, " Index : %d\n", (UINT32
) Index
));
368 DEBUG ((EFI_D_INFO
, " Start LBA : %lx\n", (UINT64
) HdDev
.PartitionStart
));
369 DEBUG ((EFI_D_INFO
, " End LBA : %lx\n", (UINT64
) PartEntry
[Index
].EndingLBA
));
370 DEBUG ((EFI_D_INFO
, " Partition size: %lx\n", (UINT64
) HdDev
.PartitionSize
));
371 DEBUG ((EFI_D_INFO
, " Start : %lx", MultU64x32 (PartEntry
[Index
].StartingLBA
, BlockSize
)));
372 DEBUG ((EFI_D_INFO
, " End : %lx\n", MultU64x32 (PartEntry
[Index
].EndingLBA
, BlockSize
)));
374 Status
= PartitionInstallChildHandle (
381 (EFI_DEVICE_PATH_PROTOCOL
*) &HdDev
,
382 PartEntry
[Index
].StartingLBA
,
383 PartEntry
[Index
].EndingLBA
,
385 CompareGuid(&PartEntry
[Index
].PartitionTypeGUID
, &gEfiPartTypeSystemPartGuid
)
389 DEBUG ((EFI_D_INFO
, "Prepare to Free Pool\n"));
392 if (ProtectiveMbr
!= NULL
) {
393 FreePool (ProtectiveMbr
);
395 if (PrimaryHeader
!= NULL
) {
396 FreePool (PrimaryHeader
);
398 if (BackupHeader
!= NULL
) {
399 FreePool (BackupHeader
);
401 if (PartEntry
!= NULL
) {
402 FreePool (PartEntry
);
404 if (PEntryStatus
!= NULL
) {
405 FreePool (PEntryStatus
);
408 return GptValidStatus
;
412 Install child handles if the Handle supports GPT partition structure.
414 @param[in] BlockIo Parent BlockIo interface.
415 @param[in] DiskIo Disk Io protocol.
416 @param[in] Lba The starting Lba of the Partition Table
417 @param[out] PartHeader Stores the partition table that is read
419 @retval TRUE The partition table is valid
420 @retval FALSE The partition table is not valid
424 PartitionValidGptTable (
425 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
426 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
428 OUT EFI_PARTITION_TABLE_HEADER
*PartHeader
433 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
436 BlockSize
= BlockIo
->Media
->BlockSize
;
437 MediaId
= BlockIo
->Media
->MediaId
;
438 PartHdr
= AllocateZeroPool (BlockSize
);
440 if (PartHdr
== NULL
) {
441 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
445 // Read the EFI Partition Table Header
447 Status
= DiskIo
->ReadDisk (
450 MultU64x32 (Lba
, BlockSize
),
454 if (EFI_ERROR (Status
)) {
459 if ((PartHdr
->Header
.Signature
!= EFI_PTAB_HEADER_ID
) ||
460 !PartitionCheckCrc (BlockSize
, &PartHdr
->Header
) ||
461 PartHdr
->MyLBA
!= Lba
463 DEBUG ((EFI_D_INFO
, "Invalid efi partition table header\n"));
468 CopyMem (PartHeader
, PartHdr
, sizeof (EFI_PARTITION_TABLE_HEADER
));
469 if (!PartitionCheckGptEntryArrayCRC (BlockIo
, DiskIo
, PartHeader
)) {
474 DEBUG ((EFI_D_INFO
, " Valid efi partition table header\n"));
480 Check if the CRC field in the Partition table header is valid
481 for Partition entry array.
483 @param[in] BlockIo Parent BlockIo interface
484 @param[in] DiskIo Disk Io Protocol.
485 @param[in] PartHeader Partition table header structure
487 @retval TRUE the CRC is valid
488 @retval FALSE the CRC is invalid
492 PartitionCheckGptEntryArrayCRC (
493 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
494 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
495 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
504 // Read the EFI Partition Entries
506 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
508 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
512 Status
= DiskIo
->ReadDisk (
514 BlockIo
->Media
->MediaId
,
515 MultU64x32(PartHeader
->PartitionEntryLBA
, BlockIo
->Media
->BlockSize
),
516 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
519 if (EFI_ERROR (Status
)) {
524 Size
= PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
;
526 Status
= gBS
->CalculateCrc32 (Ptr
, Size
, &Crc
);
527 if (EFI_ERROR (Status
)) {
528 DEBUG ((EFI_D_ERROR
, "CheckPEntryArrayCRC: Crc calculation failed\n"));
535 return (BOOLEAN
) (PartHeader
->PartitionEntryArrayCRC32
== Crc
);
540 Restore Partition Table to its alternate place
541 (Primary -> Backup or Backup -> Primary).
543 @param[in] BlockIo Parent BlockIo interface.
544 @param[in] DiskIo Disk Io Protocol.
545 @param[in] PartHeader Partition table header structure.
547 @retval TRUE Restoring succeeds
548 @retval FALSE Restoring failed
552 PartitionRestoreGptTable (
553 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
554 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
555 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
560 EFI_PARTITION_TABLE_HEADER
*PartHdr
;
568 BlockSize
= BlockIo
->Media
->BlockSize
;
569 MediaId
= BlockIo
->Media
->MediaId
;
571 PartHdr
= AllocateZeroPool (BlockSize
);
573 if (PartHdr
== NULL
) {
574 DEBUG ((EFI_D_ERROR
, "Allocate pool error\n"));
578 PEntryLBA
= (PartHeader
->MyLBA
== PRIMARY_PART_HEADER_LBA
) ? \
579 (PartHeader
->LastUsableLBA
+ 1) : \
580 (PRIMARY_PART_HEADER_LBA
+ 1);
582 CopyMem (PartHdr
, PartHeader
, sizeof (EFI_PARTITION_TABLE_HEADER
));
584 PartHdr
->MyLBA
= PartHeader
->AlternateLBA
;
585 PartHdr
->AlternateLBA
= PartHeader
->MyLBA
;
586 PartHdr
->PartitionEntryLBA
= PEntryLBA
;
587 PartitionSetCrc ((EFI_TABLE_HEADER
*) PartHdr
);
589 Status
= DiskIo
->WriteDisk (
592 MultU64x32 (PartHdr
->MyLBA
, (UINT32
) BlockSize
),
596 if (EFI_ERROR (Status
)) {
600 Ptr
= AllocatePool (PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
);
602 DEBUG ((EFI_D_ERROR
, " Allocate pool error\n"));
603 Status
= EFI_OUT_OF_RESOURCES
;
607 Status
= DiskIo
->ReadDisk (
610 MultU64x32(PartHeader
->PartitionEntryLBA
, (UINT32
) BlockSize
),
611 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
614 if (EFI_ERROR (Status
)) {
618 Status
= DiskIo
->WriteDisk (
621 MultU64x32(PEntryLBA
, (UINT32
) BlockSize
),
622 PartHeader
->NumberOfPartitionEntries
* PartHeader
->SizeOfPartitionEntry
,
633 if (EFI_ERROR (Status
)) {
642 Restore Partition Table to its alternate place.
643 (Primary -> Backup or Backup -> Primary)
645 @param[in] PartHeader Partition table header structure
646 @param[in] PartEntry The partition entry array
647 @param[out] PEntryStatus the partition entry status array
648 recording the status of each partition
652 PartitionCheckGptEntry (
653 IN EFI_PARTITION_TABLE_HEADER
*PartHeader
,
654 IN EFI_PARTITION_ENTRY
*PartEntry
,
655 OUT EFI_PARTITION_ENTRY_STATUS
*PEntryStatus
664 DEBUG ((EFI_D_INFO
, " start check partition entries\n"));
665 for (Index1
= 0; Index1
< PartHeader
->NumberOfPartitionEntries
; Index1
++) {
666 if (CompareGuid (&PartEntry
[Index1
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
670 StartingLBA
= PartEntry
[Index1
].StartingLBA
;
671 EndingLBA
= PartEntry
[Index1
].EndingLBA
;
672 if (StartingLBA
> EndingLBA
||
673 StartingLBA
< PartHeader
->FirstUsableLBA
||
674 StartingLBA
> PartHeader
->LastUsableLBA
||
675 EndingLBA
< PartHeader
->FirstUsableLBA
||
676 EndingLBA
> PartHeader
->LastUsableLBA
678 PEntryStatus
[Index1
].OutOfRange
= TRUE
;
682 for (Index2
= Index1
+ 1; Index2
< PartHeader
->NumberOfPartitionEntries
; Index2
++) {
684 if (CompareGuid (&PartEntry
[Index2
].PartitionTypeGUID
, &gEfiPartTypeUnusedGuid
)) {
688 if (PartEntry
[Index2
].EndingLBA
>= StartingLBA
&& PartEntry
[Index2
].StartingLBA
<= EndingLBA
) {
690 // This region overlaps with the Index1'th region
692 PEntryStatus
[Index1
].Overlap
= TRUE
;
693 PEntryStatus
[Index2
].Overlap
= TRUE
;
699 Attributes
= PartEntry
[Index1
].Attributes
;
700 if ((Attributes
& BIT1
) != 0) {
702 // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
704 PEntryStatus
[Index1
].OsSpecific
= TRUE
;
708 DEBUG ((EFI_D_INFO
, " End check partition entries\n"));
713 Updates the CRC32 value in the table header.
715 @param Hdr Table to update
720 IN OUT EFI_TABLE_HEADER
*Hdr
723 PartitionSetCrcAltSize (Hdr
->HeaderSize
, Hdr
);
728 Updates the CRC32 value in the table header.
730 @param Size The size of the table
731 @param Hdr Table to update
735 PartitionSetCrcAltSize (
737 IN OUT EFI_TABLE_HEADER
*Hdr
743 gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
749 Checks the CRC32 value in the table header.
751 @param MaxSize Max Size limit
752 @param Hdr Table to check
754 @return TRUE CRC Valid
755 @return FALSE CRC Invalid
761 IN OUT EFI_TABLE_HEADER
*Hdr
764 return PartitionCheckCrcAltSize (MaxSize
, Hdr
->HeaderSize
, Hdr
);
769 Checks the CRC32 value in the table header.
771 @param MaxSize Max Size limit
772 @param Size The size of the table
773 @param Hdr Table to check
775 @return TRUE CRC Valid
776 @return FALSE CRC Invalid
780 PartitionCheckCrcAltSize (
783 IN OUT EFI_TABLE_HEADER
*Hdr
794 // If header size is 0 CRC will pass so return FALSE here
799 if ((MaxSize
!= 0) && (Size
> MaxSize
)) {
800 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Size > MaxSize\n"));
804 // clear old crc from header
809 Status
= gBS
->CalculateCrc32 ((UINT8
*) Hdr
, Size
, &Crc
);
810 if (EFI_ERROR (Status
)) {
811 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc calculation failed\n"));
824 DEBUG ((EFI_D_ERROR
, "CheckCrc32: Crc check failed\n"));
828 return (BOOLEAN
) (OrgCrc
== Crc
);