/** @file Implement variable library related functions. ;****************************************************************************** ;* Copyright (c) 2013 - 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include UINT8 EFIAPI SmmSensitiveVariableCall ( IN UINT8 *InPutBuff, // rcx IN UINTN DataSize, // rdx IN UINT8 SubFunNum, // r8 IN UINT16 SmiPort // r9 ); STATIC EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable; STATIC EFI_SMM_SYSTEM_TABLE2 *mSmst; STATIC BOOLEAN mAtRuntime; STATIC EFI_EVENT mExitBootServicesEvent; STATIC EFI_RUNTIME_SERVICES *mRT; STATIC UINTN mVariableDefaultBase; STATIC UINTN mVariableDefaultSize; STATIC VARIABLE_STORE_HEADER *mVariableStoreBase; STATIC VOID *mSmmVariableProtocolRegistration; /** Notification function of gEfiEventExitBootServicesGuid. This is a notification function registered on gEfiEventExitBootServicesGuid event. @param Event Event whose notification function is being invoked. @param Context Pointer to the notification function's context. **/ STATIC VOID EFIAPI ExitBootServicesEvent ( IN EFI_EVENT Event, IN VOID *Context ) { mAtRuntime = TRUE; gBS->CloseEvent (Event); } /** This function allows the caller to determine if UEFI ExitBootServices() has been called. This function returns TRUE after all the EVT_SIGNAL_EXIT_BOOT_SERVICES functions have executed as a result of the OS calling ExitBootServices(). Prior to this time FALSE is returned. This function is used by runtime code to decide it is legal to access services that go away after ExitBootServices(). @retval TRUE The system has finished executing the EVT_SIGNAL_EXIT_BOOT_SERVICES event. @retval FALSE The system has not finished executing the EVT_SIGNAL_EXIT_BOOT_SERVICES event. **/ STATIC BOOLEAN AtRuntime ( VOID ) { return mAtRuntime; } /** According to system mode to allocate pool. Allocate BootServicesData pool in protect mode if AtRuntime () returns FALSE. Allocate memory from SMM ram if system in SMM mode. Return NULL pointer if system is in protected mode and AtRuntime () returns TRUE. @param[in] Size The size of buffer to allocate @retval NULL Buffer unsuccessfully allocated. @retval Other Buffer successfully allocated. **/ STATIC VOID * InternalAllocateZeroBuffer ( IN UINTN Size ) { if (mSmst == NULL && AtRuntime ()) { return NULL; } return AllocateZeroPool(Size); } /** Internal function to return the value of a variable in different mode (DXE/SMM). @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @param[out] Attributes Attribute value of the variable found. @param[in,out] DataSize Size of Data found. If size is less than the data, this value contains the required size. @param[out] Data Data pointer. @retval EFI_SUCCESS Find the specified variable. @retval EFI_INVALID_PARAMETER Invalid parameter. @retval EFI_NOT_FOUND Not found. @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result. **/ STATIC EFI_STATUS InternalGetVariable ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, OUT VOID *Data ) { if (mSmst != NULL && mSmmVariable == NULL) { return EFI_UNSUPPORTED; } if (mSmmVariable == NULL) { return mRT->GetVariable ( VariableName, VendorGuid, Attributes, DataSize, Data ); } else { return mSmmVariable->SmmGetVariable ( VariableName, VendorGuid, Attributes, DataSize, Data ); } } /** Internal function to set variable in different mode (DXE/SMM). @param[in] VariableName Name of Variable. @param[in] VendorGuid Variable vendor GUID. @param[in] Attributes Attribute value of the variable. @param[in] DataSize Size of variable data by bytes. @param[in] Data Data pointer. @return EFI_SUCCESS Set variable successfully. @retval EFI_INVALID_PARAMETER Invalid parameter. @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable. @retval EFI_WRITE_PROTECTED Variable is read-only. @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS being set, but the AuthInfo does NOT pass the validation check carried out by the firmware. @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. **/ STATIC EFI_STATUS InternalSetVariable ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN VOID *Data ) { if (mSmst != NULL && mSmmVariable == NULL) { return EFI_UNSUPPORTED; } if (mSmmVariable == NULL) { return mRT->SetVariable ( VariableName, VendorGuid, Attributes, DataSize, Data ); } else { return mSmmVariable->SmmSetVariable ( VariableName, VendorGuid, Attributes, DataSize, Data ); } } /** Internal function to enumerates the current variable name in different mode (DXE/SMM). @param[in, out] VariableNameSize Size of the variable name. @param[in, out] VariableName Pointer to variable name. @param[in, out] VendorGuid Variable Vendor Guid. @retval EFI_SUCCESS Invalid parameter. @retval EFI_BUFFER_TOO_SMALL Find the specified variable. @retval EFI_NOT_FOUND Not found. **/ STATIC EFI_STATUS InternalGetNextVariableName ( IN OUT UINTN *VariableNameSize, IN OUT CHAR16 *VariableName, IN OUT EFI_GUID *VendorGuid ) { if (mSmst != NULL && mSmmVariable == NULL) { return EFI_UNSUPPORTED; } if (mSmmVariable == NULL) { return mRT->GetNextVariableName ( VariableNameSize, VariableName, VendorGuid ); } else { return mSmmVariable->SmmGetNextVariableName ( VariableNameSize, VariableName, VendorGuid ); } } /** Detect whether the system is in SMM mode. @retval TRUE System is at SMM mode. @retval FALSE System is not at SMM mode. **/ STATIC BOOLEAN IsInSmm ( VOID ) { EFI_STATUS Status; EFI_SMM_BASE2_PROTOCOL *SmmBase; BOOLEAN InSmm; Status = gBS->LocateProtocol ( &gEfiSmmBase2ProtocolGuid, NULL, (VOID **) &SmmBase ); if (EFI_ERROR (Status)) { return FALSE; } InSmm = FALSE; SmmBase->InSmm (SmmBase, &InSmm); return InSmm; } /** The notification of gEfiSmmVariableProtocolGuid protocol is installed @param Protocol Points to the protocol's unique identifier. @param Interface Points to the interface instance. @param Handle The handle on which the interface was installed. **/ EFI_STATUS EFIAPI SmmVariableProtocolInstalled ( IN CONST EFI_GUID *Protocol, IN VOID *Interface, IN EFI_HANDLE Handle ) { return mSmst->SmmLocateProtocol ( &gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mSmmVariable ); } STATIC EFI_STATUS InitializeSmstAndSmmVariable ( VOID ) { EFI_STATUS Status; EFI_SMM_BASE2_PROTOCOL *SmmBase; Status = gBS->LocateProtocol ( &gEfiSmmBase2ProtocolGuid, NULL, (VOID **) &SmmBase ); if (EFI_ERROR (Status)) { return Status; } Status = SmmBase->GetSmstLocation( SmmBase, &mSmst ); if (EFI_ERROR (Status)) { return Status; } Status = mSmst->SmmLocateProtocol ( &gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable ); if (EFI_ERROR (Status)) { Status = mSmst->SmmRegisterProtocolNotify ( &gEfiSmmVariableProtocolGuid, SmmVariableProtocolInstalled, &mSmmVariableProtocolRegistration ); } return Status; } /** The constructor function to check current mode is protected mode or SMM mode. If system is in SMM mode, constructor will locate gEfiSmmVariableProtocolGuid instance for future usage. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_NOT_FOUND Variable region does not exist. @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. **/ EFI_STATUS EFIAPI DxeVariableLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_GUID VariableDefaultId = FDM_VARIABLE_DEFAULT_ID_VARIABLE_DEFAULT; EFI_FIRMWARE_VOLUME_HEADER *FvHeader; mVariableDefaultBase = (UINTN) FdmGetAddressById (&gH2OFlashMapRegionVarDefaultGuid, &VariableDefaultId, 1); mVariableDefaultSize = (UINTN) FdmGetSizeById (&gH2OFlashMapRegionVarDefaultGuid, &VariableDefaultId, 1); FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FdmGetNAtAddr (&gH2OFlashMapRegionVarGuid, 1); if (FvHeader == NULL) { return EFI_NOT_FOUND; } mVariableStoreBase = (VARIABLE_STORE_HEADER *) ((UINT8 *) FvHeader + FvHeader->HeaderLength); if (IsInSmm ()) { return InitializeSmstAndSmmVariable (); } else { mRT = gRT; IrsiAddVirtualPointer ((VOID **) &mRT); IrsiAddVirtualPointer ((VOID **) &mVariableDefaultBase); IrsiAddVirtualPointer ((VOID **) &mVariableStoreBase); return gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, ExitBootServicesEvent, NULL, &gEfiEventExitBootServicesGuid, &mExitBootServicesEvent ); } } /** If a runtime driver exits with an error, it must call this routine to free the allocated resource before the exiting. It will ASSERT() if gBS is NULL. @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 Runtime Driver Lib shutdown successfully. **/ EFI_STATUS EFIAPI DxeVariableLibDestructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; ASSERT (gBS != NULL); if (mExitBootServicesEvent != NULL) { Status = gBS->CloseEvent (mExitBootServicesEvent); ASSERT_EFI_ERROR (Status); } if (mRT != NULL) { IrsiRemoveVirtualPointer ((VOID **) &mRT); IrsiRemoveVirtualPointer ((VOID **) &mVariableDefaultBase); } if (mSmst != NULL && mSmmVariableProtocolRegistration != NULL) { mSmst->SmmRegisterProtocolNotify ( &gEfiSmmVariableProtocolGuid, NULL, &mSmmVariableProtocolRegistration ); } return EFI_SUCCESS; } /** Read the EFI variable (VariableName/VendorGuid) according to input variable data size. @param[in] VariableName String part of EFI variable name. @param[in] VendorGuid GUID part of EFI variable name. @param[in, out] VariableDataSize Returns the size of the EFI variable that was read. @param[out] VariableData Points to the buffer which will hold the returned variable value. May be NULL with a zero VariableDataSize in order to determine the size of the buffer needed. @retval EFI_SUCCESS Get EFI variable Successful. @retval EFI_INVALID_PARAMETER VariableName is NULL or VendorGuid is NULL or VariableDataSize is NULL or VariableData is NULL. @retval EFI_NOT_FOUND Cannot find specific EFI variable. @retval EFI_BUFFER_TOO_SMALL Input variable data size is too small. VariableDataSize has been updated with the size needed to complete the request. @return Other Other errors cause get variable failed. **/ EFI_STATUS EFIAPI CommonGetVariable ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN OUT UINTN *VariableDataSize, OUT VOID *VariableData ) { return InternalGetVariable ( VariableName, VendorGuid, NULL, VariableDataSize, VariableData ); } /** Read the EFI variable (VariableName/VendorGuid) and return a dynamically allocated buffer. @param[in] VariableName String part of EFI variable name. @param[in] VendorGuid GUID part of EFI variable name. @retval NULL The variable could not be retrieved. @retval NULL There are not enough resources available for the variable contents. @retval Other A pointer to allocated buffer containing the variable contents. **/ VOID * EFIAPI CommonGetVariableData ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid ) { UINTN DataSize; VOID *Data; Data = NULL; CommonGetVariableDataAndSize (VariableName, VendorGuid, &DataSize, &Data); return Data; } /** Read the EFI variable (VariableName/VendorGuid) and return a dynamically allocated buffer, and the size of the buffer. @param[in] VariableName String part of EFI variable name. @param[in] VendorGuid GUID part of EFI variable name. @param[out] VariableDataSize Returns the size of the EFI variable that was read. @param[out] VariableData Dynamically allocated memory that contains a copy of the EFI variable. Caller is responsible freeing the buffer. @retval EFI_SUCCESS Get EFI variable Successful. @retval EFI_INVALID_PARAMETER VariableName is NULL or VendorGuid is NULL or VariableDataSize is NULL or VariableData is NULL. @retval EFI_NOT_FOUND Cannot find specific EFI variable. @retval EFI_OUT_OF_RESOURCES Allocate memory for read variable data failed. @return Other Other errors cause get variable failed. **/ EFI_STATUS EFIAPI CommonGetVariableDataAndSize ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINTN *VariableDataSize, OUT VOID **VariableData ) { EFI_STATUS Status; UINTN DataSize; VOID *DataPtr; if (VariableDataSize == NULL || VariableData == NULL) { return EFI_INVALID_PARAMETER; } if (mSmst == NULL && AtRuntime ()) { return EFI_OUT_OF_RESOURCES; } DataSize = 0; Status = InternalGetVariable ( VariableName, VendorGuid, NULL, &DataSize, NULL ); if (Status == EFI_SUCCESS) { return EFI_UNSUPPORTED; } if (Status != EFI_BUFFER_TOO_SMALL) { return Status; } DataPtr = InternalAllocateZeroBuffer (DataSize); if (DataPtr == NULL) { return EFI_OUT_OF_RESOURCES; } Status = InternalGetVariable ( VariableName, VendorGuid, NULL, &DataSize, DataPtr ); if (EFI_ERROR (Status)) { FreePool (DataPtr); return Status; } *VariableDataSize = DataSize; *VariableData = DataPtr; return EFI_SUCCESS; } /** Read the EFI variable (VariableName/VendorGuid) and return a dynamically allocated buffer, and the size of the buffer. @param[in] VariableName String part of EFI variable name. @param[in] VendorGuid GUID part of EFI variable name. @param[out] VariableDataSize Returns the size of the EFI variable that was read. @param[out] VariableData Dynamically allocated memory that contains a copy of the EFI variable. Caller is responsible freeing the buffer. @param[in] DefaultVariableDataSize Default variable data size. @param[in] DefaultVariableData Pointer to default variable data. @retval TRUE The variable exists and the VariableDataSize and VariableData is filled by variable data size and variable data respectively. @retval FALSE The variable doesn't exit and the VariableDataSize and VariableData is filled by default variable data size and default variable data respectively. **/ BOOLEAN EFIAPI CommonGetVariableWithDefault ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINTN *VariableDataSize, OUT VOID **VariableData, IN UINTN DefaultVariableDataSize, IN VOID *DefaultVariableData ) { EFI_STATUS Status; Status = CommonGetVariableDataAndSize (VariableName, VendorGuid, VariableDataSize, VariableData); if (!EFI_ERROR (Status)) { return TRUE; } ASSERT (DefaultVariableDataSize != 0 && DefaultVariableData != NULL); *VariableData = InternalAllocateZeroBuffer (DefaultVariableDataSize); if (*VariableData == NULL) { return FALSE; } CopyMem (*VariableData, DefaultVariableData, DefaultVariableDataSize); *VariableDataSize = DefaultVariableDataSize; return FALSE; } /** Enumerates the current variable names. @param[in,out] VariableNameSize The size of the VariableName buffer. @param[in,out] VariableName On input, supplies the last VariableName that was returned by GetNextVariableName(). On output, returns the Null-terminated string of the current variable. @param[in,out] VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName(). On output, returns the VendorGuid of the current variable. @retval EFI_SUCCESS The function completed successfully. @retval EFI_NOT_FOUND The next variable was not found. @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result. VariableNameSize has been updated with the size needed to complete the request. @retval EFI_INVALID_PARAMETER VariableNameSize is NULL or VariableName is NULL or VendorGuid is NULL. @retval EFI_DEVICE_ERROR The variable name could not be retrieved due to a hardware error. **/ EFI_STATUS EFIAPI CommonGetNextVariableName ( IN OUT UINTN *VariableNameSize, IN OUT CHAR16 *VariableName, IN OUT EFI_GUID *VendorGuid ) { return InternalGetNextVariableName ( VariableNameSize, VariableName, VendorGuid ); } /** Sets the value of a variable. Since variable PPI only provide read-only services, this function always returns EFI_UNSUPPORTED in PEI phase. @param[in] VariableName String part of EFI variable name. @param[in] VendorGuid GUID part of EFI variable name. @param[in] Attributes Attributes bitmask to set for the variable @param[in] DataSize The size in bytes of the Data buffer. @param[in] Data The contents for the variable. @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as defined by the Attributes. @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the DataSize exceeds the maximum allowed or name is a empty string. @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. @retval EFI_DEVICE_ERROR The variable name could not be retrieved due to a hardware error. @retval EFI_WRITE_PROTECTED The variable in question is read-only or the variable cannot be deleted. @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS being set, but the AuthInfo does NOT pass the validation check carried out by the firmware. **/ EFI_STATUS EFIAPI CommonSetVariable ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN VOID *Data ) { return InternalSetVariable ( VariableName, VendorGuid, Attributes, DataSize, Data ); } /** Initial communication buffer header. @param[in] CommunicationBuffer Input communication buffer. @param[in] CommunicationBufferSize Size of communication buffer in bytes. **/ STATIC VOID InitCommunicationBufferHeader ( IN VOID *CommunicationBuffer, IN UINTN CommunicationBufferSize ) { EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; if (CommunicationBuffer == NULL || CommunicationBufferSize < SMM_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VAR_BUFFER)) { return; } SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommunicationBuffer; ZeroMem (SmmCommunicateHeader, SMM_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VAR_BUFFER)); CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid); SmmCommunicateHeader->MessageLength = SMM_COMMUNICATE_BUFFER_SIZE; } /** Set changed sensitive setup data to sensitive setup variable. @param[in] VariableName A pointer to a null-terminated string that is the variable's name. @param[in] VendorGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of VendorGuid and VariableName must be unique. @param[in] Attributes Attributes bitmask to set for the variable. @param[out] DataSize The data size by byte of found variable @param[out] Data Pointer to the start address of found data. @retval EFI_SUCCESS Find variable from sensitive variable successfully. @retval EFI_INVALID_PARAMETER Any input parameter is incorrect. @retval EFI_UNSUPPORTED The data format to set sensitive variable is incorrect. @retval EFI_WRITE_PROTECTED The service to set variable through SMI is disabled. **/ EFI_STATUS EFIAPI SetVariableToSensitiveVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN VOID *Data ) { EFI_STATUS Status; UINTN BufferSize; EFI_SMM_VARIABLE_PROTOCOL *SmmVariable; EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol; SMM_VAR_BUFFER *SmmVarBuffer; UINT8 *VarBuffer; EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication; NON_VOLATILE_VARIABLE_PROTOCOL *NonVolatileVariableProtocol; VOID *VariableBuffer; UINTN VariableBufferSize; EFI_TPL Tpl; if (AtRuntime ()) { return EFI_UNSUPPORTED; } SmmVariable = NULL; if (mSmst == NULL) { Status = gBS->LocateProtocol ( &gEfiSmmVariableProtocolGuid, NULL, (VOID **) &SmmVariable ); // // Set variable directly if system doesn't provide variable lock protocol to lock variable. // Status = gBS->LocateProtocol ( &gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLockProtocol ); if (EFI_ERROR (Status)) { return CommonSetVariable ( (CHAR16 *) VariableName, (EFI_GUID *) VendorGuid, Attributes, DataSize, Data ); } } // // If mSmst isn't NULL, set variable through SmmVariable instance directly. // If mSmst is NULL and SmmVariable is NULL, set variable through gRT variable services directly. // if (mSmst != NULL || SmmVariable == NULL) { return CommonSetVariable ( (CHAR16 *) VariableName, (EFI_GUID *) VendorGuid, Attributes, DataSize, Data ); } if (VariableName == NULL || VendorGuid == NULL) { return EFI_INVALID_PARAMETER; } if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) { return EFI_INVALID_PARAMETER; } if (DataSize != 0 && Data == NULL) { return EFI_INVALID_PARAMETER; } BufferSize = SMM_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VAR_BUFFER) + StrSize (VariableName) + DataSize; Status = gBS->LocateProtocol ( &gEfiNonVolatileVariableProtocolGuid, NULL, (VOID **) &NonVolatileVariableProtocol ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } Status = gBS->LocateProtocol ( &gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &SmmCommunication ); Status = NonVolatileVariableProtocol->GetRuntimeVariableBuffer (&VariableBuffer, &VariableBufferSize); if (EFI_ERROR (Status) || BufferSize > VariableBufferSize) { return EFI_OUT_OF_RESOURCES; } Tpl = gBS->RaiseTPL (TPL_NOTIFY); InitCommunicationBufferHeader (VariableBuffer, VariableBufferSize); SmmVarBuffer = (SMM_VAR_BUFFER *)((UINTN) VariableBuffer + SMM_COMMUNICATE_HEADER_SIZE); SmmVarBuffer->Signature = SET_SENSITIVE_VARIABLE_SIGNATURE; SmmVarBuffer->DataSize = DataSize; SmmVarBuffer->AccessType = SET_SENSITIVE_VARIABLE_FUN_NUM; SmmVarBuffer->Attributes = Attributes; SmmVarBuffer->VariableNameSize = StrSize (VariableName); CopyGuid (&SmmVarBuffer->VarGuid, VendorGuid); VarBuffer = (UINT8 *) (SmmVarBuffer + 1); StrCpyS ((CHAR16 *) VarBuffer, (MAX_VARIABLE_NAME_SIZE + MAX_VARIABLE_SIZE) / sizeof(CHAR16), VariableName); VarBuffer += SmmVarBuffer->VariableNameSize; CopyMem (VarBuffer, Data, DataSize); SmmVarBuffer->Status = EFI_UNSUPPORTED; Status = SmmCommunication->Communicate (SmmCommunication, VariableBuffer, &VariableBufferSize); gBS->RestoreTPL (Tpl); return SmmVarBuffer->Status; } /** Internal function to get the start address of variable default header according to input SKU ID. @param[in] SkuId Input SKU ID. @return The address of variable store header or NULL if not found. **/ STATIC VOID * GetVariableDefaultStoreHeaderBySkuId ( IN H2O_BOARD_ID SkuId ) { VARIABLE_STORE_HEADER *VariableStoreHeader; ECP_VARIABLE_STORE_HEADER *EcpVariableStoreHeader; if (PcdGetBool (PcdUseEcpVariableStoreHeader)) { for (EcpVariableStoreHeader = (ECP_VARIABLE_STORE_HEADER *) mVariableDefaultBase; EcpVariableStoreHeader != NULL && EcpVariableStoreHeader->Signature == ECP_VARIABLE_STORE_SIGNATURE && EcpVariableStoreHeader->Format == VARIABLE_STORE_FORMATTED && EcpVariableStoreHeader->State == VARIABLE_STORE_HEALTHY && (EcpVariableStoreHeader->Flags & VARIABLE_STORE_ACTIVE_MASK) == VARIABLE_STORE_ACTIVE && EcpVariableStoreHeader->Size >= sizeof (ECP_VARIABLE_STORE_HEADER) && (UINTN) EcpVariableStoreHeader < mVariableDefaultBase + mVariableDefaultSize; EcpVariableStoreHeader = (ECP_VARIABLE_STORE_HEADER *) ((UINT8 *) EcpVariableStoreHeader + EcpVariableStoreHeader->Size)) { if (EcpVariableStoreHeader->DefaultId == 0 && SkuId == GetBoardIdFromVariableStore ((VARIABLE_STORE_HEADER*) EcpVariableStoreHeader)) { return (VOID *) EcpVariableStoreHeader; } } } else { for (VariableStoreHeader = (VARIABLE_STORE_HEADER *) mVariableDefaultBase; VariableStoreHeader != NULL && (CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) || CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid)) && VariableStoreHeader->Format == VARIABLE_STORE_FORMATTED && VariableStoreHeader->State == VARIABLE_STORE_HEALTHY && (VariableStoreHeader->Flags & VARIABLE_STORE_ACTIVE_MASK) == VARIABLE_STORE_ACTIVE && VariableStoreHeader->Size >= sizeof (VARIABLE_STORE_HEADER) && (UINTN) VariableStoreHeader < mVariableDefaultBase + mVariableDefaultSize; VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) VariableStoreHeader + VariableStoreHeader->Size)) { if (VariableStoreHeader->DefaultId == 0 && SkuId == GetBoardIdFromVariableStore (VariableStoreHeader)) { return (VOID *) VariableStoreHeader; } } } return NULL; } /** Read the EFI variable (VariableName/VendorGuid) according to input variable data size. @param[in] VariableName String part of EFI variable name. @param[in] VendorGuid GUID part of EFI variable name. @param[in] SkuId Input SKU ID. @param[in] Attributes Attribute value of the variable found. @param[in, out] VariableDataSize Returns the size of the EFI variable that was read. @param[out] VariableData Dynamically allocated memory that contains a copy of the EFI variable. Caller is responsible freeing the buffer. @retval EFI_SUCCESS Get EFI variable Successful. @retval EFI_INVALID_PARAMETER VariableName is NULL or VendorGuid is NULL or VariableDataSize is NULL or VariableData is NULL. @retval EFI_NOT_FOUND Cannot find specific EFI variable. @retval EFI_BUFFER_TOO_SMALL Input variable data size is too small. VariableDataSize has been updated with the size needed to complete the request. **/ EFI_STATUS EFIAPI CommonGetDefaultVariable ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN H2O_BOARD_ID SkuId, IN UINT32 *Attributes, OPTIONAL IN OUT UINTN *VariableDataSize, OUT VOID *VariableData ) { VOID *VariableStoreHeader; VARIABLE_HEADER *Variable; VARIABLE_HEADER *EndVariable; if (VariableName == NULL || VendorGuid == NULL || VariableDataSize == NULL || VariableName[0] == 0) { return EFI_INVALID_PARAMETER; } VariableStoreHeader = GetVariableDefaultStoreHeaderBySkuId (SkuId); if (VariableStoreHeader == NULL) { return EFI_NOT_FOUND; } Variable = (VARIABLE_HEADER *) ((UINT8 *) VariableStoreHeader + GetVariableStoreHeaderSize ()); EndVariable = (VARIABLE_HEADER *) ((UINT8 *) VariableStoreHeader + GetVariableStoreSize (VariableStoreHeader)); while ((GetNextVariablePtr (Variable) <= EndVariable) && IsValidVariableHeader (Variable)) { if ((CompareGuid (VendorGuid, &Variable->VendorGuid) && !StrCmp (VariableName, GET_VARIABLE_NAME_PTR (Variable)))) { if (Variable->State == VAR_ADDED) { if (*VariableDataSize >= Variable->DataSize) { if (VariableData == NULL) { return EFI_INVALID_PARAMETER; } CopyMem (VariableData, GetVariableDataPtr (Variable), Variable->DataSize); if (Attributes != NULL) { *Attributes = (Variable->Attributes & ~(EFI_VARIABLE_DEFAULT_READY_ONLY | EFI_VARIABLE_INSYDE_AUTHENTICATED_WRITE_ACCESS)); } *VariableDataSize = Variable->DataSize; return EFI_SUCCESS; } else { *VariableDataSize = Variable->DataSize; return EFI_BUFFER_TOO_SMALL; } } } Variable = GetNextVariablePtr (Variable); } return EFI_NOT_FOUND; } /** Read the EFI variable (VariableName/VendorGuid) and return a dynamically allocated buffer, and the size of the buffer. @param[in] VariableName String part of EFI variable name. @param[in] VendorGuid GUID part of EFI variable name. @param[in] SkuId Input SKU ID. @param[in] Attributes Attribute value of the variable found. @param[out] VariableDataSize Returns the size of the EFI variable that was read. @param[out] VariableData Dynamically allocated memory that contains a copy of the EFI variable. Caller is responsible freeing the buffer. @retval EFI_SUCCESS Get EFI variable Successful. @retval EFI_INVALID_PARAMETER VariableName is NULL or VendorGuid is NULL or VariableDataSize is NULL or VariableData is NULL. @retval EFI_NOT_FOUND Cannot find specific EFI variable. @retval EFI_OUT_OF_RESOURCES Allocate memory for read variable data failed. @return Other Other errors cause get variable failed. **/ EFI_STATUS EFIAPI CommonGetDefaultVariableDataAndSize ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN H2O_BOARD_ID SkuId, IN UINT32 *Attribute, OPTIONAL OUT UINTN *VariableDataSize, OUT VOID **VariableData ) { EFI_STATUS Status; UINTN DataSize; VOID *DataPtr; if (VariableDataSize == NULL || VariableData == NULL) { return EFI_INVALID_PARAMETER; } if (mSmst == NULL && AtRuntime ()) { return EFI_OUT_OF_RESOURCES; } DataSize = 0; Status = CommonGetDefaultVariable ( VariableName, VendorGuid, SkuId, Attribute, &DataSize, NULL ); if (Status == EFI_SUCCESS) { return EFI_UNSUPPORTED; } if (Status != EFI_BUFFER_TOO_SMALL) { return Status; } DataPtr = InternalAllocateZeroBuffer (DataSize); if (DataPtr == NULL) { return EFI_OUT_OF_RESOURCES; } Status = CommonGetDefaultVariable ( VariableName, VendorGuid, SkuId, Attribute, &DataSize, DataPtr ); if (EFI_ERROR (Status)) { FreePool (DataPtr); return Status; } *VariableDataSize = DataSize; *VariableData = DataPtr; return EFI_SUCCESS; } /** Check the input variable is stored in variable store region. @param[in] VariableName String part of EFI variable name. @param[in] VendorGuid GUID part of EFI variable name. @retval TRUE Variable is stored in variable store region. @retval FALSE Variable isn't stored in variable store region or doesn't exist. **/ BOOLEAN EFIAPI IsVariableInVariableStoreRegion ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid ) { VARIABLE_HEADER *VariableHeader; VARIABLE_HEADER *VariableEnd; VariableHeader = (VARIABLE_HEADER *) ((UINT8 *) mVariableStoreBase + GetVariableStoreHeaderSize ()); VariableEnd = GetEndPointer (mVariableStoreBase); while (IsValidVariableHeader (VariableHeader) && VariableHeader < VariableEnd) { if ((VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) && StrCmp (VariableName, GET_VARIABLE_NAME_PTR (VariableHeader)) == 0 && CompareGuid (VendorGuid, &VariableHeader->VendorGuid)) { return TRUE; } VariableHeader = GetNextVariablePtr (VariableHeader); } return FALSE; }