]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EbcDxe/EbcInt.c
apply for doxgen format.
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / EbcInt.c
1 /** @file
2 Top level module for the EBC virtual machine implementation.
3 Provides auxilliary 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, Intel Corporation
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "EbcInt.h"
18 #include "EbcExecute.h"
19
20 //
21 // We'll keep track of all thunks we create in a linked list. Each
22 // thunk is tied to an image handle, so we have a linked list of
23 // image handles, with each having a linked list of thunks allocated
24 // to that image handle.
25 //
26 typedef struct _EBC_THUNK_LIST {
27 VOID *ThunkBuffer;
28 struct _EBC_THUNK_LIST *Next;
29 } EBC_THUNK_LIST;
30
31 typedef struct _EBC_IMAGE_LIST {
32 struct _EBC_IMAGE_LIST *Next;
33 EFI_HANDLE ImageHandle;
34 EBC_THUNK_LIST *ThunkList;
35 } EBC_IMAGE_LIST;
36
37 STATIC
38 EFI_STATUS
39 EFIAPI
40 EbcUnloadImage (
41 IN EFI_EBC_PROTOCOL *This,
42 IN EFI_HANDLE ImageHandle
43 );
44
45 STATIC
46 EFI_STATUS
47 EFIAPI
48 EbcCreateThunk (
49 IN EFI_EBC_PROTOCOL *This,
50 IN EFI_HANDLE ImageHandle,
51 IN VOID *EbcEntryPoint,
52 OUT VOID **Thunk
53 );
54
55 STATIC
56 EFI_STATUS
57 EFIAPI
58 EbcGetVersion (
59 IN EFI_EBC_PROTOCOL *This,
60 IN OUT UINT64 *Version
61 );
62
63 STATIC
64 EFI_STATUS
65 EFIAPI
66 InitializeEbcCallback (
67 IN EFI_DEBUG_SUPPORT_PROTOCOL *This
68 );
69
70 STATIC
71 VOID
72 EFIAPI
73 CommonEbcExceptionHandler (
74 IN EFI_EXCEPTION_TYPE InterruptType,
75 IN EFI_SYSTEM_CONTEXT SystemContext
76 );
77
78 STATIC
79 VOID
80 EFIAPI
81 EbcPeriodicNotifyFunction (
82 IN EFI_EVENT Event,
83 IN VOID *Context
84 );
85
86 STATIC
87 EFI_STATUS
88 EFIAPI
89 EbcDebugPeriodic (
90 IN VM_CONTEXT *VmPtr
91 );
92
93 //
94 // These two functions and the GUID are used to produce an EBC test protocol.
95 // This functionality is definitely not required for execution.
96 //
97 STATIC
98 EFI_STATUS
99 InitEbcVmTestProtocol (
100 IN EFI_HANDLE *Handle
101 );
102
103 STATIC
104 EFI_STATUS
105 EbcVmTestUnsupported (
106 VOID
107 );
108
109 STATIC
110 EFI_STATUS
111 EFIAPI
112 EbcRegisterICacheFlush (
113 IN EFI_EBC_PROTOCOL *This,
114 IN EBC_ICACHE_FLUSH Flush
115 );
116
117 STATIC
118 EFI_STATUS
119 EFIAPI
120 EbcDebugGetMaximumProcessorIndex (
121 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
122 OUT UINTN *MaxProcessorIndex
123 );
124
125 STATIC
126 EFI_STATUS
127 EFIAPI
128 EbcDebugRegisterPeriodicCallback (
129 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
130 IN UINTN ProcessorIndex,
131 IN EFI_PERIODIC_CALLBACK PeriodicCallback
132 );
133
134 STATIC
135 EFI_STATUS
136 EFIAPI
137 EbcDebugRegisterExceptionCallback (
138 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
139 IN UINTN ProcessorIndex,
140 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
141 IN EFI_EXCEPTION_TYPE ExceptionType
142 );
143
144 STATIC
145 EFI_STATUS
146 EFIAPI
147 EbcDebugInvalidateInstructionCache (
148 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
149 IN UINTN ProcessorIndex,
150 IN VOID *Start,
151 IN UINT64 Length
152 );
153
154 //
155 // We have one linked list of image handles for the whole world. Since
156 // there should only be one interpreter, make them global. They must
157 // also be global since the execution of an EBC image does not provide
158 // a This pointer.
159 //
160 static EBC_IMAGE_LIST *mEbcImageList = NULL;
161
162 //
163 // Callback function to flush the icache after thunk creation
164 //
165 static EBC_ICACHE_FLUSH mEbcICacheFlush;
166
167 //
168 // These get set via calls by the debug agent
169 //
170 static EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;
171 static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};
172 static EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;
173
174 static VOID* mStackBuffer[MAX_STACK_NUM];
175 static EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];
176 static UINTN mStackNum = 0;
177
178 //
179 // Event for Periodic callback
180 //
181 static EFI_EVENT mEbcPeriodicEvent;
182 VM_CONTEXT *mVmPtr = NULL;
183
184
185 /**
186 Initializes the VM EFI interface. Allocates memory for the VM interface
187 and registers the VM protocol.
188
189 @param ImageHandle EFI image handle.
190 @param SystemTable Pointer to the EFI system table.
191
192 @return Standard EFI status code.
193
194 **/
195 EFI_STATUS
196 EFIAPI
197 InitializeEbcDriver (
198 IN EFI_HANDLE ImageHandle,
199 IN EFI_SYSTEM_TABLE *SystemTable
200 )
201 {
202 EFI_EBC_PROTOCOL *EbcProtocol;
203 EFI_EBC_PROTOCOL *OldEbcProtocol;
204 EFI_STATUS Status;
205 EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol;
206 EFI_HANDLE *HandleBuffer;
207 UINTN NumHandles;
208 UINTN Index;
209 BOOLEAN Installed;
210
211 EbcProtocol = NULL;
212 EbcDebugProtocol = NULL;
213
214 //
215 // Allocate memory for our protocol. Then fill in the blanks.
216 //
217 EbcProtocol = AllocatePool (sizeof (EFI_EBC_PROTOCOL));
218
219 if (EbcProtocol == NULL) {
220 return EFI_OUT_OF_RESOURCES;
221 }
222
223 EbcProtocol->CreateThunk = EbcCreateThunk;
224 EbcProtocol->UnloadImage = EbcUnloadImage;
225 EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush;
226 EbcProtocol->GetVersion = EbcGetVersion;
227 mEbcICacheFlush = NULL;
228
229 //
230 // Find any already-installed EBC protocols and uninstall them
231 //
232 Installed = FALSE;
233 HandleBuffer = NULL;
234 Status = gBS->LocateHandleBuffer (
235 ByProtocol,
236 &gEfiEbcProtocolGuid,
237 NULL,
238 &NumHandles,
239 &HandleBuffer
240 );
241 if (Status == EFI_SUCCESS) {
242 //
243 // Loop through the handles
244 //
245 for (Index = 0; Index < NumHandles; Index++) {
246 Status = gBS->HandleProtocol (
247 HandleBuffer[Index],
248 &gEfiEbcProtocolGuid,
249 (VOID **) &OldEbcProtocol
250 );
251 if (Status == EFI_SUCCESS) {
252 if (gBS->ReinstallProtocolInterface (
253 HandleBuffer[Index],
254 &gEfiEbcProtocolGuid,
255 OldEbcProtocol,
256 EbcProtocol
257 ) == EFI_SUCCESS) {
258 Installed = TRUE;
259 }
260 }
261 }
262 }
263
264 if (HandleBuffer != NULL) {
265 FreePool (HandleBuffer);
266 HandleBuffer = NULL;
267 }
268 //
269 // Add the protocol so someone can locate us if we haven't already.
270 //
271 if (!Installed) {
272 Status = gBS->InstallProtocolInterface (
273 &ImageHandle,
274 &gEfiEbcProtocolGuid,
275 EFI_NATIVE_INTERFACE,
276 EbcProtocol
277 );
278 if (EFI_ERROR (Status)) {
279 FreePool (EbcProtocol);
280 return Status;
281 }
282 }
283
284 Status = InitEBCStack();
285 if (EFI_ERROR(Status)) {
286 goto ErrorExit;
287 }
288
289 //
290 // Allocate memory for our debug protocol. Then fill in the blanks.
291 //
292 EbcDebugProtocol = AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL));
293
294 if (EbcDebugProtocol == NULL) {
295 goto ErrorExit;
296 }
297
298 EbcDebugProtocol->Isa = IsaEbc;
299 EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex;
300 EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback;
301 EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback;
302 EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache;
303
304 //
305 // Add the protocol so the debug agent can find us
306 //
307 Status = gBS->InstallProtocolInterface (
308 &ImageHandle,
309 &gEfiDebugSupportProtocolGuid,
310 EFI_NATIVE_INTERFACE,
311 EbcDebugProtocol
312 );
313 //
314 // This is recoverable, so free the memory and continue.
315 //
316 if (EFI_ERROR (Status)) {
317 FreePool (EbcDebugProtocol);
318 goto ErrorExit;
319 }
320 //
321 // Install EbcDebugSupport Protocol Successfully
322 // Now we need to initialize the Ebc default Callback
323 //
324 Status = InitializeEbcCallback (EbcDebugProtocol);
325
326 //
327 // Produce a VM test interface protocol. Not required for execution.
328 //
329 DEBUG_CODE_BEGIN ();
330 InitEbcVmTestProtocol (&ImageHandle);
331 DEBUG_CODE_END ();
332
333 return EFI_SUCCESS;
334
335 ErrorExit:
336 FreeEBCStack();
337 HandleBuffer = NULL;
338 Status = gBS->LocateHandleBuffer (
339 ByProtocol,
340 &gEfiEbcProtocolGuid,
341 NULL,
342 &NumHandles,
343 &HandleBuffer
344 );
345 if (Status == EFI_SUCCESS) {
346 //
347 // Loop through the handles
348 //
349 for (Index = 0; Index < NumHandles; Index++) {
350 Status = gBS->HandleProtocol (
351 HandleBuffer[Index],
352 &gEfiEbcProtocolGuid,
353 (VOID **) &OldEbcProtocol
354 );
355 if (Status == EFI_SUCCESS) {
356 gBS->UninstallProtocolInterface (
357 HandleBuffer[Index],
358 &gEfiEbcProtocolGuid,
359 OldEbcProtocol
360 );
361 }
362 }
363 }
364
365 if (HandleBuffer != NULL) {
366 FreePool (HandleBuffer);
367 HandleBuffer = NULL;
368 }
369
370 FreePool (EbcProtocol);
371
372 return Status;
373 }
374
375
376 /**
377 This is the top-level routine plugged into the EBC protocol. Since thunks
378 are very processor-specific, from here we dispatch directly to the very
379 processor-specific routine EbcCreateThunks().
380
381 @param This protocol instance pointer
382 @param ImageHandle handle to the image. The EBC interpreter may use
383 this to keep track of any resource allocations
384 performed in loading and executing the image.
385 @param EbcEntryPoint the entry point for the image (as defined in the
386 file header)
387 @param Thunk pointer to thunk pointer where the address of the
388 created thunk is returned.
389
390 @return EFI_STATUS
391
392 **/
393 STATIC
394 EFI_STATUS
395 EFIAPI
396 EbcCreateThunk (
397 IN EFI_EBC_PROTOCOL *This,
398 IN EFI_HANDLE ImageHandle,
399 IN VOID *EbcEntryPoint,
400 OUT VOID **Thunk
401 )
402 {
403 EFI_STATUS Status;
404
405 Status = EbcCreateThunks (
406 ImageHandle,
407 EbcEntryPoint,
408 Thunk,
409 FLAG_THUNK_ENTRY_POINT
410 );
411 return Status;
412 }
413
414
415 /**
416 This EBC debugger protocol service is called by the debug agent
417
418 @param This pointer to the caller's debug support protocol
419 interface
420 @param MaxProcessorIndex pointer to a caller allocated UINTN in which the
421 maximum processor index is returned.
422
423 @return Standard EFI_STATUS
424
425 **/
426 STATIC
427 EFI_STATUS
428 EFIAPI
429 EbcDebugGetMaximumProcessorIndex (
430 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
431 OUT UINTN *MaxProcessorIndex
432 )
433 {
434 *MaxProcessorIndex = 0;
435 return EFI_SUCCESS;
436 }
437
438
439 /**
440 This protocol service is called by the debug agent to register a function
441 for us to call on a periodic basis.
442
443 @param This pointer to the caller's debug support protocol
444 interface
445 @param PeriodicCallback pointer to the function to call periodically
446
447 @return Always EFI_SUCCESS
448
449 **/
450 STATIC
451 EFI_STATUS
452 EFIAPI
453 EbcDebugRegisterPeriodicCallback (
454 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
455 IN UINTN ProcessorIndex,
456 IN EFI_PERIODIC_CALLBACK PeriodicCallback
457 )
458 {
459 if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {
460 return EFI_INVALID_PARAMETER;
461 }
462 if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {
463 return EFI_ALREADY_STARTED;
464 }
465
466 mDebugPeriodicCallback = PeriodicCallback;
467 return EFI_SUCCESS;
468 }
469
470
471 /**
472 This protocol service is called by the debug agent to register a function
473 for us to call when we detect an exception.
474
475 @param This pointer to the caller's debug support protocol
476 interface
477 @param ExceptionCallback pointer to the function to the exception
478
479 @return Always EFI_SUCCESS
480
481 **/
482 STATIC
483 EFI_STATUS
484 EFIAPI
485 EbcDebugRegisterExceptionCallback (
486 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
487 IN UINTN ProcessorIndex,
488 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
489 IN EFI_EXCEPTION_TYPE ExceptionType
490 )
491 {
492 if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {
493 return EFI_INVALID_PARAMETER;
494 }
495 if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {
496 return EFI_INVALID_PARAMETER;
497 }
498 if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {
499 return EFI_ALREADY_STARTED;
500 }
501 mDebugExceptionCallback[ExceptionType] = ExceptionCallback;
502 return EFI_SUCCESS;
503 }
504
505
506 /**
507 This EBC debugger protocol service is called by the debug agent. Required
508 for DebugSupport compliance but is only stubbed out for EBC.
509
510
511 @return EFI_SUCCESS
512
513 **/
514 STATIC
515 EFI_STATUS
516 EFIAPI
517 EbcDebugInvalidateInstructionCache (
518 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
519 IN UINTN ProcessorIndex,
520 IN VOID *Start,
521 IN UINT64 Length
522 )
523 {
524 return EFI_SUCCESS;
525 }
526
527
528 /**
529 The VM interpreter calls this function when an exception is detected.
530
531 @param VmPtr pointer to a VM context for passing info to the
532 EFI debugger.
533
534 @return EFI_SUCCESS if it returns at all
535
536 **/
537 EFI_STATUS
538 EbcDebugSignalException (
539 IN EFI_EXCEPTION_TYPE ExceptionType,
540 IN EXCEPTION_FLAGS ExceptionFlags,
541 IN VM_CONTEXT *VmPtr
542 )
543 {
544 EFI_SYSTEM_CONTEXT_EBC EbcContext;
545 EFI_SYSTEM_CONTEXT SystemContext;
546
547 ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));
548 //
549 // Save the exception in the context passed in
550 //
551 VmPtr->ExceptionFlags |= ExceptionFlags;
552 VmPtr->LastException = ExceptionType;
553 //
554 // If it's a fatal exception, then flag it in the VM context in case an
555 // attached debugger tries to return from it.
556 //
557 if (ExceptionFlags & EXCEPTION_FLAG_FATAL) {
558 VmPtr->StopFlags |= STOPFLAG_APP_DONE;
559 }
560
561 //
562 // If someone's registered for exception callbacks, then call them.
563 //
564 // EBC driver will register default exception callback to report the
565 // status code via the status code API
566 //
567 if (mDebugExceptionCallback[ExceptionType] != NULL) {
568
569 //
570 // Initialize the context structure
571 //
572 EbcContext.R0 = VmPtr->R[0];
573 EbcContext.R1 = VmPtr->R[1];
574 EbcContext.R2 = VmPtr->R[2];
575 EbcContext.R3 = VmPtr->R[3];
576 EbcContext.R4 = VmPtr->R[4];
577 EbcContext.R5 = VmPtr->R[5];
578 EbcContext.R6 = VmPtr->R[6];
579 EbcContext.R7 = VmPtr->R[7];
580 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
581 EbcContext.Flags = VmPtr->Flags;
582 EbcContext.ControlFlags = 0;
583 SystemContext.SystemContextEbc = &EbcContext;
584
585 mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);
586 //
587 // Restore the context structure and continue to execute
588 //
589 VmPtr->R[0] = EbcContext.R0;
590 VmPtr->R[1] = EbcContext.R1;
591 VmPtr->R[2] = EbcContext.R2;
592 VmPtr->R[3] = EbcContext.R3;
593 VmPtr->R[4] = EbcContext.R4;
594 VmPtr->R[5] = EbcContext.R5;
595 VmPtr->R[6] = EbcContext.R6;
596 VmPtr->R[7] = EbcContext.R7;
597 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
598 VmPtr->Flags = EbcContext.Flags;
599 }
600
601 return EFI_SUCCESS;
602 }
603
604
605 /**
606 To install default Callback function for the VM interpreter.
607
608 @param This pointer to the instance of DebugSupport protocol
609
610 @return None
611
612 **/
613 STATIC
614 EFI_STATUS
615 InitializeEbcCallback (
616 IN EFI_DEBUG_SUPPORT_PROTOCOL *This
617 )
618 {
619 INTN Index;
620 EFI_STATUS Status;
621
622 //
623 // For ExceptionCallback
624 //
625 for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {
626 EbcDebugRegisterExceptionCallback (
627 This,
628 0,
629 CommonEbcExceptionHandler,
630 Index
631 );
632 }
633
634 //
635 // For PeriodicCallback
636 //
637 Status = gBS->CreateEvent (
638 EVT_TIMER | EVT_NOTIFY_SIGNAL,
639 TPL_NOTIFY,
640 EbcPeriodicNotifyFunction,
641 &mVmPtr,
642 &mEbcPeriodicEvent
643 );
644 if (EFI_ERROR(Status)) {
645 return Status;
646 }
647
648 Status = gBS->SetTimer (
649 mEbcPeriodicEvent,
650 TimerPeriodic,
651 EBC_VM_PERIODIC_CALLBACK_RATE
652 );
653 if (EFI_ERROR(Status)) {
654 return Status;
655 }
656
657 return EFI_SUCCESS;
658 }
659
660
661 /**
662 The default Exception Callback for the VM interpreter.
663 In this function, we report status code, and print debug information
664 about EBC_CONTEXT, then dead loop.
665
666 @param InterruptType Interrupt type.
667 @param SystemContext EBC system context.
668
669 @return None
670
671 **/
672 STATIC
673 VOID
674 CommonEbcExceptionHandler (
675 IN EFI_EXCEPTION_TYPE InterruptType,
676 IN EFI_SYSTEM_CONTEXT SystemContext
677 )
678 {
679 //
680 // We deadloop here to make it easy to debug this issue.
681 //
682 ASSERT (FALSE);
683
684 return ;
685 }
686
687
688 /**
689 The periodic callback function for EBC VM interpreter, which is used
690 to support the EFI debug support protocol.
691
692 @param Event The Periodic Callback Event.
693 @param Context It should be the address of VM_CONTEXT pointer.
694
695 @return None.
696
697 **/
698 STATIC
699 VOID
700 EFIAPI
701 EbcPeriodicNotifyFunction (
702 IN EFI_EVENT Event,
703 IN VOID *Context
704 )
705 {
706 VM_CONTEXT *VmPtr;
707
708 VmPtr = *(VM_CONTEXT **)Context;
709
710 if (VmPtr != NULL) {
711 EbcDebugPeriodic (VmPtr);
712 }
713
714 return ;
715 }
716
717
718 /**
719 The VM interpreter calls this function on a periodic basis to support
720 the EFI debug support protocol.
721
722 @param VmPtr pointer to a VM context for passing info to the
723 debugger.
724
725 @return Standard EFI status.
726
727 **/
728 STATIC
729 EFI_STATUS
730 EbcDebugPeriodic (
731 IN VM_CONTEXT *VmPtr
732 )
733 {
734 EFI_SYSTEM_CONTEXT_EBC EbcContext;
735 EFI_SYSTEM_CONTEXT SystemContext;
736
737 //
738 // If someone's registered for periodic callbacks, then call them.
739 //
740 if (mDebugPeriodicCallback != NULL) {
741
742 //
743 // Initialize the context structure
744 //
745 EbcContext.R0 = VmPtr->R[0];
746 EbcContext.R1 = VmPtr->R[1];
747 EbcContext.R2 = VmPtr->R[2];
748 EbcContext.R3 = VmPtr->R[3];
749 EbcContext.R4 = VmPtr->R[4];
750 EbcContext.R5 = VmPtr->R[5];
751 EbcContext.R6 = VmPtr->R[6];
752 EbcContext.R7 = VmPtr->R[7];
753 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
754 EbcContext.Flags = VmPtr->Flags;
755 EbcContext.ControlFlags = 0;
756 SystemContext.SystemContextEbc = &EbcContext;
757
758 mDebugPeriodicCallback (SystemContext);
759
760 //
761 // Restore the context structure and continue to execute
762 //
763 VmPtr->R[0] = EbcContext.R0;
764 VmPtr->R[1] = EbcContext.R1;
765 VmPtr->R[2] = EbcContext.R2;
766 VmPtr->R[3] = EbcContext.R3;
767 VmPtr->R[4] = EbcContext.R4;
768 VmPtr->R[5] = EbcContext.R5;
769 VmPtr->R[6] = EbcContext.R6;
770 VmPtr->R[7] = EbcContext.R7;
771 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
772 VmPtr->Flags = EbcContext.Flags;
773 }
774
775 return EFI_SUCCESS;
776 }
777
778
779 /**
780 This routine is called by the core when an image is being unloaded from
781 memory. Basically we now have the opportunity to do any necessary cleanup.
782 Typically this will include freeing any memory allocated for thunk-creation.
783
784 @param This protocol instance pointer
785 @param ImageHandle handle to the image being unloaded.
786
787 @retval EFI_INVALID_PARAMETER the ImageHandle passed in was not found in the
788 internal list of EBC image handles.
789 @retval EFI_STATUS completed successfully
790
791 **/
792 STATIC
793 EFI_STATUS
794 EFIAPI
795 EbcUnloadImage (
796 IN EFI_EBC_PROTOCOL *This,
797 IN EFI_HANDLE ImageHandle
798 )
799 {
800 EBC_THUNK_LIST *ThunkList;
801 EBC_THUNK_LIST *NextThunkList;
802 EBC_IMAGE_LIST *ImageList;
803 EBC_IMAGE_LIST *PrevImageList;
804 //
805 // First go through our list of known image handles and see if we've already
806 // created an image list element for this image handle.
807 //
808 ReturnEBCStackByHandle(ImageHandle);
809 PrevImageList = NULL;
810 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
811 if (ImageList->ImageHandle == ImageHandle) {
812 break;
813 }
814 //
815 // Save the previous so we can connect the lists when we remove this one
816 //
817 PrevImageList = ImageList;
818 }
819
820 if (ImageList == NULL) {
821 return EFI_INVALID_PARAMETER;
822 }
823 //
824 // Free up all the thunk buffers and thunks list elements for this image
825 // handle.
826 //
827 ThunkList = ImageList->ThunkList;
828 while (ThunkList != NULL) {
829 NextThunkList = ThunkList->Next;
830 FreePool (ThunkList->ThunkBuffer);
831 FreePool (ThunkList);
832 ThunkList = NextThunkList;
833 }
834 //
835 // Now remove this image list element from the chain
836 //
837 if (PrevImageList == NULL) {
838 //
839 // Remove from head
840 //
841 mEbcImageList = ImageList->Next;
842 } else {
843 PrevImageList->Next = ImageList->Next;
844 }
845 //
846 // Now free up the image list element
847 //
848 FreePool (ImageList);
849 return EFI_SUCCESS;
850 }
851
852
853 /**
854 Add a thunk to our list of thunks for a given image handle.
855 Also flush the instruction cache since we've written thunk code
856 to memory that will be executed eventually.
857
858 @param ImageHandle the image handle to which the thunk is tied
859 @param ThunkBuffer the buffer we've created/allocated
860 @param ThunkSize the size of the thunk memory allocated
861
862 @retval EFI_OUT_OF_RESOURCES memory allocation failed
863 @retval EFI_SUCCESS successful completion
864
865 **/
866 EFI_STATUS
867 EbcAddImageThunk (
868 IN EFI_HANDLE ImageHandle,
869 IN VOID *ThunkBuffer,
870 IN UINT32 ThunkSize
871 )
872 {
873 EBC_THUNK_LIST *ThunkList;
874 EBC_IMAGE_LIST *ImageList;
875 EFI_STATUS Status;
876
877 //
878 // It so far so good, then flush the instruction cache
879 //
880 if (mEbcICacheFlush != NULL) {
881 Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);
882 if (EFI_ERROR (Status)) {
883 return Status;
884 }
885 }
886 //
887 // Go through our list of known image handles and see if we've already
888 // created a image list element for this image handle.
889 //
890 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
891 if (ImageList->ImageHandle == ImageHandle) {
892 break;
893 }
894 }
895
896 if (ImageList == NULL) {
897 //
898 // Allocate a new one
899 //
900 ImageList = AllocatePool (sizeof (EBC_IMAGE_LIST));
901
902 if (ImageList == NULL) {
903 return EFI_OUT_OF_RESOURCES;
904 }
905
906 ImageList->ThunkList = NULL;
907 ImageList->ImageHandle = ImageHandle;
908 ImageList->Next = mEbcImageList;
909 mEbcImageList = ImageList;
910 }
911 //
912 // Ok, now create a new thunk element to add to the list
913 //
914 ThunkList = AllocatePool (sizeof (EBC_THUNK_LIST));
915
916 if (ThunkList == NULL) {
917 return EFI_OUT_OF_RESOURCES;
918 }
919 //
920 // Add it to the head of the list
921 //
922 ThunkList->Next = ImageList->ThunkList;
923 ThunkList->ThunkBuffer = ThunkBuffer;
924 ImageList->ThunkList = ThunkList;
925 return EFI_SUCCESS;
926 }
927
928 STATIC
929 EFI_STATUS
930 EFIAPI
931 EbcRegisterICacheFlush (
932 IN EFI_EBC_PROTOCOL *This,
933 IN EBC_ICACHE_FLUSH Flush
934 )
935 {
936 mEbcICacheFlush = Flush;
937 return EFI_SUCCESS;
938 }
939
940 STATIC
941 EFI_STATUS
942 EFIAPI
943 EbcGetVersion (
944 IN EFI_EBC_PROTOCOL *This,
945 IN OUT UINT64 *Version
946 )
947 {
948 if (Version == NULL) {
949 return EFI_INVALID_PARAMETER;
950 }
951
952 *Version = GetVmVersion ();
953 return EFI_SUCCESS;
954 }
955
956 EFI_STATUS
957 GetEBCStack(
958 EFI_HANDLE Handle,
959 VOID **StackBuffer,
960 UINTN *BufferIndex
961 )
962 {
963 UINTN Index;
964 EFI_TPL OldTpl;
965 OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);
966 for (Index = 0; Index < mStackNum; Index ++) {
967 if (mStackBufferIndex[Index] == NULL) {
968 mStackBufferIndex[Index] = Handle;
969 break;
970 }
971 }
972 gBS->RestoreTPL(OldTpl);
973 if (Index == mStackNum) {
974 return EFI_OUT_OF_RESOURCES;
975 }
976 *BufferIndex = Index;
977 *StackBuffer = mStackBuffer[Index];
978 return EFI_SUCCESS;
979 }
980
981 EFI_STATUS
982 ReturnEBCStack(
983 UINTN Index
984 )
985 {
986 mStackBufferIndex[Index] =NULL;
987 return EFI_SUCCESS;
988 }
989
990 EFI_STATUS
991 ReturnEBCStackByHandle(
992 EFI_HANDLE Handle
993 )
994 {
995 UINTN Index;
996 for (Index = 0; Index < mStackNum; Index ++) {
997 if (mStackBufferIndex[Index] == Handle) {
998 break;
999 }
1000 }
1001 if (Index == mStackNum) {
1002 return EFI_NOT_FOUND;
1003 }
1004 mStackBufferIndex[Index] = NULL;
1005 return EFI_SUCCESS;
1006 }
1007
1008 EFI_STATUS
1009 InitEBCStack (
1010 VOID
1011 )
1012 {
1013 for (mStackNum = 0; mStackNum < MAX_STACK_NUM; mStackNum ++) {
1014 mStackBuffer[mStackNum] = AllocatePool(STACK_POOL_SIZE);
1015 mStackBufferIndex[mStackNum] = NULL;
1016 if (mStackBuffer[mStackNum] == NULL) {
1017 break;
1018 }
1019 }
1020 if (mStackNum == 0) {
1021 return EFI_OUT_OF_RESOURCES;
1022 }
1023 return EFI_SUCCESS;
1024 }
1025
1026 EFI_STATUS
1027 FreeEBCStack(
1028 VOID
1029 )
1030 {
1031 UINTN Index;
1032 for (Index = 0; Index < mStackNum; Index ++) {
1033 FreePool(mStackBuffer[Index]);
1034 }
1035 return EFI_SUCCESS;
1036 }
1037
1038 /**
1039 Produce an EBC VM test protocol that can be used for regression tests.
1040
1041 @param IHandle handle on which to install the protocol.
1042
1043 @retval EFI_OUT_OF_RESOURCES memory allocation failed
1044 @retval EFI_SUCCESS successful completion
1045
1046 **/
1047 STATIC
1048 EFI_STATUS
1049 InitEbcVmTestProtocol (
1050 IN EFI_HANDLE *IHandle
1051 )
1052 {
1053 EFI_HANDLE Handle;
1054 EFI_STATUS Status;
1055 EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;
1056
1057 //
1058 // Allocate memory for the protocol, then fill in the fields
1059 //
1060 EbcVmTestProtocol = AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL));
1061 if (EbcVmTestProtocol == NULL) {
1062 return EFI_OUT_OF_RESOURCES;
1063 }
1064 EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
1065
1066 DEBUG_CODE_BEGIN ();
1067 EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
1068 EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
1069 DEBUG_CODE_END ();
1070
1071 //
1072 // Publish the protocol
1073 //
1074 Handle = NULL;
1075 Status = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
1076 if (EFI_ERROR (Status)) {
1077 FreePool (EbcVmTestProtocol);
1078 }
1079 return Status;
1080 }
1081 STATIC
1082 EFI_STATUS
1083 EbcVmTestUnsupported ()
1084 {
1085 return EFI_UNSUPPORTED;
1086 }
1087