]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.c
110165b20b4bb715ee3ca422fced778f63591f26
[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 ((EFI_D_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst64->SmmConfigurationTable));
201 DEBUG ((EFI_D_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 return NULL;
210 } else {
211 DEBUG ((EFI_D_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst->SmmConfigurationTable));
212 DEBUG ((EFI_D_INFO, "InitCommunicationContext - NumberOfTableEntries: %x\n", Smst->NumberOfTableEntries));
213 SmmConfigurationTable = Smst->SmmConfigurationTable;
214 NumberOfTableEntries = Smst->NumberOfTableEntries;
215 for (Index = 0; Index < NumberOfTableEntries; Index++) {
216 if (CompareGuid (&SmmConfigurationTable[Index].VendorGuid, VendorGuid)) {
217 return (VOID *)SmmConfigurationTable[Index].VendorTable;
218 }
219 }
220 return NULL;
221 }
222 }
223
224 /**
225 Init SMM communication context.
226 **/
227 VOID
228 InitCommunicationContext (
229 VOID
230 )
231 {
232 EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
233 SMM_S3_RESUME_STATE *SmmS3ResumeState;
234 VOID *GuidHob;
235 EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext;
236
237 GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
238 ASSERT (GuidHob != NULL);
239 SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
240 SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
241
242 DEBUG ((EFI_D_INFO, "InitCommunicationContext - SmmS3ResumeState: %x\n", SmmS3ResumeState));
243 DEBUG ((EFI_D_INFO, "InitCommunicationContext - Smst: %x\n", SmmS3ResumeState->Smst));
244
245 SmmCommunicationContext = (EFI_SMM_COMMUNICATION_CONTEXT *)InternalSmstGetVendorTableByGuid (
246 SmmS3ResumeState->Signature,
247 (EFI_SMM_SYSTEM_TABLE2 *)(UINTN)SmmS3ResumeState->Smst,
248 &gEfiPeiSmmCommunicationPpiGuid
249 );
250 ASSERT (SmmCommunicationContext != NULL);
251
252 SetCommunicationContext (SmmCommunicationContext);
253
254 return ;
255 }
256
257 /**
258 Communicates with a registered handler.
259
260 This function provides a service to send and receive messages from a registered UEFI service.
261
262 @param[in] This The EFI_PEI_SMM_COMMUNICATION_PPI instance.
263 @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
264 @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data
265 being returned. Zero if the handler does not wish to reply with any data.
266
267 @retval EFI_SUCCESS The message was successfully posted.
268 @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
269 @retval EFI_NOT_STARTED The service is NOT started.
270 **/
271 EFI_STATUS
272 EFIAPI
273 Communicate (
274 IN CONST EFI_PEI_SMM_COMMUNICATION_PPI *This,
275 IN OUT VOID *CommBuffer,
276 IN OUT UINTN *CommSize
277 )
278 {
279 EFI_STATUS Status;
280 PEI_SMM_CONTROL_PPI *SmmControl;
281 PEI_SMM_ACCESS_PPI *SmmAccess;
282 UINT8 SmiCommand;
283 UINTN Size;
284 EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext;
285
286 DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei Communicate Enter\n"));
287
288 if (CommBuffer == NULL) {
289 return EFI_INVALID_PARAMETER;
290 }
291
292 //
293 // Get needed resource
294 //
295 Status = PeiServicesLocatePpi (
296 &gPeiSmmControlPpiGuid,
297 0,
298 NULL,
299 (VOID **)&SmmControl
300 );
301 if (EFI_ERROR (Status)) {
302 return EFI_NOT_STARTED;
303 }
304
305 Status = PeiServicesLocatePpi (
306 &gPeiSmmAccessPpiGuid,
307 0,
308 NULL,
309 (VOID **)&SmmAccess
310 );
311 if (EFI_ERROR (Status)) {
312 return EFI_NOT_STARTED;
313 }
314
315 //
316 // Check SMRAM locked, it should be done after SMRAM lock.
317 //
318 if (!SmmAccess->LockState) {
319 DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState));
320 return EFI_NOT_STARTED;
321 }
322
323 SmmCommunicationContext = GetCommunicationContext ();
324 DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei BufferPtrAddress - 0x%016lx, BufferPtr: 0x%016lx\n", SmmCommunicationContext->BufferPtrAddress, *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress));
325
326 //
327 // No need to check if BufferPtr is 0, because it is in PEI phase.
328 //
329 *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CommBuffer;
330 DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei CommBuffer - %x\n", (UINTN)CommBuffer));
331
332 //
333 // Send command
334 //
335 SmiCommand = (UINT8)SmmCommunicationContext->SwSmiNumber;
336 Size = sizeof(SmiCommand);
337 Status = SmmControl->Trigger (
338 (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
339 SmmControl,
340 (INT8 *)&SmiCommand,
341 &Size,
342 FALSE,
343 0
344 );
345 ASSERT_EFI_ERROR (Status);
346
347 //
348 // Setting BufferPtr to 0 means this transaction is done.
349 //
350 *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress = 0;
351
352 DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei Communicate Exit\n"));
353
354 return EFI_SUCCESS;
355 }
356
357 /**
358 Entry Point for PI SMM communication PEIM.
359
360 @param FileHandle Handle of the file being invoked.
361 @param PeiServices Pointer to PEI Services table.
362
363 @retval EFI_SUCCESS
364 @return Others Some error occurs.
365 **/
366 EFI_STATUS
367 EFIAPI
368 PiSmmCommunicationPeiEntryPoint (
369 IN EFI_PEI_FILE_HANDLE FileHandle,
370 IN CONST EFI_PEI_SERVICES **PeiServices
371 )
372 {
373 EFI_STATUS Status;
374 PEI_SMM_ACCESS_PPI *SmmAccess;
375 EFI_BOOT_MODE BootMode;
376 UINTN Index;
377
378 BootMode = GetBootModeHob ();
379 if (BootMode != BOOT_ON_S3_RESUME) {
380 return EFI_UNSUPPORTED;
381 }
382
383 Status = PeiServicesLocatePpi (
384 &gPeiSmmAccessPpiGuid,
385 0,
386 NULL,
387 (VOID **)&SmmAccess
388 );
389 if (EFI_ERROR (Status)) {
390 return EFI_NOT_STARTED;
391 }
392
393 //
394 // Check SMRAM locked, it should be done before SMRAM lock.
395 //
396 if (SmmAccess->LockState) {
397 DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState));
398 return EFI_ACCESS_DENIED;
399 }
400
401 //
402 // Open all SMRAM
403 //
404 for (Index = 0; !EFI_ERROR (Status); Index++) {
405 Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
406 }
407
408 InitCommunicationContext ();
409
410 PeiServicesInstallPpi (&mPpiList);
411
412 return RETURN_SUCCESS;
413 }