|
| 1 | +/** @file -- SmmVariablePei.c |
| 2 | + Provides interface for reading Secure System Variables during PEI. |
| 3 | +
|
| 4 | + Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> |
| 5 | + Copyright (c) Microsoft Corporation.<BR> |
| 6 | + SPDX-License-Identifier: BSD-2-Clause-Patent |
| 7 | +**/ |
| 8 | + |
| 9 | +#include "SmmVariablePei.h" |
| 10 | + |
| 11 | +// |
| 12 | +// Module globals |
| 13 | +// |
| 14 | +EFI_PEI_READ_ONLY_VARIABLE2_PPI mPeiSecureVariableRead = { |
| 15 | + PeiSmmGetVariable, |
| 16 | + PeiSmmGetNextVariableName |
| 17 | +}; |
| 18 | + |
| 19 | +EFI_PEI_PPI_DESCRIPTOR mPeiSmmVariablePpi = { |
| 20 | + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), |
| 21 | + &gEfiPeiReadOnlyVariable2PpiGuid, |
| 22 | + &mPeiSecureVariableRead |
| 23 | +}; |
| 24 | + |
| 25 | +/** |
| 26 | + * Entry point of PEI Secure Variable read driver |
| 27 | + * |
| 28 | + * @param FileHandle Handle of the file being invoked. |
| 29 | + * Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile(). |
| 30 | + * @param PeiServices General purpose services available to every PEIM. |
| 31 | + * |
| 32 | + * @retval EFI_SUCCESS If the interface could be successfully installed |
| 33 | + * @retval Others Returned from PeiServicesInstallPpi() |
| 34 | + * |
| 35 | +**/ |
| 36 | +EFI_STATUS |
| 37 | +EFIAPI |
| 38 | +PeiSmmVariableInitialize ( |
| 39 | + IN EFI_PEI_FILE_HANDLE FileHandle, |
| 40 | + IN CONST EFI_PEI_SERVICES **PeiServices |
| 41 | + ) |
| 42 | +{ |
| 43 | + return PeiServicesInstallPpi (&mPeiSmmVariablePpi); |
| 44 | +} |
| 45 | + |
| 46 | +/** |
| 47 | + This service retrieves a variable's value using its name and GUID. |
| 48 | +
|
| 49 | + This function is using the Secure Variable Store. If the Data |
| 50 | + buffer is too small to hold the contents of the variable, the error |
| 51 | + EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer |
| 52 | + size to obtain the data. |
| 53 | +
|
| 54 | + @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI. |
| 55 | + @param VariableName A pointer to a null-terminated string that is the variable's name. |
| 56 | + @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of |
| 57 | + VariableGuid and VariableName must be unique. |
| 58 | + @param Attributes If non-NULL, on return, points to the variable's attributes. |
| 59 | + @param DataSize On entry, points to the size in bytes of the Data buffer. |
| 60 | + On return, points to the size of the data returned in Data. |
| 61 | + @param Data Points to the buffer which will hold the returned variable value. |
| 62 | + May be NULL with a zero DataSize in order to determine the size of the buffer needed. |
| 63 | +
|
| 64 | + @retval EFI_SUCCESS The variable was read successfully. |
| 65 | + @retval EFI_NOT_FOUND The variable was not found. |
| 66 | + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data. |
| 67 | + DataSize is updated with the size required for |
| 68 | + the specified variable. |
| 69 | + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL. |
| 70 | + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. |
| 71 | +
|
| 72 | +**/ |
| 73 | +EFI_STATUS |
| 74 | +EFIAPI |
| 75 | +PeiSmmGetVariable ( |
| 76 | + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, |
| 77 | + IN CONST CHAR16 *VariableName, |
| 78 | + IN CONST EFI_GUID *VariableGuid, |
| 79 | + OUT UINT32 *Attributes, OPTIONAL |
| 80 | + IN OUT UINTN *DataSize, |
| 81 | + OUT VOID *Data OPTIONAL |
| 82 | + ) |
| 83 | +{ |
| 84 | + EFI_STATUS Status; |
| 85 | + UINTN MessageSize; |
| 86 | + EFI_MM_COMMUNICATE_HEADER *CommunicateHeader; |
| 87 | + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVarCommsHeader; |
| 88 | + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVarAccessHeader; |
| 89 | + UINT8 *MmCommunicateBuffer; |
| 90 | + UINT8 RequiredPages; |
| 91 | + EFI_PEI_MM_COMMUNICATION_PPI *MmCommunicationPpi; |
| 92 | + |
| 93 | + // Check input parameters |
| 94 | + if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == NULL)) { |
| 95 | + return EFI_INVALID_PARAMETER; |
| 96 | + } |
| 97 | + |
| 98 | + if (VariableName[0] == 0) { |
| 99 | + return EFI_NOT_FOUND; |
| 100 | + } |
| 101 | + |
| 102 | + if ((*DataSize > 0) && (Data == NULL)) { |
| 103 | + return EFI_INVALID_PARAMETER; |
| 104 | + } |
| 105 | + |
| 106 | + Status = PeiServicesLocatePpi (&gEfiPeiMmCommunicationPpiGuid, 0, NULL, (VOID **)&MmCommunicationPpi); |
| 107 | + if (EFI_ERROR (Status)) { |
| 108 | + DEBUG ((DEBUG_ERROR, "%a: Failed to locate PEI MM Communication PPI: %r\n", __FUNCTION__, Status)); |
| 109 | + return Status; |
| 110 | + } |
| 111 | + |
| 112 | + // Allocate required pages to send MM request |
| 113 | + RequiredPages = EFI_SIZE_TO_PAGES ( |
| 114 | + sizeof (EFI_MM_COMMUNICATE_HEADER) + \ |
| 115 | + sizeof (SMM_VARIABLE_COMMUNICATE_HEADER) + \ |
| 116 | + sizeof (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE) + \ |
| 117 | + StrSize (VariableName) + *DataSize |
| 118 | + ); |
| 119 | + MmCommunicateBuffer = (UINT8 *)AllocatePages (RequiredPages); |
| 120 | + |
| 121 | + if (MmCommunicateBuffer == NULL) { |
| 122 | + Status = EFI_OUT_OF_RESOURCES; |
| 123 | + DEBUG ((DEBUG_ERROR, "%a: Failed to allocate memory: %r\n", __FUNCTION__, Status)); |
| 124 | + return Status; |
| 125 | + } |
| 126 | + |
| 127 | + // Zero the entire Communication Buffer |
| 128 | + ZeroMem (MmCommunicateBuffer, (RequiredPages * EFI_PAGE_SIZE)); |
| 129 | + |
| 130 | + CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)MmCommunicateBuffer; |
| 131 | + |
| 132 | + SmmVarCommsHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommunicateHeader->Data; |
| 133 | + |
| 134 | + SmmVarAccessHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)SmmVarCommsHeader->Data; |
| 135 | + |
| 136 | + // Use gEfiSmmVariableProtocolGuid to request the SMM variable service in S-EL0 |
| 137 | + CopyMem ((VOID *)&CommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid, sizeof (GUID)); |
| 138 | + |
| 139 | + // We are only supporting GetVariable |
| 140 | + SmmVarCommsHeader->Function = SMM_VARIABLE_FUNCTION_GET_VARIABLE; |
| 141 | + |
| 142 | + // Variable GUID |
| 143 | + CopyMem ((VOID *)&SmmVarAccessHeader->Guid, VariableGuid, sizeof (GUID)); |
| 144 | + |
| 145 | + // Program the max amount of data we accept. |
| 146 | + SmmVarAccessHeader->DataSize = *DataSize; |
| 147 | + |
| 148 | + // Get size of the variable name |
| 149 | + SmmVarAccessHeader->NameSize = StrSize (VariableName); |
| 150 | + |
| 151 | + // |
| 152 | + // Program all data structure sizes |
| 153 | + // |
| 154 | + |
| 155 | + // Program the MM header size |
| 156 | + CommunicateHeader->MessageLength = sizeof (SMM_VARIABLE_COMMUNICATE_HEADER) - 1 + \ |
| 157 | + sizeof (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE) - 1 + \ |
| 158 | + SmmVarAccessHeader->NameSize + SmmVarAccessHeader->DataSize; |
| 159 | + |
| 160 | + // Size of the entire message sent to the secure world. |
| 161 | + MessageSize = CommunicateHeader->MessageLength + \ |
| 162 | + sizeof (CommunicateHeader->HeaderGuid) + \ |
| 163 | + sizeof (CommunicateHeader->MessageLength); |
| 164 | + |
| 165 | + CopyMem ((VOID *)&SmmVarAccessHeader->Name, VariableName, SmmVarAccessHeader->NameSize); |
| 166 | + |
| 167 | + // Send the MM request using MmCommunicationPeiLib |
| 168 | + Status = MmCommunicationPpi->Communicate (MmCommunicationPpi, CommunicateHeader, &MessageSize); |
| 169 | + |
| 170 | + if (EFI_ERROR (Status)) { |
| 171 | + // Received an error from MM interface. |
| 172 | + DEBUG ((DEBUG_ERROR, "%a - MM Interface Error: %r\n", __FUNCTION__, Status)); |
| 173 | + goto Exit; |
| 174 | + } |
| 175 | + |
| 176 | + // MM request was successfully handled by the framework. |
| 177 | + // Set status to the Variable Service Status Code |
| 178 | + Status = SmmVarCommsHeader->ReturnStatus; |
| 179 | + if (EFI_ERROR (Status)) { |
| 180 | + // We received an error from Variable Service. |
| 181 | + // We cant do anymore so return Status |
| 182 | + if (Status != EFI_BUFFER_TOO_SMALL) { |
| 183 | + DEBUG ((DEBUG_ERROR, "%a - Variable Service Error: %r\n", __FUNCTION__, Status)); |
| 184 | + } |
| 185 | + |
| 186 | + goto Exit; |
| 187 | + } |
| 188 | + |
| 189 | + Status = EFI_SUCCESS; |
| 190 | + |
| 191 | + // User provided buffer is too small |
| 192 | + if (*DataSize < SmmVarAccessHeader->DataSize) { |
| 193 | + Status = EFI_BUFFER_TOO_SMALL; |
| 194 | + } |
| 195 | + |
| 196 | +Exit: |
| 197 | + // Check if we need to set Attributes |
| 198 | + if (Attributes != NULL) { |
| 199 | + *Attributes = SmmVarAccessHeader->Attributes; |
| 200 | + } |
| 201 | + |
| 202 | + *DataSize = SmmVarAccessHeader->DataSize; |
| 203 | + |
| 204 | + if (Status == EFI_SUCCESS) { |
| 205 | + CopyMem ((VOID *)Data, (UINT8 *)SmmVarAccessHeader->Name + SmmVarAccessHeader->NameSize, *DataSize); |
| 206 | + } |
| 207 | + |
| 208 | + // Free the Communication Buffer |
| 209 | + if (MmCommunicateBuffer != NULL) { |
| 210 | + FreePages (MmCommunicateBuffer, RequiredPages); |
| 211 | + } |
| 212 | + |
| 213 | + return Status; |
| 214 | +} |
| 215 | + |
| 216 | +/** |
| 217 | + * This function is not supported |
| 218 | + * @retval EFI_UNSUPPORTED |
| 219 | + * |
| 220 | +**/ |
| 221 | +EFI_STATUS |
| 222 | +EFIAPI |
| 223 | +PeiSmmGetNextVariableName ( |
| 224 | + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, |
| 225 | + IN OUT UINTN *VariableNameSize, |
| 226 | + IN OUT CHAR16 *VariableName, |
| 227 | + IN OUT EFI_GUID *VariableGuid |
| 228 | + ) |
| 229 | +{ |
| 230 | + return EFI_UNSUPPORTED; |
| 231 | +} |
0 commit comments