UefiCpuPkg: Add SMM Communication PPI and Handler Modules
[mirror_edk2.git] / UefiCpuPkg / PiSmmCommunication / PiSmmCommunicationSmm.c
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
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
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*
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
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 }