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