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 *
GetCommunicationContext(VOID)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
SetCommunicationContext(IN EFI_SMM_COMMUNICATION_CONTEXT * SmmCommunicationContext)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 *
InternalSmstGetVendorTableByGuid(IN UINT64 Signature,IN EFI_SMM_SYSTEM_TABLE2 * Smst,IN EFI_GUID * VendorGuid)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
InitCommunicationContext(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
Communicate(IN CONST EFI_PEI_SMM_COMMUNICATION_PPI * This,IN OUT VOID * CommBuffer,IN OUT UINTN * CommSize)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
PiSmmCommunicationPeiEntryPoint(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)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 }
426