2 SMM SwDispatch2 Protocol on SMM SwDispatch Protocol Thunk driver.
4 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include <FrameworkSmm.h>
15 #include <Protocol/SmmSwDispatch2.h>
16 #include <Protocol/SmmSwDispatch.h>
17 #include <Protocol/SmmControl.h>
18 #include <Protocol/SmmCpu.h>
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>
29 EFI_HANDLE DispatchHandle
;
30 UINTN SwSmiInputValue
;
31 UINTN DispatchFunction
;
32 } EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT
;
35 Register a child SMI source dispatch function for the specified software SMI.
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
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
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
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
60 @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be assigned
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
73 Unregister a child SMI source dispatch function for the specified software SMI.
75 This service removes the handler associated with DispatchHandle so that it will no longer be
76 called in response to a software SMI.
78 @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
79 @param[in] DispatchHandle Handle of dispatch function to deregister.
81 @retval EFI_SUCCESS The dispatch function has been successfully unregistered.
82 @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid.
86 SmmSwDispatch2UnRegister (
87 IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL
*This
,
88 IN EFI_HANDLE DispatchHandle
91 EFI_SMM_SW_DISPATCH2_PROTOCOL gSmmSwDispatch2
= {
92 SmmSwDispatch2Register
,
93 SmmSwDispatch2UnRegister
,
97 EFI_SMM_SW_DISPATCH_PROTOCOL
*mSmmSwDispatch
;
98 UINT8 mSmiTriggerRegister
;
99 UINT8 mSmiDataRegister
;
101 EFI_SMM_CPU_PROTOCOL
*mSmmCpuProtocol
;
102 LIST_ENTRY mSmmSwDispatch2ThunkQueue
= INITIALIZE_LIST_HEAD_VARIABLE (mSmmSwDispatch2ThunkQueue
);
105 This function find SmmSwDispatch2Context by SwSmiInputValue.
107 @param SwSmiInputValue The SwSmiInputValue to indentify the SmmSwDispatch2 context
109 @return SmmSwDispatch2 context
111 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT
*
112 FindSmmSwDispatch2ContextBySwSmiInputValue (
113 IN UINTN SwSmiInputValue
117 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT
*ThunkContext
;
119 for (Link
= mSmmSwDispatch2ThunkQueue
.ForwardLink
;
120 Link
!= &mSmmSwDispatch2ThunkQueue
;
121 Link
= Link
->ForwardLink
) {
122 ThunkContext
= BASE_CR (
124 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT
,
127 if (ThunkContext
->SwSmiInputValue
== SwSmiInputValue
) {
135 This function find SmmSwDispatch2Context by DispatchHandle.
137 @param DispatchHandle The DispatchHandle to indentify the SmmSwDispatch2Thunk context
139 @return SmmSwDispatch2Thunk context
141 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT
*
142 FindSmmSwDispatch2ContextByDispatchHandle (
143 IN EFI_HANDLE DispatchHandle
147 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT
*ThunkContext
;
149 for (Link
= mSmmSwDispatch2ThunkQueue
.ForwardLink
;
150 Link
!= &mSmmSwDispatch2ThunkQueue
;
151 Link
= Link
->ForwardLink
) {
152 ThunkContext
= BASE_CR (
154 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT
,
157 if (ThunkContext
->DispatchHandle
== DispatchHandle
) {
165 Framework dispatch function for a Software SMI handler.
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.
180 FrameworkDispatchFunction (
181 IN EFI_HANDLE DispatchHandle
,
182 IN EFI_SMM_SW_DISPATCH_CONTEXT
*DispatchContext
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
;
191 EFI_SMM_SAVE_STATE_IO_INFO IoInfo
;
197 ThunkContext
= FindSmmSwDispatch2ContextBySwSmiInputValue (DispatchContext
->SwSmiInputValue
);
198 ASSERT (ThunkContext
!= NULL
);
199 if (ThunkContext
== NULL
) {
204 // Construct new context
206 RegisterContext
.SwSmiInputValue
= DispatchContext
->SwSmiInputValue
;
207 Size
= sizeof(SwContext
);
208 SwContext
.CommandPort
= IoRead8 (mSmiTriggerRegister
);
209 SwContext
.DataPort
= IoRead8 (mSmiDataRegister
);
212 // Try to find which CPU trigger SWSMI
214 SwContext
.SwSmiCpuIndex
= 0;
215 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
216 Status
= mSmmCpuProtocol
->ReadSaveState (
219 EFI_SMM_SAVE_STATE_REGISTER_IO
,
223 if (EFI_ERROR (Status
)) {
226 if (IoInfo
.IoPort
== mSmiTriggerRegister
) {
230 SwContext
.SwSmiCpuIndex
= Index
;
238 DispatchFunction
= (EFI_SMM_HANDLER_ENTRY_POINT2
)ThunkContext
->DispatchFunction
;
249 Register a child SMI source dispatch function for the specified software SMI.
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
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
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
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
274 @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be assigned
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
286 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT
*ThunkContext
;
287 EFI_SMM_SW_DISPATCH_CONTEXT DispatchContext
;
291 if (RegisterContext
->SwSmiInputValue
== (UINTN
)-1) {
293 // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure.
295 Status
= EFI_NOT_FOUND
;
296 for (Index
= 1; Index
< gSmmSwDispatch2
.MaximumSwiValue
; Index
++) {
297 DispatchContext
.SwSmiInputValue
= Index
;
298 Status
= mSmmSwDispatch
->Register (
300 FrameworkDispatchFunction
,
304 if (!EFI_ERROR (Status
)) {
305 RegisterContext
->SwSmiInputValue
= Index
;
309 if (RegisterContext
->SwSmiInputValue
== (UINTN
)-1) {
310 return EFI_OUT_OF_RESOURCES
;
313 DispatchContext
.SwSmiInputValue
= RegisterContext
->SwSmiInputValue
;
314 Status
= mSmmSwDispatch
->Register (
316 FrameworkDispatchFunction
,
321 if (!EFI_ERROR (Status
)) {
325 Status
= gSmst
->SmmAllocatePool (
326 EfiRuntimeServicesData
,
327 sizeof(*ThunkContext
),
328 (VOID
**)&ThunkContext
330 ASSERT_EFI_ERROR (Status
);
331 if (EFI_ERROR (Status
)) {
332 mSmmSwDispatch
->UnRegister (mSmmSwDispatch
, *DispatchHandle
);
333 return EFI_OUT_OF_RESOURCES
;
336 ThunkContext
->SwSmiInputValue
= RegisterContext
->SwSmiInputValue
;
337 ThunkContext
->DispatchFunction
= (UINTN
)DispatchFunction
;
338 ThunkContext
->DispatchHandle
= *DispatchHandle
;
339 InsertTailList (&mSmmSwDispatch2ThunkQueue
, &ThunkContext
->Link
);
346 Unregister a child SMI source dispatch function for the specified software SMI.
348 This service removes the handler associated with DispatchHandle so that it will no longer be
349 called in response to a software SMI.
351 @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
352 @param[in] DispatchHandle Handle of dispatch function to deregister.
354 @retval EFI_SUCCESS The dispatch function has been successfully unregistered.
355 @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid.
359 SmmSwDispatch2UnRegister (
360 IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL
*This
,
361 IN EFI_HANDLE DispatchHandle
364 EFI_SMM_SW_DISPATCH2_THUNK_CONTEXT
*ThunkContext
;
367 Status
= mSmmSwDispatch
->UnRegister (mSmmSwDispatch
, DispatchHandle
);
368 if (!EFI_ERROR (Status
)) {
372 ThunkContext
= FindSmmSwDispatch2ContextByDispatchHandle (DispatchHandle
);
373 ASSERT (ThunkContext
!= NULL
);
374 if (ThunkContext
!= NULL
) {
375 RemoveEntryList (&ThunkContext
->Link
);
376 gSmst
->SmmFreePool (ThunkContext
);
384 Entry Point for this thunk driver.
386 @param[in] ImageHandle Image handle of this driver.
387 @param[in] SystemTable A Pointer to the EFI System Table.
389 @retval EFI_SUCCESS The entry point is executed successfully.
390 @retval other Some error occurred when executing this entry point.
394 SmmSwDispatch2ThunkMain (
395 IN EFI_HANDLE ImageHandle
,
396 IN EFI_SYSTEM_TABLE
*SystemTable
400 EFI_SMM_CONTROL_PROTOCOL
*SmmControl
;
401 EFI_SMM_CONTROL_REGISTER RegisterInfo
;
404 // Locate Framework SMM SwDispatch Protocol
406 Status
= gBS
->LocateProtocol (
407 &gEfiSmmSwDispatchProtocolGuid
,
409 (VOID
**)&mSmmSwDispatch
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;
419 // Locate Framework SMM Control Protocol
421 Status
= gBS
->LocateProtocol (
422 &gEfiSmmControlProtocolGuid
,
427 ASSERT_EFI_ERROR (Status
);
428 Status
= SmmControl
->GetRegisterInfo (
432 ASSERT_EFI_ERROR (Status
);
433 mSmiTriggerRegister
= RegisterInfo
.SmiTriggerRegister
;
434 mSmiDataRegister
= RegisterInfo
.SmiDataRegister
;
437 // Locate PI SMM CPU protocol
439 Status
= gSmst
->SmmLocateProtocol (
440 &gEfiSmmCpuProtocolGuid
,
442 (VOID
**)&mSmmCpuProtocol
444 ASSERT_EFI_ERROR (Status
);
447 // Publish PI SMM SwDispatch2 Protocol
450 Status
= gSmst
->SmmInstallProtocolInterface (
452 &gEfiSmmSwDispatch2ProtocolGuid
,
453 EFI_NATIVE_INTERFACE
,
456 ASSERT_EFI_ERROR (Status
);