2 Source file for CD recovery PEIM
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "PeiCdExpress.h"
19 PEI_CD_EXPRESS_PRIVATE_DATA
*mPrivateData
= NULL
;
20 CHAR8
*mRecoveryFileName
;
21 UINTN mRecoveryFileNameSize
;
24 Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
25 installation notification
27 @param FileHandle The file handle of the image.
28 @param PeiServices General purpose services available to every PEIM.
30 @retval EFI_SUCCESS The function completed successfully.
31 @retval EFI_OUT_OF_RESOURCES There is not enough system memory.
37 IN EFI_PEI_FILE_HANDLE FileHandle
,
38 IN CONST EFI_PEI_SERVICES
**PeiServices
42 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
44 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
48 PrivateData
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*PrivateData
)));
49 if (PrivateData
== NULL
) {
50 return EFI_OUT_OF_RESOURCES
;
53 mRecoveryFileNameSize
= PcdGetSize(PcdRecoveryFileName
) / sizeof(CHAR16
);
54 mRecoveryFileName
= AllocatePool(mRecoveryFileNameSize
);
55 if (mRecoveryFileName
== NULL
) {
56 return EFI_OUT_OF_RESOURCES
;
58 Status
= UnicodeStrToAsciiStrS(PcdGetPtr(PcdRecoveryFileName
), mRecoveryFileName
, mRecoveryFileNameSize
);
59 if (EFI_ERROR(Status
)) {
64 // Initialize Private Data (to zero, as is required by subsequent operations)
66 ZeroMem (PrivateData
, sizeof (*PrivateData
));
67 PrivateData
->Signature
= PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE
;
69 PrivateData
->BlockBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (PEI_CD_BLOCK_SIZE
));
70 if (PrivateData
->BlockBuffer
== NULL
) {
71 return EFI_OUT_OF_RESOURCES
;
74 PrivateData
->CapsuleCount
= 0;
75 Status
= UpdateBlocksAndVolumes (PrivateData
, TRUE
);
76 Status
= UpdateBlocksAndVolumes (PrivateData
, FALSE
);
81 PrivateData
->DeviceRecoveryPpi
.GetNumberRecoveryCapsules
= GetNumberRecoveryCapsules
;
82 PrivateData
->DeviceRecoveryPpi
.GetRecoveryCapsuleInfo
= GetRecoveryCapsuleInfo
;
83 PrivateData
->DeviceRecoveryPpi
.LoadRecoveryCapsule
= LoadRecoveryCapsule
;
85 PrivateData
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
86 PrivateData
->PpiDescriptor
.Guid
= &gEfiPeiDeviceRecoveryModulePpiGuid
;
87 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->DeviceRecoveryPpi
;
89 Status
= PeiServicesInstallPpi (&PrivateData
->PpiDescriptor
);
90 if (EFI_ERROR (Status
)) {
91 return EFI_OUT_OF_RESOURCES
;
94 // PrivateData is allocated now, set it to the module variable
96 mPrivateData
= PrivateData
;
99 // Installs Block Io Ppi notification function
101 PrivateData
->NotifyDescriptor
.Flags
=
103 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
105 PrivateData
->NotifyDescriptor
.Guid
= &gEfiPeiVirtualBlockIoPpiGuid
;
106 PrivateData
->NotifyDescriptor
.Notify
= BlockIoNotifyEntry
;
108 PrivateData
->NotifyDescriptor2
.Flags
=
110 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
|
111 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
113 PrivateData
->NotifyDescriptor2
.Guid
= &gEfiPeiVirtualBlockIo2PpiGuid
;
114 PrivateData
->NotifyDescriptor2
.Notify
= BlockIoNotifyEntry
;
116 return PeiServicesNotifyPpi (&PrivateData
->NotifyDescriptor
);
121 BlockIo installation notification function.
123 This function finds out all the current Block IO PPIs in the system and add them
126 @param PeiServices Indirect reference to the PEI Services Table.
127 @param NotifyDescriptor Address of the notification descriptor data structure.
128 @param Ppi Address of the PPI that was installed.
130 @retval EFI_SUCCESS The function completes successfully.
136 IN EFI_PEI_SERVICES
**PeiServices
,
137 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
141 if (CompareGuid (NotifyDescriptor
->Guid
, &gEfiPeiVirtualBlockIo2PpiGuid
)) {
142 UpdateBlocksAndVolumes (mPrivateData
, TRUE
);
144 UpdateBlocksAndVolumes (mPrivateData
, FALSE
);
151 Finds out all the current Block IO PPIs in the system and add them into private data.
153 @param PrivateData The private data structure that contains recovery module information.
154 @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo.
156 @retval EFI_SUCCESS The blocks and volumes are updated successfully.
160 UpdateBlocksAndVolumes (
161 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
,
166 EFI_PEI_PPI_DESCRIPTOR
*TempPpiDescriptor
;
167 UINTN BlockIoPpiInstance
;
168 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
169 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
170 UINTN NumberBlockDevices
;
171 UINTN IndexBlockDevice
;
172 EFI_PEI_BLOCK_IO_MEDIA Media
;
173 EFI_PEI_BLOCK_IO2_MEDIA Media2
;
174 EFI_PEI_SERVICES
**PeiServices
;
176 IndexBlockDevice
= 0;
180 // Find out all Block Io Ppi instances within the system
181 // Assuming all device Block Io Peims are dispatched already
183 for (BlockIoPpiInstance
= 0; BlockIoPpiInstance
< PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI
; BlockIoPpiInstance
++) {
185 Status
= PeiServicesLocatePpi (
186 &gEfiPeiVirtualBlockIo2PpiGuid
,
189 (VOID
**) &BlockIo2Ppi
192 Status
= PeiServicesLocatePpi (
193 &gEfiPeiVirtualBlockIoPpiGuid
,
196 (VOID
**) &BlockIoPpi
199 if (EFI_ERROR (Status
)) {
201 // Done with all Block Io Ppis
206 PeiServices
= (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer ();
208 Status
= BlockIo2Ppi
->GetNumberOfBlockDevices (
214 Status
= BlockIoPpi
->GetNumberOfBlockDevices (
220 if (EFI_ERROR (Status
) || (NumberBlockDevices
== 0)) {
224 // Just retrieve the first block, should emulate all blocks.
226 for (IndexBlockDevice
= 1; IndexBlockDevice
<= NumberBlockDevices
&& PrivateData
->CapsuleCount
< PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER
; IndexBlockDevice
++) {
228 Status
= BlockIo2Ppi
->GetBlockDeviceMediaInfo (
234 if (EFI_ERROR (Status
) ||
235 !Media2
.MediaPresent
||
236 ((Media2
.InterfaceType
!= MSG_ATAPI_DP
) && (Media2
.InterfaceType
!= MSG_USB_DP
)) ||
237 (Media2
.BlockSize
!= PEI_CD_BLOCK_SIZE
)
241 DEBUG ((EFI_D_INFO
, "PeiCdExpress InterfaceType is %d\n", Media2
.InterfaceType
));
242 DEBUG ((EFI_D_INFO
, "PeiCdExpress MediaPresent is %d\n", Media2
.MediaPresent
));
243 DEBUG ((EFI_D_INFO
, "PeiCdExpress BlockSize is 0x%x\n", Media2
.BlockSize
));
245 Status
= BlockIoPpi
->GetBlockDeviceMediaInfo (
251 if (EFI_ERROR (Status
) ||
252 !Media
.MediaPresent
||
253 ((Media
.DeviceType
!= IdeCDROM
) && (Media
.DeviceType
!= UsbMassStorage
)) ||
254 (Media
.BlockSize
!= PEI_CD_BLOCK_SIZE
)
258 DEBUG ((EFI_D_INFO
, "PeiCdExpress DeviceType is %d\n", Media
.DeviceType
));
259 DEBUG ((EFI_D_INFO
, "PeiCdExpress MediaPresent is %d\n", Media
.MediaPresent
));
260 DEBUG ((EFI_D_INFO
, "PeiCdExpress BlockSize is 0x%x\n", Media
.BlockSize
));
263 DEBUG ((EFI_D_INFO
, "PeiCdExpress Status is %d\n", Status
));
265 DEBUG ((EFI_D_INFO
, "IndexBlockDevice is %d\n", IndexBlockDevice
));
266 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].IndexBlock
= IndexBlockDevice
;
268 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo2
= BlockIo2Ppi
;
270 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo
= BlockIoPpi
;
272 Status
= FindRecoveryCapsules (PrivateData
);
273 DEBUG ((EFI_D_INFO
, "Status is %d\n", Status
));
275 if (EFI_ERROR (Status
)) {
279 PrivateData
->CapsuleCount
++;
288 Finds out the recovery capsule in the current volume.
290 @param PrivateData The private data structure that contains recovery module information.
292 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
293 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
298 FindRecoveryCapsules (
299 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
304 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
305 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
311 PEI_CD_EXPRESS_DIR_FILE_RECORD
*RoorDirRecord
;
312 UINTN VolumeSpaceSize
;
313 BOOLEAN StartOfVolume
;
315 UINTN IndexBlockDevice
;
317 Buffer
= PrivateData
->BlockBuffer
;
318 BufferSize
= PEI_CD_BLOCK_SIZE
;
322 // The volume descriptor starts on Lba 16
324 IndexBlockDevice
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].IndexBlock
;
325 BlockIoPpi
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo
;
326 BlockIo2Ppi
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo2
;
329 StartOfVolume
= TRUE
;
333 SetMem (Buffer
, BufferSize
, 0);
334 if (BlockIo2Ppi
!= NULL
) {
335 Status
= BlockIo2Ppi
->ReadBlocks (
336 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
344 Status
= BlockIoPpi
->ReadBlocks (
345 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
353 if (EFI_ERROR (Status
)) {
357 StandardID
= (UINT8
*) (Buffer
+ PEI_CD_EXPRESS_STANDARD_ID_OFFSET
);
358 if (!StringCmp (StandardID
, (UINT8
*) PEI_CD_STANDARD_ID
, PEI_CD_EXPRESS_STANDARD_ID_SIZE
, TRUE
)) {
364 StartOfVolume
= FALSE
;
367 Type
= *(UINT8
*) (Buffer
+ PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET
);
368 if (Type
== PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR
) {
369 if (VolumeSpaceSize
== 0) {
372 Lba
= (OriginalLBA
+ VolumeSpaceSize
);
374 StartOfVolume
= TRUE
;
379 if (Type
!= PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY
) {
384 VolumeSpaceSize
= *(UINT32
*) (Buffer
+ PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET
);
386 RoorDirRecord
= (PEI_CD_EXPRESS_DIR_FILE_RECORD
*) (Buffer
+ PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET
);
387 RootDirLBA
= RoorDirRecord
->LocationOfExtent
[0];
389 Status
= RetrieveCapsuleFileFromRoot (PrivateData
, BlockIoPpi
, BlockIo2Ppi
, IndexBlockDevice
, RootDirLBA
);
390 if (!EFI_ERROR (Status
)) {
392 // Just look for the first primary descriptor
400 return EFI_NOT_FOUND
;
404 Retrieves the recovery capsule in root directory of the current volume.
406 @param PrivateData The private data structure that contains recovery module information.
407 @param BlockIoPpi The Block IO PPI used to access the volume.
408 @param BlockIo2Ppi The Block IO 2 PPI used to access the volume.
409 @param IndexBlockDevice The index of current block device.
410 @param Lba The starting logic block address to retrieve capsule.
412 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
413 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
419 RetrieveCapsuleFileFromRoot (
420 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
,
421 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
,
422 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
,
423 IN UINTN IndexBlockDevice
,
430 PEI_CD_EXPRESS_DIR_FILE_RECORD
*FileRecord
;
433 Buffer
= PrivateData
->BlockBuffer
;
434 BufferSize
= PEI_CD_BLOCK_SIZE
;
436 SetMem (Buffer
, BufferSize
, 0);
438 if (BlockIo2Ppi
!= NULL
) {
439 Status
= BlockIo2Ppi
->ReadBlocks (
440 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
448 Status
= BlockIoPpi
->ReadBlocks (
449 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
457 if (EFI_ERROR (Status
)) {
462 FileRecord
= (PEI_CD_EXPRESS_DIR_FILE_RECORD
*) Buffer
;
464 if (FileRecord
->Length
== 0) {
468 // Not intend to check other flag now
470 if ((FileRecord
->Flag
& PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR
) != 0) {
471 Buffer
+= FileRecord
->Length
;
475 for (Index
= 0; Index
< FileRecord
->FileIDLength
; Index
++) {
476 if (FileRecord
->FileID
[Index
] == ';') {
481 if (Index
!= mRecoveryFileNameSize
- 1) {
482 Buffer
+= FileRecord
->Length
;
486 if (!StringCmp (FileRecord
->FileID
, (UINT8
*)mRecoveryFileName
, mRecoveryFileNameSize
- 1, FALSE
)) {
487 Buffer
+= FileRecord
->Length
;
491 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleStartLBA
= FileRecord
->LocationOfExtent
[0];
492 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleBlockAlignedSize
=
494 FileRecord
->DataLength
[0] /
499 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleSize
= FileRecord
->DataLength
[0];
504 return EFI_NOT_FOUND
;
508 Returns the number of DXE capsules residing on the device.
510 This function searches for DXE capsules from the associated device and returns
511 the number and maximum size in bytes of the capsules discovered. Entry 1 is
512 assumed to be the highest load priority and entry N is assumed to be the lowest
515 @param[in] PeiServices General-purpose services that are available
517 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
519 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
520 output, *NumberRecoveryCapsules contains
521 the number of recovery capsule images
522 available for retrieval from this PEIM
525 @retval EFI_SUCCESS One or more capsules were discovered.
526 @retval EFI_DEVICE_ERROR A device error occurred.
527 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
532 GetNumberRecoveryCapsules (
533 IN EFI_PEI_SERVICES
**PeiServices
,
534 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
535 OUT UINTN
*NumberRecoveryCapsules
538 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
540 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
541 UpdateBlocksAndVolumes (PrivateData
, TRUE
);
542 UpdateBlocksAndVolumes (PrivateData
, FALSE
);
543 *NumberRecoveryCapsules
= PrivateData
->CapsuleCount
;
545 if (*NumberRecoveryCapsules
== 0) {
546 return EFI_NOT_FOUND
;
553 Returns the size and type of the requested recovery capsule.
555 This function gets the size and type of the capsule specified by CapsuleInstance.
557 @param[in] PeiServices General-purpose services that are available to every PEIM
558 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
560 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
561 the information. This parameter must be between
562 one and the value returned by GetNumberRecoveryCapsules()
563 in NumberRecoveryCapsules.
564 @param[out] Size A pointer to a caller-allocated UINTN in which
565 the size of the requested recovery module is
567 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
568 the type of the requested recovery capsule is
569 returned. The semantic meaning of the value
570 returned is defined by the implementation.
572 @retval EFI_SUCCESS One or more capsules were discovered.
573 @retval EFI_DEVICE_ERROR A device error occurred.
574 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
579 GetRecoveryCapsuleInfo (
580 IN EFI_PEI_SERVICES
**PeiServices
,
581 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
582 IN UINTN CapsuleInstance
,
584 OUT EFI_GUID
*CapsuleType
587 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
588 UINTN NumberRecoveryCapsules
;
591 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
593 if (EFI_ERROR (Status
)) {
597 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
598 CapsuleInstance
= CapsuleInstance
+ 1;
601 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
602 return EFI_NOT_FOUND
;
605 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
607 *Size
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleSize
;
610 &gRecoveryOnDataCdGuid
,
618 Loads a DXE capsule from some media into memory.
620 This function, by whatever mechanism, retrieves a DXE capsule from some device
621 and loads it into memory. Note that the published interface is device neutral.
623 @param[in] PeiServices General-purpose services that are available
625 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
627 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
628 @param[out] Buffer Specifies a caller-allocated buffer in which
629 the requested recovery capsule will be returned.
631 @retval EFI_SUCCESS The capsule was loaded correctly.
632 @retval EFI_DEVICE_ERROR A device error occurred.
633 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
638 LoadRecoveryCapsule (
639 IN EFI_PEI_SERVICES
**PeiServices
,
640 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
641 IN UINTN CapsuleInstance
,
646 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
647 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
648 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
649 UINTN NumberRecoveryCapsules
;
651 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
653 if (EFI_ERROR (Status
)) {
657 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
658 CapsuleInstance
= CapsuleInstance
+ 1;
661 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
662 return EFI_NOT_FOUND
;
665 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
666 BlockIoPpi
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].BlockIo
;
667 BlockIo2Ppi
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].BlockIo2
;
669 if (BlockIo2Ppi
!= NULL
) {
670 Status
= BlockIo2Ppi
->ReadBlocks (
673 PrivateData
->CapsuleData
[CapsuleInstance
- 1].IndexBlock
,
674 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleStartLBA
,
675 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleBlockAlignedSize
,
679 Status
= BlockIoPpi
->ReadBlocks (
682 PrivateData
->CapsuleData
[CapsuleInstance
- 1].IndexBlock
,
683 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleStartLBA
,
684 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleBlockAlignedSize
,
692 This function compares two ASCII strings in case sensitive/insensitive way.
694 @param Source1 The first string.
695 @param Source2 The second string.
696 @param Size The maximum comparison length.
697 @param CaseSensitive Flag to indicate whether the comparison is case sensitive.
699 @retval TRUE The two strings are the same.
700 @retval FALSE The two string are not the same.
708 IN BOOLEAN CaseSensitive
714 for (Index
= 0; Index
< Size
; Index
++) {
715 if (Source1
[Index
] == Source2
[Index
]) {
719 if (!CaseSensitive
) {
720 Dif
= (UINT8
) ((Source1
[Index
] > Source2
[Index
]) ? (Source1
[Index
] - Source2
[Index
]) : (Source2
[Index
] - Source1
[Index
]));
721 if (Dif
== ('a' - 'A')) {