]> git.proxmox.com Git - mirror_edk2.git/blob - Vlv2TbltDevicePkg/SmmSwDispatch2OnSmmSwDispatchThunk/SmmSwDispatch2OnSmmSwDispatchThunk.c
Vlv2TbltDevicePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / Vlv2TbltDevicePkg / SmmSwDispatch2OnSmmSwDispatchThunk / SmmSwDispatch2OnSmmSwDispatchThunk.c
1 /** @file
2 SMM SwDispatch2 Protocol on SMM SwDispatch Protocol Thunk driver.
3
4 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8
9
10 **/
11
12 #include <PiDxe.h>
13 #include <FrameworkSmm.h>
14
15 #include <Protocol/SmmSwDispatch2.h>
16 #include <Protocol/SmmSwDispatch.h>
17 #include <Protocol/SmmControl.h>
18 #include <Protocol/SmmCpu.h>
19
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/UefiDriverEntryPoint.h>
22 #include <Library/SmmServicesTableLib.h>
23 #include <Library/BaseLib.h>
24 #include <Library/IoLib.h>
25 #include <Library/DebugLib.h>
26
27 typedef struct {
28 LIST_ENTRY Link;
29 EFI_HANDLE DispatchHandle;
30 UINTN SwSmiInputValue;
31 UINTN DispatchFunction;
32 } EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT;
33
34 /**
35 Register a child SMI source dispatch function for the specified software SMI.
36
37 This service registers a function (DispatchFunction) which will be called when the software
38 SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return,
39 DispatchHandle contains a unique handle which may be used later to unregister the function
40 using UnRegister().
41
42 @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
43 @param[in] DispatchFunction Function to register for handler when the specified software
44 SMI is generated.
45 @param[in, out] RegisterContext Pointer to the dispatch function's context.
46 The caller fills this context in before calling
47 the register function to indicate to the register
48 function which Software SMI input value the
49 dispatch function should be invoked for.
50 @param[out] DispatchHandle Handle generated by the dispatcher to track the
51 function instance.
52
53 @retval EFI_SUCCESS The dispatch function has been successfully
54 registered and the SMI source has been enabled.
55 @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SMI source.
56 @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI input value
57 is not within valid range.
58 @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this
59 child.
60 @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be assigned
61 for this dispatch.
62 **/
63 EFI_STATUS
64 EFIAPI
65 SmmSwDispatch2Register (
66 IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This,
67 IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
68 IN OUT EFI_SMM_SW_REGISTER_CONTEXT *RegisterContext,
69 OUT EFI_HANDLE *DispatchHandle
70 );
71
72 /**
73 Unregister a child SMI source dispatch function for the specified software SMI.
74
75 This service removes the handler associated with DispatchHandle so that it will no longer be
76 called in response to a software SMI.
77
78 @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
79 @param[in] DispatchHandle Handle of dispatch function to deregister.
80
81 @retval EFI_SUCCESS The dispatch function has been successfully unregistered.
82 @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid.
83 **/
84 EFI_STATUS
85 EFIAPI
86 SmmSwDispatch2UnRegister (
87 IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This,
88 IN EFI_HANDLE DispatchHandle
89 );
90
91 EFI_SMM_SW_DISPATCH2_PROTOCOL gSmmSwDispatch2 = {
92 SmmSwDispatch2Register,
93 SmmSwDispatch2UnRegister,
94 0 // MaximumSwiValue
95 };
96
97 EFI_SMM_SW_DISPATCH_PROTOCOL *mSmmSwDispatch;
98 UINT8 mSmiTriggerRegister;
99 UINT8 mSmiDataRegister;
100
101 EFI_SMM_CPU_PROTOCOL *mSmmCpuProtocol;
102 LIST_ENTRY mSmmSwDispatch2ThunkQueue = INITIALIZE_LIST_HEAD_VARIABLE (mSmmSwDispatch2ThunkQueue);
103
104 /**
105 This function find SmmSwDispatch2Context by SwSmiInputValue.
106
107 @param SwSmiInputValue The SwSmiInputValue to indentify the SmmSwDispatch2 context
108
109 @return SmmSwDispatch2 context
110 **/
111 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *
112 FindSmmSwDispatch2ContextBySwSmiInputValue (
113 IN UINTN SwSmiInputValue
114 )
115 {
116 LIST_ENTRY *Link;
117 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *ThunkContext;
118
119 for (Link = mSmmSwDispatch2ThunkQueue.ForwardLink;
120 Link != &mSmmSwDispatch2ThunkQueue;
121 Link = Link->ForwardLink) {
122 ThunkContext = BASE_CR (
123 Link,
124 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT,
125 Link
126 );
127 if (ThunkContext->SwSmiInputValue == SwSmiInputValue) {
128 return ThunkContext;
129 }
130 }
131 return NULL;
132 }
133
134 /**
135 This function find SmmSwDispatch2Context by DispatchHandle.
136
137 @param DispatchHandle The DispatchHandle to indentify the SmmSwDispatch2Thunk context
138
139 @return SmmSwDispatch2Thunk context
140 **/
141 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *
142 FindSmmSwDispatch2ContextByDispatchHandle (
143 IN EFI_HANDLE DispatchHandle
144 )
145 {
146 LIST_ENTRY *Link;
147 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *ThunkContext;
148
149 for (Link = mSmmSwDispatch2ThunkQueue.ForwardLink;
150 Link != &mSmmSwDispatch2ThunkQueue;
151 Link = Link->ForwardLink) {
152 ThunkContext = BASE_CR (
153 Link,
154 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT,
155 Link
156 );
157 if (ThunkContext->DispatchHandle == DispatchHandle) {
158 return ThunkContext;
159 }
160 }
161 return NULL;
162 }
163
164 /**
165 Framework dispatch function for a Software SMI handler.
166
167 @param DispatchHandle The handle of this dispatch function.
168 @param DispatchContext The pointer to the dispatch function's context.
169 The SwSmiInputValue field is filled in
170 by the software dispatch driver prior to
171 invoking this dispatch function.
172 The dispatch function will only be called
173 for input values for which it is registered.
174
175 @return None
176
177 **/
178 VOID
179 EFIAPI
180 FrameworkDispatchFunction (
181 IN EFI_HANDLE DispatchHandle,
182 IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
183 )
184 {
185 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *ThunkContext;
186 EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction;
187 EFI_SMM_SW_REGISTER_CONTEXT RegisterContext;
188 EFI_SMM_SW_CONTEXT SwContext;
189 UINTN Size;
190 UINTN Index;
191 EFI_SMM_SAVE_STATE_IO_INFO IoInfo;
192 EFI_STATUS Status;
193
194 //
195 // Search context
196 //
197 ThunkContext = FindSmmSwDispatch2ContextBySwSmiInputValue (DispatchContext->SwSmiInputValue);
198 ASSERT (ThunkContext != NULL);
199 if (ThunkContext == NULL) {
200 return ;
201 }
202
203 //
204 // Construct new context
205 //
206 RegisterContext.SwSmiInputValue = DispatchContext->SwSmiInputValue;
207 Size = sizeof(SwContext);
208 SwContext.CommandPort = IoRead8 (mSmiTriggerRegister);
209 SwContext.DataPort = IoRead8 (mSmiDataRegister);
210
211 //
212 // Try to find which CPU trigger SWSMI
213 //
214 SwContext.SwSmiCpuIndex = 0;
215 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
216 Status = mSmmCpuProtocol->ReadSaveState (
217 mSmmCpuProtocol,
218 sizeof(IoInfo),
219 EFI_SMM_SAVE_STATE_REGISTER_IO,
220 Index,
221 &IoInfo
222 );
223 if (EFI_ERROR (Status)) {
224 continue;
225 }
226 if (IoInfo.IoPort == mSmiTriggerRegister) {
227 //
228 // Great! Find it.
229 //
230 SwContext.SwSmiCpuIndex = Index;
231 break;
232 }
233 }
234
235 //
236 // Dispatch
237 //
238 DispatchFunction = (EFI_SMM_HANDLER_ENTRY_POINT2)ThunkContext->DispatchFunction;
239 DispatchFunction (
240 DispatchHandle,
241 &RegisterContext,
242 &SwContext,
243 &Size
244 );
245 return ;
246 }
247
248 /**
249 Register a child SMI source dispatch function for the specified software SMI.
250
251 This service registers a function (DispatchFunction) which will be called when the software
252 SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return,
253 DispatchHandle contains a unique handle which may be used later to unregister the function
254 using UnRegister().
255
256 @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
257 @param[in] DispatchFunction Function to register for handler when the specified software
258 SMI is generated.
259 @param[in, out] RegisterContext Pointer to the dispatch function's context.
260 The caller fills this context in before calling
261 the register function to indicate to the register
262 function which Software SMI input value the
263 dispatch function should be invoked for.
264 @param[out] DispatchHandle Handle generated by the dispatcher to track the
265 function instance.
266
267 @retval EFI_SUCCESS The dispatch function has been successfully
268 registered and the SMI source has been enabled.
269 @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SMI source.
270 @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI input value
271 is not within valid range.
272 @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this
273 child.
274 @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be assigned
275 for this dispatch.
276 **/
277 EFI_STATUS
278 EFIAPI
279 SmmSwDispatch2Register (
280 IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This,
281 IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
282 IN OUT EFI_SMM_SW_REGISTER_CONTEXT *RegisterContext,
283 OUT EFI_HANDLE *DispatchHandle
284 )
285 {
286 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *ThunkContext;
287 EFI_SMM_SW_DISPATCH_CONTEXT DispatchContext;
288 EFI_STATUS Status;
289 UINTN Index;
290
291 if (RegisterContext->SwSmiInputValue == (UINTN)-1) {
292 //
293 // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure.
294 //
295 Status = EFI_NOT_FOUND;
296 for (Index = 1; Index < gSmmSwDispatch2.MaximumSwiValue; Index++) {
297 DispatchContext.SwSmiInputValue = Index;
298 Status = mSmmSwDispatch->Register (
299 mSmmSwDispatch,
300 FrameworkDispatchFunction,
301 &DispatchContext,
302 DispatchHandle
303 );
304 if (!EFI_ERROR (Status)) {
305 RegisterContext->SwSmiInputValue = Index;
306 break;
307 }
308 }
309 if (RegisterContext->SwSmiInputValue == (UINTN)-1) {
310 return EFI_OUT_OF_RESOURCES;
311 }
312 } else {
313 DispatchContext.SwSmiInputValue = RegisterContext->SwSmiInputValue;
314 Status = mSmmSwDispatch->Register (
315 mSmmSwDispatch,
316 FrameworkDispatchFunction,
317 &DispatchContext,
318 DispatchHandle
319 );
320 }
321 if (!EFI_ERROR (Status)) {
322 //
323 // Register
324 //
325 Status = gSmst->SmmAllocatePool (
326 EfiRuntimeServicesData,
327 sizeof(*ThunkContext),
328 (VOID **)&ThunkContext
329 );
330 ASSERT_EFI_ERROR (Status);
331 if (EFI_ERROR (Status)) {
332 mSmmSwDispatch->UnRegister (mSmmSwDispatch, *DispatchHandle);
333 return EFI_OUT_OF_RESOURCES;
334 }
335
336 ThunkContext->SwSmiInputValue = RegisterContext->SwSmiInputValue;
337 ThunkContext->DispatchFunction = (UINTN)DispatchFunction;
338 ThunkContext->DispatchHandle = *DispatchHandle;
339 InsertTailList (&mSmmSwDispatch2ThunkQueue, &ThunkContext->Link);
340 }
341
342 return Status;
343 }
344
345 /**
346 Unregister a child SMI source dispatch function for the specified software SMI.
347
348 This service removes the handler associated with DispatchHandle so that it will no longer be
349 called in response to a software SMI.
350
351 @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
352 @param[in] DispatchHandle Handle of dispatch function to deregister.
353
354 @retval EFI_SUCCESS The dispatch function has been successfully unregistered.
355 @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid.
356 **/
357 EFI_STATUS
358 EFIAPI
359 SmmSwDispatch2UnRegister (
360 IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This,
361 IN EFI_HANDLE DispatchHandle
362 )
363 {
364 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT *ThunkContext;
365 EFI_STATUS Status;
366
367 Status = mSmmSwDispatch->UnRegister (mSmmSwDispatch, DispatchHandle);
368 if (!EFI_ERROR (Status)) {
369 //
370 // Unregister
371 //
372 ThunkContext = FindSmmSwDispatch2ContextByDispatchHandle (DispatchHandle);
373 ASSERT (ThunkContext != NULL);
374 if (ThunkContext != NULL) {
375 RemoveEntryList (&ThunkContext->Link);
376 gSmst->SmmFreePool (ThunkContext);
377 }
378 }
379
380 return Status;
381 }
382
383 /**
384 Entry Point for this thunk driver.
385
386 @param[in] ImageHandle Image handle of this driver.
387 @param[in] SystemTable A Pointer to the EFI System Table.
388
389 @retval EFI_SUCCESS The entry point is executed successfully.
390 @retval other Some error occurred when executing this entry point.
391 **/
392 EFI_STATUS
393 EFIAPI
394 SmmSwDispatch2ThunkMain (
395 IN EFI_HANDLE ImageHandle,
396 IN EFI_SYSTEM_TABLE *SystemTable
397 )
398 {
399 EFI_STATUS Status;
400 EFI_SMM_CONTROL_PROTOCOL *SmmControl;
401 EFI_SMM_CONTROL_REGISTER RegisterInfo;
402
403 //
404 // Locate Framework SMM SwDispatch Protocol
405 //
406 Status = gBS->LocateProtocol (
407 &gEfiSmmSwDispatchProtocolGuid,
408 NULL,
409 (VOID **)&mSmmSwDispatch
410 );
411 ASSERT_EFI_ERROR (Status);
412 gSmmSwDispatch2.MaximumSwiValue = mSmmSwDispatch->MaximumSwiValue;
413 if (gSmmSwDispatch2.MaximumSwiValue == 0x0) {
414 DEBUG ((EFI_D_ERROR, "BUGBUG: MaximumSwiValue is 0, work-around to make it 0xFF\n"));
415 gSmmSwDispatch2.MaximumSwiValue = 0xFF;
416 }
417
418 //
419 // Locate Framework SMM Control Protocol
420 //
421 Status = gBS->LocateProtocol (
422 &gEfiSmmControlProtocolGuid,
423 NULL,
424 (VOID **)&SmmControl
425 );
426
427 ASSERT_EFI_ERROR (Status);
428 Status = SmmControl->GetRegisterInfo (
429 SmmControl,
430 &RegisterInfo
431 );
432 ASSERT_EFI_ERROR (Status);
433 mSmiTriggerRegister = RegisterInfo.SmiTriggerRegister;
434 mSmiDataRegister = RegisterInfo.SmiDataRegister;
435
436 //
437 // Locate PI SMM CPU protocol
438 //
439 Status = gSmst->SmmLocateProtocol (
440 &gEfiSmmCpuProtocolGuid,
441 NULL,
442 (VOID **)&mSmmCpuProtocol
443 );
444 ASSERT_EFI_ERROR (Status);
445
446 //
447 // Publish PI SMM SwDispatch2 Protocol
448 //
449 ImageHandle = NULL;
450 Status = gSmst->SmmInstallProtocolInterface (
451 &ImageHandle,
452 &gEfiSmmSwDispatch2ProtocolGuid,
453 EFI_NATIVE_INTERFACE,
454 &gSmmSwDispatch2
455 );
456 ASSERT_EFI_ERROR (Status);
457 return Status;
458 }
459