]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / PiSmmCommunication / PiSmmCommunicationPei.c
1 /** @file
2 PiSmmCommunication PEI Driver.
3
4 Copyright (c) 2010 - 2021, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <PiPei.h>
10 #include <PiDxe.h>
11 #include <PiSmm.h>
12 #include <Library/PeiServicesTablePointerLib.h>
13 #include <Library/PeiServicesLib.h>
14 #include <Library/BaseLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/HobLib.h>
17 #include <Library/DebugLib.h>
18 #include <Protocol/SmmCommunication.h>
19 #include <Ppi/SmmCommunication.h>
20 #include <Ppi/SmmAccess.h>
21 #include <Ppi/SmmControl.h>
22 #include <Guid/AcpiS3Context.h>
23
24 #include "PiSmmCommunicationPrivate.h"
25
26 /**
27 the whole picture is below:
28
29 +----------------------------------+
30 | ACPI_VARIABLE_HOB |
31 | SmramDescriptor | <- DRAM
32 | CpuStart |---
33 +----------------------------------+ |
34 |
35 +----------------------------------+<--
36 | SMM_S3_RESUME_STATE |
37 | Signature | <- SMRAM
38 | Smst |---
39 +----------------------------------+ |
40 |
41 +----------------------------------+<--
42 | EFI_SMM_SYSTEM_TABLE2 |
43 | NumberOfTableEntries | <- SMRAM
44 | SmmConfigurationTable |---
45 +----------------------------------+ |
46 |
47 +----------------------------------+<--
48 | EFI_SMM_COMMUNICATION_CONTEXT |
49 | SwSmiNumber | <- SMRAM
50 | BufferPtrAddress |---
51 +----------------------------------+ |
52 |
53 +----------------------------------+<--
54 | Communication Buffer Pointer | <- AcpiNvs
55 +----------------------------------+---
56 |
57 +----------------------------------+<--
58 | EFI_SMM_COMMUNICATE_HEADER |
59 | HeaderGuid | <- DRAM
60 | MessageLength |
61 +----------------------------------+
62
63 **/
64
65 #if defined (MDE_CPU_IA32)
66 typedef struct {
67 EFI_TABLE_HEADER Hdr;
68 UINT64 SmmFirmwareVendor;
69 UINT64 SmmFirmwareRevision;
70 UINT64 SmmInstallConfigurationTable;
71 UINT64 SmmIoMemRead;
72 UINT64 SmmIoMemWrite;
73 UINT64 SmmIoIoRead;
74 UINT64 SmmIoIoWrite;
75 UINT64 SmmAllocatePool;
76 UINT64 SmmFreePool;
77 UINT64 SmmAllocatePages;
78 UINT64 SmmFreePages;
79 UINT64 SmmStartupThisAp;
80 UINT64 CurrentlyExecutingCpu;
81 UINT64 NumberOfCpus;
82 UINT64 CpuSaveStateSize;
83 UINT64 CpuSaveState;
84 UINT64 NumberOfTableEntries;
85 UINT64 SmmConfigurationTable;
86 } EFI_SMM_SYSTEM_TABLE2_64;
87
88 typedef struct {
89 EFI_GUID VendorGuid;
90 UINT64 VendorTable;
91 } EFI_CONFIGURATION_TABLE64;
92 #endif
93
94 #if defined (MDE_CPU_X64)
95 typedef EFI_SMM_SYSTEM_TABLE2 EFI_SMM_SYSTEM_TABLE2_64;
96 typedef EFI_CONFIGURATION_TABLE EFI_CONFIGURATION_TABLE64;
97 #endif
98
99 /**
100 Communicates with a registered handler.
101
102 This function provides a service to send and receive messages from a registered UEFI service.
103
104 @param[in] This The EFI_PEI_SMM_COMMUNICATION_PPI instance.
105 @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
106 @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data
107 being returned. Zero if the handler does not wish to reply with any data.
108
109 @retval EFI_SUCCESS The message was successfully posted.
110 @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
111 @retval EFI_NOT_STARTED The service is NOT started.
112 **/
113 EFI_STATUS
114 EFIAPI
115 Communicate (
116 IN CONST EFI_PEI_SMM_COMMUNICATION_PPI *This,
117 IN OUT VOID *CommBuffer,
118 IN OUT UINTN *CommSize
119 );
120
121 EFI_PEI_SMM_COMMUNICATION_PPI mSmmCommunicationPpi = { Communicate };
122
123 EFI_PEI_PPI_DESCRIPTOR mPpiList = {
124 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
125 &gEfiPeiSmmCommunicationPpiGuid,
126 &mSmmCommunicationPpi
127 };
128
129 /**
130 Get SMM communication context.
131
132 @return SMM communication context.
133 **/
134 EFI_SMM_COMMUNICATION_CONTEXT *
135 GetCommunicationContext (
136 VOID
137 )
138 {
139 EFI_HOB_GUID_TYPE *GuidHob;
140 EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext;
141
142 GuidHob = GetFirstGuidHob (&gEfiPeiSmmCommunicationPpiGuid);
143 ASSERT (GuidHob != NULL);
144
145 SmmCommunicationContext = (EFI_SMM_COMMUNICATION_CONTEXT *)GET_GUID_HOB_DATA (GuidHob);
146
147 return SmmCommunicationContext;
148 }
149
150 /**
151 Set SMM communication context.
152
153 @param SmmCommunicationContext SMM communication context.
154 **/
155 VOID
156 SetCommunicationContext (
157 IN EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext
158 )
159 {
160 EFI_PEI_HOB_POINTERS Hob;
161 UINTN BufferSize;
162
163 BufferSize = sizeof (*SmmCommunicationContext);
164 Hob.Raw = BuildGuidHob (
165 &gEfiPeiSmmCommunicationPpiGuid,
166 BufferSize
167 );
168 ASSERT (Hob.Raw);
169
170 CopyMem ((VOID *)Hob.Raw, SmmCommunicationContext, sizeof (*SmmCommunicationContext));
171 }
172
173 /**
174 Get VendorTable by VendorGuid in Smst.
175
176 @param Signature Signature of SMM_S3_RESUME_STATE
177 @param Smst SMM system table
178 @param VendorGuid vendor guid
179
180 @return vendor table.
181 **/
182 VOID *
183 InternalSmstGetVendorTableByGuid (
184 IN UINT64 Signature,
185 IN EFI_SMM_SYSTEM_TABLE2 *Smst,
186 IN EFI_GUID *VendorGuid
187 )
188 {
189 EFI_CONFIGURATION_TABLE *SmmConfigurationTable;
190 UINTN NumberOfTableEntries;
191 UINTN Index;
192 EFI_SMM_SYSTEM_TABLE2_64 *Smst64;
193 EFI_CONFIGURATION_TABLE64 *SmmConfigurationTable64;
194
195 if ((sizeof (UINTN) == sizeof (UINT32)) && (Signature == SMM_S3_RESUME_SMM_64)) {
196 //
197 // 32 PEI + 64 DXE
198 //
199 Smst64 = (EFI_SMM_SYSTEM_TABLE2_64 *)Smst;
200 DEBUG ((DEBUG_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst64->SmmConfigurationTable));
201 DEBUG ((DEBUG_INFO, "InitCommunicationContext - NumberOfTableEntries: %x\n", Smst64->NumberOfTableEntries));
202 SmmConfigurationTable64 = (EFI_CONFIGURATION_TABLE64 *)(UINTN)Smst64->SmmConfigurationTable;
203 NumberOfTableEntries = (UINTN)Smst64->NumberOfTableEntries;
204 for (Index = 0; Index < NumberOfTableEntries; Index++) {
205 if (CompareGuid (&SmmConfigurationTable64[Index].VendorGuid, VendorGuid)) {
206 return (VOID *)(UINTN)SmmConfigurationTable64[Index].VendorTable;
207 }
208 }
209
210 return NULL;
211 } else {
212 DEBUG ((DEBUG_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst->SmmConfigurationTable));
213 DEBUG ((DEBUG_INFO, "InitCommunicationContext - NumberOfTableEntries: %x\n", Smst->NumberOfTableEntries));
214 SmmConfigurationTable = Smst->SmmConfigurationTable;
215 NumberOfTableEntries = Smst->NumberOfTableEntries;
216 for (Index = 0; Index < NumberOfTableEntries; Index++) {
217 if (CompareGuid (&SmmConfigurationTable[Index].VendorGuid, VendorGuid)) {
218 return (VOID *)SmmConfigurationTable[Index].VendorTable;
219 }
220 }
221
222 return NULL;
223 }
224 }
225
226 /**
227 Init SMM communication context.
228 **/
229 VOID
230 InitCommunicationContext (
231 VOID
232 )
233 {
234 EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
235 SMM_S3_RESUME_STATE *SmmS3ResumeState;
236 VOID *GuidHob;
237 EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext;
238
239 GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
240 ASSERT (GuidHob != NULL);
241 SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *)GET_GUID_HOB_DATA (GuidHob);
242 SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
243
244 DEBUG ((DEBUG_INFO, "InitCommunicationContext - SmmS3ResumeState: %x\n", SmmS3ResumeState));
245 DEBUG ((DEBUG_INFO, "InitCommunicationContext - Smst: %x\n", SmmS3ResumeState->Smst));
246
247 SmmCommunicationContext = (EFI_SMM_COMMUNICATION_CONTEXT *)InternalSmstGetVendorTableByGuid (
248 SmmS3ResumeState->Signature,
249 (EFI_SMM_SYSTEM_TABLE2 *)(UINTN)SmmS3ResumeState->Smst,
250 &gEfiPeiSmmCommunicationPpiGuid
251 );
252 ASSERT (SmmCommunicationContext != NULL);
253
254 SetCommunicationContext (SmmCommunicationContext);
255
256 return;
257 }
258
259 /**
260 Communicates with a registered handler.
261
262 This function provides a service to send and receive messages from a registered UEFI service.
263
264 @param[in] This The EFI_PEI_SMM_COMMUNICATION_PPI instance.
265 @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
266 @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data
267 being returned. Zero if the handler does not wish to reply with any data.
268
269 @retval EFI_SUCCESS The message was successfully posted.
270 @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
271 @retval EFI_NOT_STARTED The service is NOT started.
272 **/
273 EFI_STATUS
274 EFIAPI
275 Communicate (
276 IN CONST EFI_PEI_SMM_COMMUNICATION_PPI *This,
277 IN OUT VOID *CommBuffer,
278 IN OUT UINTN *CommSize
279 )
280 {
281 EFI_STATUS Status;
282 PEI_SMM_CONTROL_PPI *SmmControl;
283 PEI_SMM_ACCESS_PPI *SmmAccess;
284 UINT8 SmiCommand;
285 UINTN Size;
286 EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext;
287
288 DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei Communicate Enter\n"));
289
290 if (CommBuffer == NULL) {
291 return EFI_INVALID_PARAMETER;
292 }
293
294 //
295 // Get needed resource
296 //
297 Status = PeiServicesLocatePpi (
298 &gPeiSmmControlPpiGuid,
299 0,
300 NULL,
301 (VOID **)&SmmControl
302 );
303 if (EFI_ERROR (Status)) {
304 return EFI_NOT_STARTED;
305 }
306
307 Status = PeiServicesLocatePpi (
308 &gPeiSmmAccessPpiGuid,
309 0,
310 NULL,
311 (VOID **)&SmmAccess
312 );
313 if (EFI_ERROR (Status)) {
314 return EFI_NOT_STARTED;
315 }
316
317 //
318 // Check SMRAM locked, it should be done after SMRAM lock.
319 //
320 if (!SmmAccess->LockState) {
321 DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState));
322 return EFI_NOT_STARTED;
323 }
324
325 SmmCommunicationContext = GetCommunicationContext ();
326 DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei BufferPtrAddress - 0x%016lx, BufferPtr: 0x%016lx\n", SmmCommunicationContext->BufferPtrAddress, *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress));
327
328 //
329 // No need to check if BufferPtr is 0, because it is in PEI phase.
330 //
331 *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CommBuffer;
332 DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei CommBuffer - %x\n", (UINTN)CommBuffer));
333
334 //
335 // Send command
336 //
337 SmiCommand = (UINT8)SmmCommunicationContext->SwSmiNumber;
338 Size = sizeof (SmiCommand);
339 Status = SmmControl->Trigger (
340 (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
341 SmmControl,
342 (INT8 *)&SmiCommand,
343 &Size,
344 FALSE,
345 0
346 );
347 ASSERT_EFI_ERROR (Status);
348
349 //
350 // Setting BufferPtr to 0 means this transaction is done.
351 //
352 *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress = 0;
353
354 DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei Communicate Exit\n"));
355
356 return EFI_SUCCESS;
357 }
358
359 /**
360 Entry Point for PI SMM communication PEIM.
361
362 @param FileHandle Handle of the file being invoked.
363 @param PeiServices Pointer to PEI Services table.
364
365 @retval EFI_SUCCESS
366 @return Others Some error occurs.
367 **/
368 EFI_STATUS
369 EFIAPI
370 PiSmmCommunicationPeiEntryPoint (
371 IN EFI_PEI_FILE_HANDLE FileHandle,
372 IN CONST EFI_PEI_SERVICES **PeiServices
373 )
374 {
375 EFI_STATUS Status;
376 PEI_SMM_ACCESS_PPI *SmmAccess;
377 EFI_BOOT_MODE BootMode;
378 UINTN Index;
379
380 BootMode = GetBootModeHob ();
381 if (BootMode != BOOT_ON_S3_RESUME) {
382 return EFI_UNSUPPORTED;
383 }
384
385 Status = PeiServicesLocatePpi (
386 &gPeiSmmAccessPpiGuid,
387 0,
388 NULL,
389 (VOID **)&SmmAccess
390 );
391 if (EFI_ERROR (Status)) {
392 return EFI_NOT_STARTED;
393 }
394
395 //
396 // Check SMRAM locked, it should be done before SMRAM lock.
397 //
398 if (SmmAccess->LockState) {
399 DEBUG ((DEBUG_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState));
400 return EFI_ACCESS_DENIED;
401 }
402
403 //
404 // Open all SMRAM
405 //
406 for (Index = 0; !EFI_ERROR (Status); Index++) {
407 Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
408 }
409
410 InitCommunicationContext ();
411
412 PeiServicesInstallPpi (&mPpiList);
413
414 return RETURN_SUCCESS;
415 }