TianoCore EDK2 master
Loading...
Searching...
No Matches
PchSmiDispatchSmm.c
Go to the documentation of this file.
1
11#include "PchSmiDispatchSmm.h"
12
13typedef struct {
14 UINT8 EosBitOffset;
15 UINT8 ApmBitOffset;
16 UINT32 SmiEosAddr;
17 UINT32 SmiApmStsAddr;
19
20SMM_PCH_REGISTER mSmiPchReg;
21
22EFI_SMM_CPU_PROTOCOL *mSmmCpuProtocol;
23LIST_ENTRY mSmmSwDispatch2Queue = INITIALIZE_LIST_HEAD_VARIABLE (mSmmSwDispatch2Queue);
24
34 IN UINTN SwSmiInputValue
35 )
36{
37 LIST_ENTRY *Node;
38 EFI_SMM_SW_DISPATCH2_CONTEXT *Dispatch2Context;
39
40 Node = mSmmSwDispatch2Queue.ForwardLink;
41 for ( ; Node != &mSmmSwDispatch2Queue; Node = Node->ForwardLink) {
42 Dispatch2Context = BASE_CR (Node, EFI_SMM_SW_DISPATCH2_CONTEXT, Link);
43 if (Dispatch2Context->SwSmiInputValue == SwSmiInputValue) {
44 return Dispatch2Context;
45 }
46 }
47
48 return NULL;
49}
50
60 IN EFI_HANDLE DispatchHandle
61 )
62{
63 LIST_ENTRY *Node;
64 EFI_SMM_SW_DISPATCH2_CONTEXT *Dispatch2Context;
65
66 Node = mSmmSwDispatch2Queue.ForwardLink;
67 for ( ; Node != &mSmmSwDispatch2Queue; Node = Node->ForwardLink) {
68 Dispatch2Context = BASE_CR (Node, EFI_SMM_SW_DISPATCH2_CONTEXT, Link);
69 if (Dispatch2Context->DispatchHandle == DispatchHandle) {
70 return Dispatch2Context;
71 }
72 }
73
74 return NULL;
75}
76
91 IN EFI_HANDLE DispatchHandle,
92 IN CONST VOID *RegisterContext,
93 IN OUT VOID *CommBuffer,
94 IN OUT UINTN *CommBufferSize
95 )
96{
97 EFI_STATUS Status;
98 EFI_SMM_SW_CONTEXT SwContext;
99 UINTN Index;
101 EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction;
102 EFI_SMM_SW_REGISTER_CONTEXT DispatchContext;
103 UINTN Size;
105
106 //
107 // Construct new context
108 //
109 SwContext.SwSmiCpuIndex = 0;
110 SwContext.CommandPort = IoRead8 (SMM_CONTROL_PORT);
111 SwContext.DataPort = IoRead8 (SMM_DATA_PORT);
112
113 //
114 // Try to find which CPU trigger SWSMI
115 //
116 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
117 Status = mSmmCpuProtocol->ReadSaveState (
118 mSmmCpuProtocol,
119 sizeof (IoInfo),
120 EFI_SMM_SAVE_STATE_REGISTER_IO,
121 Index,
122 &IoInfo
123 );
124 if (EFI_ERROR (Status)) {
125 continue;
126 }
127
128 if (IoInfo.IoPort == SMM_CONTROL_PORT) {
129 //
130 // Great! Find it.
131 //
132 SwContext.SwSmiCpuIndex = Index;
133 DEBUG ((DEBUG_VERBOSE, "CPU index = 0x%x/0x%x\n", Index, gSmst->NumberOfCpus));
134 break;
135 }
136 }
137
138 if (SwContext.CommandPort == 0) {
139 DEBUG ((DEBUG_VERBOSE, "NOT SW SMI\n"));
140 Status = EFI_SUCCESS;
141 goto End;
142 }
143
144 //
145 // Search context
146 //
147 Context = FindContextBySwSmiInputValue (SwContext.CommandPort);
148 if (Context == NULL) {
149 DEBUG ((DEBUG_INFO, "No handler for SMI value 0x%x\n", SwContext.CommandPort));
150 Status = EFI_SUCCESS;
151 goto End;
152 }
153
154 DEBUG ((DEBUG_VERBOSE, "Prepare to call handler for 0x%x\n", SwContext.CommandPort));
155
156 //
157 // Dispatch
158 //
159 DispatchContext.SwSmiInputValue = SwContext.CommandPort;
160 Size = sizeof (SwContext);
161 DispatchFunction = (EFI_SMM_HANDLER_ENTRY_POINT2)Context->DispatchFunction;
162 Status = DispatchFunction (DispatchHandle, &DispatchContext, &SwContext, &Size);
163
164End:
165 //
166 // Clear SMI APM status
167 //
168 IoOr32 (mSmiPchReg.SmiApmStsAddr, 1 << mSmiPchReg.ApmBitOffset);
169
170 //
171 // Set EOS bit
172 //
173 IoOr32 (mSmiPchReg.SmiEosAddr, 1 << mSmiPchReg.EosBitOffset);
174
175 return Status;
176}
177
189 IN UINTN SwSmiInputValue
190 )
191{
192 LIST_ENTRY *Node;
193 EFI_SMM_SW_DISPATCH2_CONTEXT *Dispatch2Context;
194
195 Node = mSmmSwDispatch2Queue.ForwardLink;
196 for ( ; Node != &mSmmSwDispatch2Queue; Node = Node->ForwardLink) {
197 Dispatch2Context = BASE_CR (Node, EFI_SMM_SW_DISPATCH2_CONTEXT, Link);
198 if (Dispatch2Context->SwSmiInputValue == SwSmiInputValue) {
199 return EFI_INVALID_PARAMETER;
200 }
201 }
202
203 return EFI_SUCCESS;
204}
205
235EFIAPI
238 IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
240 OUT EFI_HANDLE *DispatchHandle
241 )
242{
243 EFI_STATUS Status;
244 UINTN Index;
246
247 if (RegContext->SwSmiInputValue == (UINTN)-1) {
248 //
249 // If SwSmiInputValue is set to (UINTN) -1 then a unique value
250 // will be assigned and returned in the structure.
251 //
252 Status = EFI_NOT_FOUND;
253 for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {
254 Status = SmiInputValueCheck (Index);
255 if (!EFI_ERROR (Status)) {
256 RegContext->SwSmiInputValue = Index;
257 break;
258 }
259 }
260
261 if (RegContext->SwSmiInputValue == (UINTN)-1) {
262 return EFI_OUT_OF_RESOURCES;
263 }
264 }
265
266 if ((RegContext->SwSmiInputValue > MAXIMUM_SWI_VALUE) || (RegContext->SwSmiInputValue == 0)) {
267 DEBUG ((DEBUG_ERROR, "ERROR: SMI value range (1 ~ 0x%x)\n", MAXIMUM_SWI_VALUE));
268 return EFI_INVALID_PARAMETER;
269 }
270
271 //
272 // Register
273 //
274 Status = gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (*Context), (VOID **)&Context);
275 ASSERT_EFI_ERROR (Status);
276 if (EFI_ERROR (Status)) {
277 return EFI_OUT_OF_RESOURCES;
278 }
279
280 *DispatchHandle = (EFI_HANDLE)Context;
281 Context->Signature = SMI_SW_HANDLER_SIGNATURE;
282 Context->SwSmiInputValue = RegContext->SwSmiInputValue;
283 Context->DispatchFunction = (UINTN)DispatchFunction;
284 Context->DispatchHandle = *DispatchHandle;
285 InsertTailList (&mSmmSwDispatch2Queue, &Context->Link);
286
287 return Status;
288}
289
303EFIAPI
306 IN EFI_HANDLE DispatchHandle
307 )
308{
310
311 //
312 // Unregister
313 //
314 Context = FindContextByDispatchHandle (DispatchHandle);
315 ASSERT (Context != NULL);
316 if (Context != NULL) {
317 RemoveEntryList (&Context->Link);
318 gSmst->SmmFreePool (Context);
319 }
320
321 return EFI_SUCCESS;
322}
323
324EFI_SMM_SW_DISPATCH2_PROTOCOL gSmmSwDispatch2 = {
327 MAXIMUM_SWI_VALUE
328};
329
342 IN PLD_SMM_REGISTERS *SmmRegister,
343 IN UINT32 Id
344 )
345{
346 UINT32 Index;
347 PLD_GENERIC_REGISTER *PldReg;
348
349 PldReg = NULL;
350 for (Index = 0; Index < SmmRegister->Count; Index++) {
351 if (SmmRegister->Registers[Index].Id == Id) {
352 PldReg = &SmmRegister->Registers[Index];
353 break;
354 }
355 }
356
357 if (PldReg == NULL) {
358 DEBUG ((DEBUG_INFO, "Register %d not found.\n", Id));
359 return NULL;
360 }
361
362 //
363 // Checking the register if it is expected.
364 //
365 if ((PldReg->Address.AccessSize != EFI_ACPI_3_0_DWORD) ||
366 (PldReg->Address.Address == 0) ||
367 (PldReg->Address.RegisterBitWidth != 1) ||
368 (PldReg->Address.AddressSpaceId != EFI_ACPI_3_0_SYSTEM_IO) ||
369 (PldReg->Value != 1))
370 {
371 DEBUG ((DEBUG_INFO, "Unexpected SMM register.\n"));
372 DEBUG ((DEBUG_INFO, "AddressSpaceId= 0x%x\n", PldReg->Address.AddressSpaceId));
373 DEBUG ((DEBUG_INFO, "RegBitWidth = 0x%x\n", PldReg->Address.RegisterBitWidth));
374 DEBUG ((DEBUG_INFO, "RegBitOffset = 0x%x\n", PldReg->Address.RegisterBitOffset));
375 DEBUG ((DEBUG_INFO, "AccessSize = 0x%x\n", PldReg->Address.AccessSize));
376 DEBUG ((DEBUG_INFO, "Address = 0x%lx\n", PldReg->Address.Address));
377 return NULL;
378 }
379
380 return PldReg;
381}
382
393EFIAPI
395 IN EFI_HANDLE ImageHandle,
396 IN EFI_SYSTEM_TABLE *SystemTable
397 )
398{
399 EFI_STATUS Status;
400 EFI_HANDLE DispatchHandle;
401 EFI_HOB_GUID_TYPE *GuidHob;
402 PLD_SMM_REGISTERS *SmmRegister;
403 PLD_GENERIC_REGISTER *SmiEosReg;
404 PLD_GENERIC_REGISTER *SmiApmStsReg;
405
407 if (GuidHob == NULL) {
408 return EFI_UNSUPPORTED;
409 }
410
411 SmmRegister = (PLD_SMM_REGISTERS *)GET_GUID_HOB_DATA (GuidHob);
412 SmiEosReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_EOS);
413 if (SmiEosReg == NULL) {
414 DEBUG ((DEBUG_ERROR, "SMI EOS reg not found.\n"));
415 return EFI_NOT_FOUND;
416 }
417
418 mSmiPchReg.SmiEosAddr = (UINT32)SmiEosReg->Address.Address;
419 mSmiPchReg.EosBitOffset = SmiEosReg->Address.RegisterBitOffset;
420
421 SmiApmStsReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_APM_STS);
422 if (SmiApmStsReg == NULL) {
423 DEBUG ((DEBUG_ERROR, "SMI APM status reg not found.\n"));
424 return EFI_NOT_FOUND;
425 }
426
427 mSmiPchReg.SmiApmStsAddr = (UINT32)SmiApmStsReg->Address.Address;
428 mSmiPchReg.ApmBitOffset = SmiApmStsReg->Address.RegisterBitOffset;
429
430 //
431 // Locate PI SMM CPU protocol
432 //
433 Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **)&mSmmCpuProtocol);
434 ASSERT_EFI_ERROR (Status);
435
436 //
437 // Register a SMM handler to handle subsequent SW SMIs.
438 //
439 Status = gSmst->SmiHandlerRegister ((EFI_MM_HANDLER_ENTRY_POINT)SmmSwDispatcher, NULL, &DispatchHandle);
440 ASSERT_EFI_ERROR (Status);
441
442 //
443 // Publish PI SMM SwDispatch2 Protocol
444 //
445 ImageHandle = NULL;
447 &ImageHandle,
448 &gEfiSmmSwDispatch2ProtocolGuid,
450 &gSmmSwDispatch2
451 );
452 ASSERT_EFI_ERROR (Status);
453
454 return Status;
455}
UINT64 UINTN
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition: HobLib.c:215
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
#define INITIALIZE_LIST_HEAD_VARIABLE(ListHead)
Definition: BaseLib.h:2904
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
UINT32 EFIAPI IoOr32(IN UINTN Port, IN UINT32 OrData)
Definition: IoHighLevel.c:618
UINT8 EFIAPI IoRead8(IN UINTN Port)
Definition: IoLibArmVirt.c:175
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define BASE_CR(Record, TYPE, Field)
Definition: Base.h:891
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
EFI_STATUS SmmSwDispatcher(IN EFI_HANDLE DispatchHandle, IN CONST VOID *RegisterContext, IN OUT VOID *CommBuffer, IN OUT UINTN *CommBufferSize)
PLD_GENERIC_REGISTER * GetSmmCtrlRegById(IN PLD_SMM_REGISTERS *SmmRegister, IN UINT32 Id)
EFI_SMM_SW_DISPATCH2_CONTEXT * FindContextBySwSmiInputValue(IN UINTN SwSmiInputValue)
EFI_STATUS EFIAPI PchSmiDispatchEntryPoint(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
EFI_SMM_SW_DISPATCH2_CONTEXT * FindContextByDispatchHandle(IN EFI_HANDLE DispatchHandle)
EFI_STATUS EFIAPI SmmSwDispatch2UnRegister(IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, IN EFI_HANDLE DispatchHandle)
EFI_STATUS SmiInputValueCheck(IN UINTN SwSmiInputValue)
EFI_STATUS EFIAPI SmmSwDispatch2Register(IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, IN OUT EFI_SMM_SW_REGISTER_CONTEXT *RegContext, OUT EFI_HANDLE *DispatchHandle)
EFI_STATUS(EFIAPI * EFI_MM_HANDLER_ENTRY_POINT)(IN EFI_HANDLE DispatchHandle, IN CONST VOID *Context OPTIONAL, IN OUT VOID *CommBuffer OPTIONAL, IN OUT UINTN *CommBufferSize OPTIONAL)
Definition: PiMmCis.h:162
EFI_SMM_SYSTEM_TABLE2 * gSmst
EFI_GUID gSmmRegisterInfoGuid
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
@ EfiRuntimeServicesData
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
EFI_INSTALL_PROTOCOL_INTERFACE SmmInstallProtocolInterface
Definition: PiSmmCis.h:185
EFI_ALLOCATE_POOL SmmAllocatePool
Definition: PiSmmCis.h:132