Skip to content

Commit 852a5e5

Browse files
kuqin12rohansenUSAShriram Masanamuthu Chinnathuraipharlikar
authored andcommitted
ArmPkg: SmmVariablePei: Introduce variable read service in PEI
This change introduced the Standalone MM based variable read capability in PEI phase for ARM based platforms. Similar to the IA32 counterpart, MM communicate PPI is used to request variable information from TrustZone. Co-authored-by: Ronny Hansen <[email protected]> Co-authored-by: Shriram Masanamuthu Chinnathurai <[email protected]> Co-authored-by: Preshit Harlikar <[email protected]> Signed-off-by: Kun Qin <[email protected]>
1 parent 5b44a2e commit 852a5e5

File tree

4 files changed

+388
-0
lines changed

4 files changed

+388
-0
lines changed

ArmPkg/ArmPkg.dsc

+1
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@
184184
# MU_CHANGE [BEGIN]
185185
ArmPkg/Drivers/StandaloneMmCpu/StandaloneMmCpu.inf
186186
ArmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf
187+
ArmPkg/Drivers/SmmVariablePei/SmmVariablePei.inf
187188
# MU_CHANGE [END]
188189
ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
189190

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/** @file -- SmmVariablePei.h
2+
Provides interface for reading Secure System Variables during PEI.
3+
4+
Copyright (c) Microsoft Corporation.
5+
SPDX-License-Identifier: BSD-2-Clause-Patent
6+
**/
7+
8+
#ifndef _PEI_SMM_VARIABLE_LIB_H_
9+
#define _PEI_SMM_VARIABLE_LIB_H_
10+
11+
#include <PiPei.h>
12+
#include <Uefi/UefiSpec.h>
13+
14+
#include <Library/DebugLib.h>
15+
#include <Library/PcdLib.h>
16+
#include <Library/BaseMemoryLib.h>
17+
#include <Library/PeimEntryPoint.h>
18+
#include <Library/PeiServicesLib.h>
19+
#include <Library/MemoryAllocationLib.h>
20+
#include <Library/HobLib.h>
21+
22+
#include <Guid/SmmVariableCommon.h>
23+
24+
#include <Ppi/ReadOnlyVariable2.h>
25+
#include <Ppi/MmCommunication.h>
26+
27+
#include <Protocol/MmCommunication.h>
28+
29+
/**
30+
* Entry point of PEI Secure Variable read driver
31+
*
32+
* @param FileHandle Handle of the file being invoked.
33+
* Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().
34+
* @param PeiServices General purpose services available to every PEIM.
35+
*
36+
* @retval EFI_SUCCESS If the interface could be successfully installed
37+
* @retval Others Returned from PeiServicesInstallPpi()
38+
*
39+
**/
40+
EFI_STATUS
41+
EFIAPI
42+
PeiSmmVariableInitialize (
43+
IN EFI_PEI_FILE_HANDLE FileHandle,
44+
IN CONST EFI_PEI_SERVICES **PeiServices
45+
);
46+
47+
/**
48+
49+
This function enables the read of Secure Variables during PEI.
50+
51+
This function is using the Secure Variable Store.If the Data
52+
buffer is too small to hold the contents of the variable, the error
53+
EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
54+
size to obtain the data.
55+
56+
The function performs the following:
57+
58+
1) Creates an MM request
59+
2) Fills out the following data structures for the Secure Variable Service
60+
SMM_VARIABLE_COMMUNICATE_HEADER/SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
61+
3) Adds the SMM data structures to the MM request.
62+
4) Sends the MM request to EL3 using MmCommunicationPeiLib.
63+
5) The MM request is sent to S-EL0.
64+
6) The MM request is then handled by the registered handler with GUID: gEfiSmmVariableProtocolGuid
65+
66+
@param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
67+
@param VariableName A pointer to a null-terminated string that is the variable's name.
68+
@param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of
69+
VariableGuid and VariableName must be unique.
70+
@param Attributes If non-NULL, on return, points to the variable's attributes.
71+
@param DataSize On entry, points to the size in bytes of the Data buffer.
72+
On return, points to the size of the data returned in Data.
73+
@param Data Points to the buffer which will hold the returned variable value.
74+
May be NULL with a zero DataSize in order to determine the size of the buffer needed.
75+
76+
@retval EFI_SUCCESS The variable was read successfully.
77+
@retval EFI_NOT_FOUND The variable was not found.
78+
@retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.
79+
DataSize is updated with the size required for
80+
the specified variable.
81+
@retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
82+
@retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.
83+
84+
**/
85+
EFI_STATUS
86+
EFIAPI
87+
PeiSmmGetVariable (
88+
IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
89+
IN CONST CHAR16 *VariableName,
90+
IN CONST EFI_GUID *VariableGuid,
91+
OUT UINT32 *Attributes,
92+
IN OUT UINTN *DataSize,
93+
OUT VOID *Data OPTIONAL
94+
);
95+
96+
/**
97+
* This function is not supported
98+
* @retval EFI_UNSUPPORTED
99+
*
100+
**/
101+
EFI_STATUS
102+
EFIAPI
103+
PeiSmmGetNextVariableName (
104+
IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
105+
IN OUT UINTN *VariableNameSize,
106+
IN OUT CHAR16 *VariableName,
107+
IN OUT EFI_GUID *VariableGuid
108+
);
109+
110+
#endif /* _PEI_SMM_VARIABLE_LIB_H_ */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
## @file -- SmmVariablePei.inf
2+
# Provides interface for reading Secure System Variables during PEI.
3+
#
4+
# Copyright (c) Microsoft Corporation.
5+
# SPDX-License-Identifier: BSD-2-Clause-Patent
6+
##
7+
8+
9+
[Defines]
10+
INF_VERSION = 0x00010005
11+
BASE_NAME = SmmVariablePei
12+
FILE_GUID = 7B93DCF8-8F5D-4BC1-A3E5-8288D337CAA0
13+
MODULE_TYPE = PEIM
14+
VERSION_STRING = 1.0
15+
ENTRY_POINT = PeiSmmVariableInitialize
16+
17+
[Sources]
18+
SmmVariablePei.c
19+
SmmVariablePei.h
20+
21+
[Packages]
22+
MdePkg/MdePkg.dec
23+
MdeModulePkg/MdeModulePkg.dec
24+
ArmPkg/ArmPkg.dec
25+
26+
[LibraryClasses]
27+
PcdLib
28+
PeiServicesLib
29+
PeimEntryPoint
30+
MemoryAllocationLib
31+
HobLib
32+
33+
[Pcd]
34+
gArmTokenSpaceGuid.PcdMmBufferBase
35+
gArmTokenSpaceGuid.PcdMmBufferSize
36+
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
37+
38+
[Protocols]
39+
gEfiSmmVariableProtocolGuid ## CONSUMES
40+
41+
[Ppis]
42+
gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES
43+
gEfiPeiMmCommunicationPpiGuid ## CONSUMES
44+
45+
[Depex]
46+
gEfiPeiMmCommunicationPpiGuid

0 commit comments

Comments
 (0)