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