7b15a1a84b4679e347da795c874106dc551f82c4
[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 //
81 // These two functions and the GUID are used to produce an EBC test protocol.
82 // This functionality is definitely not required for execution.
83 //
84 STATIC
85 EFI_STATUS
86 InitEbcVmTestProtocol (
87 IN EFI_HANDLE *Handle
88 );
89
90 STATIC
91 EFI_STATUS
92 EbcVmTestUnsupported (
93 VOID
94 );
95
96 STATIC
97 EFI_STATUS
98 EFIAPI
99 EbcRegisterICacheFlush (
100 IN EFI_EBC_PROTOCOL *This,
101 IN EBC_ICACHE_FLUSH Flush
102 );
103
104 STATIC
105 EFI_STATUS
106 EFIAPI
107 EbcDebugGetMaximumProcessorIndex (
108 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
109 OUT UINTN *MaxProcessorIndex
110 );
111
112 STATIC
113 EFI_STATUS
114 EFIAPI
115 EbcDebugRegisterPeriodicCallback (
116 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
117 IN UINTN ProcessorIndex,
118 IN EFI_PERIODIC_CALLBACK PeriodicCallback
119 );
120
121 STATIC
122 EFI_STATUS
123 EFIAPI
124 EbcDebugRegisterExceptionCallback (
125 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
126 IN UINTN ProcessorIndex,
127 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
128 IN EFI_EXCEPTION_TYPE ExceptionType
129 );
130
131 STATIC
132 EFI_STATUS
133 EFIAPI
134 EbcDebugInvalidateInstructionCache (
135 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
136 IN UINTN ProcessorIndex,
137 IN VOID *Start,
138 IN UINT64 Length
139 );
140
141 //
142 // We have one linked list of image handles for the whole world. Since
143 // there should only be one interpreter, make them global. They must
144 // also be global since the execution of an EBC image does not provide
145 // a This pointer.
146 //
147 static EBC_IMAGE_LIST *mEbcImageList = NULL;
148
149 //
150 // Callback function to flush the icache after thunk creation
151 //
152 static EBC_ICACHE_FLUSH mEbcICacheFlush;
153
154 //
155 // These get set via calls by the debug agent
156 //
157 static EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;
158 static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback = NULL;
159 static EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;
160
161 EFI_STATUS
162 EFIAPI
163 InitializeEbcDriver (
164 IN EFI_HANDLE ImageHandle,
165 IN EFI_SYSTEM_TABLE *SystemTable
166 )
167 /*++
168
169 Routine Description:
170
171 Initializes the VM EFI interface. Allocates memory for the VM interface
172 and registers the VM protocol.
173
174 Arguments:
175
176 ImageHandle - EFI image handle.
177 SystemTable - Pointer to the EFI system table.
178
179 Returns:
180 Standard EFI status code.
181
182 --*/
183 {
184 EFI_EBC_PROTOCOL *EbcProtocol;
185 EFI_EBC_PROTOCOL *OldEbcProtocol;
186 EFI_STATUS Status;
187 EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol;
188 EFI_HANDLE *HandleBuffer;
189 UINTN NumHandles;
190 UINTN Index;
191 BOOLEAN Installed;
192
193 //
194 // Allocate memory for our protocol. Then fill in the blanks.
195 //
196 Status = gBS->AllocatePool (
197 EfiBootServicesData,
198 sizeof (EFI_EBC_PROTOCOL),
199 (VOID **) &EbcProtocol
200 );
201 if (Status != EFI_SUCCESS) {
202 return EFI_OUT_OF_RESOURCES;
203 }
204
205 EbcProtocol->CreateThunk = EbcCreateThunk;
206 EbcProtocol->UnloadImage = EbcUnloadImage;
207 EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush;
208 EbcProtocol->GetVersion = EbcGetVersion;
209 mEbcICacheFlush = NULL;
210
211 //
212 // Find any already-installed EBC protocols and uninstall them
213 //
214 Installed = FALSE;
215 HandleBuffer = NULL;
216 Status = gBS->LocateHandleBuffer (
217 ByProtocol,
218 &gEfiEbcProtocolGuid,
219 NULL,
220 &NumHandles,
221 &HandleBuffer
222 );
223 if (Status == EFI_SUCCESS) {
224 //
225 // Loop through the handles
226 //
227 for (Index = 0; Index < NumHandles; Index++) {
228 Status = gBS->HandleProtocol (
229 HandleBuffer[Index],
230 &gEfiEbcProtocolGuid,
231 (VOID **) &OldEbcProtocol
232 );
233 if (Status == EFI_SUCCESS) {
234 if (gBS->ReinstallProtocolInterface (
235 HandleBuffer[Index],
236 &gEfiEbcProtocolGuid,
237 OldEbcProtocol,
238 EbcProtocol
239 ) == EFI_SUCCESS) {
240 Installed = TRUE;
241 }
242 }
243 }
244 }
245
246 if (HandleBuffer != NULL) {
247 gBS->FreePool (HandleBuffer);
248 HandleBuffer = NULL;
249 }
250 //
251 // Add the protocol so someone can locate us if we haven't already.
252 //
253 if (!Installed) {
254 Status = gBS->InstallProtocolInterface (
255 &ImageHandle,
256 &gEfiEbcProtocolGuid,
257 EFI_NATIVE_INTERFACE,
258 EbcProtocol
259 );
260 if (EFI_ERROR (Status)) {
261 gBS->FreePool (EbcProtocol);
262 return Status;
263 }
264 }
265 //
266 // Allocate memory for our debug protocol. Then fill in the blanks.
267 //
268 Status = gBS->AllocatePool (
269 EfiBootServicesData,
270 sizeof (EFI_DEBUG_SUPPORT_PROTOCOL),
271 (VOID **) &EbcDebugProtocol
272 );
273 if (Status != EFI_SUCCESS) {
274 return EFI_OUT_OF_RESOURCES;
275 }
276
277 EbcDebugProtocol->Isa = IsaEbc;
278 EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex;
279 EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback;
280 EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback;
281 EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache;
282
283 //
284 // Add the protocol so the debug agent can find us
285 //
286 Status = gBS->InstallProtocolInterface (
287 &ImageHandle,
288 &gEfiDebugSupportProtocolGuid,
289 EFI_NATIVE_INTERFACE,
290 EbcDebugProtocol
291 );
292 //
293 // This is recoverable, so free the memory and continue.
294 //
295 if (EFI_ERROR (Status)) {
296 gBS->FreePool (EbcDebugProtocol);
297 }
298 //
299 // Produce a VM test interface protocol. Not required for execution.
300 //
301 DEBUG_CODE_BEGIN ();
302 InitEbcVmTestProtocol (&ImageHandle);
303 DEBUG_CODE_END ();
304
305 return Status;
306 }
307
308 STATIC
309 EFI_STATUS
310 EFIAPI
311 EbcCreateThunk (
312 IN EFI_EBC_PROTOCOL *This,
313 IN EFI_HANDLE ImageHandle,
314 IN VOID *EbcEntryPoint,
315 OUT VOID **Thunk
316 )
317 /*++
318
319 Routine Description:
320
321 This is the top-level routine plugged into the EBC protocol. Since thunks
322 are very processor-specific, from here we dispatch directly to the very
323 processor-specific routine EbcCreateThunks().
324
325 Arguments:
326
327 This - protocol instance pointer
328 ImageHandle - handle to the image. The EBC interpreter may use this to keep
329 track of any resource allocations performed in loading and
330 executing the image.
331 EbcEntryPoint - the entry point for the image (as defined in the file header)
332 Thunk - pointer to thunk pointer where the address of the created
333 thunk is returned.
334
335 Returns:
336
337 EFI_STATUS
338
339 --*/
340 {
341 EFI_STATUS Status;
342
343 Status = EbcCreateThunks (
344 ImageHandle,
345 EbcEntryPoint,
346 Thunk,
347 FLAG_THUNK_ENTRY_POINT
348 );
349 return Status;
350 }
351
352 STATIC
353 EFI_STATUS
354 EFIAPI
355 EbcDebugGetMaximumProcessorIndex (
356 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
357 OUT UINTN *MaxProcessorIndex
358 )
359 /*++
360
361 Routine Description:
362
363 This EBC debugger protocol service is called by the debug agent
364
365 Arguments:
366
367 This - pointer to the caller's debug support protocol interface
368 MaxProcessorIndex - pointer to a caller allocated UINTN in which the maximum
369 processor index is returned.
370
371 Returns:
372
373 Standard EFI_STATUS
374
375 --*/
376 {
377 *MaxProcessorIndex = 0;
378 return EFI_SUCCESS;
379 }
380
381 STATIC
382 EFI_STATUS
383 EFIAPI
384 EbcDebugRegisterPeriodicCallback (
385 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
386 IN UINTN ProcessorIndex,
387 IN EFI_PERIODIC_CALLBACK PeriodicCallback
388 )
389 /*++
390
391 Routine Description:
392
393 This protocol service is called by the debug agent to register a function
394 for us to call on a periodic basis.
395
396
397 Arguments:
398
399 This - pointer to the caller's debug support protocol interface
400 PeriodicCallback - pointer to the function to call periodically
401
402 Returns:
403
404 Always EFI_SUCCESS
405
406 --*/
407 {
408 mDebugPeriodicCallback = PeriodicCallback;
409 return EFI_SUCCESS;
410 }
411
412 STATIC
413 EFI_STATUS
414 EFIAPI
415 EbcDebugRegisterExceptionCallback (
416 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
417 IN UINTN ProcessorIndex,
418 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
419 IN EFI_EXCEPTION_TYPE ExceptionType
420 )
421 /*++
422
423 Routine Description:
424
425 This protocol service is called by the debug agent to register a function
426 for us to call when we detect an exception.
427
428
429 Arguments:
430
431 This - pointer to the caller's debug support protocol interface
432 PeriodicCallback - pointer to the function to call periodically
433
434 Returns:
435
436 Always EFI_SUCCESS
437
438 --*/
439 {
440 mDebugExceptionCallback = ExceptionCallback;
441 return EFI_SUCCESS;
442 }
443
444 STATIC
445 EFI_STATUS
446 EFIAPI
447 EbcDebugInvalidateInstructionCache (
448 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
449 IN UINTN ProcessorIndex,
450 IN VOID *Start,
451 IN UINT64 Length
452 )
453 /*++
454
455 Routine Description:
456
457 This EBC debugger protocol service is called by the debug agent. Required
458 for DebugSupport compliance but is only stubbed out for EBC.
459
460 Arguments:
461
462 Returns:
463
464 EFI_SUCCESS
465
466 --*/
467 {
468 return EFI_SUCCESS;
469 }
470
471 EFI_STATUS
472 EbcDebugSignalException (
473 IN EFI_EXCEPTION_TYPE ExceptionType,
474 IN EXCEPTION_FLAGS ExceptionFlags,
475 IN VM_CONTEXT *VmPtr
476 )
477 /*++
478
479 Routine Description:
480
481 The VM interpreter calls this function when an exception is detected.
482
483 Arguments:
484
485 VmPtr - pointer to a VM context for passing info to the EFI debugger.
486
487 Returns:
488
489 EFI_SUCCESS if it returns at all
490
491 --*/
492 {
493 EFI_SYSTEM_CONTEXT_EBC EbcContext;
494 EFI_SYSTEM_CONTEXT SystemContext;
495 EFI_STATUS_CODE_VALUE StatusCodeValue;
496 BOOLEAN Report;
497 //
498 // Save the exception in the context passed in
499 //
500 VmPtr->ExceptionFlags |= ExceptionFlags;
501 VmPtr->LastException = ExceptionType;
502 //
503 // If it's a fatal exception, then flag it in the VM context in case an
504 // attached debugger tries to return from it.
505 //
506 if (ExceptionFlags & EXCEPTION_FLAG_FATAL) {
507 VmPtr->StopFlags |= STOPFLAG_APP_DONE;
508 }
509 //
510 // Initialize the context structure
511 //
512 EbcContext.R0 = VmPtr->R[0];
513 EbcContext.R1 = VmPtr->R[1];
514 EbcContext.R2 = VmPtr->R[2];
515 EbcContext.R3 = VmPtr->R[3];
516 EbcContext.R4 = VmPtr->R[4];
517 EbcContext.R5 = VmPtr->R[5];
518 EbcContext.R6 = VmPtr->R[6];
519 EbcContext.R7 = VmPtr->R[7];
520 EbcContext.Ip = (UINT64) (UINTN) VmPtr->Ip;
521 EbcContext.Flags = VmPtr->Flags;
522 SystemContext.SystemContextEbc = &EbcContext;
523 //
524 // If someone's registered for exception callbacks, then call them.
525 // Otherwise report the status code via the status code API
526 //
527 if (mDebugExceptionCallback != NULL) {
528 mDebugExceptionCallback (ExceptionType, SystemContext);
529 }
530 //
531 // Determine if we should report the exception. We report all of them by default,
532 // but if a debugger is attached don't report the breakpoint, debug, and step exceptions.
533 // Note that EXCEPT_EBC_OVERFLOW is never reported by this VM implementation, so is
534 // not included in the switch statement.
535 //
536 Report = TRUE;
537 switch (ExceptionType) {
538 case EXCEPT_EBC_UNDEFINED:
539 StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_UNDEFINED;
540 break;
541
542 case EXCEPT_EBC_DIVIDE_ERROR:
543 StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_DIVIDE_ERROR;
544 break;
545
546 case EXCEPT_EBC_DEBUG:
547 StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_DEBUG;
548 Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE);
549 break;
550
551 case EXCEPT_EBC_BREAKPOINT:
552 StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_BREAKPOINT;
553 Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE);
554 break;
555
556 case EXCEPT_EBC_INVALID_OPCODE:
557 StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_INVALID_OPCODE;
558 break;
559
560 case EXCEPT_EBC_STACK_FAULT:
561 StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_STACK_FAULT;
562 break;
563
564 case EXCEPT_EBC_ALIGNMENT_CHECK:
565 StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_ALIGNMENT_CHECK;
566 break;
567
568 case EXCEPT_EBC_INSTRUCTION_ENCODING:
569 StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_INSTRUCTION_ENCODING;
570 break;
571
572 case EXCEPT_EBC_BAD_BREAK:
573 StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_BAD_BREAK;
574 break;
575
576 case EXCEPT_EBC_STEP:
577 StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_STEP;
578 Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE);
579 break;
580
581 default:
582 StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_NON_SPECIFIC;
583 break;
584 }
585 //
586 // If we determined that we should report the condition, then do so now.
587 //
588 if (Report) {
589 REPORT_STATUS_CODE (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, StatusCodeValue);
590 }
591
592 switch (ExceptionType) {
593 //
594 // If ReportStatusCode returned, then for most exceptions we do an assert. The
595 // ExceptionType++ is done simply to force the ASSERT() condition to be met.
596 // For breakpoints, assume a debugger did not insert a software breakpoint
597 // and skip the instruction.
598 //
599 case EXCEPT_EBC_BREAKPOINT:
600 VmPtr->Ip += 2;
601 break;
602
603 case EXCEPT_EBC_STEP:
604 break;
605
606 case EXCEPT_EBC_UNDEFINED:
607 ExceptionType++;
608 ASSERT (ExceptionType == EXCEPT_EBC_UNDEFINED);
609 break;
610
611 case EXCEPT_EBC_DIVIDE_ERROR:
612 ExceptionType++;
613 ASSERT (ExceptionType == EXCEPT_EBC_DIVIDE_ERROR);
614 break;
615
616 case EXCEPT_EBC_DEBUG:
617 ExceptionType++;
618 ASSERT (ExceptionType == EXCEPT_EBC_DEBUG);
619 break;
620
621 case EXCEPT_EBC_INVALID_OPCODE:
622 ExceptionType++;
623 ASSERT (ExceptionType == EXCEPT_EBC_INVALID_OPCODE);
624 break;
625
626 case EXCEPT_EBC_STACK_FAULT:
627 ExceptionType++;
628 ASSERT (ExceptionType == EXCEPT_EBC_STACK_FAULT);
629 break;
630
631 case EXCEPT_EBC_ALIGNMENT_CHECK:
632 ExceptionType++;
633 ASSERT (ExceptionType == EXCEPT_EBC_ALIGNMENT_CHECK);
634 break;
635
636 case EXCEPT_EBC_INSTRUCTION_ENCODING:
637 ExceptionType++;
638 ASSERT (ExceptionType == EXCEPT_EBC_INSTRUCTION_ENCODING);
639 break;
640
641 case EXCEPT_EBC_BAD_BREAK:
642 ExceptionType++;
643 ASSERT (ExceptionType == EXCEPT_EBC_BAD_BREAK);
644 break;
645
646 default:
647 //
648 // Unknown
649 //
650 ASSERT (0);
651 break;
652 }
653
654 return EFI_SUCCESS;
655 }
656
657 EFI_STATUS
658 EbcDebugPeriodic (
659 IN VM_CONTEXT *VmPtr
660 )
661 /*++
662
663 Routine Description:
664
665 The VM interpreter calls this function on a periodic basis to support
666 the EFI debug support protocol.
667
668 Arguments:
669
670 VmPtr - pointer to a VM context for passing info to the debugger.
671
672 Returns:
673
674 Standard EFI status.
675
676 --*/
677 {
678 return EFI_SUCCESS;
679 }
680
681 STATIC
682 EFI_STATUS
683 EFIAPI
684 EbcUnloadImage (
685 IN EFI_EBC_PROTOCOL *This,
686 IN EFI_HANDLE ImageHandle
687 )
688 /*++
689
690 Routine Description:
691
692 This routine is called by the core when an image is being unloaded from
693 memory. Basically we now have the opportunity to do any necessary cleanup.
694 Typically this will include freeing any memory allocated for thunk-creation.
695
696 Arguments:
697
698 This - protocol instance pointer
699 ImageHandle - handle to the image being unloaded.
700
701 Returns:
702
703 EFI_INVALID_PARAMETER - the ImageHandle passed in was not found in
704 the internal list of EBC image handles.
705 EFI_STATUS - completed successfully
706
707 --*/
708 {
709 EBC_THUNK_LIST *ThunkList;
710 EBC_THUNK_LIST *NextThunkList;
711 EBC_IMAGE_LIST *ImageList;
712 EBC_IMAGE_LIST *PrevImageList;
713 //
714 // First go through our list of known image handles and see if we've already
715 // created an image list element for this image handle.
716 //
717 PrevImageList = NULL;
718 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
719 if (ImageList->ImageHandle == ImageHandle) {
720 break;
721 }
722 //
723 // Save the previous so we can connect the lists when we remove this one
724 //
725 PrevImageList = ImageList;
726 }
727
728 if (ImageList == NULL) {
729 return EFI_INVALID_PARAMETER;
730 }
731 //
732 // Free up all the thunk buffers and thunks list elements for this image
733 // handle.
734 //
735 ThunkList = ImageList->ThunkList;
736 while (ThunkList != NULL) {
737 NextThunkList = ThunkList->Next;
738 gBS->FreePool (ThunkList->ThunkBuffer);
739 gBS->FreePool (ThunkList);
740 ThunkList = NextThunkList;
741 }
742 //
743 // Now remove this image list element from the chain
744 //
745 if (PrevImageList == NULL) {
746 //
747 // Remove from head
748 //
749 mEbcImageList = ImageList->Next;
750 } else {
751 PrevImageList->Next = ImageList->Next;
752 }
753 //
754 // Now free up the image list element
755 //
756 gBS->FreePool (ImageList);
757 return EFI_SUCCESS;
758 }
759
760 EFI_STATUS
761 EbcAddImageThunk (
762 IN EFI_HANDLE ImageHandle,
763 IN VOID *ThunkBuffer,
764 IN UINT32 ThunkSize
765 )
766 /*++
767
768 Routine Description:
769
770 Add a thunk to our list of thunks for a given image handle.
771 Also flush the instruction cache since we've written thunk code
772 to memory that will be executed eventually.
773
774 Arguments:
775
776 ImageHandle - the image handle to which the thunk is tied
777 ThunkBuffer - the buffer we've created/allocated
778 ThunkSize - the size of the thunk memory allocated
779
780 Returns:
781
782 EFI_OUT_OF_RESOURCES - memory allocation failed
783 EFI_SUCCESS - successful completion
784
785 --*/
786 {
787 EBC_THUNK_LIST *ThunkList;
788 EBC_IMAGE_LIST *ImageList;
789 EFI_STATUS Status;
790
791 //
792 // It so far so good, then flush the instruction cache
793 //
794 if (mEbcICacheFlush != NULL) {
795 Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);
796 if (EFI_ERROR (Status)) {
797 return Status;
798 }
799 }
800 //
801 // Go through our list of known image handles and see if we've already
802 // created a image list element for this image handle.
803 //
804 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
805 if (ImageList->ImageHandle == ImageHandle) {
806 break;
807 }
808 }
809
810 if (ImageList == NULL) {
811 //
812 // Allocate a new one
813 //
814 Status = gBS->AllocatePool (
815 EfiBootServicesData,
816 sizeof (EBC_IMAGE_LIST),
817 (VOID **) &ImageList
818 );
819 if (Status != EFI_SUCCESS) {
820 return EFI_OUT_OF_RESOURCES;
821 }
822
823 ImageList->ThunkList = NULL;
824 ImageList->ImageHandle = ImageHandle;
825 ImageList->Next = mEbcImageList;
826 mEbcImageList = ImageList;
827 }
828 //
829 // Ok, now create a new thunk element to add to the list
830 //
831 Status = gBS->AllocatePool (
832 EfiBootServicesData,
833 sizeof (EBC_THUNK_LIST),
834 (VOID **) &ThunkList
835 );
836 if (Status != EFI_SUCCESS) {
837 return EFI_OUT_OF_RESOURCES;
838 }
839 //
840 // Add it to the head of the list
841 //
842 ThunkList->Next = ImageList->ThunkList;
843 ThunkList->ThunkBuffer = ThunkBuffer;
844 ImageList->ThunkList = ThunkList;
845 return EFI_SUCCESS;
846 }
847
848 STATIC
849 EFI_STATUS
850 EFIAPI
851 EbcRegisterICacheFlush (
852 IN EFI_EBC_PROTOCOL *This,
853 IN EBC_ICACHE_FLUSH Flush
854 )
855 {
856 mEbcICacheFlush = Flush;
857 return EFI_SUCCESS;
858 }
859
860 STATIC
861 EFI_STATUS
862 EFIAPI
863 EbcGetVersion (
864 IN EFI_EBC_PROTOCOL *This,
865 IN OUT UINT64 *Version
866 )
867 {
868 if (Version == NULL) {
869 return EFI_INVALID_PARAMETER;
870 }
871
872 *Version = GetVmVersion ();
873 return EFI_SUCCESS;
874 }
875
876 STATIC
877 EFI_STATUS
878 InitEbcVmTestProtocol (
879 IN EFI_HANDLE *IHandle
880 )
881 /*++
882
883 Routine Description:
884
885 Produce an EBC VM test protocol that can be used for regression tests.
886
887 Arguments:
888
889 IHandle - handle on which to install the protocol.
890
891 Returns:
892
893 EFI_OUT_OF_RESOURCES - memory allocation failed
894 EFI_SUCCESS - successful completion
895
896 --*/
897 {
898 EFI_HANDLE Handle;
899 EFI_STATUS Status;
900 EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;
901
902 //
903 // Allocate memory for the protocol, then fill in the fields
904 //
905 Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_EBC_VM_TEST_PROTOCOL), (VOID **) &EbcVmTestProtocol);
906 if (Status != EFI_SUCCESS) {
907 return EFI_OUT_OF_RESOURCES;
908 }
909 EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
910
911 DEBUG_CODE_BEGIN ();
912 EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
913 EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
914 DEBUG_CODE_END ();
915
916 //
917 // Publish the protocol
918 //
919 Handle = NULL;
920 Status = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
921 if (EFI_ERROR (Status)) {
922 gBS->FreePool (EbcVmTestProtocol);
923 }
924 return Status;
925 }
926 STATIC
927 EFI_STATUS
928 EbcVmTestUnsupported ()
929 {
930 return EFI_UNSUPPORTED;
931 }
932