]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c
cf683295ea03e65c189277180f2c45c727d1bf96
[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 //
182 // Event for Periodic callback
183 //
184 static EFI_EVENT mEbcPeriodicEvent;
185 VM_CONTEXT *mVmPtr = NULL;
186
187 EFI_STATUS
188 EFIAPI
189 InitializeEbcDriver (
190 IN EFI_HANDLE ImageHandle,
191 IN EFI_SYSTEM_TABLE *SystemTable
192 )
193 /*++
194
195 Routine Description:
196
197 Initializes the VM EFI interface. Allocates memory for the VM interface
198 and registers the VM protocol.
199
200 Arguments:
201
202 ImageHandle - EFI image handle.
203 SystemTable - Pointer to the EFI system table.
204
205 Returns:
206 Standard EFI status code.
207
208 --*/
209 {
210 EFI_EBC_PROTOCOL *EbcProtocol;
211 EFI_EBC_PROTOCOL *OldEbcProtocol;
212 EFI_STATUS Status;
213 EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol;
214 EFI_HANDLE *HandleBuffer;
215 UINTN NumHandles;
216 UINTN Index;
217 BOOLEAN Installed;
218
219 EbcProtocol = NULL;
220 EbcDebugProtocol = NULL;
221
222 //
223 // Allocate memory for our protocol. Then fill in the blanks.
224 //
225 Status = gBS->AllocatePool (
226 EfiBootServicesData,
227 sizeof (EFI_EBC_PROTOCOL),
228 (VOID **) &EbcProtocol
229 );
230 if (Status != EFI_SUCCESS) {
231 return EFI_OUT_OF_RESOURCES;
232 }
233
234 EbcProtocol->CreateThunk = EbcCreateThunk;
235 EbcProtocol->UnloadImage = EbcUnloadImage;
236 EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush;
237 EbcProtocol->GetVersion = EbcGetVersion;
238 mEbcICacheFlush = NULL;
239
240 //
241 // Find any already-installed EBC protocols and uninstall them
242 //
243 Installed = FALSE;
244 HandleBuffer = NULL;
245 Status = gBS->LocateHandleBuffer (
246 ByProtocol,
247 &gEfiEbcProtocolGuid,
248 NULL,
249 &NumHandles,
250 &HandleBuffer
251 );
252 if (Status == EFI_SUCCESS) {
253 //
254 // Loop through the handles
255 //
256 for (Index = 0; Index < NumHandles; Index++) {
257 Status = gBS->HandleProtocol (
258 HandleBuffer[Index],
259 &gEfiEbcProtocolGuid,
260 (VOID **) &OldEbcProtocol
261 );
262 if (Status == EFI_SUCCESS) {
263 if (gBS->ReinstallProtocolInterface (
264 HandleBuffer[Index],
265 &gEfiEbcProtocolGuid,
266 OldEbcProtocol,
267 EbcProtocol
268 ) == EFI_SUCCESS) {
269 Installed = TRUE;
270 }
271 }
272 }
273 }
274
275 if (HandleBuffer != NULL) {
276 gBS->FreePool (HandleBuffer);
277 HandleBuffer = NULL;
278 }
279 //
280 // Add the protocol so someone can locate us if we haven't already.
281 //
282 if (!Installed) {
283 Status = gBS->InstallProtocolInterface (
284 &ImageHandle,
285 &gEfiEbcProtocolGuid,
286 EFI_NATIVE_INTERFACE,
287 EbcProtocol
288 );
289 if (EFI_ERROR (Status)) {
290 gBS->FreePool (EbcProtocol);
291 return Status;
292 }
293 }
294 //
295 // Allocate memory for our debug protocol. Then fill in the blanks.
296 //
297 Status = gBS->AllocatePool (
298 EfiBootServicesData,
299 sizeof (EFI_DEBUG_SUPPORT_PROTOCOL),
300 (VOID **) &EbcDebugProtocol
301 );
302 if (Status != EFI_SUCCESS) {
303 goto ErrorExit;
304 }
305
306 EbcDebugProtocol->Isa = IsaEbc;
307 EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex;
308 EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback;
309 EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback;
310 EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache;
311
312 //
313 // Add the protocol so the debug agent can find us
314 //
315 Status = gBS->InstallProtocolInterface (
316 &ImageHandle,
317 &gEfiDebugSupportProtocolGuid,
318 EFI_NATIVE_INTERFACE,
319 EbcDebugProtocol
320 );
321 //
322 // This is recoverable, so free the memory and continue.
323 //
324 if (EFI_ERROR (Status)) {
325 gBS->FreePool (EbcDebugProtocol);
326 goto ErrorExit;
327 }
328 //
329 // Install EbcDebugSupport Protocol Successfully
330 // Now we need to initialize the Ebc default Callback
331 //
332 Status = InitializeEbcCallback (EbcDebugProtocol);
333
334 //
335 // Produce a VM test interface protocol. Not required for execution.
336 //
337 DEBUG_CODE_BEGIN ();
338 InitEbcVmTestProtocol (&ImageHandle);
339 DEBUG_CODE_END ();
340
341 return EFI_SUCCESS;
342
343 ErrorExit:
344 HandleBuffer = NULL;
345 Status = gBS->LocateHandleBuffer (
346 ByProtocol,
347 &gEfiEbcProtocolGuid,
348 NULL,
349 &NumHandles,
350 &HandleBuffer
351 );
352 if (Status == EFI_SUCCESS) {
353 //
354 // Loop through the handles
355 //
356 for (Index = 0; Index < NumHandles; Index++) {
357 Status = gBS->HandleProtocol (
358 HandleBuffer[Index],
359 &gEfiEbcProtocolGuid,
360 (VOID **) &OldEbcProtocol
361 );
362 if (Status == EFI_SUCCESS) {
363 gBS->UninstallProtocolInterface (
364 HandleBuffer[Index],
365 &gEfiEbcProtocolGuid,
366 OldEbcProtocol
367 );
368 }
369 }
370 }
371
372 if (HandleBuffer != NULL) {
373 gBS->FreePool (HandleBuffer);
374 HandleBuffer = NULL;
375 }
376
377 gBS->FreePool (EbcProtocol);
378
379 return Status;
380 }
381
382 STATIC
383 EFI_STATUS
384 EFIAPI
385 EbcCreateThunk (
386 IN EFI_EBC_PROTOCOL *This,
387 IN EFI_HANDLE ImageHandle,
388 IN VOID *EbcEntryPoint,
389 OUT VOID **Thunk
390 )
391 /*++
392
393 Routine Description:
394
395 This is the top-level routine plugged into the EBC protocol. Since thunks
396 are very processor-specific, from here we dispatch directly to the very
397 processor-specific routine EbcCreateThunks().
398
399 Arguments:
400
401 This - protocol instance pointer
402 ImageHandle - handle to the image. The EBC interpreter may use this to keep
403 track of any resource allocations performed in loading and
404 executing the image.
405 EbcEntryPoint - the entry point for the image (as defined in the file header)
406 Thunk - pointer to thunk pointer where the address of the created
407 thunk is returned.
408
409 Returns:
410
411 EFI_STATUS
412
413 --*/
414 {
415 EFI_STATUS Status;
416
417 Status = EbcCreateThunks (
418 ImageHandle,
419 EbcEntryPoint,
420 Thunk,
421 FLAG_THUNK_ENTRY_POINT
422 );
423 return 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
435 Routine Description:
436
437 This EBC debugger protocol service is called by the debug agent
438
439 Arguments:
440
441 This - pointer to the caller's debug support protocol interface
442 MaxProcessorIndex - pointer to a caller allocated UINTN in which the maximum
443 processor index is returned.
444
445 Returns:
446
447 Standard EFI_STATUS
448
449 --*/
450 {
451 *MaxProcessorIndex = 0;
452 return EFI_SUCCESS;
453 }
454
455 STATIC
456 EFI_STATUS
457 EFIAPI
458 EbcDebugRegisterPeriodicCallback (
459 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
460 IN UINTN ProcessorIndex,
461 IN EFI_PERIODIC_CALLBACK PeriodicCallback
462 )
463 /*++
464
465 Routine Description:
466
467 This protocol service is called by the debug agent to register a function
468 for us to call on a periodic basis.
469
470
471 Arguments:
472
473 This - pointer to the caller's debug support protocol interface
474 PeriodicCallback - pointer to the function to call periodically
475
476 Returns:
477
478 Always EFI_SUCCESS
479
480 --*/
481 {
482 if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {
483 return EFI_INVALID_PARAMETER;
484 }
485 if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {
486 return EFI_ALREADY_STARTED;
487 }
488
489 mDebugPeriodicCallback = PeriodicCallback;
490 return EFI_SUCCESS;
491 }
492
493 STATIC
494 EFI_STATUS
495 EFIAPI
496 EbcDebugRegisterExceptionCallback (
497 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
498 IN UINTN ProcessorIndex,
499 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
500 IN EFI_EXCEPTION_TYPE ExceptionType
501 )
502 /*++
503
504 Routine Description:
505
506 This protocol service is called by the debug agent to register a function
507 for us to call when we detect an exception.
508
509
510 Arguments:
511
512 This - pointer to the caller's debug support protocol interface
513 PeriodicCallback - pointer to the function to call periodically
514
515 Returns:
516
517 Always EFI_SUCCESS
518
519 --*/
520 {
521 if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {
522 return EFI_INVALID_PARAMETER;
523 }
524 if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {
525 return EFI_INVALID_PARAMETER;
526 }
527 if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {
528 return EFI_ALREADY_STARTED;
529 }
530 mDebugExceptionCallback[ExceptionType] = ExceptionCallback;
531 return EFI_SUCCESS;
532 }
533
534 STATIC
535 EFI_STATUS
536 EFIAPI
537 EbcDebugInvalidateInstructionCache (
538 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
539 IN UINTN ProcessorIndex,
540 IN VOID *Start,
541 IN UINT64 Length
542 )
543 /*++
544
545 Routine Description:
546
547 This EBC debugger protocol service is called by the debug agent. Required
548 for DebugSupport compliance but is only stubbed out for EBC.
549
550 Arguments:
551
552 Returns:
553
554 EFI_SUCCESS
555
556 --*/
557 {
558 return EFI_SUCCESS;
559 }
560
561 EFI_STATUS
562 EbcDebugSignalException (
563 IN EFI_EXCEPTION_TYPE ExceptionType,
564 IN EXCEPTION_FLAGS ExceptionFlags,
565 IN VM_CONTEXT *VmPtr
566 )
567 /*++
568
569 Routine Description:
570
571 The VM interpreter calls this function when an exception is detected.
572
573 Arguments:
574
575 VmPtr - pointer to a VM context for passing info to the EFI debugger.
576
577 Returns:
578
579 EFI_SUCCESS if it returns at all
580
581 --*/
582 {
583 EFI_SYSTEM_CONTEXT_EBC EbcContext;
584 EFI_SYSTEM_CONTEXT SystemContext;
585
586 ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));
587 //
588 // Save the exception in the context passed in
589 //
590 VmPtr->ExceptionFlags |= ExceptionFlags;
591 VmPtr->LastException = ExceptionType;
592 //
593 // If it's a fatal exception, then flag it in the VM context in case an
594 // attached debugger tries to return from it.
595 //
596 if (ExceptionFlags & EXCEPTION_FLAG_FATAL) {
597 VmPtr->StopFlags |= STOPFLAG_APP_DONE;
598 }
599
600 //
601 // If someone's registered for exception callbacks, then call them.
602 //
603 // EBC driver will register default exception callback to report the
604 // status code via the status code API
605 //
606 if (mDebugExceptionCallback[ExceptionType] != NULL) {
607
608 //
609 // Initialize the context structure
610 //
611 EbcContext.R0 = VmPtr->R[0];
612 EbcContext.R1 = VmPtr->R[1];
613 EbcContext.R2 = VmPtr->R[2];
614 EbcContext.R3 = VmPtr->R[3];
615 EbcContext.R4 = VmPtr->R[4];
616 EbcContext.R5 = VmPtr->R[5];
617 EbcContext.R6 = VmPtr->R[6];
618 EbcContext.R7 = VmPtr->R[7];
619 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
620 EbcContext.Flags = VmPtr->Flags;
621 EbcContext.ControlFlags = 0;
622 SystemContext.SystemContextEbc = &EbcContext;
623
624 mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);
625 //
626 // Restore the context structure and continue to execute
627 //
628 VmPtr->R[0] = EbcContext.R0;
629 VmPtr->R[1] = EbcContext.R1;
630 VmPtr->R[2] = EbcContext.R2;
631 VmPtr->R[3] = EbcContext.R3;
632 VmPtr->R[4] = EbcContext.R4;
633 VmPtr->R[5] = EbcContext.R5;
634 VmPtr->R[6] = EbcContext.R6;
635 VmPtr->R[7] = EbcContext.R7;
636 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
637 VmPtr->Flags = EbcContext.Flags;
638 }
639
640 return EFI_SUCCESS;
641 }
642
643 STATIC
644 EFI_STATUS
645 InitializeEbcCallback (
646 IN EFI_DEBUG_SUPPORT_PROTOCOL *This
647 )
648 /*++
649
650 Routine Description:
651
652 To install default Callback function for the VM interpreter.
653
654 Arguments:
655
656 This - pointer to the instance of DebugSupport protocol
657
658 Returns:
659
660 None
661
662 --*/
663 {
664 INTN Index;
665 EFI_STATUS Status;
666
667 //
668 // For ExceptionCallback
669 //
670 for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {
671 EbcDebugRegisterExceptionCallback (
672 This,
673 0,
674 CommonEbcExceptionHandler,
675 Index
676 );
677 }
678
679 //
680 // For PeriodicCallback
681 //
682 Status = gBS->CreateEvent (
683 EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
684 EFI_TPL_NOTIFY,
685 EbcPeriodicNotifyFunction,
686 &mVmPtr,
687 &mEbcPeriodicEvent
688 );
689 if (EFI_ERROR(Status)) {
690 return Status;
691 }
692
693 Status = gBS->SetTimer (
694 mEbcPeriodicEvent,
695 TimerPeriodic,
696 EBC_VM_PERIODIC_CALLBACK_RATE
697 );
698 if (EFI_ERROR(Status)) {
699 return Status;
700 }
701
702 return EFI_SUCCESS;
703 }
704
705 STATIC
706 VOID
707 CommonEbcExceptionHandler (
708 IN EFI_EXCEPTION_TYPE InterruptType,
709 IN EFI_SYSTEM_CONTEXT SystemContext
710 )
711 /*++
712
713 Routine Description:
714
715 The default Exception Callback for the VM interpreter.
716 In this function, we report status code, and print debug information
717 about EBC_CONTEXT, then dead loop.
718
719 Arguments:
720
721 InterruptType - Interrupt type.
722 SystemContext - EBC system context.
723
724 Returns:
725
726 None
727
728 --*/
729 {
730 //
731 // We deadloop here to make it easy to debug this issue.
732 //
733 ASSERT (FALSE);
734
735 return ;
736 }
737
738 STATIC
739 VOID
740 EFIAPI
741 EbcPeriodicNotifyFunction (
742 IN EFI_EVENT Event,
743 IN VOID *Context
744 )
745 /*++
746
747 Routine Description:
748
749 The periodic callback function for EBC VM interpreter, which is used
750 to support the EFI debug support protocol.
751
752 Arguments:
753
754 Event - The Periodic Callback Event.
755 Context - It should be the address of VM_CONTEXT pointer.
756
757 Returns:
758
759 None.
760
761 --*/
762 {
763 VM_CONTEXT *VmPtr;
764
765 VmPtr = *(VM_CONTEXT **)Context;
766
767 if (VmPtr != NULL) {
768 EbcDebugPeriodic (VmPtr);
769 }
770
771 return ;
772 }
773
774 STATIC
775 EFI_STATUS
776 EbcDebugPeriodic (
777 IN VM_CONTEXT *VmPtr
778 )
779 /*++
780
781 Routine Description:
782
783 The VM interpreter calls this function on a periodic basis to support
784 the EFI debug support protocol.
785
786 Arguments:
787
788 VmPtr - pointer to a VM context for passing info to the debugger.
789
790 Returns:
791
792 Standard EFI status.
793
794 --*/
795 {
796 EFI_SYSTEM_CONTEXT_EBC EbcContext;
797 EFI_SYSTEM_CONTEXT SystemContext;
798
799 //
800 // If someone's registered for periodic callbacks, then call them.
801 //
802 if (mDebugPeriodicCallback != NULL) {
803
804 //
805 // Initialize the context structure
806 //
807 EbcContext.R0 = VmPtr->R[0];
808 EbcContext.R1 = VmPtr->R[1];
809 EbcContext.R2 = VmPtr->R[2];
810 EbcContext.R3 = VmPtr->R[3];
811 EbcContext.R4 = VmPtr->R[4];
812 EbcContext.R5 = VmPtr->R[5];
813 EbcContext.R6 = VmPtr->R[6];
814 EbcContext.R7 = VmPtr->R[7];
815 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
816 EbcContext.Flags = VmPtr->Flags;
817 EbcContext.ControlFlags = 0;
818 SystemContext.SystemContextEbc = &EbcContext;
819
820 mDebugPeriodicCallback (SystemContext);
821
822 //
823 // Restore the context structure and continue to execute
824 //
825 VmPtr->R[0] = EbcContext.R0;
826 VmPtr->R[1] = EbcContext.R1;
827 VmPtr->R[2] = EbcContext.R2;
828 VmPtr->R[3] = EbcContext.R3;
829 VmPtr->R[4] = EbcContext.R4;
830 VmPtr->R[5] = EbcContext.R5;
831 VmPtr->R[6] = EbcContext.R6;
832 VmPtr->R[7] = EbcContext.R7;
833 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
834 VmPtr->Flags = EbcContext.Flags;
835 }
836
837 return EFI_SUCCESS;
838 }
839
840 STATIC
841 EFI_STATUS
842 EFIAPI
843 EbcUnloadImage (
844 IN EFI_EBC_PROTOCOL *This,
845 IN EFI_HANDLE ImageHandle
846 )
847 /*++
848
849 Routine Description:
850
851 This routine is called by the core when an image is being unloaded from
852 memory. Basically we now have the opportunity to do any necessary cleanup.
853 Typically this will include freeing any memory allocated for thunk-creation.
854
855 Arguments:
856
857 This - protocol instance pointer
858 ImageHandle - handle to the image being unloaded.
859
860 Returns:
861
862 EFI_INVALID_PARAMETER - the ImageHandle passed in was not found in
863 the internal list of EBC image handles.
864 EFI_STATUS - completed successfully
865
866 --*/
867 {
868 EBC_THUNK_LIST *ThunkList;
869 EBC_THUNK_LIST *NextThunkList;
870 EBC_IMAGE_LIST *ImageList;
871 EBC_IMAGE_LIST *PrevImageList;
872 //
873 // First go through our list of known image handles and see if we've already
874 // created an image list element for this image handle.
875 //
876 PrevImageList = NULL;
877 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
878 if (ImageList->ImageHandle == ImageHandle) {
879 break;
880 }
881 //
882 // Save the previous so we can connect the lists when we remove this one
883 //
884 PrevImageList = ImageList;
885 }
886
887 if (ImageList == NULL) {
888 return EFI_INVALID_PARAMETER;
889 }
890 //
891 // Free up all the thunk buffers and thunks list elements for this image
892 // handle.
893 //
894 ThunkList = ImageList->ThunkList;
895 while (ThunkList != NULL) {
896 NextThunkList = ThunkList->Next;
897 gBS->FreePool (ThunkList->ThunkBuffer);
898 gBS->FreePool (ThunkList);
899 ThunkList = NextThunkList;
900 }
901 //
902 // Now remove this image list element from the chain
903 //
904 if (PrevImageList == NULL) {
905 //
906 // Remove from head
907 //
908 mEbcImageList = ImageList->Next;
909 } else {
910 PrevImageList->Next = ImageList->Next;
911 }
912 //
913 // Now free up the image list element
914 //
915 gBS->FreePool (ImageList);
916 return EFI_SUCCESS;
917 }
918
919 EFI_STATUS
920 EbcAddImageThunk (
921 IN EFI_HANDLE ImageHandle,
922 IN VOID *ThunkBuffer,
923 IN UINT32 ThunkSize
924 )
925 /*++
926
927 Routine Description:
928
929 Add a thunk to our list of thunks for a given image handle.
930 Also flush the instruction cache since we've written thunk code
931 to memory that will be executed eventually.
932
933 Arguments:
934
935 ImageHandle - the image handle to which the thunk is tied
936 ThunkBuffer - the buffer we've created/allocated
937 ThunkSize - the size of the thunk memory allocated
938
939 Returns:
940
941 EFI_OUT_OF_RESOURCES - memory allocation failed
942 EFI_SUCCESS - successful completion
943
944 --*/
945 {
946 EBC_THUNK_LIST *ThunkList;
947 EBC_IMAGE_LIST *ImageList;
948 EFI_STATUS Status;
949
950 //
951 // It so far so good, then flush the instruction cache
952 //
953 if (mEbcICacheFlush != NULL) {
954 Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);
955 if (EFI_ERROR (Status)) {
956 return Status;
957 }
958 }
959 //
960 // Go through our list of known image handles and see if we've already
961 // created a image list element for this image handle.
962 //
963 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
964 if (ImageList->ImageHandle == ImageHandle) {
965 break;
966 }
967 }
968
969 if (ImageList == NULL) {
970 //
971 // Allocate a new one
972 //
973 Status = gBS->AllocatePool (
974 EfiBootServicesData,
975 sizeof (EBC_IMAGE_LIST),
976 (VOID **) &ImageList
977 );
978 if (Status != EFI_SUCCESS) {
979 return EFI_OUT_OF_RESOURCES;
980 }
981
982 ImageList->ThunkList = NULL;
983 ImageList->ImageHandle = ImageHandle;
984 ImageList->Next = mEbcImageList;
985 mEbcImageList = ImageList;
986 }
987 //
988 // Ok, now create a new thunk element to add to the list
989 //
990 Status = gBS->AllocatePool (
991 EfiBootServicesData,
992 sizeof (EBC_THUNK_LIST),
993 (VOID **) &ThunkList
994 );
995 if (Status != EFI_SUCCESS) {
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 STATIC
1036 EFI_STATUS
1037 InitEbcVmTestProtocol (
1038 IN EFI_HANDLE *IHandle
1039 )
1040 /*++
1041
1042 Routine Description:
1043
1044 Produce an EBC VM test protocol that can be used for regression tests.
1045
1046 Arguments:
1047
1048 IHandle - handle on which to install the protocol.
1049
1050 Returns:
1051
1052 EFI_OUT_OF_RESOURCES - memory allocation failed
1053 EFI_SUCCESS - successful completion
1054
1055 --*/
1056 {
1057 EFI_HANDLE Handle;
1058 EFI_STATUS Status;
1059 EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;
1060
1061 //
1062 // Allocate memory for the protocol, then fill in the fields
1063 //
1064 Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_EBC_VM_TEST_PROTOCOL), (VOID **) &EbcVmTestProtocol);
1065 if (Status != EFI_SUCCESS) {
1066 return EFI_OUT_OF_RESOURCES;
1067 }
1068 EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
1069
1070 DEBUG_CODE_BEGIN ();
1071 EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
1072 EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
1073 DEBUG_CODE_END ();
1074
1075 //
1076 // Publish the protocol
1077 //
1078 Handle = NULL;
1079 Status = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
1080 if (EFI_ERROR (Status)) {
1081 gBS->FreePool (EbcVmTestProtocol);
1082 }
1083 return Status;
1084 }
1085 STATIC
1086 EFI_STATUS
1087 EbcVmTestUnsupported ()
1088 {
1089 return EFI_UNSUPPORTED;
1090 }
1091