alder_lake_bios/Intel/AlderLake/AlderLakeChipsetPkg/BiosRegionLockDxe/BiosRegionLockHelpFun.c

358 lines
12 KiB
C

/** @file
Provide some misc subfunctions
;******************************************************************************
;* Copyright (c) 2014 - 2020, Insyde Software Corporation. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include <Uefi.h>
#include <ChipsetAccess.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/IoLib.h>
#include <Library/S3BootScriptLib.h>
#include "BiosRegionLockInfo.h"
#include "BiosRegionLockHelpFun.h"
#include <Library/MmPciLib.h>
#include <Register/PchRegs.h>
#include <Register/SpiRegs.h>
//[-start-191225-IB16740000-add]// for PCI_DEVICE_NUMBER_PCH_LPC & PCI_FUNCTION_NUMBER_PCH_XHCI define
#include <PchBdfAssignment.h>
//[-end-191225-IB16740000-add]//
#define B_PCH_SPI_PRB_MASK 0x00001FFF
#define B_PCH_SPI_PR0_WPE BIT31
#define B_PCH_SPI_PR0_PRL_MASK 0x7FFF0000
#define B_PCH_SPI_PR0_PRB_MASK 0x00007FFF
/**
This function sort the BIOS regions described in BiosLock record array.
@param[in, out] Array Private protected BIOS region record.
@param[in] Length The length of input Array.
*/
STATIC
VOID
Sort (
IN OUT BIOS_REGION_LOCK_BASE *Array,
IN UINTN Length
)
{
UINTN Index1;
UINTN Index2;
UINTN Swap;
for (Index1 = 0; Index1 < Length; ++Index1) {
for (Index2 = Index1 + 1; Index2 <= Length; ++Index2) {
if (Array[Index1].Base < Array[Index2].Base) {
Swap = Array[Index1].Base;
Array[Index1].Base = Array[Index2].Base;
Array[Index2].Base = Swap;
Swap = Array[Index1].Length;
Array[Index1].Length = Array[Index2].Length;
Array[Index2].Length = Swap;
}
}
}
}
/**
This function merges the requested BIOS region to the private protected BIOS region record.
@param[in] BiosLock Private protected BIOS region record.
@param[in] BaseAddress The start address of the BIOS region which need to be merged.
@param[in] Length The Length of the BIOS region which need to be merged.
@retval EFI_OUT_OF_RESOURCES The max number of BIOS protect regions have been reached and the requested region
can not be merge to existing protected region.
@retval EFI_SUCCESS Merge successfully
*/
EFI_STATUS
MergeToBase (
IN BIOS_REGION_LOCK_BASE *BiosLock,
IN UINTN Base,
IN UINTN Length
)
{
INTN Index1;
INTN Index2;
UINTN Top1;
UINTN Top2;
BIOS_REGION_LOCK_BASE LockTemp[MAX_BIOS_REGION_LOCK + 1];
ZeroMem ((VOID *)LockTemp, sizeof(BIOS_REGION_LOCK_BASE) * (MAX_BIOS_REGION_LOCK + 1));
CopyMem ((VOID *)LockTemp, (VOID *)BiosLock, sizeof(BIOS_REGION_LOCK_BASE) * MAX_BIOS_REGION_LOCK);
for (Index1 = 0; Index1 <= MAX_BIOS_REGION_LOCK; ++Index1) {
if (LockTemp[Index1].Base == 0) {
LockTemp[Index1].Base = Base;
LockTemp[Index1].Length = Length;
break;
}
}
if (PcdGetBool (PcdStatusCodeUseSerial)) {
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "\nMergeToBase\n"));
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "Array Status (Before Sort)....\n"));
for (Index1 = 0; Index1 <= MAX_BIOS_REGION_LOCK; ++Index1) {
Top1 = LockTemp[Index1].Base + LockTemp[Index1].Length - 1;
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "%d => Base:%8x Length:%8x Top:%8x\n", Index1 + 1, LockTemp[Index1].Base, LockTemp[Index1].Length, Top1) );
}
}
Sort (LockTemp, MAX_BIOS_REGION_LOCK);
if (PcdGetBool (PcdStatusCodeUseSerial)) {
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "\nArray Status (After Sort)....\n"));
for (Index1 = 0; Index1 <= MAX_BIOS_REGION_LOCK; ++Index1) {
Top1 = LockTemp[Index1].Base + LockTemp[Index1].Length - 1;
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "%d => Base:%8x Length:%8x Top:%8x\n", Index1 + 1, LockTemp[Index1].Base, LockTemp[Index1].Length, Top1) );
}
}
for (Index1 = MAX_BIOS_REGION_LOCK - 1; Index1 >= 0; --Index1) {
Index2 = Index1 + 1;
if (LockTemp[Index2].Base == 0) {
continue;
}
Top1 = LockTemp[Index1].Base + LockTemp[Index1].Length - 1;
Top2 = LockTemp[Index2].Base + LockTemp[Index2].Length - 1;
if (LockTemp[Index2].Base == LockTemp[Index1].Base) {
if (LockTemp[Index2].Length > LockTemp[Index1].Length) {
LockTemp[Index1].Length = LockTemp[Index2].Length;
}
LockTemp[Index2].Base = 0;
LockTemp[Index2].Length = 0;
} else if ((LockTemp[Index1].Base - 1) <= Top2) {
if (Top2 > Top1) {
LockTemp[Index1].Base = LockTemp[Index2].Base;
LockTemp[Index1].Length = LockTemp[Index2].Length;
} else {
LockTemp[Index1].Base = LockTemp[Index2].Base;
LockTemp[Index1].Length = Top1 - LockTemp[Index2].Base + 1;
}
LockTemp[Index2].Base = 0;
LockTemp[Index2].Length = 0;
}
}
Sort (LockTemp, MAX_BIOS_REGION_LOCK);
if (PcdGetBool (PcdStatusCodeUseSerial)) {
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "\nArray Status (After Merge)....\n"));
for (Index1 = 0; Index1 <= MAX_BIOS_REGION_LOCK; ++Index1) {
Top1 = LockTemp[Index1].Base + LockTemp[Index1].Length - 1;
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "%d => Base:%8x Length:%8x Top:%8x\n", Index1 + 1, LockTemp[Index1].Base, LockTemp[Index1].Length, Top1));
}
}
if (LockTemp[MAX_BIOS_REGION_LOCK].Base != 0) {
return EFI_OUT_OF_RESOURCES;
}
CopyMem ((VOID *)BiosLock, (VOID *)LockTemp, sizeof (BIOS_REGION_LOCK_BASE) * MAX_BIOS_REGION_LOCK);
return EFI_SUCCESS;
}
/**
This function removes the requested BIOS region from the private protected BIOS region record.
@param[in] BiosLock Private protected BIOS region record.
@param[in] BaseAddress The start address of the BIOS region which need to be removed.
@param[in] Length The Length of the BIOS region which need to be removed.
@retval EFI_OUT_OF_RESOURCES The BIOS protect region registers are not enough to set for all discontinuous BIOS region
@retval EFI_SUCCESS Remove successfully
*/
EFI_STATUS
RemoveFromBase (
IN BIOS_REGION_LOCK_BASE *BiosLock,
IN UINTN Base,
IN UINTN Length
)
{
UINTN Index;
UINTN Top1;
UINTN Top2;
BIOS_REGION_LOCK_BASE LockTemp[MAX_BIOS_REGION_LOCK + 1];
CopyMem ((VOID *)LockTemp, (VOID *)BiosLock, sizeof(BIOS_REGION_LOCK_BASE) * MAX_BIOS_REGION_LOCK);
if (PcdGetBool (PcdStatusCodeUseSerial)) {
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "\nRemoveFromBase\n"));
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "Array Status (Before Remove)....\n"));
for (Index = 0; Index <= MAX_BIOS_REGION_LOCK; ++Index) {
Top1 = LockTemp[Index].Base + LockTemp[Index].Length - 1;
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "%d => Base:%8x Length:%8x Top:%8x\n", Index + 1, LockTemp[Index].Base, LockTemp[Index].Length, Top1));
}
}
for (Index = 0; Index < MAX_BIOS_REGION_LOCK; ++Index) {
Top1 = LockTemp[Index].Base + LockTemp[Index].Length - 1;
Top2 = Base + Length - 1;
if (Top1 <= (Base - 1) || Top2 <= (LockTemp[Index].Base - 1)) {
continue;
}
if (LockTemp[Index].Base >= Base) {
if (Top1 <= Top2) {
LockTemp[Index].Base = 0;
LockTemp[Index].Length = 0;
if (Top1 == Top2) {
break;
}
} else {
LockTemp[Index].Base = Top2 + 1;
LockTemp[Index].Length = Top1 - Top2;
}
} else {
LockTemp[Index].Length = Base - LockTemp[Index].Base;
if (Top1 == Top2) {
break;
} else if (Top1 > Top2) {
LockTemp[MAX_BIOS_REGION_LOCK].Base = Top2 + 1;
LockTemp[MAX_BIOS_REGION_LOCK].Length = Top1 - Top2;
}
}
}
if (PcdGetBool (PcdStatusCodeUseSerial)) {
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "\nArray Status (After Remove)....\n"));
for (Index = 0; Index <= MAX_BIOS_REGION_LOCK; ++Index) {
Top1 = LockTemp[Index].Base + LockTemp[Index].Length - 1;
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "%d => Base:%8x Length:%8x Top:%8x\n", Index + 1, LockTemp[Index].Base, LockTemp[Index].Length, Top1));
}
}
Sort (LockTemp, MAX_BIOS_REGION_LOCK);
if (PcdGetBool (PcdStatusCodeUseSerial)) {
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "\nArray Status (After Sort)....\n"));
for (Index = 0; Index <= MAX_BIOS_REGION_LOCK; ++Index) {
Top1 = LockTemp[Index].Base + LockTemp[Index].Length - 1;
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "%d => Base:%8x Length:%8x Top:%8x\n", Index + 1, LockTemp[Index].Base, LockTemp[Index].Length, Top1));
}
}
if (LockTemp[MAX_BIOS_REGION_LOCK].Base != 0) {
return EFI_OUT_OF_RESOURCES;
}
CopyMem ((VOID *)BiosLock, (VOID *)LockTemp, sizeof(BIOS_REGION_LOCK_BASE) * MAX_BIOS_REGION_LOCK);
return EFI_SUCCESS;
}
/**
This function programs the BIOS regions described in BiosLock record to the BIOS protect region registers.
@param[in] BiosLock Private protected BIOS region record.
@retval EFI_SUCCESS
*/
EFI_STATUS
ProgramRegister (
IN BIOS_REGION_LOCK_BASE *BiosLock
)
{
UINTN Index;
UINT32 PRRegister;
UINTN RangeBase;
UINTN RangeLimit;
UINTN Offset;
UINTN BiosRegionStart;
EFI_STATUS Status;
UINTN PchSpiBase;
UINTN PciSpiRegBase;
UINT32 DlockValue;
PciSpiRegBase = MmPciBase (
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_SPI,
PCI_FUNCTION_NUMBER_PCH_SPI
);
PchSpiBase = MmioRead32 (PciSpiRegBase + R_SPI_CFG_BAR0) &~(B_SPI_CFG_BAR0_MASK);
//[-start-190613-IB16990059-add]//
BiosRegionStart = ((UINTN) (MmioRead32 (PchSpiBase + R_SPI_MEM_BFPR) & B_PCH_SPI_PRB_MASK) << 12);
//[-end-190613-IB16990059-add]//
Offset = PcdGet32 (PcdFlashAreaBaseAddress) - BiosRegionStart;
if (PcdGetBool (PcdStatusCodeUseSerial)) {
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "\nBIOS Region Lock Base ........\n"));
}
for (Index = 0; Index < MAX_BIOS_REGION_LOCK; ++Index) {
PRRegister = MmioRead32 (PchSpiBase + R_SPI_MEM_PR0 + (Index << 2));
if (PRRegister != 0) {
//[-start-190613-IB16990059-add]//
RangeBase = ((UINTN) (PRRegister & B_PCH_SPI_PR0_PRB_MASK) << 12) + Offset;
//[-end-190613-IB16990059-add]//
RangeLimit = ((PRRegister & B_PCH_SPI_PR0_PRL_MASK) >> 4) + Offset;
Status = MergeToBase(
BiosLock,
RangeBase,
RangeLimit - RangeBase + 0x1000
);
if (EFI_ERROR (Status)) {
return Status;
}
}
}
DlockValue = MmioRead32 (PchSpiBase + R_SPI_MEM_DLOCK);
for (Index = 0; Index < MAX_BIOS_REGION_LOCK; ++Index) {
PRRegister = 0;
if (BiosLock[Index].Base != 0) {
RangeBase = BiosLock[Index].Base - Offset;
RangeLimit = RangeBase + BiosLock[Index].Length - 1;
DEBUG ((DEBUG_ERROR | DEBUG_INFO, "%d => Base:%8x Length:%8x BiosBase:%8x Limit:%0x\n", Index, BiosLock[Index].Base, BiosLock[Index].Length, RangeBase, RangeLimit));
RangeBase = (RangeBase >> 12) & B_PCH_SPI_PR0_PRB_MASK;
RangeLimit = (RangeLimit << 4) & B_PCH_SPI_PR0_PRL_MASK;
PRRegister = (UINT32)(RangeBase | RangeLimit | B_PCH_SPI_PR0_WPE);
DlockValue |= (UINT32) (B_SPI_MEM_DLOCK_PR0LOCKDN << Index);
}
MmioAndThenOr32 ((PchSpiBase + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX))), 0x00, PRRegister);
S3BootScriptSaveMemWrite (
S3BootScriptWidthUint32,
(UINTN) (PchSpiBase + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX))),
1,
(VOID *) (UINTN) (PchSpiBase + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX)))
);
if (PcdGetBool (PcdStatusCodeUseSerial)) {
PRRegister = MmioRead32 (PchSpiBase + R_SPI_MEM_PR0 + (Index << 2));
DEBUG ((DEBUG_ERROR | DEBUG_INFO, " Register:%8x\n", PRRegister));
}
}
//
// Program DLOCK register
//
MmioWrite32 ((UINTN) (PchSpiBase + R_SPI_MEM_DLOCK), DlockValue);
S3BootScriptSaveMemWrite (
S3BootScriptWidthUint32,
(UINTN) (PchSpiBase + R_SPI_MEM_DLOCK),
1,
(VOID *) (UINTN) (PchSpiBase + R_SPI_MEM_DLOCK)
);
return EFI_SUCCESS;
}