alder_lake_bios/Intel/AlderLake/AlderLakeChipsetPkg/IhisiSmm/Fbts.c

566 lines
16 KiB
C

/** @file
This driver provides IHISI interface in SMM mode
;******************************************************************************
;* Copyright (c) 2017 - 2020, Insyde Software Corp. 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 "Fbts.h"
#include <Library/BaseOemSvcKernelLib.h>
#include <Library/IoLib.h>
#include <Protocol/Spi.h>
//#include <Library/PchPlatformLib.h>
#include <Library/PchCycleDecodingLib.h>
#include <Library/PchInfoLib.h>
#include <Library/VariableLib.h>
#include <Library/MmPciLib.h>
#include <KernelSetupConfig.h>
#include <Register/MeRegs.h>
#include <CpuRegs.h>
#include <SetupConfig.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include "IhisiSmm.h"
//[-start-190701-16990084-add]//
#include <Register/FlashRegs.h>
#include <Register/SpiRegs.h>
//[-end-190701-16990084-add]//
UINT8 mA0A1MEdelta;
STATIC
IHISI_REGISTER_TABLE
CHIPSET_FBTS_REGISTER_TABLE[] = {
//
// AH=17h
//
{ FBTSGetRomFileAndPlatformTable, "S17Cs_GetPlatformTb", GetRomFileAndPlatformTable}, \
//
// AH=1Ch
//
{ FBTSGetATpInformation, "S1CCs_GetATpInfo000", FbtsGetATpInformation}, \
//
// AH=1Eh
//
{ FBTSGetWholeBiosRomMap, "S1ECs_WholeBiosRomp", FbtsGetWholeBiosRomMap}, \
//
// AH=1Fh
//
{ FBTSApHookPoint, "S1FCs_ApHookForBios", FbtsApHookForBios}
};
STATIC
IHISI_REGISTER_TABLE
CHIPSET_FBTS2_REGISTER_TABLE[] = {
//
// AH=4Dh
//
{ FBTSPassImageFromTool, "S4DCs_ImageCheck000", ImageCheck}
};
/**
Check the flash region whether is used.
@param[in] FlashRegion Flash Region x Register (x = 0 - 3).
@retval TRUE This region is used
@retval FALSE This region is not used
**/
STATIC
BOOLEAN
CheckFlashRegionIsValid (
IN UINT32 FlashRegion
)
{
BOOLEAN Flag = TRUE;
//[-start-190701-16990084-add]//
UINT32 RegionBase;
UINT32 RegionLimit;
RegionBase = ((FlashRegion & B_SPI_MEM_FREGX_BASE_MASK) >> N_SPI_MEM_FREGX_BASE) << N_SPI_MEM_FREGX_BASE_REPR;
RegionLimit = ((((FlashRegion & B_SPI_MEM_FREGX_LIMIT_MASK) >> N_SPI_MEM_FREGX_LIMIT)) << N_SPI_MEM_FREGX_LIMIT_REPR);
if (RegionBase > RegionLimit) {
Flag = FALSE;
}
//[-end-190701-16990084-add]//
return Flag;
}
/**
Passing information to flash program on whether
if current BIOS (AT-p capable) can be flashed with
other BIOS ROM file
AT-p: (Anti-Theft PC Protection).
@retval EFI_SUCCESS Success returns.
**/
EFI_STATUS
FbtsGetATpInformation (
VOID
)
{
UINT32 Ecx_data = 0;
//
// Return ECX for tool to determin proper error message.
// Please refer to IHISI spec.
//
mH2OIhisi->WriteCpuReg32 (EFI_SMM_SAVE_STATE_REGISTER_RCX, Ecx_data);
return EFI_SUCCESS;
}
/**
AH=17h Get platform and Rom file flash descriptor region.
@retval EFI_SUCCESS Success returns.
**/
EFI_STATUS
GetRomFileAndPlatformTable (
VOID
)
{
UINTN DataSize;
UINT8 *OutputDataBuffer;
UINT8 *InputDataBuffer;
UINT8 Index;
FLASH_REGION *FlashRegionPtr;
EFI_STATUS Status;
Index = 0;
Status = EFI_UNSUPPORTED;
DataSize = (UINTN) mH2OIhisi->ReadCpuReg32 (EFI_SMM_SAVE_STATE_REGISTER_RCX);
if (DataSize == 0) {
return IHISI_INVALID_PARAMETER;
}
OutputDataBuffer = (UINT8 *)(UINTN) mH2OIhisi->ReadCpuReg32 (EFI_SMM_SAVE_STATE_REGISTER_RDI);
InputDataBuffer = (UINT8 *)(UINTN) mH2OIhisi->ReadCpuReg32 (EFI_SMM_SAVE_STATE_REGISTER_RSI);
if (!mH2OIhisi->BufferInCmdBuffer ((VOID *) InputDataBuffer, DataSize) || !mH2OIhisi->BufferInCmdBuffer ((VOID *) OutputDataBuffer, DataSize)) {
return IHISI_BUFFER_RANGE_ERROR;
}
//
//we must get platform region table through read chipset register, because
//1. we can override access permissions in the Flash Descriptor through BMWAG and BMRAG
//2. Flash regions may be haven't read/write access.
//
Status = mSmmFwBlockService->GetFlashTable (
mSmmFwBlockService,
OutputDataBuffer
);
//
// Calculate actually Flash table numbers
//
FlashRegionPtr = (FLASH_REGION *) OutputDataBuffer;
while (FlashRegionPtr->Type != FLASH_REGION_TYPE_OF_EOS) {
Index ++;
FlashRegionPtr ++;
}
if (DataSize < sizeof (FLASH_REGION) * (Index + 1)) {
return IHISI_BUFFER_RANGE_ERROR;
}
OutputDataBuffer += ROM_FILE_REGION_OFFSET;
FlashRegionPtr = (FLASH_REGION *) OutputDataBuffer;
if (*((UINT32 *) (InputDataBuffer + 0x10)) == FLASH_VALID_SIGNATURE) {
mA0A1MEdelta = 0x10; // B0 stepping, ME has been shift 0x10 bytes
}
else{
mA0A1MEdelta = 0x0; // else keep what it is
}
//
//check Rom file is whether descriptor mode
//
if (*((UINT32 *) (InputDataBuffer + mA0A1MEdelta)) == FLASH_VALID_SIGNATURE) {
Status = GetRomFileFlashTable (InputDataBuffer, FlashRegionPtr, TRUE);
} else {
Status = GetRomFileFlashTable (InputDataBuffer, FlashRegionPtr, FALSE);
}
return Status;
}
/**
Get Flash table from Rom file.
if DescriptorMode is true, the FlashTable will be filled.
if the descriptor is false,the FlashTable will be filled RegionTypeEos(0xff) directly.
@param[in] InputDataBuffer the pointer to Rom file.
@param[in] DataBuffer IN: the input buffer address.
OUT:the flash region table from rom file.
@param[in] DescriptorMode TRUE is indicate this Rom file is descriptor mode
FALSE is indicate this Rom file is non-descriptor mode
@retval EFI_SUCCESS Successfully returns
**/
EFI_STATUS
GetRomFileFlashTable (
IN UINT8 *InputDataBuffer,
IN OUT FLASH_REGION *DataBuffer,
IN BOOLEAN DescriptorMode
)
{
UINT8 Index;
UINT32 *FlashRegionPtr;
UINT32 Frba;
UINT32 *FlashMasterPtr;
UINT32 Fmba;
UINT32 FlashMap0Reg;
UINT32 FlashMap1Reg;
UINT32 ReadAccess;
UINT32 WriteAccess;
//[-start-190701-16990084-add]//
UINT32 BaseAddress;
//[-end-190701-16990084-add]//
//
//calulate Flash region base address
//
FlashMap0Reg = *((UINT32 *)(InputDataBuffer + FLASH_MAP_0_OFFSET + mA0A1MEdelta));
//[-start-190701-16990084-modify]//
Frba = (FlashMap0Reg & B_FLASH_FDBAR_FRBA) >> 12;
//[-end-190701-16990084-modify]//
FlashRegionPtr = (UINT32 *)(InputDataBuffer + Frba);
//
//calulate Flash master base address
//
FlashMap1Reg = *((UINT32 *)(InputDataBuffer + FLASH_MAP_1_OFFSET + mA0A1MEdelta));
//[-start-190701-16990084-modify]//
Fmba = (FlashMap1Reg & B_FLASH_FDBAR_FMBA) << 4;
//[-end-190701-16990084-modify]//
FlashMasterPtr = (UINT32 *)(InputDataBuffer + Fmba);
if (DescriptorMode) {
for (Index = FlashRegionDescriptor; Index < FlashRegionMax; Index++, FlashRegionPtr++) {
if (DataBuffer->Type == FLASH_REGION_TYPE_OF_EOS){
break;
}
if (CheckFlashRegionIsValid (*FlashRegionPtr)){
DataBuffer->Type = Index;
//[-start-190701-16990084-modify]//
DataBuffer->Offset = (*FlashRegionPtr & B_SPI_MEM_FREGX_BASE_MASK) << N_SPI_MEM_FREGX_BASE_REPR;
// Refer Silicon code, SpiCommon.c
BaseAddress = ((*FlashRegionPtr & B_SPI_MEM_FREGX_BASE_MASK) >> N_SPI_MEM_FREGX_BASE) << N_SPI_MEM_FREGX_BASE_REPR;
//
// Region limit address Bits[11:0] are assumed to be FFFh
//
DataBuffer->Size = ((((*FlashRegionPtr & B_SPI_MEM_FREGX_LIMIT_MASK) >> N_SPI_MEM_FREGX_LIMIT) + 1) << N_SPI_MEM_FREGX_LIMIT_REPR) - BaseAddress;
//[-end-190701-16990084-modify]//
//
//Bios primary master always has access permissions to it's primary region
//
if (Index == FlashRegionBios) {
ReadAccess = ACCESS_AVAILABLE;
WriteAccess = ACCESS_AVAILABLE;
} else if (Index < MAX_FLASH_REGION) {
ReadAccess = (*FlashMasterPtr >> (FLASH_MASTER_1_READ_ACCESS_BIT + Index)) & ACCESS_AVAILABLE;
WriteAccess = (*FlashMasterPtr >> (FLASH_MASTER_1_WRITE_ACCESS_BIT + Index)) & ACCESS_AVAILABLE;
} else {
ReadAccess = ACCESS_AVAILABLE;
WriteAccess = ACCESS_AVAILABLE;
}
if (ReadAccess == ACCESS_AVAILABLE && WriteAccess == ACCESS_AVAILABLE) {
DataBuffer->Access = ACCESS_AVAILABLE;
} else {
DataBuffer->Access = ACCESS_NOT_AVAILABLE;
}
DataBuffer++;
}
}
}
DataBuffer->Type = REGION_TYPE_OF_EOS;
return EFI_SUCCESS;
}
/**
Initialize Fbts relative services
@retval EFI_SUCCESS Initialize Fbts services successful.
@return Others Any error occurred.
**/
EFI_STATUS
FbtsInit (
VOID
)
{
EFI_STATUS Status;
IHISI_REGISTER_TABLE *SubFuncTable;
UINT16 TableCount;
Status = gSmst->SmmLocateProtocol (
&gEfiSmmFwBlockServiceProtocolGuid,
NULL,
(VOID **) &mSmmFwBlockService
);
if (EFI_ERROR (Status)) {
return Status;
}
SubFuncTable = CHIPSET_FBTS_REGISTER_TABLE;
TableCount = sizeof(CHIPSET_FBTS_REGISTER_TABLE)/sizeof(CHIPSET_FBTS_REGISTER_TABLE[0]);
Status = RegisterIhisiSubFunction (SubFuncTable, TableCount);
if (EFI_ERROR(Status)) {
ASSERT_EFI_ERROR (Status);
}
return Status;
}
/**
Initialize Fbts2 relative services
@retval EFI_SUCCESS Initialize Fbts services successful.
@return Others Any error occurred.
**/
EFI_STATUS
Fbts2Init (
VOID
)
{
EFI_STATUS Status;
IHISI_REGISTER_TABLE *SubFuncTable;
UINT16 TableCount;
Status = gSmst->SmmLocateProtocol (
&gEfiSmmFwBlockServiceProtocolGuid,
NULL,
(VOID **) &mSmmFwBlockService
);
if (EFI_ERROR (Status)) {
return Status;
}
SubFuncTable = CHIPSET_FBTS2_REGISTER_TABLE;
TableCount = sizeof(CHIPSET_FBTS2_REGISTER_TABLE)/sizeof(CHIPSET_FBTS2_REGISTER_TABLE[0]);
Status = RegisterIhisiSubFunction (SubFuncTable, TableCount);
if (EFI_ERROR(Status)) {
ASSERT_EFI_ERROR (Status);
}
return Status;
}
EFI_STATUS
FbtsApHookForBios (
VOID
)
/*++
Routine Description:
AH=1Fh, This call back function will be invoked several times during flash process.
BIOS can know which step is running now.
BIOS can base on it to do specific hook such as EC idle and weak up.
Arguments:
CL - denote the start of AP process.
CL = 0x00, AP terminate. (Before IHISI 0x16)
CL = 0x01, AP start. (After IHISI 0x10)
CL = 0x02, Start to read ROM. (Before IHISI 0x14)
CL = 0x03, Start to write ROM. (Before IHISI 0x15)
CL = 0x04, Start to write EC. (Before IHISI 0x20)
CL = 0x05, Before dialog popup.
CL = 0x06, After dialog close and continue running.
Returns:
--*/
{
UINT8 ApState;
EFI_STATUS OemSvcStatus;
ApState = (UINT8) mH2OIhisi->ReadCpuReg32 (EFI_SMM_SAVE_STATE_REGISTER_RCX); // CL
switch(ApState) {
case 0x00:
//
// Here provided a hook before AP terminate.
//
if (PcdGetBool (PcdEcSharedFlashSupported) && !PcdGetBool (PcdEcIdlePerWriteBlockSupported)) {
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcEcIdle \n"));
OemSvcStatus = OemSvcEcIdle (FALSE);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcEcIdle Status: %r\n", OemSvcStatus));
}
break;
case 0x01:
//
// Here provided a hook before AP start.
//
break;
case 0x02:
//
// Here provided a hook before FbtsRead.
//
if (PcdGetBool (PcdEcSharedFlashSupported) && !PcdGetBool (PcdEcIdlePerWriteBlockSupported)) {
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcEcIdle \n"));
OemSvcStatus = OemSvcEcIdle (TRUE);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcEcIdle Status: %r\n", OemSvcStatus));
}
break;
case 0x03:
//
// Here provided a hook before FbtsWrite.
//
if (PcdGetBool (PcdEcSharedFlashSupported) && !PcdGetBool (PcdEcIdlePerWriteBlockSupported)) {
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcEcIdle \n"));
OemSvcStatus = OemSvcEcIdle (TRUE);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcEcIdle Status: %r\n", OemSvcStatus));
}
break;
case 0x04:
//
// Here provided a hook before FetsWrite.
//
if (PcdGetBool (PcdEcSharedFlashSupported) && !PcdGetBool (PcdEcIdlePerWriteBlockSupported)) {
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcEcIdle \n"));
OemSvcStatus = OemSvcEcIdle (TRUE);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcEcIdle Status: %r\n", OemSvcStatus));
}
break;
case 0x05:
//
// Here provided a hook before dialog popup. (Winflash)
//
if (PcdGetBool (PcdEcSharedFlashSupported) && !PcdGetBool (PcdEcIdlePerWriteBlockSupported)) {
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcEcIdle \n"));
OemSvcStatus = OemSvcEcIdle (FALSE);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcEcIdle Status: %r\n", OemSvcStatus));
}
break;
case 0x06:
//
// Here provided a hook after dialog close and continue running. (Winflash)
//
break;
}
return EFI_SUCCESS;
}
//EFI_STATUS
//EFIAPI
//SmmCsSvcIhisiFbtsBiosGuardCheck (
// VOID
// )
//{
// UINT64 MsrValue;
// EFI_GUID VarStoreGuid = SYSTEM_CONFIGURATION_GUID;
// CHIPSET_CONFIGURATION SetupVariable;
// UINTN DataSize;
// EFI_STATUS Status;
//
// Status = EFI_SUCCESS;
// DataSize = PcdGet32 (PcdSetupConfigSize);
//
// Status = CommonGetVariable (L"Setup", &VarStoreGuid, &DataSize, &SetupVariable);
// if (EFI_ERROR (Status)) {
// return Status;
// }
//
// MsrValue = AsmReadMsr64 (MSR_PLAT_FRMW_PROT_CTRL);
//
// if ((SetupVariable.BiosGuard) && !(MsrValue & B_MSR_PLAT_FRMW_PROT_CTRL_EN)){
// return EFI_UNSUPPORTED;
// }
//
// if (!(SetupVariable.BiosGuard) && (MsrValue & B_MSR_PLAT_FRMW_PROT_CTRL_EN)){
// return EFI_UNSUPPORTED;
// }
//
// return Status;
//}
/**
AH=11h Get platform Info
@retval EFI_SUCCESS Success returns.
**/
EFI_STATUS
GetPlatformInfoHook (
VOID
)
{
EFI_STATUS Status;
Status = EFI_SUCCESS;
// Status = SmmCsSvcIhisiFbtsBiosGuardCheck();
return Status;
}
/**
AH=1Eh, Chipset Get whole BIOS ROM map.
@retval EFI_SUCCESS FBTS get BIOS ROM map success.
@return Others FBTS get BIOS ROM map failed.
**/
EFI_STATUS
EFIAPI
FbtsGetWholeBiosRomMap (
VOID
)
{
UINTN RomMapSize;
UINTN NumberOfRegions;
FBTS_INTERNAL_BIOS_ROM_MAP *BiosRomMap;
UINTN Indxe;
NumberOfRegions = 0;
BiosRomMap = (FBTS_INTERNAL_BIOS_ROM_MAP *) (UINTN) mH2OIhisi->ReadCpuReg32 (EFI_SMM_SAVE_STATE_REGISTER_RDI);
if (BiosRomMap == NULL) {
return IHISI_ACCESS_PROHIBITED;
}
while (BiosRomMap[NumberOfRegions].Type != FbtsRomMapEos) {
NumberOfRegions++;
}
NumberOfRegions++;
RomMapSize = NumberOfRegions * sizeof (FBTS_INTERNAL_BIOS_ROM_MAP);
for (Indxe = 0; Indxe < (NumberOfRegions - 1); Indxe++) {
BiosRomMap[Indxe].Address = BiosRomMap[Indxe].Address - PcdGet32 (PcdFlashAreaBaseAddress) + PcdGet32(PcdFlashPartBaseAddress);
}
CopyMem ((VOID *)(UINTN)mH2OIhisi->ReadCpuReg32 (EFI_SMM_SAVE_STATE_REGISTER_RDI), (VOID *)BiosRomMap, RomMapSize);
return IHISI_SUCCESS;
}