358 lines
12 KiB
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;
|
|
}
|