/** @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 #include #include #include #include #include #include "BiosRegionLockInfo.h" #include "BiosRegionLockHelpFun.h" #include #include #include //[-start-191225-IB16740000-add]// for PCI_DEVICE_NUMBER_PCH_LPC & PCI_FUNCTION_NUMBER_PCH_XHCI define #include //[-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; }