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