alder_lake_bios/Insyde/InsydeModulePkg/Universal/IhisiServicesSmm/IhisiCommonRegionCommunicat...

965 lines
33 KiB
C

/** @file
FactoryDefaultLib Library Instance implementation
;******************************************************************************
;* Copyright (c) 2014 - 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 "IhisiCommonRegionCommunication.h"
#include <Library/MemoryAllocationLib.h>
#include <Library/VariableSupportLib.h>
#include <Library/FlashRegionLib.h>
#include <Guid/ImageAuthentication.h>
STATIC COMMON_REGION_READ_STRUCTURE mCommonRegionReadControl = {0};
//
//Data communcation sub function
//
STATIC COMMON_REGION_COMMUNICATION_FUNCTION_TABLE DataCommunicationSubFun []= {
{FACTORY_COPY_EVENT, WriteDefaultSettingsToFactoryCopy},
{FACTORY_COPY_READ, ReadDefaultSettingsToFactoryCopy},
{FACTORY_COPY_RESTORE_WITH_CLEARING_ALL_SETTINGS, RestoreFactoryCopyWithClearingAllSettings},
{FACTORY_COPY_RESTORE_WITH_RESERVING_OTHER_SETTINGS, RestoreFactoryCopyWithReservingOtherSettings}
};
//
// Factory default Support Function
//
STATIC
IHISI_REGISTER_TABLE
COMMON_REGION_REGISTER_TABLE[] = {
//
// AH=49h
//
{ FBTSCommonCommunication, "S49Kn_ComDataCommun", CommonRegionDataCommunication}, \
//
// AH=4Bh
//
{ FBTSCommonRead, "S4BKn_ComDataRead00", CommonRegionDataRead}
};
/**
Get all of secure boot settings from factory copy region.
@param[in, out] BufferSize On input, Total buffer size.
On output, The size of all secure boot settings.
@param[out] Buffer Buffer to save secure boot settings.
@retval EFI_SUCCESS Collect all of secure boot settings successful.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
@retval EFI_OUT_OF_RESOURCES Allocate memory failed.
**/
EFI_STATUS
CollectSecureBootSettings (
IN OUT UINTN *BufferSize,
OUT UINT8 *Buffer
)
{
UINTN Index;
UINTN CopySize;
UINTN TotalSize;
UINTN HeaderSize;
UINTN FunctionCnt;
BOOLEAN VariableFound;
UINTN LastVariableIndex;
UINT8 *ReadBuffer;
UINT64 FactoryCopySize;
VARIABLE_HEADER *VariableHeader;
VARIABLE_HEADER *InDeletedVariable;
SPECIFIC_VARIABLE GetVariable [] = {IsPkVariable, IsKekVariable, IsDbVariable, IsDbxVariable};
FactoryCopySize = 0;
HeaderSize = sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY) + GetVariableStoreHeaderSize ();;
if (BufferSize == NULL || Buffer == NULL || *BufferSize < HeaderSize) {
return EFI_INVALID_PARAMETER;
}
FactoryCopySize = FdmGetSizeById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1);
if (FactoryCopySize == 0) {
return EFI_OUT_OF_RESOURCES;
}
ReadBuffer = AllocatePool ( ((UINTN) FactoryCopySize) - HeaderSize);
if (ReadBuffer == NULL) {
ASSERT (ReadBuffer != NULL);
return EFI_OUT_OF_RESOURCES;
}
TotalSize = *BufferSize;
LastVariableIndex = 0;
FunctionCnt = sizeof (GetVariable) / sizeof (SPECIFIC_VARIABLE);
for (Index = 0; Index < FunctionCnt; Index++) {
VariableFound = FALSE;
VariableHeader = (VARIABLE_HEADER *) (Buffer + HeaderSize);
InDeletedVariable = NULL;
while (IsValidVariableHeader (VariableHeader) && (UINTN) VariableHeader - (UINTN) Buffer < TotalSize) {
if (VariableHeader->State == VAR_ADDED &&
GetVariable[Index] ((CHAR16 *) (VariableHeader + 1), &VariableHeader->VendorGuid)) {
CopySize = (UINTN) GetNextVariablePtr (VariableHeader) - (UINTN) VariableHeader;
if (CopySize + LastVariableIndex + HeaderSize > ((UINTN) FactoryCopySize) ) {
FreePool (ReadBuffer);
ASSERT (FALSE);
return EFI_OUT_OF_RESOURCES;
}
CopyMem (&ReadBuffer[LastVariableIndex], VariableHeader, CopySize);
LastVariableIndex += CopySize;
VariableFound = TRUE;
break;
} else if (VariableHeader->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION) &&
GetVariable[Index] ((CHAR16 *) (VariableHeader + 1), &VariableHeader->VendorGuid)) {
InDeletedVariable = VariableHeader;
}
VariableHeader = GetNextVariablePtr (VariableHeader);
}
if (!VariableFound && InDeletedVariable != NULL) {
CopySize = (UINTN) GetNextVariablePtr (InDeletedVariable) - (UINTN) InDeletedVariable;
if (CopySize + LastVariableIndex + HeaderSize > (UINTN) FactoryCopySize) {
FreePool (ReadBuffer);
ASSERT (FALSE);
return EFI_OUT_OF_RESOURCES;
}
CopyMem (&ReadBuffer[LastVariableIndex], InDeletedVariable, CopySize);
LastVariableIndex += CopySize;
VariableFound = TRUE;
}
//
// if factory copy doesn't have dbx variable, it still a legal factory default copy.
//
if (!VariableFound && Index != FunctionCnt - 1) {
FreePool (ReadBuffer);
return EFI_NOT_FOUND;
}
}
//
// copy collected secure boot settings to input buffer
//
SetMem (Buffer + HeaderSize, TotalSize - HeaderSize, 0xFF);
CopyMem (Buffer + HeaderSize, ReadBuffer, LastVariableIndex);
FreePool (ReadBuffer);
//
// Setting output buffer size
//
*BufferSize = LastVariableIndex + HeaderSize;
return EFI_SUCCESS;
}
/**
The implementation of IHISI function 49h type 2. return default factory default settings
information to application.
@retval EFI_SUCCESS The function completed successfully.
**/
STATIC
EFI_STATUS
ReadDefaultSettingsToFactoryCopy (
VOID
)
{
OUTPUT_DATA_STRUCTURE *OutputData;
UINT64 FactoryCopySize;
OutputData = (OUTPUT_DATA_STRUCTURE *) (UINTN) IhisiProtReadCpuReg32 (EFI_SMM_SAVE_STATE_REGISTER_RCX);
OutputData->BlockSize = COMMON_REGION_BLOCK_SIZE_4K;
FactoryCopySize = FdmGetSizeById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1);
if (FactoryCopySize == 0) {
return EFI_OUT_OF_RESOURCES;
}
if (FactoryCopySize == 0x10000) {
OutputData->DataSize = COMMON_REGION_SIZE_64K;
} else {
OutputData->DataSize = COMMON_REGION_REPORT_READ_SIZE;
OutputData->PhysicalDataSize = (UINT32) FactoryCopySize;
}
mCommonRegionReadControl.WantToReadData = TRUE;
mCommonRegionReadControl.InCommonReadProcess = FALSE;
mCommonRegionReadControl.BlockSize = 0x1000;
mCommonRegionReadControl.DataSize = (UINTN) FactoryCopySize;
mCommonRegionReadControl.RemainDataSize = (UINTN) FactoryCopySize;
return IHISI_SUCCESS;
}
/**
The implementation of IHISI function 49h type 1. Write secure boot settings from
variable store to factory copy region.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_OUT_OF_RESOURCES Allocate pool failed.
@retval Others Other error occurred in this function.
**/
STATIC
EFI_STATUS
WriteDefaultSettingsToFactoryCopy (
VOID
)
{
EFI_STATUS Status;
UINTN EraseSize;
UINTN WriteSize;
UINTN WriteCount;
BOOLEAN WriteSuccess;
UINTN ReadBufferSize;
UINTN WriteBufferSize;
UINT8 *Buffer;
UINT64 FactoryCopyAddr;
UINT64 FactoryCopySize;
UINT64 VariableAddr;
FactoryCopyAddr = FdmGetAddressById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1);
if (FactoryCopyAddr == 0) {
return EFI_OUT_OF_RESOURCES;
}
FactoryCopySize = FdmGetSizeById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1);
if (FactoryCopySize == 0) {
return EFI_OUT_OF_RESOURCES;
}
VariableAddr = FdmGetNAtAddr (&gH2OFlashMapRegionVarGuid, 1);
if (VariableAddr == 0) {
return EFI_OUT_OF_RESOURCES;
}
ReadBufferSize = (UINTN) FactoryCopySize;
Buffer = AllocatePool (ReadBufferSize);
if (Buffer == NULL) {
ASSERT (Buffer != NULL);
return IHISI_OUT_OF_RESOURCES;
}
Status = mSmmFwBlockService->Read (
mSmmFwBlockService,
(UINTN) VariableAddr,
0,
&ReadBufferSize,
Buffer
);
if (EFI_ERROR(Status)) {
FreePool (Buffer);
return IHISI_UNSUPPORTED_FUNCTION;
}
WriteBufferSize = ReadBufferSize;
Status = CollectSecureBootSettings (&WriteBufferSize, Buffer);
if (EFI_ERROR(Status) || ReadBufferSize < WriteBufferSize + FACTORY_COPY_HEADER_SIZE) {
FreePool (Buffer);
return IHISI_UNSUPPORTED_FUNCTION;
}
//
// Combine factory copy header and foctory copy content
//
CopyMem (Buffer + FACTORY_COPY_HEADER_SIZE, Buffer, WriteBufferSize);
ReadBufferSize = FACTORY_COPY_HEADER_SIZE;
Status = mSmmFwBlockService->Read (
mSmmFwBlockService,
(UINTN) FactoryCopyAddr,
0,
&ReadBufferSize,
Buffer
);
WriteBufferSize += FACTORY_COPY_HEADER_SIZE;
if (EFI_ERROR(Status)) {
FreePool (Buffer);
return IHISI_UNSUPPORTED_FUNCTION;
}
WriteCount = 0;
WriteSuccess = FALSE;
do {
EraseSize = (UINTN) FactoryCopySize;
Status = mSmmFwBlockService->EraseBlocks (
mSmmFwBlockService,
(UINTN) FactoryCopyAddr,
(UINTN *) &EraseSize
);
if (!EFI_ERROR (Status)) {
WriteSize = WriteBufferSize;
Status = mSmmFwBlockService->Write (
mSmmFwBlockService,
(UINTN) FactoryCopyAddr,
(UINTN *) &WriteSize,
Buffer
);
if (!EFI_ERROR (Status)) {
WriteSuccess = TRUE;
}
}
WriteCount++;
} while (WriteCount < 100 && !WriteSuccess);
FreePool (Buffer);
return WriteSuccess ? EFI_SUCCESS : IHISI_ACCESS_PROHIBITED;
}
/**
Initialize output data for IHISI function 49h
@param[out] OutputData Pointer to OUTPUT_DATA_STRUCTURE structure.
@retval EFI_SUCCESS Initailize output data successful.
@retval EFI_INVALID_PARAMETER OutputData is NULL.
**/
EFI_STATUS
InitializeOutputData (
OUT OUTPUT_DATA_STRUCTURE *OutputData
)
{
if (OutputData == NULL) {
return EFI_INVALID_PARAMETER;
}
OutputData->Signature = COMMON_REGION_OUTPUT_SIGNATURE;
OutputData->StructureSize = sizeof (OUTPUT_DATA_STRUCTURE);
OutputData->Status = 0;
return EFI_SUCCESS;
}
/**
The entry point of IHISI function 4Bh.
@retval EFI_SUCCESS The function completed successfully
@retval EFI_BUFFER_TOO_SMALL The size of input buffer is too small to save read data.
@return Others Other error causes this function cannot work properly.
**/
EFI_STATUS
EFIAPI
CommonRegionDataRead (
VOID
)
{
EFI_STATUS Status;
UINTN ReadBufferSize;
UINT32 OutputBufferSize;
UINT8 *OutputBuffer;
UINT64 FactoryCopyAddr;
Status = EFI_UNSUPPORTED;
if (mCommonRegionReadControl.WantToReadData) {
OutputBuffer = (UINT8 *) (UINTN) IhisiProtReadCpuReg32 (EFI_SMM_SAVE_STATE_REGISTER_RSI);
if (!IhisiProtBufferInCmdBuffer ((VOID *)(UINTN)IhisiProtReadCpuReg32(EFI_SMM_SAVE_STATE_REGISTER_RDI), sizeof (UINT32))) {
return IHISI_BUFFER_RANGE_ERROR;
}
CopyMem (&OutputBufferSize, (VOID *) (UINTN) IhisiProtReadCpuReg32 (EFI_SMM_SAVE_STATE_REGISTER_RDI), sizeof (UINT32));
if (OutputBuffer == NULL || OutputBufferSize != mCommonRegionReadControl.BlockSize) {
return IHISI_UNSUPPORTED_FUNCTION;
}
if (!IhisiProtBufferInCmdBuffer ((VOID *) OutputBuffer, OutputBufferSize)) {
return IHISI_BUFFER_RANGE_ERROR;
}
mCommonRegionReadControl.InCommonReadProcess = TRUE;
ReadBufferSize = (UINTN) OutputBufferSize;
FactoryCopyAddr = FdmGetAddressById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1);
if (FactoryCopyAddr == 0) {
return EFI_OUT_OF_RESOURCES;
}
Status = mSmmFwBlockService->Read (
mSmmFwBlockService,
(UINTN) FactoryCopyAddr,
mCommonRegionReadControl.DataSize - mCommonRegionReadControl.RemainDataSize,
&ReadBufferSize,
OutputBuffer
);
if (EFI_ERROR (Status) || ReadBufferSize < OutputBufferSize) {
return EFI_OUT_OF_RESOURCES;
}
if (mCommonRegionReadControl.RemainDataSize > OutputBufferSize) {
mCommonRegionReadControl.RemainDataSize -= OutputBufferSize;
} else {
//
// The factory copy size must be integer multiple of flash blocks. If RemainDataSize smaller than
// output buffer size indicates this read is inavlid
//
if (mCommonRegionReadControl.RemainDataSize < OutputBufferSize) {
Status = EFI_OUT_OF_RESOURCES;
}
mCommonRegionReadControl.WantToReadData = FALSE;
mCommonRegionReadControl.RemainDataSize = 0;
mCommonRegionReadControl.InCommonReadProcess = FALSE;
}
if (!EFI_ERROR(Status)) {
OutputBufferSize = (UINT32) ReadBufferSize;
CopyMem ((VOID *) (UINTN) IhisiProtReadCpuReg32 (EFI_SMM_SAVE_STATE_REGISTER_RDI), &OutputBufferSize, sizeof (UINT32));
Status = IHISI_SUCCESS;
} else {
Status = IHISI_UNSUPPORTED_FUNCTION;
}
} else {
Status = IHISI_UNSUPPORTED_FUNCTION;
}
return Status;
}
/**
This funciotn uses to export merged factory default setting. The merged factory copy
default setting means keep all of original variable data and then merge variable data
in factory copy region with original data. If finding the same variable, system will
use the variable in factory default to replace oringnal variable.
@param[in, out] DataSize On input, the size in bytes of the return Data buffer.
On output the size of data returned in Data buffer.
@param[out] Data The buffer to return the contents of the variable.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER Some input parameter is invalid.
@retval EFI_BUFFER_TOO_SMALL The VariableStoreLength is too small for the result. DataSize has
been updated with the size needed to complete the request.
@return Others Other error causes merge factory default setting failed.
**/
EFI_STATUS
ExportMergedFactoryDefaultSetting (
IN OUT UINTN *DataSize,
OUT UINT8 *Data
)
{
EFI_STATUS Status;
UINTN WorkingBufferLength;
UINTN VariableBufferLength;
UINTN FactoryCopyRegionSize;
UINT8 *WorkingBuffer;
UINT8 *VariableBuffer;
UINT64 VariableAddr;
UINT64 VariableSize;
UINT64 FactoryCopyAddr;
UINT64 FactoryCopySize;
if (DataSize == NULL || Data == NULL) {
return EFI_INVALID_PARAMETER;
}
WorkingBuffer = NULL;
VariableBuffer = NULL;
WorkingBufferLength = 0;
FactoryCopySize = 0;
FactoryCopyAddr = 0;
VariableSize = 0;
VariableSize = FdmGetNAtSize (&gH2OFlashMapRegionVarGuid, 1);
if (VariableSize == 0) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
VariableAddr = FdmGetNAtAddr (&gH2OFlashMapRegionVarGuid, 1);
if ( VariableAddr == 0) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
FactoryCopySize = FdmGetSizeById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1);
if ( FactoryCopySize == 0) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
ASSERT ( VariableSize >= FactoryCopySize);
//
// Read whole factory copy sub-region data
//
WorkingBufferLength = (UINTN) VariableSize;
WorkingBuffer = AllocatePool (WorkingBufferLength);
if (WorkingBuffer == NULL) {
ASSERT (WorkingBuffer != NULL);
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
SetMem (WorkingBuffer, WorkingBufferLength, 0xFF);
FactoryCopyRegionSize = (UINTN) FactoryCopySize - FACTORY_COPY_HEADER_SIZE;
Status = mSmmFwBlockService->Read (
mSmmFwBlockService,
(UINTN) FdmGetAddressById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1),
FACTORY_COPY_HEADER_SIZE,
&FactoryCopyRegionSize,
WorkingBuffer
);
if (EFI_ERROR (Status)) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
//
// Read whole variable store data
//
VariableBufferLength = (UINTN) VariableSize;
VariableBuffer = AllocatePool (VariableBufferLength);
if (VariableBuffer == NULL) {
ASSERT (VariableBuffer != NULL);
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
SetMem (VariableBuffer, VariableBufferLength, 0xFF);
Status = mSmmFwBlockService->Read (
mSmmFwBlockService,
(UINTN) VariableAddr,
0,
&VariableBufferLength,
VariableBuffer
);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = MergeVariableToFactoryCopy (WorkingBuffer, &WorkingBufferLength, VariableBuffer, VariableBufferLength);
Done:
if (!EFI_ERROR (Status)) {
if (WorkingBufferLength <= *DataSize) {
CopyMem (Data, WorkingBuffer, WorkingBufferLength);
} else {
Status = EFI_BUFFER_TOO_SMALL;
}
*DataSize = WorkingBufferLength;
}
if (WorkingBuffer != NULL) {
FreePool (WorkingBuffer);
}
if (VariableBuffer != NULL) {
FreePool (VariableBuffer);
}
return Status;
}
/**
Checks the contain of factory copy region is valid or not
@retval EFI_SUCCESS The contain in factory copy region is valid.
@retval EFI_NOT_READY The contain in factory copy region is invalid.
@retval EFI_OUT_OF_RESOURCES Not have enough memory to store factory data for check.
**/
STATIC
EFI_STATUS
CheckFacotryCopyData (
VOID
)
{
EFI_STATUS Status;
UINTN Index;
UINTN ReadBufferSize;
UINTN NumberOfInteger;
UINTN *ReadBuffer;
UINT64 FactoryCopySize;
FactoryCopySize = FdmGetSizeById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1);
if (FactoryCopySize == 0) {
return EFI_OUT_OF_RESOURCES;
}
ReadBufferSize = (UINTN) FactoryCopySize - FACTORY_COPY_HEADER_SIZE;
ReadBuffer = AllocatePool (ReadBufferSize);
if (ReadBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = mSmmFwBlockService->Read (
mSmmFwBlockService,
(UINTN) FdmGetAddressById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1),
FACTORY_COPY_HEADER_SIZE,
&ReadBufferSize,
(UINT8 *) ReadBuffer
);
if (!EFI_ERROR (Status)) {
NumberOfInteger = ReadBufferSize / sizeof (UINTN);
for (Index = 0; Index < NumberOfInteger; Index++) {
if (ReadBuffer[Index] != (UINTN) (-1)) {
FreePool (ReadBuffer);
return EFI_SUCCESS;
}
}
}
FreePool (ReadBuffer);
return EFI_NOT_READY;
}
/**
This funciotn uses to export factory default setting to input buffer.
@param[in, out] DataSize On input, the size in bytes of the return Data buffer.
On output the size of data returned in Data buffer.
@param[out] Data The buffer to return the contents of the variable.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER Some input parameter is invalid.
@retval EFI_BUFFER_TOO_SMALL The VariableStoreLength is too small for the result. DataSize has
been updated with the size needed to complete the request.
@return Others Other error causes merge factory default setting failed.
**/
EFI_STATUS
ExportFactoryDefaultSetting (
IN OUT UINTN *DataSize,
OUT UINT8 *Data
)
{
EFI_STATUS Status;
UINTN HeaderSize;
UINTN ReadDataSize;
UINTN RequiredDataSize;
UINT8 *HeaderBuffer;
UINT8 *FactoryDefaultBuffer;
UINT64 FactoryCopySize;
UINT64 VariableAddr;
FactoryDefaultBuffer = NULL;
HeaderBuffer = NULL;
if (DataSize == NULL || Data == NULL) {
return EFI_INVALID_PARAMETER;
}
FactoryCopySize = FdmGetSizeById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1);
if (FactoryCopySize == 0) {
return EFI_OUT_OF_RESOURCES;
}
VariableAddr = FdmGetNAtAddr (&gH2OFlashMapRegionVarGuid, 1);
if (VariableAddr == 0) {
return EFI_OUT_OF_RESOURCES;
}
RequiredDataSize = (UINTN) FactoryCopySize - FACTORY_COPY_HEADER_SIZE;
if (*DataSize < RequiredDataSize) {
*DataSize = RequiredDataSize;
return EFI_BUFFER_TOO_SMALL;
}
//
// Read original firmware volume header and variable store header
//
HeaderSize = sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY) + GetVariableStoreHeaderSize ();
HeaderBuffer = AllocatePool (HeaderSize);
if (HeaderBuffer == NULL) {
ASSERT (HeaderBuffer != NULL);
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
Status = mSmmFwBlockService->Read (
mSmmFwBlockService,
(UINTN) VariableAddr,
0,
&HeaderSize,
HeaderBuffer
);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Read whole factory store data except for factory default header, firmware volume header and variable store header.
//
ReadDataSize = RequiredDataSize - HeaderSize;
FactoryDefaultBuffer = AllocatePool (ReadDataSize);
if (FactoryDefaultBuffer == NULL) {
ASSERT (FactoryDefaultBuffer != NULL);
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
Status = mSmmFwBlockService->Read (
mSmmFwBlockService,
(UINTN) FdmGetAddressById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1),
FACTORY_COPY_HEADER_SIZE + HeaderSize,
&ReadDataSize,
FactoryDefaultBuffer
);
if (EFI_ERROR (Status)) {
goto Done;
}
CopyMem (Data, HeaderBuffer, HeaderSize);
CopyMem (Data + HeaderSize, FactoryDefaultBuffer, RequiredDataSize - HeaderSize);
*DataSize = RequiredDataSize;
Done:
if (FactoryDefaultBuffer != NULL) {
FreePool (FactoryDefaultBuffer);
}
if (HeaderBuffer != NULL) {
FreePool (HeaderBuffer);
}
return Status;
}
/**
According to restore type to collect factory default settings and restore these settings
in output buffer.
@param[in] RestoreType Factory copy restore type.
@param[in, out] BufferSize On input, the size in bytes of the return BufferSize.
On output the size of data returned in BufferSize.
@param[out] FactoryDefaultBuffer The buffer to return the contents of the factory default settings.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER Some input parameter is invalid.
@retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has
been updated with the size needed to complete the request.
@retval EFI_NOT_READY The contain of factory copy region is invalid.
@return Others Other error cause collect factory default setting failed.
**/
EFI_STATUS
CollectFactoryDefaultSetting (
IN UINTN RestoreType,
IN OUT UINTN *BufferSize,
OUT UINT8 *FactoryDefaultBuffer
)
{
EFI_STATUS Status;
if (RestoreType != FACTORY_COPY_RESTORE_WITH_CLEARING_ALL_SETTINGS &&
RestoreType != FACTORY_COPY_RESTORE_WITH_RESERVING_OTHER_SETTINGS) {
return EFI_INVALID_PARAMETER;
}
if (BufferSize == NULL || FactoryDefaultBuffer == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = CheckFacotryCopyData ();
if (EFI_ERROR (Status)) {
return Status;
}
Status = EFI_INVALID_PARAMETER;
switch (RestoreType) {
case FACTORY_COPY_RESTORE_WITH_CLEARING_ALL_SETTINGS:
Status = ExportFactoryDefaultSetting (BufferSize, FactoryDefaultBuffer);
break;
case FACTORY_COPY_RESTORE_WITH_RESERVING_OTHER_SETTINGS:
Status = ExportMergedFactoryDefaultSetting (BufferSize, FactoryDefaultBuffer);
break;
}
return Status;
}
/**
According to restore type to restore factory default.
@param[in] RestoreType Input restore type. this funtion only supports FACTORY_COPY_RESTORE_WITH_CLEARING_ALL_SETTINGS
and FACTORY_COPY_RESTORE_WITH_RESERVING_OTHER_SETTINGS. Other restore type will return
EFI_INVALId_PARAMETER.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
@return Others Other error cause collect factory default setting failed.
**/
EFI_STATUS
RestoreFactory (
IN UINTN RestoreType
)
{
EFI_STATUS Status;
UINTN EraseSize;
UINTN WriteSize;
UINTN BufferSize;
UINTN WriteCount;
BOOLEAN WriteSuccess;
UINT8 *Buffer;
UINT64 FactoryCopySize;
UINT64 VariableAddr;
UINT64 VariableSize;
if (RestoreType != FACTORY_COPY_RESTORE_WITH_CLEARING_ALL_SETTINGS &&
RestoreType != FACTORY_COPY_RESTORE_WITH_RESERVING_OTHER_SETTINGS) {
return EFI_INVALID_PARAMETER;
}
VariableSize = FdmGetNAtSize (&gH2OFlashMapRegionVarGuid, 1);
if (VariableSize == 0) {
return EFI_OUT_OF_RESOURCES;
}
VariableAddr = FdmGetNAtAddr (&gH2OFlashMapRegionVarGuid, 1);
if (VariableAddr == 0) {
return EFI_OUT_OF_RESOURCES;
}
FactoryCopySize = FdmGetSizeById (&gH2OFlashMapRegionVarDefaultGuid, &gH2OFlashMapRegionFactoryCopyGuid, 1);
if (FactoryCopySize == 0) {
return EFI_OUT_OF_RESOURCES;
}
ASSERT (FactoryCopySize <= VariableSize);
BufferSize = (UINTN) VariableSize;
Buffer = AllocatePool (BufferSize);
if (Buffer == NULL) {
ASSERT (Buffer != NULL);
return EFI_OUT_OF_RESOURCES;
}
SetMem (Buffer, BufferSize, 0xFF);
Status = CollectFactoryDefaultSetting (RestoreType, &BufferSize, Buffer);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return Status;
}
WriteSuccess = FALSE;
WriteCount = 0;
do {
EraseSize = (UINTN) VariableSize;
Status = mSmmFwBlockService->EraseBlocks (
mSmmFwBlockService,
(UINTN) VariableAddr,
(UINTN *) &EraseSize
);
if (!EFI_ERROR (Status)) {
WriteSize = BufferSize;
Status = mSmmFwBlockService->Write (
mSmmFwBlockService,
(UINTN) VariableAddr,
(UINTN *) &WriteSize,
Buffer
);
if (!EFI_ERROR (Status)) {
WriteSuccess = TRUE;
}
}
WriteCount++;
} while (WriteCount < 100 && !WriteSuccess);
FreePool (Buffer);
return WriteSuccess ? EFI_SUCCESS : Status;
}
/**
The implementation of IHISI function 49h type 3. Restore variable data from factory copy region and
clear all of variable data in variable store.
@retval EFI_SUCCESS The function completed successfully.
@retval Others Other error cause restoring factory copy failed.
**/
STATIC
EFI_STATUS
RestoreFactoryCopyWithClearingAllSettings (
VOID
)
{
EFI_STATUS Status;
Status = RestoreFactory (FACTORY_COPY_RESTORE_WITH_CLEARING_ALL_SETTINGS);
if (EFI_ERROR (Status)) {
Status = IHISI_ACCESS_PROHIBITED;
}
return Status;
}
/**
The implementation of IHISI function 49h type 4. Clearing all of secure boot settings in variable store and then using
then using variable data contained in factory copy region to update variable. All of other variables (not secure boot
relative variables or variables are located in factory copy region) will not be cleared.
@retval EFI_SUCCESS The function completed successfully.
@retval Others Other error cause restoring factory copy failed.
**/
STATIC
EFI_STATUS
RestoreFactoryCopyWithReservingOtherSettings (
VOID
)
{
EFI_STATUS Status;
Status = RestoreFactory (FACTORY_COPY_RESTORE_WITH_RESERVING_OTHER_SETTINGS);
if (EFI_ERROR (Status)) {
Status = IHISI_ACCESS_PROHIBITED;
}
return Status;
}
EFI_STATUS
CommonRegionDataCommunication (
VOID
)
/*++
Routine Description:
The entry point of IHISI function 49h.
Arguments:
None
Returns:
EFI_SUCCESS - The function completed successfully
EFI_UNSUPPORTED - The type of function 49H is unsupported.
Other - Other error cause in this function.
--*/
{
EFI_STATUS Status;
UINTN Index;
UINT8 DataType;
INPUT_DATA_STRUCTURE *InputData;
OUTPUT_DATA_STRUCTURE *OutputData;
InputData = (INPUT_DATA_STRUCTURE *) (UINTN) IhisiProtReadCpuReg32(EFI_SMM_SAVE_STATE_REGISTER_RCX);
OutputData = (OUTPUT_DATA_STRUCTURE *) (UINTN) IhisiProtReadCpuReg32(EFI_SMM_SAVE_STATE_REGISTER_RCX);
if (!IhisiProtBufferInCmdBuffer ((VOID *) InputData, sizeof (INPUT_DATA_STRUCTURE)) ||
!IhisiProtBufferInCmdBuffer ((VOID *) OutputData, sizeof (OUTPUT_DATA_STRUCTURE))) {
return IHISI_BUFFER_RANGE_ERROR;
}
DataType = InputData->DataType;
Status = InitializeOutputData (OutputData);
ASSERT_EFI_ERROR (Status);
for (Index = 0; Index < sizeof (DataCommunicationSubFun) / sizeof (COMMON_REGION_COMMUNICATION_FUNCTION_TABLE); Index++) {
if (DataType == DataCommunicationSubFun[Index].DataType) {
Status = DataCommunicationSubFun[Index].Function ();
break;
}
}
if (Index == sizeof (DataCommunicationSubFun) / sizeof (COMMON_REGION_COMMUNICATION_FUNCTION_TABLE) || EFI_ERROR (Status)) {
OutputData->Status = UNSUPPORTED_TYPE;
Status = IHISI_UNSUPPORTED_FUNCTION;
}
return Status;
}
EFI_STATUS
InstallCommonRegionCommunicationServices (
VOID
)
{
EFI_STATUS Status;
IHISI_REGISTER_TABLE *SubFuncTable;
UINT16 TableCount;
if (!FeaturePcdGet (PcdH2OSecureBootSupported)) {
return EFI_SUCCESS;
}
SubFuncTable = COMMON_REGION_REGISTER_TABLE;
TableCount = sizeof(COMMON_REGION_REGISTER_TABLE)/sizeof(COMMON_REGION_REGISTER_TABLE[0]);
Status = RegisterIhisiSubFunction (SubFuncTable, TableCount);
if (EFI_ERROR(Status)) {
ASSERT_EFI_ERROR (Status);
}
return EFI_SUCCESS;
}