1 /** @file
2 PiSmmCommunication SMM 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 <PiSmm.h>
16 #include <Library/UefiDriverEntryPoint.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/UefiRuntimeServicesTableLib.h>
19 #include <Library/SmmServicesTableLib.h>
20 #include <Library/BaseLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/HobLib.h>
23 #include <Library/DebugLib.h>
24 #include <Library/SmmMemLib.h>
25 #include <Library/PcdLib.h>
26 #include <Protocol/SmmSwDispatch2.h>
27 #include <Protocol/SmmReadyToLock.h>
28 #include <Protocol/SmmCommunication.h>
29 #include <Protocol/AcpiTable.h>
30 #include <Ppi/SmmCommunication.h>
31 #include <Guid/Acpi.h>
32 
33 #include "PiSmmCommunicationPrivate.h"
34 
35 EFI_SMM_COMMUNICATION_CONTEXT  mSmmCommunicationContext = {
36   SMM_COMMUNICATION_SIGNATURE
37 };
38 
39 EFI_SMM_COMMUNICATION_ACPI_TABLE  mSmmCommunicationAcpiTable = {
40   {
41     {
42       EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE,
43       sizeof (EFI_SMM_COMMUNICATION_ACPI_TABLE),
44       0x1,   // Revision
45       0x0,   // Checksum
46       {0x0}, // OemId[6]
47       0x0,   // OemTableId
48       0x0,   // OemRevision
49       0x0,   // CreatorId
50       0x0    // CreatorRevision
51     },
52     {0x0},                                                      // Identifier
53     OFFSET_OF (EFI_SMM_COMMUNICATION_ACPI_TABLE, SwSmiNumber)   // DataOffset
54   },
55   0x0,                                                   // SwSmiNumber
56   0x0                                                    // BufferPtrAddress
57 };
58 
59 /**
60   Set SMM communication context.
61 **/
62 VOID
SetCommunicationContext(VOID)63 SetCommunicationContext (
64   VOID
65   )
66 {
67   EFI_STATUS  Status;
68 
69   Status = gSmst->SmmInstallConfigurationTable (
70                     gSmst,
71                     &gEfiPeiSmmCommunicationPpiGuid,
72                     &mSmmCommunicationContext,
73                     sizeof(mSmmCommunicationContext)
74                     );
75   ASSERT_EFI_ERROR (Status);
76 }
77 
78 /**
79   Dispatch function for a Software SMI handler.
80 
81   @param DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
82   @param Context         Points to an optional handler context which was specified when the
83                          handler was registered.
84   @param CommBuffer      A pointer to a collection of data in memory that will
85                          be conveyed from a non-SMM environment into an SMM environment.
86   @param CommBufferSize  The size of the CommBuffer.
87 
88   @retval EFI_SUCCESS Command is handled successfully.
89 
90 **/
91 EFI_STATUS
92 EFIAPI
PiSmmCommunicationHandler(IN EFI_HANDLE DispatchHandle,IN CONST VOID * Context OPTIONAL,IN OUT VOID * CommBuffer OPTIONAL,IN OUT UINTN * CommBufferSize OPTIONAL)93 PiSmmCommunicationHandler (
94   IN EFI_HANDLE  DispatchHandle,
95   IN CONST VOID  *Context         OPTIONAL,
96   IN OUT VOID    *CommBuffer      OPTIONAL,
97   IN OUT UINTN   *CommBufferSize  OPTIONAL
98   )
99 {
100   UINTN                            CommSize;
101   EFI_STATUS                       Status;
102   EFI_SMM_COMMUNICATE_HEADER       *CommunicateHeader;
103   EFI_PHYSICAL_ADDRESS             *BufferPtrAddress;
104 
105   DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Enter\n"));
106 
107   BufferPtrAddress = (EFI_PHYSICAL_ADDRESS *)(UINTN)mSmmCommunicationContext.BufferPtrAddress;
108   CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)(UINTN)*BufferPtrAddress;
109   DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader - %x\n", CommunicateHeader));
110   if (CommunicateHeader == NULL) {
111     DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler is NULL, needn't to call dispatch function\n"));
112     Status = EFI_SUCCESS;
113   } else {
114     if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicateHeader, OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))) {
115       DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader invalid - 0x%x\n", CommunicateHeader));
116       Status = EFI_SUCCESS;
117       goto Done;
118     }
119 
120     CommSize = (UINTN)CommunicateHeader->MessageLength;
121     if (!SmmIsBufferOutsideSmmValid ((UINTN)&CommunicateHeader->Data[0], CommSize)) {
122       DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateData invalid - 0x%x\n", &CommunicateHeader->Data[0]));
123       Status = EFI_SUCCESS;
124       goto Done;
125     }
126 
127     //
128     // Call dispatch function
129     //
130     DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Data - %x\n", &CommunicateHeader->Data[0]));
131     Status = gSmst->SmiManage (
132                       &CommunicateHeader->HeaderGuid,
133                       NULL,
134                       &CommunicateHeader->Data[0],
135                       &CommSize
136                       );
137   }
138 
139 Done:
140   DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler %r\n", Status));
141   DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Exit\n"));
142 
143   return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_INTERRUPT_PENDING;
144 }
145 
146 /**
147   Allocate EfiACPIMemoryNVS below 4G memory address.
148 
149   This function allocates EfiACPIMemoryNVS below 4G memory address.
150 
151   @param  Size         Size of memory to allocate.
152 
153   @return Allocated address for output.
154 
155 **/
156 VOID*
AllocateAcpiNvsMemoryBelow4G(IN UINTN Size)157 AllocateAcpiNvsMemoryBelow4G (
158   IN   UINTN   Size
159   )
160 {
161   UINTN                 Pages;
162   EFI_PHYSICAL_ADDRESS  Address;
163   EFI_STATUS            Status;
164   VOID*                 Buffer;
165 
166   Pages = EFI_SIZE_TO_PAGES (Size);
167   Address = 0xffffffff;
168 
169   Status  = gBS->AllocatePages (
170                    AllocateMaxAddress,
171                    EfiACPIMemoryNVS,
172                    Pages,
173                    &Address
174                    );
175   ASSERT_EFI_ERROR (Status);
176 
177   Buffer = (VOID *) (UINTN) Address;
178   ZeroMem (Buffer, Size);
179 
180   return Buffer;
181 }
182 
183 /**
184   Entry Point for PI SMM communication SMM driver.
185 
186   @param[in] ImageHandle  Image handle of this driver.
187   @param[in] SystemTable  A Pointer to the EFI System Table.
188 
189   @retval EFI_SUCEESS
190   @return Others          Some error occurs.
191 **/
192 EFI_STATUS
193 EFIAPI
PiSmmCommunicationSmmEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)194 PiSmmCommunicationSmmEntryPoint (
195   IN EFI_HANDLE        ImageHandle,
196   IN EFI_SYSTEM_TABLE  *SystemTable
197   )
198 {
199   EFI_STATUS                    Status;
200   EFI_SMM_SW_DISPATCH2_PROTOCOL *SmmSwDispatch2;
201   EFI_SMM_SW_REGISTER_CONTEXT   SmmSwDispatchContext;
202   EFI_HANDLE                    DispatchHandle;
203   EFI_ACPI_TABLE_PROTOCOL       *AcpiTableProtocol;
204   UINTN                         TableKey;
205   UINT64                        OemTableId;
206   EFI_PHYSICAL_ADDRESS          *BufferPtrAddress;
207 
208   CopyMem (
209     mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId,
210     PcdGetPtr (PcdAcpiDefaultOemId),
211     sizeof (mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId)
212     );
213   OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
214   CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemTableId, &OemTableId, sizeof (UINT64));
215   mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemRevision      = PcdGet32 (PcdAcpiDefaultOemRevision);
216   mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorId        = PcdGet32 (PcdAcpiDefaultCreatorId);
217   mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorRevision  = PcdGet32 (PcdAcpiDefaultCreatorRevision);
218 
219   //
220   // Register software SMI handler
221   //
222   Status = gSmst->SmmLocateProtocol (
223                     &gEfiSmmSwDispatch2ProtocolGuid,
224                     NULL,
225                     (VOID **)&SmmSwDispatch2
226                     );
227   ASSERT_EFI_ERROR (Status);
228 
229   SmmSwDispatchContext.SwSmiInputValue = (UINTN)-1;
230   Status = SmmSwDispatch2->Register (
231                              SmmSwDispatch2,
232                              PiSmmCommunicationHandler,
233                              &SmmSwDispatchContext,
234                              &DispatchHandle
235                              );
236   ASSERT_EFI_ERROR (Status);
237 
238   DEBUG ((EFI_D_INFO, "SmmCommunication SwSmi: %x\n", (UINTN)SmmSwDispatchContext.SwSmiInputValue));
239 
240   //
241   // Set ACPI table
242   //
243   Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
244   ASSERT_EFI_ERROR (Status);
245 
246   mSmmCommunicationAcpiTable.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue;
247   BufferPtrAddress = AllocateAcpiNvsMemoryBelow4G (sizeof(EFI_PHYSICAL_ADDRESS));
248   ASSERT (BufferPtrAddress != NULL);
249   DEBUG ((EFI_D_INFO, "SmmCommunication BufferPtrAddress: 0x%016lx, BufferPtr: 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress, *BufferPtrAddress));
250   mSmmCommunicationAcpiTable.BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress;
251   CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Identifier, &gEfiSmmCommunicationProtocolGuid, sizeof(gEfiSmmCommunicationProtocolGuid));
252 
253   Status = AcpiTableProtocol->InstallAcpiTable (
254                                 AcpiTableProtocol,
255                                 &mSmmCommunicationAcpiTable,
256                                 sizeof(mSmmCommunicationAcpiTable),
257                                 &TableKey
258                                 );
259   ASSERT_EFI_ERROR (Status);
260 
261   //
262   // Save context
263   //
264   mSmmCommunicationContext.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue;
265   mSmmCommunicationContext.BufferPtrAddress = mSmmCommunicationAcpiTable.BufferPtrAddress;
266   SetCommunicationContext ();
267 
268   return Status;
269 }
270