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