]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EbcDxe/EbcInt.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / EbcInt.c
1 /** @file
2 Top level module for the EBC virtual machine implementation.
3 Provides auxiliary support routines for the VM. That is, routines
4 that are not particularly related to VM execution of EBC instructions.
5
6 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "EbcInt.h"
12 #include "EbcExecute.h"
13 #include "EbcDebuggerHook.h"
14
15 //
16 // We'll keep track of all thunks we create in a linked list. Each
17 // thunk is tied to an image handle, so we have a linked list of
18 // image handles, with each having a linked list of thunks allocated
19 // to that image handle.
20 //
21 typedef struct _EBC_THUNK_LIST EBC_THUNK_LIST;
22 struct _EBC_THUNK_LIST {
23 VOID *ThunkBuffer;
24 EBC_THUNK_LIST *Next;
25 };
26
27 typedef struct _EBC_IMAGE_LIST EBC_IMAGE_LIST;
28 struct _EBC_IMAGE_LIST {
29 EBC_IMAGE_LIST *Next;
30 EFI_HANDLE ImageHandle;
31 EBC_THUNK_LIST *ThunkList;
32 };
33
34 /**
35 This routine is called by the core when an image is being unloaded from
36 memory. Basically we now have the opportunity to do any necessary cleanup.
37 Typically this will include freeing any memory allocated for thunk-creation.
38
39 @param This A pointer to the EFI_EBC_PROTOCOL instance.
40 @param ImageHandle Handle of image for which the thunk is being
41 created.
42
43 @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
44 internal list of EBC image handles.
45 @retval EFI_SUCCESS The function completed successfully.
46
47 **/
48 EFI_STATUS
49 EFIAPI
50 EbcUnloadImage (
51 IN EFI_EBC_PROTOCOL *This,
52 IN EFI_HANDLE ImageHandle
53 );
54
55 /**
56 This is the top-level routine plugged into the EBC protocol. Since thunks
57 are very processor-specific, from here we dispatch directly to the very
58 processor-specific routine EbcCreateThunks().
59
60 @param This A pointer to the EFI_EBC_PROTOCOL instance.
61 @param ImageHandle Handle of image for which the thunk is being
62 created. The EBC interpreter may use this to
63 keep track of any resource allocations
64 performed in loading and executing the image.
65 @param EbcEntryPoint Address of the actual EBC entry point or
66 protocol service the thunk should call.
67 @param Thunk Returned pointer to a thunk created.
68
69 @retval EFI_SUCCESS The function completed successfully.
70 @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
71 @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
72
73 **/
74 EFI_STATUS
75 EFIAPI
76 EbcCreateThunk (
77 IN EFI_EBC_PROTOCOL *This,
78 IN EFI_HANDLE ImageHandle,
79 IN VOID *EbcEntryPoint,
80 OUT VOID **Thunk
81 );
82
83 /**
84 Called to get the version of the interpreter.
85
86 @param This A pointer to the EFI_EBC_PROTOCOL instance.
87 @param Version Pointer to where to store the returned version
88 of the interpreter.
89
90 @retval EFI_SUCCESS The function completed successfully.
91 @retval EFI_INVALID_PARAMETER Version pointer is NULL.
92
93 **/
94 EFI_STATUS
95 EFIAPI
96 EbcGetVersion (
97 IN EFI_EBC_PROTOCOL *This,
98 IN OUT UINT64 *Version
99 );
100
101 /**
102 To install default Callback function for the VM interpreter.
103
104 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
105 instance.
106
107 @retval EFI_SUCCESS The function completed successfully.
108 @retval Others Some error occurs when creating periodic event.
109
110 **/
111 EFI_STATUS
112 EFIAPI
113 InitializeEbcCallback (
114 IN EFI_DEBUG_SUPPORT_PROTOCOL *This
115 );
116
117 /**
118 The default Exception Callback for the VM interpreter.
119 In this function, we report status code, and print debug information
120 about EBC_CONTEXT, then dead loop.
121
122 @param InterruptType Interrupt type.
123 @param SystemContext EBC system context.
124
125 **/
126 VOID
127 EFIAPI
128 CommonEbcExceptionHandler (
129 IN EFI_EXCEPTION_TYPE InterruptType,
130 IN EFI_SYSTEM_CONTEXT SystemContext
131 );
132
133 /**
134 The periodic callback function for EBC VM interpreter, which is used
135 to support the EFI debug support protocol.
136
137 @param Event The Periodic Callback Event.
138 @param Context It should be the address of VM_CONTEXT pointer.
139
140 **/
141 VOID
142 EFIAPI
143 EbcPeriodicNotifyFunction (
144 IN EFI_EVENT Event,
145 IN VOID *Context
146 );
147
148 /**
149 The VM interpreter calls this function on a periodic basis to support
150 the EFI debug support protocol.
151
152 @param VmPtr Pointer to a VM context for passing info to the
153 debugger.
154
155 @retval EFI_SUCCESS The function completed successfully.
156
157 **/
158 EFI_STATUS
159 EFIAPI
160 EbcDebugPeriodic (
161 IN VM_CONTEXT *VmPtr
162 );
163
164 //
165 // These two functions and the GUID are used to produce an EBC test protocol.
166 // This functionality is definitely not required for execution.
167 //
168
169 /**
170 Produces an EBC VM test protocol that can be used for regression tests.
171
172 @param IHandle Handle on which to install the protocol.
173
174 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
175 @retval EFI_SUCCESS The function completed successfully.
176
177 **/
178 EFI_STATUS
179 InitEbcVmTestProtocol (
180 IN EFI_HANDLE *IHandle
181 );
182
183 /**
184 Returns the EFI_UNSUPPORTED Status.
185
186 @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
187
188 **/
189 EFI_STATUS
190 EFIAPI
191 EbcVmTestUnsupported (
192 VOID
193 );
194
195 /**
196 Registers a callback function that the EBC interpreter calls to flush the
197 processor instruction cache following creation of thunks.
198
199 @param This A pointer to the EFI_EBC_PROTOCOL instance.
200 @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
201
202 @retval EFI_SUCCESS The function completed successfully.
203
204 **/
205 EFI_STATUS
206 EFIAPI
207 EbcRegisterICacheFlush (
208 IN EFI_EBC_PROTOCOL *This,
209 IN EBC_ICACHE_FLUSH Flush
210 );
211
212 /**
213 This EBC debugger protocol service is called by the debug agent
214
215 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
216 instance.
217 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
218 maximum supported processor index is returned.
219
220 @retval EFI_SUCCESS The function completed successfully.
221
222 **/
223 EFI_STATUS
224 EFIAPI
225 EbcDebugGetMaximumProcessorIndex (
226 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
227 OUT UINTN *MaxProcessorIndex
228 );
229
230 /**
231 This protocol service is called by the debug agent to register a function
232 for us to call on a periodic basis.
233
234 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
235 instance.
236 @param ProcessorIndex Specifies which processor the callback function
237 applies to.
238 @param PeriodicCallback A pointer to a function of type
239 PERIODIC_CALLBACK that is the main periodic
240 entry point of the debug agent. It receives as a
241 parameter a pointer to the full context of the
242 interrupted execution thread.
243
244 @retval EFI_SUCCESS The function completed successfully.
245 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
246 callback function was previously registered.
247 @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
248 callback function was previously registered.
249
250 **/
251 EFI_STATUS
252 EFIAPI
253 EbcDebugRegisterPeriodicCallback (
254 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
255 IN UINTN ProcessorIndex,
256 IN EFI_PERIODIC_CALLBACK PeriodicCallback
257 );
258
259 /**
260 This protocol service is called by the debug agent to register a function
261 for us to call when we detect an exception.
262
263 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
264 instance.
265 @param ProcessorIndex Specifies which processor the callback function
266 applies to.
267 @param ExceptionCallback A pointer to a function of type
268 EXCEPTION_CALLBACK that is called when the
269 processor exception specified by ExceptionType
270 occurs. Passing NULL unregisters any previously
271 registered function associated with
272 ExceptionType.
273 @param ExceptionType Specifies which processor exception to hook.
274
275 @retval EFI_SUCCESS The function completed successfully.
276 @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
277 callback function was previously registered.
278 @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
279 MAX_EBC_EXCEPTION.
280 @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
281 callback function was previously registered.
282
283 **/
284 EFI_STATUS
285 EFIAPI
286 EbcDebugRegisterExceptionCallback (
287 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
288 IN UINTN ProcessorIndex,
289 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
290 IN EFI_EXCEPTION_TYPE ExceptionType
291 );
292
293 /**
294 This EBC debugger protocol service is called by the debug agent. Required
295 for DebugSupport compliance but is only stubbed out for EBC.
296
297 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
298 instance.
299 @param ProcessorIndex Specifies which processor the callback function
300 applies to.
301 @param Start StartSpecifies the physical base of the memory
302 range to be invalidated.
303 @param Length Specifies the minimum number of bytes in the
304 processor's instruction cache to invalidate.
305
306 @retval EFI_SUCCESS The function completed successfully.
307
308 **/
309 EFI_STATUS
310 EFIAPI
311 EbcDebugInvalidateInstructionCache (
312 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
313 IN UINTN ProcessorIndex,
314 IN VOID *Start,
315 IN UINT64 Length
316 );
317
318 //
319 // We have one linked list of image handles for the whole world. Since
320 // there should only be one interpreter, make them global. They must
321 // also be global since the execution of an EBC image does not provide
322 // a This pointer.
323 //
324 EBC_IMAGE_LIST *mEbcImageList = NULL;
325
326 //
327 // Callback function to flush the icache after thunk creation
328 //
329 EBC_ICACHE_FLUSH mEbcICacheFlush;
330
331 //
332 // These get set via calls by the debug agent
333 //
334 EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;
335 EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = { NULL };
336
337 VOID *mStackBuffer[MAX_STACK_NUM];
338 EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];
339 UINTN mStackNum = 0;
340
341 //
342 // Event for Periodic callback
343 //
344 EFI_EVENT mEbcPeriodicEvent;
345 VM_CONTEXT *mVmPtr = NULL;
346
347 /**
348 Check whether the emulator supports executing a certain PE/COFF image
349
350 @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
351 structure
352 @param[in] ImageType Whether the image is an application, a boot time
353 driver or a runtime driver.
354 @param[in] DevicePath Path to device where the image originated
355 (e.g., a PCI option ROM)
356
357 @retval TRUE The image is supported by the emulator
358 @retval FALSE The image is not supported by the emulator.
359 **/
360 BOOLEAN
361 EFIAPI
362 EbcIsImageSupported (
363 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
364 IN UINT16 ImageType,
365 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
366 )
367 {
368 if ((ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) &&
369 (ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER))
370 {
371 return FALSE;
372 }
373
374 return TRUE;
375 }
376
377 /**
378 Register a supported PE/COFF image with the emulator. After this call
379 completes successfully, the PE/COFF image may be started as usual, and
380 it is the responsibility of the emulator implementation that any branch
381 into the code section of the image (including returns from functions called
382 from the foreign code) is executed as if it were running on the machine
383 type it was built for.
384
385 @param[in] This This pointer for
386 EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL structure
387 @param[in] ImageBase The base address in memory of the PE/COFF image
388 @param[in] ImageSize The size in memory of the PE/COFF image
389 @param[in,out] EntryPoint The entry point of the PE/COFF image. Passed by
390 reference so that the emulator may modify it.
391
392 @retval EFI_SUCCESS The image was registered with the emulator and
393 can be started as usual.
394 @retval other The image could not be registered.
395
396 If the PE/COFF machine type or image type are not supported by the emulator,
397 then ASSERT().
398 **/
399 EFI_STATUS
400 EFIAPI
401 EbcRegisterImage (
402 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
403 IN EFI_PHYSICAL_ADDRESS ImageBase,
404 IN UINT64 ImageSize,
405 IN OUT EFI_IMAGE_ENTRY_POINT *EntryPoint
406 )
407 {
408 DEBUG_CODE_BEGIN ();
409 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
410 EFI_STATUS Status;
411
412 ZeroMem (&ImageContext, sizeof (ImageContext));
413
414 ImageContext.Handle = (VOID *)(UINTN)ImageBase;
415 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
416
417 Status = PeCoffLoaderGetImageInfo (&ImageContext);
418 if (EFI_ERROR (Status)) {
419 return Status;
420 }
421
422 ASSERT (ImageContext.Machine == EFI_IMAGE_MACHINE_EBC);
423 ASSERT (
424 ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ||
425 ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
426 );
427 DEBUG_CODE_END ();
428
429 EbcRegisterICacheFlush (
430 NULL,
431 (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange
432 );
433
434 return EbcCreateThunk (
435 NULL,
436 (VOID *)(UINTN)ImageBase,
437 (VOID *)(UINTN)*EntryPoint,
438 (VOID **)EntryPoint
439 );
440 }
441
442 /**
443 Unregister a PE/COFF image that has been registered with the emulator.
444 This should be done before the image is unloaded from memory.
445
446 @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
447 structure
448 @param[in] ImageBase The base address in memory of the PE/COFF image
449
450 @retval EFI_SUCCESS The image was unregistered with the emulator.
451 @retval other Image could not be unloaded.
452 **/
453 EFI_STATUS
454 EFIAPI
455 EbcUnregisterImage (
456 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
457 IN EFI_PHYSICAL_ADDRESS ImageBase
458 )
459 {
460 return EbcUnloadImage (NULL, (VOID *)(UINTN)ImageBase);
461 }
462
463 STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mPeCoffEmuProtocol = {
464 EbcIsImageSupported,
465 EbcRegisterImage,
466 EbcUnregisterImage,
467 EDKII_PECOFF_IMAGE_EMULATOR_VERSION,
468 EFI_IMAGE_MACHINE_EBC
469 };
470
471 /**
472 Initializes the VM EFI interface. Allocates memory for the VM interface
473 and registers the VM protocol.
474
475 @param ImageHandle EFI image handle.
476 @param SystemTable Pointer to the EFI system table.
477
478 @return Standard EFI status code.
479
480 **/
481 EFI_STATUS
482 EFIAPI
483 InitializeEbcDriver (
484 IN EFI_HANDLE ImageHandle,
485 IN EFI_SYSTEM_TABLE *SystemTable
486 )
487 {
488 EFI_EBC_PROTOCOL *EbcProtocol;
489 EFI_EBC_PROTOCOL *OldEbcProtocol;
490 EFI_STATUS Status;
491 EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol;
492 EFI_HANDLE *HandleBuffer;
493 UINTN NumHandles;
494 UINTN Index;
495 BOOLEAN Installed;
496
497 EbcProtocol = NULL;
498 EbcDebugProtocol = NULL;
499
500 //
501 // Allocate memory for our protocol. Then fill in the blanks.
502 //
503 EbcProtocol = AllocatePool (sizeof (EFI_EBC_PROTOCOL));
504
505 if (EbcProtocol == NULL) {
506 return EFI_OUT_OF_RESOURCES;
507 }
508
509 EbcProtocol->CreateThunk = EbcCreateThunk;
510 EbcProtocol->UnloadImage = EbcUnloadImage;
511 EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush;
512 EbcProtocol->GetVersion = EbcGetVersion;
513 mEbcICacheFlush = NULL;
514
515 //
516 // Find any already-installed EBC protocols and uninstall them
517 //
518 Installed = FALSE;
519 HandleBuffer = NULL;
520 Status = gBS->LocateHandleBuffer (
521 ByProtocol,
522 &gEfiEbcProtocolGuid,
523 NULL,
524 &NumHandles,
525 &HandleBuffer
526 );
527 if (Status == EFI_SUCCESS) {
528 //
529 // Loop through the handles
530 //
531 for (Index = 0; Index < NumHandles; Index++) {
532 Status = gBS->HandleProtocol (
533 HandleBuffer[Index],
534 &gEfiEbcProtocolGuid,
535 (VOID **)&OldEbcProtocol
536 );
537 if (Status == EFI_SUCCESS) {
538 if (gBS->ReinstallProtocolInterface (
539 HandleBuffer[Index],
540 &gEfiEbcProtocolGuid,
541 OldEbcProtocol,
542 EbcProtocol
543 ) == EFI_SUCCESS)
544 {
545 Installed = TRUE;
546 }
547 }
548 }
549 }
550
551 if (HandleBuffer != NULL) {
552 FreePool (HandleBuffer);
553 HandleBuffer = NULL;
554 }
555
556 //
557 // Add the protocol so someone can locate us if we haven't already.
558 //
559 if (!Installed) {
560 Status = gBS->InstallMultipleProtocolInterfaces (
561 &ImageHandle,
562 &gEfiEbcProtocolGuid,
563 EbcProtocol,
564 &gEdkiiPeCoffImageEmulatorProtocolGuid,
565 &mPeCoffEmuProtocol,
566 NULL
567 );
568 if (EFI_ERROR (Status)) {
569 FreePool (EbcProtocol);
570 return Status;
571 }
572 }
573
574 Status = InitEBCStack ();
575 if (EFI_ERROR (Status)) {
576 goto ErrorExit;
577 }
578
579 //
580 // Allocate memory for our debug protocol. Then fill in the blanks.
581 //
582 EbcDebugProtocol = AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL));
583
584 if (EbcDebugProtocol == NULL) {
585 goto ErrorExit;
586 }
587
588 EbcDebugProtocol->Isa = IsaEbc;
589 EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex;
590 EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback;
591 EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback;
592 EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache;
593
594 //
595 // Add the protocol so the debug agent can find us
596 //
597 Status = gBS->InstallProtocolInterface (
598 &ImageHandle,
599 &gEfiDebugSupportProtocolGuid,
600 EFI_NATIVE_INTERFACE,
601 EbcDebugProtocol
602 );
603 //
604 // This is recoverable, so free the memory and continue.
605 //
606 if (EFI_ERROR (Status)) {
607 FreePool (EbcDebugProtocol);
608 goto ErrorExit;
609 }
610
611 //
612 // Install EbcDebugSupport Protocol Successfully
613 // Now we need to initialize the Ebc default Callback
614 //
615 Status = InitializeEbcCallback (EbcDebugProtocol);
616
617 //
618 // Produce a VM test interface protocol. Not required for execution.
619 //
620 DEBUG_CODE_BEGIN ();
621 InitEbcVmTestProtocol (&ImageHandle);
622 DEBUG_CODE_END ();
623
624 EbcDebuggerHookInit (ImageHandle, EbcDebugProtocol);
625
626 return EFI_SUCCESS;
627
628 ErrorExit:
629 FreeEBCStack ();
630 HandleBuffer = NULL;
631 Status = gBS->LocateHandleBuffer (
632 ByProtocol,
633 &gEfiEbcProtocolGuid,
634 NULL,
635 &NumHandles,
636 &HandleBuffer
637 );
638 if (Status == EFI_SUCCESS) {
639 //
640 // Loop through the handles
641 //
642 for (Index = 0; Index < NumHandles; Index++) {
643 Status = gBS->HandleProtocol (
644 HandleBuffer[Index],
645 &gEfiEbcProtocolGuid,
646 (VOID **)&OldEbcProtocol
647 );
648 if (Status == EFI_SUCCESS) {
649 gBS->UninstallProtocolInterface (
650 HandleBuffer[Index],
651 &gEfiEbcProtocolGuid,
652 OldEbcProtocol
653 );
654 }
655 }
656 }
657
658 if (HandleBuffer != NULL) {
659 FreePool (HandleBuffer);
660 HandleBuffer = NULL;
661 }
662
663 FreePool (EbcProtocol);
664
665 return Status;
666 }
667
668 /**
669 This is the top-level routine plugged into the EBC protocol. Since thunks
670 are very processor-specific, from here we dispatch directly to the very
671 processor-specific routine EbcCreateThunks().
672
673 @param This A pointer to the EFI_EBC_PROTOCOL instance.
674 @param ImageHandle Handle of image for which the thunk is being
675 created. The EBC interpreter may use this to
676 keep track of any resource allocations
677 performed in loading and executing the image.
678 @param EbcEntryPoint Address of the actual EBC entry point or
679 protocol service the thunk should call.
680 @param Thunk Returned pointer to a thunk created.
681
682 @retval EFI_SUCCESS The function completed successfully.
683 @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
684 @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
685
686 **/
687 EFI_STATUS
688 EFIAPI
689 EbcCreateThunk (
690 IN EFI_EBC_PROTOCOL *This,
691 IN EFI_HANDLE ImageHandle,
692 IN VOID *EbcEntryPoint,
693 OUT VOID **Thunk
694 )
695 {
696 EFI_STATUS Status;
697
698 Status = EbcCreateThunks (
699 ImageHandle,
700 EbcEntryPoint,
701 Thunk,
702 FLAG_THUNK_ENTRY_POINT
703 );
704 return Status;
705 }
706
707 /**
708 This EBC debugger protocol service is called by the debug agent
709
710 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
711 instance.
712 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
713 maximum supported processor index is returned.
714
715 @retval EFI_SUCCESS The function completed successfully.
716
717 **/
718 EFI_STATUS
719 EFIAPI
720 EbcDebugGetMaximumProcessorIndex (
721 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
722 OUT UINTN *MaxProcessorIndex
723 )
724 {
725 *MaxProcessorIndex = 0;
726 return EFI_SUCCESS;
727 }
728
729 /**
730 This protocol service is called by the debug agent to register a function
731 for us to call on a periodic basis.
732
733 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
734 instance.
735 @param ProcessorIndex Specifies which processor the callback function
736 applies to.
737 @param PeriodicCallback A pointer to a function of type
738 PERIODIC_CALLBACK that is the main periodic
739 entry point of the debug agent. It receives as a
740 parameter a pointer to the full context of the
741 interrupted execution thread.
742
743 @retval EFI_SUCCESS The function completed successfully.
744 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
745 callback function was previously registered.
746 @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
747 callback function was previously registered.
748
749 **/
750 EFI_STATUS
751 EFIAPI
752 EbcDebugRegisterPeriodicCallback (
753 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
754 IN UINTN ProcessorIndex,
755 IN EFI_PERIODIC_CALLBACK PeriodicCallback
756 )
757 {
758 if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {
759 return EFI_INVALID_PARAMETER;
760 }
761
762 if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {
763 return EFI_ALREADY_STARTED;
764 }
765
766 mDebugPeriodicCallback = PeriodicCallback;
767 return EFI_SUCCESS;
768 }
769
770 /**
771 This protocol service is called by the debug agent to register a function
772 for us to call when we detect an exception.
773
774 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
775 instance.
776 @param ProcessorIndex Specifies which processor the callback function
777 applies to.
778 @param ExceptionCallback A pointer to a function of type
779 EXCEPTION_CALLBACK that is called when the
780 processor exception specified by ExceptionType
781 occurs. Passing NULL unregisters any previously
782 registered function associated with
783 ExceptionType.
784 @param ExceptionType Specifies which processor exception to hook.
785
786 @retval EFI_SUCCESS The function completed successfully.
787 @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
788 callback function was previously registered.
789 @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
790 MAX_EBC_EXCEPTION.
791 @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
792 callback function was previously registered.
793
794 **/
795 EFI_STATUS
796 EFIAPI
797 EbcDebugRegisterExceptionCallback (
798 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
799 IN UINTN ProcessorIndex,
800 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
801 IN EFI_EXCEPTION_TYPE ExceptionType
802 )
803 {
804 if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {
805 return EFI_INVALID_PARAMETER;
806 }
807
808 if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {
809 return EFI_INVALID_PARAMETER;
810 }
811
812 if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {
813 return EFI_ALREADY_STARTED;
814 }
815
816 mDebugExceptionCallback[ExceptionType] = ExceptionCallback;
817 return EFI_SUCCESS;
818 }
819
820 /**
821 This EBC debugger protocol service is called by the debug agent. Required
822 for DebugSupport compliance but is only stubbed out for EBC.
823
824 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
825 instance.
826 @param ProcessorIndex Specifies which processor the callback function
827 applies to.
828 @param Start StartSpecifies the physical base of the memory
829 range to be invalidated.
830 @param Length Specifies the minimum number of bytes in the
831 processor's instruction cache to invalidate.
832
833 @retval EFI_SUCCESS The function completed successfully.
834
835 **/
836 EFI_STATUS
837 EFIAPI
838 EbcDebugInvalidateInstructionCache (
839 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
840 IN UINTN ProcessorIndex,
841 IN VOID *Start,
842 IN UINT64 Length
843 )
844 {
845 return EFI_SUCCESS;
846 }
847
848 /**
849 The VM interpreter calls this function when an exception is detected.
850
851 @param ExceptionType Specifies the processor exception detected.
852 @param ExceptionFlags Specifies the exception context.
853 @param VmPtr Pointer to a VM context for passing info to the
854 EFI debugger.
855
856 @retval EFI_SUCCESS This function completed successfully.
857
858 **/
859 EFI_STATUS
860 EbcDebugSignalException (
861 IN EFI_EXCEPTION_TYPE ExceptionType,
862 IN EXCEPTION_FLAGS ExceptionFlags,
863 IN VM_CONTEXT *VmPtr
864 )
865 {
866 EFI_SYSTEM_CONTEXT_EBC EbcContext;
867 EFI_SYSTEM_CONTEXT SystemContext;
868
869 ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));
870 //
871 // Save the exception in the context passed in
872 //
873 VmPtr->ExceptionFlags |= ExceptionFlags;
874 VmPtr->LastException = (UINTN)ExceptionType;
875 //
876 // If it's a fatal exception, then flag it in the VM context in case an
877 // attached debugger tries to return from it.
878 //
879 if ((ExceptionFlags & EXCEPTION_FLAG_FATAL) != 0) {
880 VmPtr->StopFlags |= STOPFLAG_APP_DONE;
881 }
882
883 //
884 // If someone's registered for exception callbacks, then call them.
885 //
886 // EBC driver will register default exception callback to report the
887 // status code via the status code API
888 //
889 if (mDebugExceptionCallback[ExceptionType] != NULL) {
890 //
891 // Initialize the context structure
892 //
893 EbcContext.R0 = (UINT64)VmPtr->Gpr[0];
894 EbcContext.R1 = (UINT64)VmPtr->Gpr[1];
895 EbcContext.R2 = (UINT64)VmPtr->Gpr[2];
896 EbcContext.R3 = (UINT64)VmPtr->Gpr[3];
897 EbcContext.R4 = (UINT64)VmPtr->Gpr[4];
898 EbcContext.R5 = (UINT64)VmPtr->Gpr[5];
899 EbcContext.R6 = (UINT64)VmPtr->Gpr[6];
900 EbcContext.R7 = (UINT64)VmPtr->Gpr[7];
901 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
902 EbcContext.Flags = VmPtr->Flags;
903 EbcContext.ControlFlags = 0;
904 SystemContext.SystemContextEbc = &EbcContext;
905
906 mDebugExceptionCallback[ExceptionType](ExceptionType, SystemContext);
907 //
908 // Restore the context structure and continue to execute
909 //
910 VmPtr->Gpr[0] = EbcContext.R0;
911 VmPtr->Gpr[1] = EbcContext.R1;
912 VmPtr->Gpr[2] = EbcContext.R2;
913 VmPtr->Gpr[3] = EbcContext.R3;
914 VmPtr->Gpr[4] = EbcContext.R4;
915 VmPtr->Gpr[5] = EbcContext.R5;
916 VmPtr->Gpr[6] = EbcContext.R6;
917 VmPtr->Gpr[7] = EbcContext.R7;
918 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
919 VmPtr->Flags = EbcContext.Flags;
920 }
921
922 return EFI_SUCCESS;
923 }
924
925 /**
926 To install default Callback function for the VM interpreter.
927
928 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
929 instance.
930
931 @retval EFI_SUCCESS The function completed successfully.
932 @retval Others Some error occurs when creating periodic event.
933
934 **/
935 EFI_STATUS
936 EFIAPI
937 InitializeEbcCallback (
938 IN EFI_DEBUG_SUPPORT_PROTOCOL *This
939 )
940 {
941 INTN Index;
942 EFI_STATUS Status;
943
944 //
945 // For ExceptionCallback
946 //
947 for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {
948 EbcDebugRegisterExceptionCallback (
949 This,
950 0,
951 CommonEbcExceptionHandler,
952 Index
953 );
954 }
955
956 //
957 // For PeriodicCallback
958 //
959 Status = gBS->CreateEvent (
960 EVT_TIMER | EVT_NOTIFY_SIGNAL,
961 TPL_NOTIFY,
962 EbcPeriodicNotifyFunction,
963 &mVmPtr,
964 &mEbcPeriodicEvent
965 );
966 if (EFI_ERROR (Status)) {
967 return Status;
968 }
969
970 Status = gBS->SetTimer (
971 mEbcPeriodicEvent,
972 TimerPeriodic,
973 EBC_VM_PERIODIC_CALLBACK_RATE
974 );
975 if (EFI_ERROR (Status)) {
976 return Status;
977 }
978
979 return EFI_SUCCESS;
980 }
981
982 /**
983 The default Exception Callback for the VM interpreter.
984 In this function, we report status code, and print debug information
985 about EBC_CONTEXT, then dead loop.
986
987 @param InterruptType Interrupt type.
988 @param SystemContext EBC system context.
989
990 **/
991 VOID
992 EFIAPI
993 CommonEbcExceptionHandler (
994 IN EFI_EXCEPTION_TYPE InterruptType,
995 IN EFI_SYSTEM_CONTEXT SystemContext
996 )
997 {
998 //
999 // We print debug information to let user know what happen.
1000 //
1001 DEBUG ((
1002 DEBUG_ERROR,
1003 "EBC Interrupter Version - 0x%016lx\n",
1004 (UINT64)(((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)))
1005 ));
1006 DEBUG ((
1007 DEBUG_ERROR,
1008 "Exception Type - 0x%016lx\n",
1009 (UINT64)(UINTN)InterruptType
1010 ));
1011 DEBUG ((
1012 DEBUG_ERROR,
1013 " R0 - 0x%016lx, R1 - 0x%016lx\n",
1014 SystemContext.SystemContextEbc->R0,
1015 SystemContext.SystemContextEbc->R1
1016 ));
1017 DEBUG ((
1018 DEBUG_ERROR,
1019 " R2 - 0x%016lx, R3 - 0x%016lx\n",
1020 SystemContext.SystemContextEbc->R2,
1021 SystemContext.SystemContextEbc->R3
1022 ));
1023 DEBUG ((
1024 DEBUG_ERROR,
1025 " R4 - 0x%016lx, R5 - 0x%016lx\n",
1026 SystemContext.SystemContextEbc->R4,
1027 SystemContext.SystemContextEbc->R5
1028 ));
1029 DEBUG ((
1030 DEBUG_ERROR,
1031 " R6 - 0x%016lx, R7 - 0x%016lx\n",
1032 SystemContext.SystemContextEbc->R6,
1033 SystemContext.SystemContextEbc->R7
1034 ));
1035 DEBUG ((
1036 DEBUG_ERROR,
1037 " Flags - 0x%016lx\n",
1038 SystemContext.SystemContextEbc->Flags
1039 ));
1040 DEBUG ((
1041 DEBUG_ERROR,
1042 " ControlFlags - 0x%016lx\n",
1043 SystemContext.SystemContextEbc->ControlFlags
1044 ));
1045 DEBUG ((
1046 DEBUG_ERROR,
1047 " Ip - 0x%016lx\n\n",
1048 SystemContext.SystemContextEbc->Ip
1049 ));
1050
1051 //
1052 // We deadloop here to make it easy to debug this issue.
1053 //
1054 CpuDeadLoop ();
1055
1056 return;
1057 }
1058
1059 /**
1060 The periodic callback function for EBC VM interpreter, which is used
1061 to support the EFI debug support protocol.
1062
1063 @param Event The Periodic Callback Event.
1064 @param Context It should be the address of VM_CONTEXT pointer.
1065
1066 **/
1067 VOID
1068 EFIAPI
1069 EbcPeriodicNotifyFunction (
1070 IN EFI_EVENT Event,
1071 IN VOID *Context
1072 )
1073 {
1074 VM_CONTEXT *VmPtr;
1075
1076 VmPtr = *(VM_CONTEXT **)Context;
1077
1078 if (VmPtr != NULL) {
1079 EbcDebugPeriodic (VmPtr);
1080 }
1081
1082 return;
1083 }
1084
1085 /**
1086 The VM interpreter calls this function on a periodic basis to support
1087 the EFI debug support protocol.
1088
1089 @param VmPtr Pointer to a VM context for passing info to the
1090 debugger.
1091
1092 @retval EFI_SUCCESS The function completed successfully.
1093
1094 **/
1095 EFI_STATUS
1096 EFIAPI
1097 EbcDebugPeriodic (
1098 IN VM_CONTEXT *VmPtr
1099 )
1100 {
1101 EFI_SYSTEM_CONTEXT_EBC EbcContext;
1102 EFI_SYSTEM_CONTEXT SystemContext;
1103
1104 //
1105 // If someone's registered for periodic callbacks, then call them.
1106 //
1107 if (mDebugPeriodicCallback != NULL) {
1108 //
1109 // Initialize the context structure
1110 //
1111 EbcContext.R0 = (UINT64)VmPtr->Gpr[0];
1112 EbcContext.R1 = (UINT64)VmPtr->Gpr[1];
1113 EbcContext.R2 = (UINT64)VmPtr->Gpr[2];
1114 EbcContext.R3 = (UINT64)VmPtr->Gpr[3];
1115 EbcContext.R4 = (UINT64)VmPtr->Gpr[4];
1116 EbcContext.R5 = (UINT64)VmPtr->Gpr[5];
1117 EbcContext.R6 = (UINT64)VmPtr->Gpr[6];
1118 EbcContext.R7 = (UINT64)VmPtr->Gpr[7];
1119 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
1120 EbcContext.Flags = VmPtr->Flags;
1121 EbcContext.ControlFlags = 0;
1122 SystemContext.SystemContextEbc = &EbcContext;
1123
1124 mDebugPeriodicCallback (SystemContext);
1125
1126 //
1127 // Restore the context structure and continue to execute
1128 //
1129 VmPtr->Gpr[0] = EbcContext.R0;
1130 VmPtr->Gpr[1] = EbcContext.R1;
1131 VmPtr->Gpr[2] = EbcContext.R2;
1132 VmPtr->Gpr[3] = EbcContext.R3;
1133 VmPtr->Gpr[4] = EbcContext.R4;
1134 VmPtr->Gpr[5] = EbcContext.R5;
1135 VmPtr->Gpr[6] = EbcContext.R6;
1136 VmPtr->Gpr[7] = EbcContext.R7;
1137 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
1138 VmPtr->Flags = EbcContext.Flags;
1139 }
1140
1141 return EFI_SUCCESS;
1142 }
1143
1144 /**
1145 This routine is called by the core when an image is being unloaded from
1146 memory. Basically we now have the opportunity to do any necessary cleanup.
1147 Typically this will include freeing any memory allocated for thunk-creation.
1148
1149 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1150 @param ImageHandle Handle of image for which the thunk is being
1151 created.
1152
1153 @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
1154 internal list of EBC image handles.
1155 @retval EFI_SUCCESS The function completed successfully.
1156
1157 **/
1158 EFI_STATUS
1159 EFIAPI
1160 EbcUnloadImage (
1161 IN EFI_EBC_PROTOCOL *This,
1162 IN EFI_HANDLE ImageHandle
1163 )
1164 {
1165 EBC_THUNK_LIST *ThunkList;
1166 EBC_THUNK_LIST *NextThunkList;
1167 EBC_IMAGE_LIST *ImageList;
1168 EBC_IMAGE_LIST *PrevImageList;
1169
1170 //
1171 // First go through our list of known image handles and see if we've already
1172 // created an image list element for this image handle.
1173 //
1174 ReturnEBCStackByHandle (ImageHandle);
1175 PrevImageList = NULL;
1176 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
1177 if (ImageList->ImageHandle == ImageHandle) {
1178 break;
1179 }
1180
1181 //
1182 // Save the previous so we can connect the lists when we remove this one
1183 //
1184 PrevImageList = ImageList;
1185 }
1186
1187 if (ImageList == NULL) {
1188 return EFI_INVALID_PARAMETER;
1189 }
1190
1191 //
1192 // Free up all the thunk buffers and thunks list elements for this image
1193 // handle.
1194 //
1195 ThunkList = ImageList->ThunkList;
1196 while (ThunkList != NULL) {
1197 NextThunkList = ThunkList->Next;
1198 FreePool (ThunkList->ThunkBuffer);
1199 FreePool (ThunkList);
1200 ThunkList = NextThunkList;
1201 }
1202
1203 //
1204 // Now remove this image list element from the chain
1205 //
1206 if (PrevImageList == NULL) {
1207 //
1208 // Remove from head
1209 //
1210 mEbcImageList = ImageList->Next;
1211 } else {
1212 PrevImageList->Next = ImageList->Next;
1213 }
1214
1215 //
1216 // Now free up the image list element
1217 //
1218 FreePool (ImageList);
1219
1220 EbcDebuggerHookEbcUnloadImage (ImageHandle);
1221
1222 return EFI_SUCCESS;
1223 }
1224
1225 /**
1226 Add a thunk to our list of thunks for a given image handle.
1227 Also flush the instruction cache since we've written thunk code
1228 to memory that will be executed eventually.
1229
1230 @param ImageHandle The image handle to which the thunk is tied.
1231 @param ThunkBuffer The buffer that has been created/allocated.
1232 @param ThunkSize The size of the thunk memory allocated.
1233
1234 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1235 @retval EFI_SUCCESS The function completed successfully.
1236
1237 **/
1238 EFI_STATUS
1239 EbcAddImageThunk (
1240 IN EFI_HANDLE ImageHandle,
1241 IN VOID *ThunkBuffer,
1242 IN UINT32 ThunkSize
1243 )
1244 {
1245 EBC_THUNK_LIST *ThunkList;
1246 EBC_IMAGE_LIST *ImageList;
1247 EFI_STATUS Status;
1248
1249 //
1250 // It so far so good, then flush the instruction cache
1251 //
1252 if (mEbcICacheFlush != NULL) {
1253 Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS)(UINTN)ThunkBuffer, ThunkSize);
1254 if (EFI_ERROR (Status)) {
1255 return Status;
1256 }
1257 }
1258
1259 //
1260 // Go through our list of known image handles and see if we've already
1261 // created a image list element for this image handle.
1262 //
1263 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
1264 if (ImageList->ImageHandle == ImageHandle) {
1265 break;
1266 }
1267 }
1268
1269 if (ImageList == NULL) {
1270 //
1271 // Allocate a new one
1272 //
1273 ImageList = AllocatePool (sizeof (EBC_IMAGE_LIST));
1274
1275 if (ImageList == NULL) {
1276 return EFI_OUT_OF_RESOURCES;
1277 }
1278
1279 ImageList->ThunkList = NULL;
1280 ImageList->ImageHandle = ImageHandle;
1281 ImageList->Next = mEbcImageList;
1282 mEbcImageList = ImageList;
1283 }
1284
1285 //
1286 // Ok, now create a new thunk element to add to the list
1287 //
1288 ThunkList = AllocatePool (sizeof (EBC_THUNK_LIST));
1289
1290 if (ThunkList == NULL) {
1291 return EFI_OUT_OF_RESOURCES;
1292 }
1293
1294 //
1295 // Add it to the head of the list
1296 //
1297 ThunkList->Next = ImageList->ThunkList;
1298 ThunkList->ThunkBuffer = ThunkBuffer;
1299 ImageList->ThunkList = ThunkList;
1300 return EFI_SUCCESS;
1301 }
1302
1303 /**
1304 Registers a callback function that the EBC interpreter calls to flush the
1305 processor instruction cache following creation of thunks.
1306
1307 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1308 @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
1309
1310 @retval EFI_SUCCESS The function completed successfully.
1311
1312 **/
1313 EFI_STATUS
1314 EFIAPI
1315 EbcRegisterICacheFlush (
1316 IN EFI_EBC_PROTOCOL *This,
1317 IN EBC_ICACHE_FLUSH Flush
1318 )
1319 {
1320 mEbcICacheFlush = Flush;
1321 return EFI_SUCCESS;
1322 }
1323
1324 /**
1325 Called to get the version of the interpreter.
1326
1327 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1328 @param Version Pointer to where to store the returned version
1329 of the interpreter.
1330
1331 @retval EFI_SUCCESS The function completed successfully.
1332 @retval EFI_INVALID_PARAMETER Version pointer is NULL.
1333
1334 **/
1335 EFI_STATUS
1336 EFIAPI
1337 EbcGetVersion (
1338 IN EFI_EBC_PROTOCOL *This,
1339 IN OUT UINT64 *Version
1340 )
1341 {
1342 if (Version == NULL) {
1343 return EFI_INVALID_PARAMETER;
1344 }
1345
1346 *Version = GetVmVersion ();
1347 return EFI_SUCCESS;
1348 }
1349
1350 /**
1351 Returns the stack index and buffer assosicated with the Handle parameter.
1352
1353 @param Handle The EFI handle as the index to the EBC stack.
1354 @param StackBuffer A pointer to hold the returned stack buffer.
1355 @param BufferIndex A pointer to hold the returned stack index.
1356
1357 @retval EFI_OUT_OF_RESOURCES The Handle parameter does not correspond to any
1358 existing EBC stack.
1359 @retval EFI_SUCCESS The stack index and buffer were found and
1360 returned to the caller.
1361
1362 **/
1363 EFI_STATUS
1364 GetEBCStack (
1365 IN EFI_HANDLE Handle,
1366 OUT VOID **StackBuffer,
1367 OUT UINTN *BufferIndex
1368 )
1369 {
1370 UINTN Index;
1371 EFI_TPL OldTpl;
1372
1373 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
1374 for (Index = 0; Index < mStackNum; Index++) {
1375 if (mStackBufferIndex[Index] == NULL) {
1376 mStackBufferIndex[Index] = Handle;
1377 break;
1378 }
1379 }
1380
1381 gBS->RestoreTPL (OldTpl);
1382 if (Index == mStackNum) {
1383 return EFI_OUT_OF_RESOURCES;
1384 }
1385
1386 *BufferIndex = Index;
1387 *StackBuffer = mStackBuffer[Index];
1388 return EFI_SUCCESS;
1389 }
1390
1391 /**
1392 Returns from the EBC stack by stack Index.
1393
1394 @param Index Specifies which EBC stack to return from.
1395
1396 @retval EFI_SUCCESS The function completed successfully.
1397
1398 **/
1399 EFI_STATUS
1400 ReturnEBCStack (
1401 IN UINTN Index
1402 )
1403 {
1404 mStackBufferIndex[Index] = NULL;
1405 return EFI_SUCCESS;
1406 }
1407
1408 /**
1409 Returns from the EBC stack associated with the Handle parameter.
1410
1411 @param Handle Specifies the EFI handle to find the EBC stack with.
1412
1413 @retval EFI_SUCCESS The function completed successfully.
1414
1415 **/
1416 EFI_STATUS
1417 ReturnEBCStackByHandle (
1418 IN EFI_HANDLE Handle
1419 )
1420 {
1421 UINTN Index;
1422
1423 for (Index = 0; Index < mStackNum; Index++) {
1424 if (mStackBufferIndex[Index] == Handle) {
1425 break;
1426 }
1427 }
1428
1429 if (Index == mStackNum) {
1430 return EFI_NOT_FOUND;
1431 }
1432
1433 mStackBufferIndex[Index] = NULL;
1434 return EFI_SUCCESS;
1435 }
1436
1437 /**
1438 Allocates memory to hold all the EBC stacks.
1439
1440 @retval EFI_SUCCESS The EBC stacks were allocated successfully.
1441 @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks.
1442
1443 **/
1444 EFI_STATUS
1445 InitEBCStack (
1446 VOID
1447 )
1448 {
1449 for (mStackNum = 0; mStackNum < MAX_STACK_NUM; mStackNum++) {
1450 mStackBuffer[mStackNum] = AllocatePool (STACK_POOL_SIZE);
1451 mStackBufferIndex[mStackNum] = NULL;
1452 if (mStackBuffer[mStackNum] == NULL) {
1453 break;
1454 }
1455 }
1456
1457 if (mStackNum == 0) {
1458 return EFI_OUT_OF_RESOURCES;
1459 }
1460
1461 return EFI_SUCCESS;
1462 }
1463
1464 /**
1465 Free all EBC stacks allocated before.
1466
1467 @retval EFI_SUCCESS All the EBC stacks were freed.
1468
1469 **/
1470 EFI_STATUS
1471 FreeEBCStack (
1472 VOID
1473 )
1474 {
1475 UINTN Index;
1476
1477 for (Index = 0; Index < mStackNum; Index++) {
1478 FreePool (mStackBuffer[Index]);
1479 }
1480
1481 return EFI_SUCCESS;
1482 }
1483
1484 /**
1485 Produces an EBC VM test protocol that can be used for regression tests.
1486
1487 @param IHandle Handle on which to install the protocol.
1488
1489 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1490 @retval EFI_SUCCESS The function completed successfully.
1491
1492 **/
1493 EFI_STATUS
1494 InitEbcVmTestProtocol (
1495 IN EFI_HANDLE *IHandle
1496 )
1497 {
1498 EFI_HANDLE Handle;
1499 EFI_STATUS Status;
1500 EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;
1501
1502 //
1503 // Allocate memory for the protocol, then fill in the fields
1504 //
1505 EbcVmTestProtocol = AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL));
1506 if (EbcVmTestProtocol == NULL) {
1507 return EFI_OUT_OF_RESOURCES;
1508 }
1509
1510 EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE)EbcExecuteInstructions;
1511
1512 DEBUG_CODE_BEGIN ();
1513 EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM)EbcVmTestUnsupported;
1514 EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM)EbcVmTestUnsupported;
1515 DEBUG_CODE_END ();
1516
1517 //
1518 // Publish the protocol
1519 //
1520 Handle = NULL;
1521 Status = gBS->InstallProtocolInterface (&Handle, &gEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
1522 if (EFI_ERROR (Status)) {
1523 FreePool (EbcVmTestProtocol);
1524 }
1525
1526 return Status;
1527 }
1528
1529 /**
1530 Returns the EFI_UNSUPPORTED Status.
1531
1532 @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
1533
1534 **/
1535 EFI_STATUS
1536 EFIAPI
1537 EbcVmTestUnsupported (
1538 VOID
1539 )
1540 {
1541 return EFI_UNSUPPORTED;
1542 }
1543
1544 /**
1545 Allocates a buffer of type EfiBootServicesCode.
1546
1547 @param AllocationSize The number of bytes to allocate.
1548
1549 @return A pointer to the allocated buffer or NULL if allocation fails.
1550
1551 **/
1552 VOID *
1553 EFIAPI
1554 EbcAllocatePoolForThunk (
1555 IN UINTN AllocationSize
1556 )
1557 {
1558 VOID *Buffer;
1559 EFI_STATUS Status;
1560
1561 Status = gBS->AllocatePool (EfiBootServicesCode, AllocationSize, &Buffer);
1562 if (EFI_ERROR (Status)) {
1563 return NULL;
1564 }
1565
1566 return Buffer;
1567 }