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