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