2a5d48a431f5875ea364201184c074943245167a
[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[MAX_EBC_EXCEPTION + 1] = {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 if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {
409 return EFI_INVALID_PARAMETER;
410 }
411 if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {
412 return EFI_ALREADY_STARTED;
413 }
414
415 mDebugPeriodicCallback = PeriodicCallback;
416 return EFI_SUCCESS;
417 }
418
419 STATIC
420 EFI_STATUS
421 EFIAPI
422 EbcDebugRegisterExceptionCallback (
423 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
424 IN UINTN ProcessorIndex,
425 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
426 IN EFI_EXCEPTION_TYPE ExceptionType
427 )
428 /*++
429
430 Routine Description:
431
432 This protocol service is called by the debug agent to register a function
433 for us to call when we detect an exception.
434
435
436 Arguments:
437
438 This - pointer to the caller's debug support protocol interface
439 PeriodicCallback - pointer to the function to call periodically
440
441 Returns:
442
443 Always EFI_SUCCESS
444
445 --*/
446 {
447 if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {
448 return EFI_INVALID_PARAMETER;
449 }
450 if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {
451 return EFI_INVALID_PARAMETER;
452 }
453 if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {
454 return EFI_ALREADY_STARTED;
455 }
456 mDebugExceptionCallback[ExceptionType] = ExceptionCallback;
457 return EFI_SUCCESS;
458 }
459
460 STATIC
461 EFI_STATUS
462 EFIAPI
463 EbcDebugInvalidateInstructionCache (
464 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
465 IN UINTN ProcessorIndex,
466 IN VOID *Start,
467 IN UINT64 Length
468 )
469 /*++
470
471 Routine Description:
472
473 This EBC debugger protocol service is called by the debug agent. Required
474 for DebugSupport compliance but is only stubbed out for EBC.
475
476 Arguments:
477
478 Returns:
479
480 EFI_SUCCESS
481
482 --*/
483 {
484 return EFI_SUCCESS;
485 }
486
487 EFI_STATUS
488 EbcDebugSignalException (
489 IN EFI_EXCEPTION_TYPE ExceptionType,
490 IN EXCEPTION_FLAGS ExceptionFlags,
491 IN VM_CONTEXT *VmPtr
492 )
493 /*++
494
495 Routine Description:
496
497 The VM interpreter calls this function when an exception is detected.
498
499 Arguments:
500
501 VmPtr - pointer to a VM context for passing info to the EFI debugger.
502
503 Returns:
504
505 EFI_SUCCESS if it returns at all
506
507 --*/
508 {
509 EFI_SYSTEM_CONTEXT_EBC EbcContext;
510 EFI_SYSTEM_CONTEXT SystemContext;
511 EFI_STATUS_CODE_VALUE StatusCodeValue;
512 BOOLEAN Report;
513 //
514 // Save the exception in the context passed in
515 //
516 VmPtr->ExceptionFlags |= ExceptionFlags;
517 VmPtr->LastException = ExceptionType;
518 //
519 // If it's a fatal exception, then flag it in the VM context in case an
520 // attached debugger tries to return from it.
521 //
522 if (ExceptionFlags & EXCEPTION_FLAG_FATAL) {
523 VmPtr->StopFlags |= STOPFLAG_APP_DONE;
524 }
525 //
526 // Initialize the context structure
527 //
528 EbcContext.R0 = VmPtr->R[0];
529 EbcContext.R1 = VmPtr->R[1];
530 EbcContext.R2 = VmPtr->R[2];
531 EbcContext.R3 = VmPtr->R[3];
532 EbcContext.R4 = VmPtr->R[4];
533 EbcContext.R5 = VmPtr->R[5];
534 EbcContext.R6 = VmPtr->R[6];
535 EbcContext.R7 = VmPtr->R[7];
536 EbcContext.Ip = (UINT64) (UINTN) VmPtr->Ip;
537 EbcContext.Flags = VmPtr->Flags;
538 EbcContext.ControlFlags = 0;
539 SystemContext.SystemContextEbc = &EbcContext;
540 //
541 // If someone's registered for exception callbacks, then call them.
542 // Otherwise report the status code via the status code API
543 //
544 if ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION) &&
545 (mDebugExceptionCallback[ExceptionType] != NULL)) {
546 mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);
547 }
548 //
549 // Determine if we should report the exception. We report all of them by default,
550 // but if a debugger is attached don't report the breakpoint, debug, and step exceptions.
551 // Note that EXCEPT_EBC_OVERFLOW is never reported by this VM implementation, so is
552 // not included in the switch statement.
553 //
554 Report = TRUE;
555 switch (ExceptionType) {
556 case EXCEPT_EBC_UNDEFINED:
557 StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_UNDEFINED;
558 break;
559
560 case EXCEPT_EBC_DIVIDE_ERROR:
561 StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_DIVIDE_ERROR;
562 break;
563
564 case EXCEPT_EBC_DEBUG:
565 StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_DEBUG;
566 Report = (BOOLEAN) ((mDebugExceptionCallback[ExceptionType] == NULL) ? TRUE : FALSE);
567 break;
568
569 case EXCEPT_EBC_BREAKPOINT:
570 StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_BREAKPOINT;
571 Report = (BOOLEAN) ((mDebugExceptionCallback[ExceptionType] == NULL) ? TRUE : FALSE);
572 break;
573
574 case EXCEPT_EBC_INVALID_OPCODE:
575 StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_INVALID_OPCODE;
576 break;
577
578 case EXCEPT_EBC_STACK_FAULT:
579 StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_STACK_FAULT;
580 break;
581
582 case EXCEPT_EBC_ALIGNMENT_CHECK:
583 StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_ALIGNMENT_CHECK;
584 break;
585
586 case EXCEPT_EBC_INSTRUCTION_ENCODING:
587 StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_INSTRUCTION_ENCODING;
588 break;
589
590 case EXCEPT_EBC_BAD_BREAK:
591 StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_BAD_BREAK;
592 break;
593
594 case EXCEPT_EBC_STEP:
595 StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_EBC_STEP;
596 Report = (BOOLEAN) ((mDebugExceptionCallback[ExceptionType] == NULL) ? TRUE : FALSE);
597 break;
598
599 default:
600 StatusCodeValue = EFI_SOFTWARE_EBC_EXCEPTION | EFI_SW_EC_NON_SPECIFIC;
601 break;
602 }
603 //
604 // If we determined that we should report the condition, then do so now.
605 //
606 if (Report) {
607 REPORT_STATUS_CODE (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, StatusCodeValue);
608 }
609
610 switch (ExceptionType) {
611 //
612 // If ReportStatusCode returned, then for most exceptions we do an assert. The
613 // ExceptionType++ is done simply to force the ASSERT() condition to be met.
614 // For breakpoints, assume a debugger did not insert a software breakpoint
615 // and skip the instruction.
616 //
617 case EXCEPT_EBC_BREAKPOINT:
618 VmPtr->Ip += 2;
619 break;
620
621 case EXCEPT_EBC_STEP:
622 break;
623
624 case EXCEPT_EBC_UNDEFINED:
625 ExceptionType++;
626 ASSERT (ExceptionType == EXCEPT_EBC_UNDEFINED);
627 break;
628
629 case EXCEPT_EBC_DIVIDE_ERROR:
630 ExceptionType++;
631 ASSERT (ExceptionType == EXCEPT_EBC_DIVIDE_ERROR);
632 break;
633
634 case EXCEPT_EBC_DEBUG:
635 ExceptionType++;
636 ASSERT (ExceptionType == EXCEPT_EBC_DEBUG);
637 break;
638
639 case EXCEPT_EBC_INVALID_OPCODE:
640 ExceptionType++;
641 ASSERT (ExceptionType == EXCEPT_EBC_INVALID_OPCODE);
642 break;
643
644 case EXCEPT_EBC_STACK_FAULT:
645 ExceptionType++;
646 ASSERT (ExceptionType == EXCEPT_EBC_STACK_FAULT);
647 break;
648
649 case EXCEPT_EBC_ALIGNMENT_CHECK:
650 ExceptionType++;
651 ASSERT (ExceptionType == EXCEPT_EBC_ALIGNMENT_CHECK);
652 break;
653
654 case EXCEPT_EBC_INSTRUCTION_ENCODING:
655 ExceptionType++;
656 ASSERT (ExceptionType == EXCEPT_EBC_INSTRUCTION_ENCODING);
657 break;
658
659 case EXCEPT_EBC_BAD_BREAK:
660 ExceptionType++;
661 ASSERT (ExceptionType == EXCEPT_EBC_BAD_BREAK);
662 break;
663
664 default:
665 //
666 // Unknown
667 //
668 ASSERT (0);
669 break;
670 }
671
672 return EFI_SUCCESS;
673 }
674
675 EFI_STATUS
676 EbcDebugPeriodic (
677 IN VM_CONTEXT *VmPtr
678 )
679 /*++
680
681 Routine Description:
682
683 The VM interpreter calls this function on a periodic basis to support
684 the EFI debug support protocol.
685
686 Arguments:
687
688 VmPtr - pointer to a VM context for passing info to the debugger.
689
690 Returns:
691
692 Standard EFI status.
693
694 --*/
695 {
696 return EFI_SUCCESS;
697 }
698
699 STATIC
700 EFI_STATUS
701 EFIAPI
702 EbcUnloadImage (
703 IN EFI_EBC_PROTOCOL *This,
704 IN EFI_HANDLE ImageHandle
705 )
706 /*++
707
708 Routine Description:
709
710 This routine is called by the core when an image is being unloaded from
711 memory. Basically we now have the opportunity to do any necessary cleanup.
712 Typically this will include freeing any memory allocated for thunk-creation.
713
714 Arguments:
715
716 This - protocol instance pointer
717 ImageHandle - handle to the image being unloaded.
718
719 Returns:
720
721 EFI_INVALID_PARAMETER - the ImageHandle passed in was not found in
722 the internal list of EBC image handles.
723 EFI_STATUS - completed successfully
724
725 --*/
726 {
727 EBC_THUNK_LIST *ThunkList;
728 EBC_THUNK_LIST *NextThunkList;
729 EBC_IMAGE_LIST *ImageList;
730 EBC_IMAGE_LIST *PrevImageList;
731 //
732 // First go through our list of known image handles and see if we've already
733 // created an image list element for this image handle.
734 //
735 PrevImageList = NULL;
736 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
737 if (ImageList->ImageHandle == ImageHandle) {
738 break;
739 }
740 //
741 // Save the previous so we can connect the lists when we remove this one
742 //
743 PrevImageList = ImageList;
744 }
745
746 if (ImageList == NULL) {
747 return EFI_INVALID_PARAMETER;
748 }
749 //
750 // Free up all the thunk buffers and thunks list elements for this image
751 // handle.
752 //
753 ThunkList = ImageList->ThunkList;
754 while (ThunkList != NULL) {
755 NextThunkList = ThunkList->Next;
756 gBS->FreePool (ThunkList->ThunkBuffer);
757 gBS->FreePool (ThunkList);
758 ThunkList = NextThunkList;
759 }
760 //
761 // Now remove this image list element from the chain
762 //
763 if (PrevImageList == NULL) {
764 //
765 // Remove from head
766 //
767 mEbcImageList = ImageList->Next;
768 } else {
769 PrevImageList->Next = ImageList->Next;
770 }
771 //
772 // Now free up the image list element
773 //
774 gBS->FreePool (ImageList);
775 return EFI_SUCCESS;
776 }
777
778 EFI_STATUS
779 EbcAddImageThunk (
780 IN EFI_HANDLE ImageHandle,
781 IN VOID *ThunkBuffer,
782 IN UINT32 ThunkSize
783 )
784 /*++
785
786 Routine Description:
787
788 Add a thunk to our list of thunks for a given image handle.
789 Also flush the instruction cache since we've written thunk code
790 to memory that will be executed eventually.
791
792 Arguments:
793
794 ImageHandle - the image handle to which the thunk is tied
795 ThunkBuffer - the buffer we've created/allocated
796 ThunkSize - the size of the thunk memory allocated
797
798 Returns:
799
800 EFI_OUT_OF_RESOURCES - memory allocation failed
801 EFI_SUCCESS - successful completion
802
803 --*/
804 {
805 EBC_THUNK_LIST *ThunkList;
806 EBC_IMAGE_LIST *ImageList;
807 EFI_STATUS Status;
808
809 //
810 // It so far so good, then flush the instruction cache
811 //
812 if (mEbcICacheFlush != NULL) {
813 Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);
814 if (EFI_ERROR (Status)) {
815 return Status;
816 }
817 }
818 //
819 // Go through our list of known image handles and see if we've already
820 // created a image list element for this image handle.
821 //
822 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
823 if (ImageList->ImageHandle == ImageHandle) {
824 break;
825 }
826 }
827
828 if (ImageList == NULL) {
829 //
830 // Allocate a new one
831 //
832 Status = gBS->AllocatePool (
833 EfiBootServicesData,
834 sizeof (EBC_IMAGE_LIST),
835 (VOID **) &ImageList
836 );
837 if (Status != EFI_SUCCESS) {
838 return EFI_OUT_OF_RESOURCES;
839 }
840
841 ImageList->ThunkList = NULL;
842 ImageList->ImageHandle = ImageHandle;
843 ImageList->Next = mEbcImageList;
844 mEbcImageList = ImageList;
845 }
846 //
847 // Ok, now create a new thunk element to add to the list
848 //
849 Status = gBS->AllocatePool (
850 EfiBootServicesData,
851 sizeof (EBC_THUNK_LIST),
852 (VOID **) &ThunkList
853 );
854 if (Status != EFI_SUCCESS) {
855 return EFI_OUT_OF_RESOURCES;
856 }
857 //
858 // Add it to the head of the list
859 //
860 ThunkList->Next = ImageList->ThunkList;
861 ThunkList->ThunkBuffer = ThunkBuffer;
862 ImageList->ThunkList = ThunkList;
863 return EFI_SUCCESS;
864 }
865
866 STATIC
867 EFI_STATUS
868 EFIAPI
869 EbcRegisterICacheFlush (
870 IN EFI_EBC_PROTOCOL *This,
871 IN EBC_ICACHE_FLUSH Flush
872 )
873 {
874 mEbcICacheFlush = Flush;
875 return EFI_SUCCESS;
876 }
877
878 STATIC
879 EFI_STATUS
880 EFIAPI
881 EbcGetVersion (
882 IN EFI_EBC_PROTOCOL *This,
883 IN OUT UINT64 *Version
884 )
885 {
886 if (Version == NULL) {
887 return EFI_INVALID_PARAMETER;
888 }
889
890 *Version = GetVmVersion ();
891 return EFI_SUCCESS;
892 }
893
894 STATIC
895 EFI_STATUS
896 InitEbcVmTestProtocol (
897 IN EFI_HANDLE *IHandle
898 )
899 /*++
900
901 Routine Description:
902
903 Produce an EBC VM test protocol that can be used for regression tests.
904
905 Arguments:
906
907 IHandle - handle on which to install the protocol.
908
909 Returns:
910
911 EFI_OUT_OF_RESOURCES - memory allocation failed
912 EFI_SUCCESS - successful completion
913
914 --*/
915 {
916 EFI_HANDLE Handle;
917 EFI_STATUS Status;
918 EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;
919
920 //
921 // Allocate memory for the protocol, then fill in the fields
922 //
923 Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_EBC_VM_TEST_PROTOCOL), (VOID **) &EbcVmTestProtocol);
924 if (Status != EFI_SUCCESS) {
925 return EFI_OUT_OF_RESOURCES;
926 }
927 EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
928
929 DEBUG_CODE_BEGIN ();
930 EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
931 EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
932 DEBUG_CODE_END ();
933
934 //
935 // Publish the protocol
936 //
937 Handle = NULL;
938 Status = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
939 if (EFI_ERROR (Status)) {
940 gBS->FreePool (EbcVmTestProtocol);
941 }
942 return Status;
943 }
944 STATIC
945 EFI_STATUS
946 EbcVmTestUnsupported ()
947 {
948 return EFI_UNSUPPORTED;
949 }
950