381 lines
11 KiB
C
381 lines
11 KiB
C
/** @file
|
|
Provide swap operation of boot block.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2020 - 2021, 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 <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/PciSegmentLib.h>
|
|
#include <Library/PchPciBdfLib.h>
|
|
#include <Library/IoLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Protocol/SwapAddressRange.h>
|
|
#include <Protocol/SmmBase2.h>
|
|
#include <Register/PchRegsLpc.h>
|
|
#include <Protocol/Spi.h>
|
|
#include <Library/PchInfoLib.h>
|
|
|
|
#define R_PCH_SPI_STRP_DSCR_P_A0 0x4C
|
|
#define R_PCH_SPI_STRP_DSCR_S_A0 0x5C
|
|
#define R_PCH_SPI_STRP_DSCR_S_B0 0x68
|
|
|
|
#define N_PCH_SPI_STRP_DSCR_TSBS (BIT4|BIT5|BIT6)
|
|
#define V_PCH_SPI_STRP_DSCR_TSBS_64KB 0x0 //(000)
|
|
#define V_PCH_SPI_STRP_DSCR_TSBS_128KB 0x1 //(001)
|
|
#define V_PCH_SPI_STRP_DSCR_TSBS_256KB 0x2 //(010)
|
|
#define V_PCH_SPI_STRP_DSCR_TSBS_512KB 0x3 //(011)
|
|
#define V_PCH_SPI_STRP_DSCR_TSBS_1MB 0x4 //(100)
|
|
#define V_PCH_SPI_STRP_DSCR_TSBS_2MB 0x5 //(101)
|
|
#define V_PCH_SPI_STRP_DSCR_TSBS_4MB 0x6 //(110)
|
|
#define V_PCH_SPI_STRP_DSCR_TSBS_8MB 0x7 //(111)
|
|
|
|
|
|
#define R_SPI_CFG_BC 0xDC
|
|
#define B_SPI_CFG_BC_TSS BIT4
|
|
|
|
EFI_SWAP_ADDRESS_RANGE_PROTOCOL mSwapAddressRange;
|
|
BOOLEAN mSwapLocked = FALSE;
|
|
|
|
|
|
UINT32
|
|
GetTopSwapSize (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
PCH_SPI_PROTOCOL *SpiProtocol = NULL;
|
|
UINT8 PchStrap;
|
|
UINT8 TSBS;
|
|
UINT32 TopswapSize;
|
|
UINT16 FlashDescriptorRecords;
|
|
|
|
DEBUG ((DEBUG_INFO, "Check PlatformCheckFtSupported.\n"));
|
|
|
|
PchStrap = 0;
|
|
TSBS = 0;
|
|
TopswapSize = 0;
|
|
|
|
//
|
|
// @TODO: Determine if we need an API from SI or not.
|
|
//
|
|
Status = gBS->LocateProtocol (&gPchSpiProtocolGuid, NULL, (VOID **) &SpiProtocol);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Failed to locate PCH SPI protocol\n"));
|
|
return 0;
|
|
}
|
|
|
|
switch (PchSeries ()) {
|
|
case PCH_S:
|
|
switch (PchStepping ()) {
|
|
case PCH_A0:
|
|
FlashDescriptorRecords = R_PCH_SPI_STRP_DSCR_S_A0;
|
|
break;
|
|
case PCH_B0:
|
|
default:
|
|
FlashDescriptorRecords = R_PCH_SPI_STRP_DSCR_S_B0;
|
|
break;
|
|
}
|
|
break;
|
|
case PCH_P:
|
|
default:
|
|
switch (PchStepping ()) {
|
|
case PCH_A0:
|
|
default:
|
|
FlashDescriptorRecords = R_PCH_SPI_STRP_DSCR_P_A0;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
Status = SpiProtocol->ReadPchSoftStrap (SpiProtocol, FlashDescriptorRecords, sizeof (PchStrap), &PchStrap);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Failed to read PCH soft strap\n"));
|
|
return 0;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "PCH Rescriptor Record: 0x%x\n", PchStrap));
|
|
|
|
TSBS = (PchStrap & N_PCH_SPI_STRP_DSCR_TSBS) >> 4;
|
|
|
|
switch (TSBS) {
|
|
case V_PCH_SPI_STRP_DSCR_TSBS_64KB:
|
|
TopswapSize = SIZE_64KB;
|
|
break;
|
|
case V_PCH_SPI_STRP_DSCR_TSBS_128KB:
|
|
TopswapSize = SIZE_128KB;
|
|
break;
|
|
case V_PCH_SPI_STRP_DSCR_TSBS_256KB:
|
|
TopswapSize = SIZE_256KB;
|
|
break;
|
|
case V_PCH_SPI_STRP_DSCR_TSBS_512KB:
|
|
TopswapSize = SIZE_512KB;
|
|
break;
|
|
case V_PCH_SPI_STRP_DSCR_TSBS_1MB:
|
|
TopswapSize = SIZE_1MB;
|
|
break;
|
|
case V_PCH_SPI_STRP_DSCR_TSBS_2MB:
|
|
TopswapSize = SIZE_2MB;
|
|
break;
|
|
case V_PCH_SPI_STRP_DSCR_TSBS_4MB:
|
|
TopswapSize = SIZE_4MB;
|
|
break;
|
|
case V_PCH_SPI_STRP_DSCR_TSBS_8MB:
|
|
TopswapSize = SIZE_8MB;
|
|
break;
|
|
default:
|
|
TopswapSize = 0;
|
|
break;
|
|
}
|
|
|
|
return TopswapSize;
|
|
}
|
|
|
|
|
|
/**
|
|
This function gets the address range location of
|
|
boot block and backup block.
|
|
|
|
@param This Indicates the calling context.
|
|
@param BootBlockBase The base address of current boot block.
|
|
@param BootBlockSize The size (in bytes) of current boot block.
|
|
@param BackupBlockBase The base address of current backup block.
|
|
@param BackupBlockSize The size (in bytes) of current backup block.
|
|
|
|
@retval EFI_SUCCESS The call was successful.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetRangeLocation (
|
|
IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
|
|
OUT EFI_PHYSICAL_ADDRESS *BootBlockBase,
|
|
OUT UINTN *BootBlockSize,
|
|
OUT EFI_PHYSICAL_ADDRESS *BackupBlockBase,
|
|
OUT UINTN *BackupBlockSize
|
|
)
|
|
{
|
|
|
|
*BootBlockBase = (EFI_PHYSICAL_ADDRESS)FixedPcdGet32 (PcdFlashPbbBase);
|
|
*BootBlockSize = (UINTN) GetTopSwapSize(); //FixedPcdGet32 (PcdFlashPbbSize);
|
|
*BackupBlockBase = (EFI_PHYSICAL_ADDRESS)FixedPcdGet32 (PcdFlashPbbRBase);
|
|
*BackupBlockSize = *BootBlockSize;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This service checks if the boot block and backup block has been swapped.
|
|
|
|
@param This Indicates the calling context.
|
|
@param SwapState True if the boot block and backup block has been swapped.
|
|
False if the boot block and backup block has not been swapped.
|
|
|
|
@retval EFI_SUCCESS The call was successful.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetSwapState (
|
|
IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
|
|
OUT BOOLEAN *SwapState
|
|
)
|
|
{
|
|
EFI_HOB_GUID_TYPE *GuidHob;
|
|
BOOLEAN TopSwapStatus;
|
|
|
|
TopSwapStatus = !!(PciSegmentRead32 (SpiPciCfgBase () + R_SPI_CFG_BC) & B_SPI_CFG_BC_TSS);
|
|
if (!TopSwapStatus) {
|
|
GuidHob = GetFirstGuidHob (&gChasmfallsTopSwapStatusGuid);
|
|
if (GuidHob != NULL) {
|
|
TopSwapStatus = *((BOOLEAN *) GET_GUID_HOB_DATA (GuidHob));
|
|
}
|
|
}
|
|
|
|
*SwapState = TopSwapStatus;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This service swaps the boot block and backup block, or swaps them back.
|
|
|
|
It also acquires and releases software swap lock during operation. The setting of the new swap state
|
|
is not affected by the old swap state.
|
|
|
|
@param This Indicates the calling context.
|
|
@param NewSwapState True to swap real boot block and backup block, False to swap them back.
|
|
|
|
@retval EFI_SUCCESS The call was successful.
|
|
@retval EFI_ABORTED Set swap state error.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetSwapState (
|
|
IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
|
|
IN BOOLEAN NewSwapState
|
|
)
|
|
{
|
|
if (mSwapLocked) {
|
|
return EFI_ABORTED;
|
|
}
|
|
if (NewSwapState) {
|
|
DEBUG ((DEBUG_INFO, "Enable TopSwap via SwSmi (0x%x)\n", PcdGet8 (PcdTopSwapEnableSwSmi)));
|
|
IoWrite8 (R_PCH_IO_APM_CNT, PcdGet8 (PcdTopSwapEnableSwSmi));
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "Disable TopSwap via SwSmi (0x%x)\n", PcdGet8 (PcdTopSwapDisableSwSmi)));
|
|
IoWrite8 (R_PCH_IO_APM_CNT, PcdGet8 (PcdTopSwapDisableSwSmi));
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This service checks if a Real Time Clock (RTC) power failure happened.
|
|
|
|
If parameter RtcPowerFailed is true after the function returns, RTC power supply failed or was removed.
|
|
It is recommended to check RTC power status before calling GetSwapState().
|
|
|
|
@param This Indicates the calling context.
|
|
@param RtcPowerFailed True if the RTC (Real Time Clock) power failed or was removed.
|
|
|
|
@retval EFI_SUCCESS The call was successful.
|
|
@retval EFI_UNSUPPORTED The service is unsupported.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetRtcPowerStatus (
|
|
IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
|
|
OUT BOOLEAN *RtcPowerFailed
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
This service returns all lock methods for swap operations that the current platform
|
|
supports. Could be software lock, hardware lock, or unsupport lock.
|
|
Note that software and hardware lock methods can be used simultaneously.
|
|
|
|
@param This Indicates the calling context.
|
|
@param LockCapability The current lock method for swap operations.
|
|
|
|
@retval EFI_SUCCESS The call was successful.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetSwapLockCapability (
|
|
IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
|
|
OUT EFI_SWAP_LOCK_CAPABILITY *LockCapability
|
|
)
|
|
{
|
|
*LockCapability = EFI_SOFTWARE_LOCK;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This service is used to acquire or release appointed kind of lock for Swap Address Range operations.
|
|
|
|
Note that software and hardware lock mothod can be used simultaneously.
|
|
|
|
@param This Indicates the calling context.
|
|
@param LockCapability Indicates which lock to acquire or release.
|
|
@param NewLockState True to acquire lock; False to release lock.
|
|
|
|
@retval EFI_SUCCESS The call was successful.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetSwapLock (
|
|
IN EFI_SWAP_ADDRESS_RANGE_PROTOCOL *This,
|
|
IN EFI_SWAP_LOCK_CAPABILITY LockCapability,
|
|
IN BOOLEAN NewLockState
|
|
)
|
|
{
|
|
if (LockCapability == EFI_SOFTWARE_LOCK) {
|
|
mSwapLocked = NewLockState;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Function performs a software lock for Swap.
|
|
|
|
@param[in] Event - A pointer to the Event that triggered the callback.
|
|
@param[in] Context - A pointer to private data registered with the callback function.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
SwapLockCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
gBS->CloseEvent (Event);
|
|
mSwapLocked = TRUE;
|
|
}
|
|
|
|
/**
|
|
The driver's entry point. It publishes Swap Address Range Protocol.
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
@retval other Some error occurs when executing this entry point.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DriverEntry (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE Handle;
|
|
EFI_EVENT EndOfDxeEvent;
|
|
|
|
mSwapAddressRange.GetRangeLocation = GetRangeLocation;
|
|
mSwapAddressRange.GetRtcPowerStatus = GetRtcPowerStatus;
|
|
mSwapAddressRange.GetSwapLockCapability = GetSwapLockCapability;
|
|
mSwapAddressRange.GetSwapState = GetSwapState;
|
|
mSwapAddressRange.SetSwapLock = SetSwapLock;
|
|
mSwapAddressRange.SetSwapState = SetSwapState;
|
|
|
|
Handle = NULL;
|
|
Status = gBS->InstallProtocolInterface (
|
|
&Handle,
|
|
&gEfiSwapAddressRangeProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&mSwapAddressRange
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Register End of DXE event
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
SwapLockCallback,
|
|
NULL,
|
|
&gEfiEndOfDxeEventGroupGuid,
|
|
&EndOfDxeEvent
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|