1 | /** @file
|
---|
2 | SMM SwDispatch2 Protocol.
|
---|
3 |
|
---|
4 | Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
|
---|
5 | SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
6 |
|
---|
7 |
|
---|
8 |
|
---|
9 | **/
|
---|
10 |
|
---|
11 | #include "PchSmiDispatchSmm.h"
|
---|
12 |
|
---|
13 | typedef struct {
|
---|
14 | UINT8 EosBitOffset;
|
---|
15 | UINT8 ApmBitOffset;
|
---|
16 | UINT32 SmiEosAddr;
|
---|
17 | UINT32 SmiApmStsAddr;
|
---|
18 | } SMM_PCH_REGISTER;
|
---|
19 |
|
---|
20 | SMM_PCH_REGISTER mSmiPchReg;
|
---|
21 |
|
---|
22 | EFI_SMM_CPU_PROTOCOL *mSmmCpuProtocol;
|
---|
23 | LIST_ENTRY mSmmSwDispatch2Queue = INITIALIZE_LIST_HEAD_VARIABLE (mSmmSwDispatch2Queue);
|
---|
24 |
|
---|
25 | /**
|
---|
26 | Find SmmSwDispatch2Context by SwSmiInputValue.
|
---|
27 |
|
---|
28 | @param[in] SwSmiInputValue The value to indentify the SmmSwDispatch2 context
|
---|
29 |
|
---|
30 | @return Pointer to EFI_SMM_SW_DISPATCH2_CONTEXT context
|
---|
31 | **/
|
---|
32 | EFI_SMM_SW_DISPATCH2_CONTEXT *
|
---|
33 | FindContextBySwSmiInputValue (
|
---|
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 |
|
---|
51 | /**
|
---|
52 | Find SmmSwDispatch2Context by DispatchHandle.
|
---|
53 |
|
---|
54 | @param DispatchHandle The handle to indentify the SmmSwDispatch2 context
|
---|
55 |
|
---|
56 | @return Pointer to EFI_SMM_SW_DISPATCH2_CONTEXT context
|
---|
57 | **/
|
---|
58 | EFI_SMM_SW_DISPATCH2_CONTEXT *
|
---|
59 | FindContextByDispatchHandle (
|
---|
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 |
|
---|
77 | /**
|
---|
78 | Dispatch registered SMM handlers
|
---|
79 |
|
---|
80 | @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
|
---|
81 | @param RegisterContext Points to an optional handler context which was specified when the handler was registered.
|
---|
82 | @param CommBuffer A pointer to a collection of data in memory that will
|
---|
83 | be conveyed from a non-SMM environment into an SMM environment.
|
---|
84 | @param CommBufferSize The size of the CommBuffer.
|
---|
85 |
|
---|
86 | @return Status Code
|
---|
87 |
|
---|
88 | **/
|
---|
89 | EFI_STATUS
|
---|
90 | SmmSwDispatcher (
|
---|
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;
|
---|
100 | EFI_SMM_SW_DISPATCH2_CONTEXT *Context;
|
---|
101 | EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction;
|
---|
102 | EFI_SMM_SW_REGISTER_CONTEXT DispatchContext;
|
---|
103 | UINTN Size;
|
---|
104 | EFI_SMM_SAVE_STATE_IO_INFO IoInfo;
|
---|
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 |
|
---|
164 | End:
|
---|
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 |
|
---|
178 | /**
|
---|
179 | Check the SwSmiInputValue is already used
|
---|
180 |
|
---|
181 | @param[in] SwSmiInputValue To indentify the SmmSwDispatch2 context
|
---|
182 |
|
---|
183 | @retval EFI_SUCCESS SwSmiInputValue could be used.
|
---|
184 | @retval EFI_INVALID_PARAMETER SwSmiInputValue is already be used.
|
---|
185 |
|
---|
186 | **/
|
---|
187 | EFI_STATUS
|
---|
188 | SmiInputValueCheck (
|
---|
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 |
|
---|
206 | /**
|
---|
207 | Register a child SMI source dispatch function for the specified software SMI.
|
---|
208 |
|
---|
209 | This service registers a function (DispatchFunction) which will be called when the software
|
---|
210 | SMI source specified by RegContext->SwSmiCpuIndex is detected. On return, DispatchHandle
|
---|
211 | contains a unique handle which may be used later to unregister the function using UnRegister().
|
---|
212 |
|
---|
213 | @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
|
---|
214 | @param[in] DispatchFunction Function to register for handler when the specified software
|
---|
215 | SMI is generated.
|
---|
216 | @param[in, out] RegContext Pointer to the dispatch function's context.
|
---|
217 | The caller fills this context in before calling
|
---|
218 | the register function to indicate to the register
|
---|
219 | function which Software SMI input value the
|
---|
220 | dispatch function should be invoked for.
|
---|
221 | @param[out] DispatchHandle Handle generated by the dispatcher to track the
|
---|
222 | function instance.
|
---|
223 |
|
---|
224 | @retval EFI_SUCCESS The dispatch function has been successfully
|
---|
225 | registered and the SMI source has been enabled.
|
---|
226 | @retval EFI_DEVICE_ERROR The SW driver was unable to enable the SMI source.
|
---|
227 | @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI input value
|
---|
228 | is not within valid range.
|
---|
229 | @retval EFI_OUT_OF_RESOURCES There is not enough memory (system or SMM) to manage this
|
---|
230 | child.
|
---|
231 | @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not be assigned
|
---|
232 | for this dispatch.
|
---|
233 | **/
|
---|
234 | EFI_STATUS
|
---|
235 | EFIAPI
|
---|
236 | SmmSwDispatch2Register (
|
---|
237 | IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This,
|
---|
238 | IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
|
---|
239 | IN OUT EFI_SMM_SW_REGISTER_CONTEXT *RegContext,
|
---|
240 | OUT EFI_HANDLE *DispatchHandle
|
---|
241 | )
|
---|
242 | {
|
---|
243 | EFI_STATUS Status;
|
---|
244 | UINTN Index;
|
---|
245 | EFI_SMM_SW_DISPATCH2_CONTEXT *Context;
|
---|
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 |
|
---|
290 | /**
|
---|
291 | Unregister a child SMI source dispatch function for the specified software SMI.
|
---|
292 |
|
---|
293 | This service removes the handler associated with DispatchHandle so that it will no longer be
|
---|
294 | called in response to a software SMI.
|
---|
295 |
|
---|
296 | @param[in] This Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
|
---|
297 | @param[in] DispatchHandle Handle of dispatch function to deregister.
|
---|
298 |
|
---|
299 | @retval EFI_SUCCESS The dispatch function has been successfully unregistered.
|
---|
300 | @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid.
|
---|
301 | **/
|
---|
302 | EFI_STATUS
|
---|
303 | EFIAPI
|
---|
304 | SmmSwDispatch2UnRegister (
|
---|
305 | IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This,
|
---|
306 | IN EFI_HANDLE DispatchHandle
|
---|
307 | )
|
---|
308 | {
|
---|
309 | EFI_SMM_SW_DISPATCH2_CONTEXT *Context;
|
---|
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 |
|
---|
324 | EFI_SMM_SW_DISPATCH2_PROTOCOL gSmmSwDispatch2 = {
|
---|
325 | SmmSwDispatch2Register,
|
---|
326 | SmmSwDispatch2UnRegister,
|
---|
327 | MAXIMUM_SWI_VALUE
|
---|
328 | };
|
---|
329 |
|
---|
330 | /**
|
---|
331 | Get specified SMI register based on given register ID
|
---|
332 |
|
---|
333 | @param[in] SmmRegister SMI related register array from bootloader
|
---|
334 | @param[in] Id The register ID to get.
|
---|
335 |
|
---|
336 | @retval NULL The register is not found or the format is not expected.
|
---|
337 | @return smi register
|
---|
338 |
|
---|
339 | **/
|
---|
340 | PLD_GENERIC_REGISTER *
|
---|
341 | GetSmmCtrlRegById (
|
---|
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 |
|
---|
383 | /**
|
---|
384 | Entry Point for this 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 | PchSmiDispatchEntryPoint (
|
---|
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 |
|
---|
406 | GuidHob = GetFirstGuidHob (&gSmmRegisterInfoGuid);
|
---|
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;
|
---|
446 | Status = gSmst->SmmInstallProtocolInterface (
|
---|
447 | &ImageHandle,
|
---|
448 | &gEfiSmmSwDispatch2ProtocolGuid,
|
---|
449 | EFI_NATIVE_INTERFACE,
|
---|
450 | &gSmmSwDispatch2
|
---|
451 | );
|
---|
452 | ASSERT_EFI_ERROR (Status);
|
---|
453 |
|
---|
454 | return Status;
|
---|
455 | }
|
---|