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