]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EbcDxe/EbcInt.c
sync comments, fix function header, rename variable name to follow coding style.
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / EbcInt.c
1 /** @file
2 Top level module for the EBC virtual machine implementation.
3 Provides auxiliary support routines for the VM. That is, routines
4 that are not particularly related to VM execution of EBC instructions.
5
6 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "EbcInt.h"
18 #include "EbcExecute.h"
19
20 //
21 // We'll keep track of all thunks we create in a linked list. Each
22 // thunk is tied to an image handle, so we have a linked list of
23 // image handles, with each having a linked list of thunks allocated
24 // to that image handle.
25 //
26 typedef struct _EBC_THUNK_LIST {
27 VOID *ThunkBuffer;
28 struct _EBC_THUNK_LIST *Next;
29 } EBC_THUNK_LIST;
30
31 typedef struct _EBC_IMAGE_LIST {
32 struct _EBC_IMAGE_LIST *Next;
33 EFI_HANDLE ImageHandle;
34 EBC_THUNK_LIST *ThunkList;
35 } EBC_IMAGE_LIST;
36
37 /**
38 This routine is called by the core when an image is being unloaded from
39 memory. Basically we now have the opportunity to do any necessary cleanup.
40 Typically this will include freeing any memory allocated for thunk-creation.
41
42 @param This A pointer to the EFI_EBC_PROTOCOL instance.
43 @param ImageHandle Handle of image for which the thunk is being
44 created.
45
46 @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
47 internal list of EBC image handles.
48 @retval EFI_SUCCESS The function completed successfully.
49
50 **/
51 EFI_STATUS
52 EFIAPI
53 EbcUnloadImage (
54 IN EFI_EBC_PROTOCOL *This,
55 IN EFI_HANDLE ImageHandle
56 );
57
58 /**
59 This is the top-level routine plugged into the EBC protocol. Since thunks
60 are very processor-specific, from here we dispatch directly to the very
61 processor-specific routine EbcCreateThunks().
62
63 @param This A pointer to the EFI_EBC_PROTOCOL instance.
64 @param ImageHandle Handle of image for which the thunk is being
65 created. The EBC interpreter may use this to
66 keep track of any resource allocations
67 performed in loading and executing the image.
68 @param EbcEntryPoint Address of the actual EBC entry point or
69 protocol service the thunk should call.
70 @param Thunk Returned pointer to a thunk created.
71
72 @retval EFI_SUCCESS The function completed successfully.
73 @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
74 @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
75
76 **/
77 EFI_STATUS
78 EFIAPI
79 EbcCreateThunk (
80 IN EFI_EBC_PROTOCOL *This,
81 IN EFI_HANDLE ImageHandle,
82 IN VOID *EbcEntryPoint,
83 OUT VOID **Thunk
84 );
85
86 /**
87 Called to get the version of the interpreter.
88
89 @param This A pointer to the EFI_EBC_PROTOCOL instance.
90 @param Version Pointer to where to store the returned version
91 of the interpreter.
92
93 @retval EFI_SUCCESS The function completed successfully.
94 @retval EFI_INVALID_PARAMETER Version pointer is NULL.
95
96 **/
97 EFI_STATUS
98 EFIAPI
99 EbcGetVersion (
100 IN EFI_EBC_PROTOCOL *This,
101 IN OUT UINT64 *Version
102 );
103
104 /**
105 To install default Callback function for the VM interpreter.
106
107 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
108 instance.
109
110 @retval EFI_SUCCESS The function completed successfully.
111 @retval Others Some error occurs when creating periodic event.
112
113 **/
114 EFI_STATUS
115 EFIAPI
116 InitializeEbcCallback (
117 IN EFI_DEBUG_SUPPORT_PROTOCOL *This
118 );
119
120 /**
121 The default Exception Callback for the VM interpreter.
122 In this function, we report status code, and print debug information
123 about EBC_CONTEXT, then dead loop.
124
125 @param InterruptType Interrupt type.
126 @param SystemContext EBC system context.
127
128 **/
129 VOID
130 EFIAPI
131 CommonEbcExceptionHandler (
132 IN EFI_EXCEPTION_TYPE InterruptType,
133 IN EFI_SYSTEM_CONTEXT SystemContext
134 );
135
136 /**
137 The periodic callback function for EBC VM interpreter, which is used
138 to support the EFI debug support protocol.
139
140 @param Event The Periodic Callback Event.
141 @param Context It should be the address of VM_CONTEXT pointer.
142
143 **/
144 VOID
145 EFIAPI
146 EbcPeriodicNotifyFunction (
147 IN EFI_EVENT Event,
148 IN VOID *Context
149 );
150
151 /**
152 The VM interpreter calls this function on a periodic basis to support
153 the EFI debug support protocol.
154
155 @param VmPtr Pointer to a VM context for passing info to the
156 debugger.
157
158 @retval EFI_SUCCESS The function completed successfully.
159
160 **/
161 EFI_STATUS
162 EFIAPI
163 EbcDebugPeriodic (
164 IN VM_CONTEXT *VmPtr
165 );
166
167 //
168 // These two functions and the GUID are used to produce an EBC test protocol.
169 // This functionality is definitely not required for execution.
170 //
171 /**
172 Produces an EBC VM test protocol that can be used for regression tests.
173
174 @param IHandle Handle on which to install the protocol.
175
176 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
177 @retval EFI_SUCCESS The function completed successfully.
178
179 **/
180 EFI_STATUS
181 InitEbcVmTestProtocol (
182 IN EFI_HANDLE *IHandle
183 );
184
185 /**
186 Returns the EFI_UNSUPPORTED Status.
187
188 @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
189
190 **/
191 EFI_STATUS
192 EbcVmTestUnsupported (
193 VOID
194 );
195
196 /**
197 Registers a callback function that the EBC interpreter calls to flush the
198 processor instruction cache following creation of thunks.
199
200 @param This A pointer to the EFI_EBC_PROTOCOL instance.
201 @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
202
203 @retval EFI_SUCCESS The function completed successfully.
204
205 **/
206 EFI_STATUS
207 EFIAPI
208 EbcRegisterICacheFlush (
209 IN EFI_EBC_PROTOCOL *This,
210 IN EBC_ICACHE_FLUSH Flush
211 );
212
213 /**
214 This EBC debugger protocol service is called by the debug agent
215
216 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
217 instance.
218 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
219 maximum supported processor index is returned.
220
221 @retval EFI_SUCCESS The function completed successfully.
222
223 **/
224 EFI_STATUS
225 EFIAPI
226 EbcDebugGetMaximumProcessorIndex (
227 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
228 OUT UINTN *MaxProcessorIndex
229 );
230
231 /**
232 This protocol service is called by the debug agent to register a function
233 for us to call on a periodic basis.
234
235 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
236 instance.
237 @param ProcessorIndex Specifies which processor the callback function
238 applies to.
239 @param PeriodicCallback A pointer to a function of type
240 PERIODIC_CALLBACK that is the main periodic
241 entry point of the debug agent. It receives as a
242 parameter a pointer to the full context of the
243 interrupted execution thread.
244
245 @retval EFI_SUCCESS The function completed successfully.
246 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
247 callback function was previously registered.
248 @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
249 callback function was previously registered.
250
251 **/
252 EFI_STATUS
253 EFIAPI
254 EbcDebugRegisterPeriodicCallback (
255 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
256 IN UINTN ProcessorIndex,
257 IN EFI_PERIODIC_CALLBACK PeriodicCallback
258 );
259
260 /**
261 This protocol service is called by the debug agent to register a function
262 for us to call when we detect an exception.
263
264 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
265 instance.
266 @param ProcessorIndex Specifies which processor the callback function
267 applies to.
268 @param ExceptionCallback A pointer to a function of type
269 EXCEPTION_CALLBACK that is called when the
270 processor exception specified by ExceptionType
271 occurs. Passing NULL unregisters any previously
272 registered function associated with
273 ExceptionType.
274 @param ExceptionType Specifies which processor exception to hook.
275
276 @retval EFI_SUCCESS The function completed successfully.
277 @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
278 callback function was previously registered.
279 @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
280 MAX_EBC_EXCEPTION.
281 @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
282 callback function was previously registered.
283
284 **/
285 EFI_STATUS
286 EFIAPI
287 EbcDebugRegisterExceptionCallback (
288 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
289 IN UINTN ProcessorIndex,
290 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
291 IN EFI_EXCEPTION_TYPE ExceptionType
292 );
293
294 /**
295 This EBC debugger protocol service is called by the debug agent. Required
296 for DebugSupport compliance but is only stubbed out for EBC.
297
298 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
299 instance.
300 @param ProcessorIndex Specifies which processor the callback function
301 applies to.
302 @param Start StartSpecifies the physical base of the memory
303 range to be invalidated.
304 @param Length Specifies the minimum number of bytes in the
305 processor's instruction cache to invalidate.
306
307 @retval EFI_SUCCESS The function completed successfully.
308
309 **/
310 EFI_STATUS
311 EFIAPI
312 EbcDebugInvalidateInstructionCache (
313 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
314 IN UINTN ProcessorIndex,
315 IN VOID *Start,
316 IN UINT64 Length
317 );
318
319 //
320 // We have one linked list of image handles for the whole world. Since
321 // there should only be one interpreter, make them global. They must
322 // also be global since the execution of an EBC image does not provide
323 // a This pointer.
324 //
325 EBC_IMAGE_LIST *mEbcImageList = NULL;
326
327 //
328 // Callback function to flush the icache after thunk creation
329 //
330 EBC_ICACHE_FLUSH mEbcICacheFlush;
331
332 //
333 // These get set via calls by the debug agent
334 //
335 EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;
336 EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};
337 EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;
338
339 VOID *mStackBuffer[MAX_STACK_NUM];
340 EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];
341 UINTN mStackNum = 0;
342
343 //
344 // Event for Periodic callback
345 //
346 EFI_EVENT mEbcPeriodicEvent;
347 VM_CONTEXT *mVmPtr = NULL;
348
349
350 /**
351 Initializes the VM EFI interface. Allocates memory for the VM interface
352 and registers the VM protocol.
353
354 @param ImageHandle EFI image handle.
355 @param SystemTable Pointer to the EFI system table.
356
357 @return Standard EFI status code.
358
359 **/
360 EFI_STATUS
361 EFIAPI
362 InitializeEbcDriver (
363 IN EFI_HANDLE ImageHandle,
364 IN EFI_SYSTEM_TABLE *SystemTable
365 )
366 {
367 EFI_EBC_PROTOCOL *EbcProtocol;
368 EFI_EBC_PROTOCOL *OldEbcProtocol;
369 EFI_STATUS Status;
370 EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol;
371 EFI_HANDLE *HandleBuffer;
372 UINTN NumHandles;
373 UINTN Index;
374 BOOLEAN Installed;
375
376 EbcProtocol = NULL;
377 EbcDebugProtocol = NULL;
378
379 //
380 // Allocate memory for our protocol. Then fill in the blanks.
381 //
382 EbcProtocol = AllocatePool (sizeof (EFI_EBC_PROTOCOL));
383
384 if (EbcProtocol == NULL) {
385 return EFI_OUT_OF_RESOURCES;
386 }
387
388 EbcProtocol->CreateThunk = EbcCreateThunk;
389 EbcProtocol->UnloadImage = EbcUnloadImage;
390 EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush;
391 EbcProtocol->GetVersion = EbcGetVersion;
392 mEbcICacheFlush = NULL;
393
394 //
395 // Find any already-installed EBC protocols and uninstall them
396 //
397 Installed = FALSE;
398 HandleBuffer = NULL;
399 Status = gBS->LocateHandleBuffer (
400 ByProtocol,
401 &gEfiEbcProtocolGuid,
402 NULL,
403 &NumHandles,
404 &HandleBuffer
405 );
406 if (Status == EFI_SUCCESS) {
407 //
408 // Loop through the handles
409 //
410 for (Index = 0; Index < NumHandles; Index++) {
411 Status = gBS->HandleProtocol (
412 HandleBuffer[Index],
413 &gEfiEbcProtocolGuid,
414 (VOID **) &OldEbcProtocol
415 );
416 if (Status == EFI_SUCCESS) {
417 if (gBS->ReinstallProtocolInterface (
418 HandleBuffer[Index],
419 &gEfiEbcProtocolGuid,
420 OldEbcProtocol,
421 EbcProtocol
422 ) == EFI_SUCCESS) {
423 Installed = TRUE;
424 }
425 }
426 }
427 }
428
429 if (HandleBuffer != NULL) {
430 FreePool (HandleBuffer);
431 HandleBuffer = NULL;
432 }
433 //
434 // Add the protocol so someone can locate us if we haven't already.
435 //
436 if (!Installed) {
437 Status = gBS->InstallProtocolInterface (
438 &ImageHandle,
439 &gEfiEbcProtocolGuid,
440 EFI_NATIVE_INTERFACE,
441 EbcProtocol
442 );
443 if (EFI_ERROR (Status)) {
444 FreePool (EbcProtocol);
445 return Status;
446 }
447 }
448
449 Status = InitEBCStack();
450 if (EFI_ERROR(Status)) {
451 goto ErrorExit;
452 }
453
454 //
455 // Allocate memory for our debug protocol. Then fill in the blanks.
456 //
457 EbcDebugProtocol = AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL));
458
459 if (EbcDebugProtocol == NULL) {
460 goto ErrorExit;
461 }
462
463 EbcDebugProtocol->Isa = IsaEbc;
464 EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex;
465 EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback;
466 EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback;
467 EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache;
468
469 //
470 // Add the protocol so the debug agent can find us
471 //
472 Status = gBS->InstallProtocolInterface (
473 &ImageHandle,
474 &gEfiDebugSupportProtocolGuid,
475 EFI_NATIVE_INTERFACE,
476 EbcDebugProtocol
477 );
478 //
479 // This is recoverable, so free the memory and continue.
480 //
481 if (EFI_ERROR (Status)) {
482 FreePool (EbcDebugProtocol);
483 goto ErrorExit;
484 }
485 //
486 // Install EbcDebugSupport Protocol Successfully
487 // Now we need to initialize the Ebc default Callback
488 //
489 Status = InitializeEbcCallback (EbcDebugProtocol);
490
491 //
492 // Produce a VM test interface protocol. Not required for execution.
493 //
494 DEBUG_CODE_BEGIN ();
495 InitEbcVmTestProtocol (&ImageHandle);
496 DEBUG_CODE_END ();
497
498 return EFI_SUCCESS;
499
500 ErrorExit:
501 FreeEBCStack();
502 HandleBuffer = NULL;
503 Status = gBS->LocateHandleBuffer (
504 ByProtocol,
505 &gEfiEbcProtocolGuid,
506 NULL,
507 &NumHandles,
508 &HandleBuffer
509 );
510 if (Status == EFI_SUCCESS) {
511 //
512 // Loop through the handles
513 //
514 for (Index = 0; Index < NumHandles; Index++) {
515 Status = gBS->HandleProtocol (
516 HandleBuffer[Index],
517 &gEfiEbcProtocolGuid,
518 (VOID **) &OldEbcProtocol
519 );
520 if (Status == EFI_SUCCESS) {
521 gBS->UninstallProtocolInterface (
522 HandleBuffer[Index],
523 &gEfiEbcProtocolGuid,
524 OldEbcProtocol
525 );
526 }
527 }
528 }
529
530 if (HandleBuffer != NULL) {
531 FreePool (HandleBuffer);
532 HandleBuffer = NULL;
533 }
534
535 FreePool (EbcProtocol);
536
537 return Status;
538 }
539
540
541 /**
542 This is the top-level routine plugged into the EBC protocol. Since thunks
543 are very processor-specific, from here we dispatch directly to the very
544 processor-specific routine EbcCreateThunks().
545
546 @param This A pointer to the EFI_EBC_PROTOCOL instance.
547 @param ImageHandle Handle of image for which the thunk is being
548 created. The EBC interpreter may use this to
549 keep track of any resource allocations
550 performed in loading and executing the image.
551 @param EbcEntryPoint Address of the actual EBC entry point or
552 protocol service the thunk should call.
553 @param Thunk Returned pointer to a thunk created.
554
555 @retval EFI_SUCCESS The function completed successfully.
556 @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
557 @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
558
559 **/
560 EFI_STATUS
561 EFIAPI
562 EbcCreateThunk (
563 IN EFI_EBC_PROTOCOL *This,
564 IN EFI_HANDLE ImageHandle,
565 IN VOID *EbcEntryPoint,
566 OUT VOID **Thunk
567 )
568 {
569 EFI_STATUS Status;
570
571 Status = EbcCreateThunks (
572 ImageHandle,
573 EbcEntryPoint,
574 Thunk,
575 FLAG_THUNK_ENTRY_POINT
576 );
577 return Status;
578 }
579
580
581 /**
582 This EBC debugger protocol service is called by the debug agent
583
584 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
585 instance.
586 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
587 maximum supported processor index is returned.
588
589 @retval EFI_SUCCESS The function completed successfully.
590
591 **/
592 EFI_STATUS
593 EFIAPI
594 EbcDebugGetMaximumProcessorIndex (
595 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
596 OUT UINTN *MaxProcessorIndex
597 )
598 {
599 *MaxProcessorIndex = 0;
600 return EFI_SUCCESS;
601 }
602
603
604 /**
605 This protocol service is called by the debug agent to register a function
606 for us to call on a periodic basis.
607
608 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
609 instance.
610 @param ProcessorIndex Specifies which processor the callback function
611 applies to.
612 @param PeriodicCallback A pointer to a function of type
613 PERIODIC_CALLBACK that is the main periodic
614 entry point of the debug agent. It receives as a
615 parameter a pointer to the full context of the
616 interrupted execution thread.
617
618 @retval EFI_SUCCESS The function completed successfully.
619 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
620 callback function was previously registered.
621 @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
622 callback function was previously registered.
623
624 **/
625 EFI_STATUS
626 EFIAPI
627 EbcDebugRegisterPeriodicCallback (
628 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
629 IN UINTN ProcessorIndex,
630 IN EFI_PERIODIC_CALLBACK PeriodicCallback
631 )
632 {
633 if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {
634 return EFI_INVALID_PARAMETER;
635 }
636 if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {
637 return EFI_ALREADY_STARTED;
638 }
639
640 mDebugPeriodicCallback = PeriodicCallback;
641 return EFI_SUCCESS;
642 }
643
644
645 /**
646 This protocol service is called by the debug agent to register a function
647 for us to call when we detect an exception.
648
649 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
650 instance.
651 @param ProcessorIndex Specifies which processor the callback function
652 applies to.
653 @param ExceptionCallback A pointer to a function of type
654 EXCEPTION_CALLBACK that is called when the
655 processor exception specified by ExceptionType
656 occurs. Passing NULL unregisters any previously
657 registered function associated with
658 ExceptionType.
659 @param ExceptionType Specifies which processor exception to hook.
660
661 @retval EFI_SUCCESS The function completed successfully.
662 @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
663 callback function was previously registered.
664 @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
665 MAX_EBC_EXCEPTION.
666 @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
667 callback function was previously registered.
668
669 **/
670 EFI_STATUS
671 EFIAPI
672 EbcDebugRegisterExceptionCallback (
673 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
674 IN UINTN ProcessorIndex,
675 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
676 IN EFI_EXCEPTION_TYPE ExceptionType
677 )
678 {
679 if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {
680 return EFI_INVALID_PARAMETER;
681 }
682 if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {
683 return EFI_INVALID_PARAMETER;
684 }
685 if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {
686 return EFI_ALREADY_STARTED;
687 }
688 mDebugExceptionCallback[ExceptionType] = ExceptionCallback;
689 return EFI_SUCCESS;
690 }
691
692
693 /**
694 This EBC debugger protocol service is called by the debug agent. Required
695 for DebugSupport compliance but is only stubbed out for EBC.
696
697 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
698 instance.
699 @param ProcessorIndex Specifies which processor the callback function
700 applies to.
701 @param Start StartSpecifies the physical base of the memory
702 range to be invalidated.
703 @param Length Specifies the minimum number of bytes in the
704 processor's instruction cache to invalidate.
705
706 @retval EFI_SUCCESS The function completed successfully.
707
708 **/
709 EFI_STATUS
710 EFIAPI
711 EbcDebugInvalidateInstructionCache (
712 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
713 IN UINTN ProcessorIndex,
714 IN VOID *Start,
715 IN UINT64 Length
716 )
717 {
718 return EFI_SUCCESS;
719 }
720
721
722 /**
723 The VM interpreter calls this function when an exception is detected.
724
725 @param ExceptionType Specifies the processor exception detected.
726 @param ExceptionFlags Specifies the exception context.
727 @param VmPtr Pointer to a VM context for passing info to the
728 EFI debugger.
729
730 @retval EFI_SUCCESS This function completed successfully.
731
732 **/
733 EFI_STATUS
734 EbcDebugSignalException (
735 IN EFI_EXCEPTION_TYPE ExceptionType,
736 IN EXCEPTION_FLAGS ExceptionFlags,
737 IN VM_CONTEXT *VmPtr
738 )
739 {
740 EFI_SYSTEM_CONTEXT_EBC EbcContext;
741 EFI_SYSTEM_CONTEXT SystemContext;
742
743 ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));
744 //
745 // Save the exception in the context passed in
746 //
747 VmPtr->ExceptionFlags |= ExceptionFlags;
748 VmPtr->LastException = ExceptionType;
749 //
750 // If it's a fatal exception, then flag it in the VM context in case an
751 // attached debugger tries to return from it.
752 //
753 if ((ExceptionFlags & EXCEPTION_FLAG_FATAL) != 0) {
754 VmPtr->StopFlags |= STOPFLAG_APP_DONE;
755 }
756
757 //
758 // If someone's registered for exception callbacks, then call them.
759 //
760 // EBC driver will register default exception callback to report the
761 // status code via the status code API
762 //
763 if (mDebugExceptionCallback[ExceptionType] != NULL) {
764
765 //
766 // Initialize the context structure
767 //
768 EbcContext.R0 = VmPtr->R[0];
769 EbcContext.R1 = VmPtr->R[1];
770 EbcContext.R2 = VmPtr->R[2];
771 EbcContext.R3 = VmPtr->R[3];
772 EbcContext.R4 = VmPtr->R[4];
773 EbcContext.R5 = VmPtr->R[5];
774 EbcContext.R6 = VmPtr->R[6];
775 EbcContext.R7 = VmPtr->R[7];
776 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
777 EbcContext.Flags = VmPtr->Flags;
778 EbcContext.ControlFlags = 0;
779 SystemContext.SystemContextEbc = &EbcContext;
780
781 mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);
782 //
783 // Restore the context structure and continue to execute
784 //
785 VmPtr->R[0] = EbcContext.R0;
786 VmPtr->R[1] = EbcContext.R1;
787 VmPtr->R[2] = EbcContext.R2;
788 VmPtr->R[3] = EbcContext.R3;
789 VmPtr->R[4] = EbcContext.R4;
790 VmPtr->R[5] = EbcContext.R5;
791 VmPtr->R[6] = EbcContext.R6;
792 VmPtr->R[7] = EbcContext.R7;
793 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
794 VmPtr->Flags = EbcContext.Flags;
795 }
796
797 return EFI_SUCCESS;
798 }
799
800
801 /**
802 To install default Callback function for the VM interpreter.
803
804 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
805 instance.
806
807 @retval EFI_SUCCESS The function completed successfully.
808 @retval Others Some error occurs when creating periodic event.
809
810 **/
811 EFI_STATUS
812 EFIAPI
813 InitializeEbcCallback (
814 IN EFI_DEBUG_SUPPORT_PROTOCOL *This
815 )
816 {
817 INTN Index;
818 EFI_STATUS Status;
819
820 //
821 // For ExceptionCallback
822 //
823 for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {
824 EbcDebugRegisterExceptionCallback (
825 This,
826 0,
827 CommonEbcExceptionHandler,
828 Index
829 );
830 }
831
832 //
833 // For PeriodicCallback
834 //
835 Status = gBS->CreateEvent (
836 EVT_TIMER | EVT_NOTIFY_SIGNAL,
837 TPL_NOTIFY,
838 EbcPeriodicNotifyFunction,
839 &mVmPtr,
840 &mEbcPeriodicEvent
841 );
842 if (EFI_ERROR(Status)) {
843 return Status;
844 }
845
846 Status = gBS->SetTimer (
847 mEbcPeriodicEvent,
848 TimerPeriodic,
849 EBC_VM_PERIODIC_CALLBACK_RATE
850 );
851 if (EFI_ERROR(Status)) {
852 return Status;
853 }
854
855 return EFI_SUCCESS;
856 }
857
858
859 /**
860 The default Exception Callback for the VM interpreter.
861 In this function, we report status code, and print debug information
862 about EBC_CONTEXT, then dead loop.
863
864 @param InterruptType Interrupt type.
865 @param SystemContext EBC system context.
866
867 **/
868 VOID
869 EFIAPI
870 CommonEbcExceptionHandler (
871 IN EFI_EXCEPTION_TYPE InterruptType,
872 IN EFI_SYSTEM_CONTEXT SystemContext
873 )
874 {
875 //
876 // We deadloop here to make it easy to debug this issue.
877 //
878 ASSERT (FALSE);
879
880 return ;
881 }
882
883
884 /**
885 The periodic callback function for EBC VM interpreter, which is used
886 to support the EFI debug support protocol.
887
888 @param Event The Periodic Callback Event.
889 @param Context It should be the address of VM_CONTEXT pointer.
890
891 **/
892 VOID
893 EFIAPI
894 EbcPeriodicNotifyFunction (
895 IN EFI_EVENT Event,
896 IN VOID *Context
897 )
898 {
899 VM_CONTEXT *VmPtr;
900
901 VmPtr = *(VM_CONTEXT **)Context;
902
903 if (VmPtr != NULL) {
904 EbcDebugPeriodic (VmPtr);
905 }
906
907 return ;
908 }
909
910
911 /**
912 The VM interpreter calls this function on a periodic basis to support
913 the EFI debug support protocol.
914
915 @param VmPtr Pointer to a VM context for passing info to the
916 debugger.
917
918 @retval EFI_SUCCESS The function completed successfully.
919
920 **/
921 EFI_STATUS
922 EFIAPI
923 EbcDebugPeriodic (
924 IN VM_CONTEXT *VmPtr
925 )
926 {
927 EFI_SYSTEM_CONTEXT_EBC EbcContext;
928 EFI_SYSTEM_CONTEXT SystemContext;
929
930 //
931 // If someone's registered for periodic callbacks, then call them.
932 //
933 if (mDebugPeriodicCallback != NULL) {
934
935 //
936 // Initialize the context structure
937 //
938 EbcContext.R0 = VmPtr->R[0];
939 EbcContext.R1 = VmPtr->R[1];
940 EbcContext.R2 = VmPtr->R[2];
941 EbcContext.R3 = VmPtr->R[3];
942 EbcContext.R4 = VmPtr->R[4];
943 EbcContext.R5 = VmPtr->R[5];
944 EbcContext.R6 = VmPtr->R[6];
945 EbcContext.R7 = VmPtr->R[7];
946 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
947 EbcContext.Flags = VmPtr->Flags;
948 EbcContext.ControlFlags = 0;
949 SystemContext.SystemContextEbc = &EbcContext;
950
951 mDebugPeriodicCallback (SystemContext);
952
953 //
954 // Restore the context structure and continue to execute
955 //
956 VmPtr->R[0] = EbcContext.R0;
957 VmPtr->R[1] = EbcContext.R1;
958 VmPtr->R[2] = EbcContext.R2;
959 VmPtr->R[3] = EbcContext.R3;
960 VmPtr->R[4] = EbcContext.R4;
961 VmPtr->R[5] = EbcContext.R5;
962 VmPtr->R[6] = EbcContext.R6;
963 VmPtr->R[7] = EbcContext.R7;
964 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
965 VmPtr->Flags = EbcContext.Flags;
966 }
967
968 return EFI_SUCCESS;
969 }
970
971
972 /**
973 This routine is called by the core when an image is being unloaded from
974 memory. Basically we now have the opportunity to do any necessary cleanup.
975 Typically this will include freeing any memory allocated for thunk-creation.
976
977 @param This A pointer to the EFI_EBC_PROTOCOL instance.
978 @param ImageHandle Handle of image for which the thunk is being
979 created.
980
981 @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
982 internal list of EBC image handles.
983 @retval EFI_SUCCESS The function completed successfully.
984
985 **/
986 EFI_STATUS
987 EFIAPI
988 EbcUnloadImage (
989 IN EFI_EBC_PROTOCOL *This,
990 IN EFI_HANDLE ImageHandle
991 )
992 {
993 EBC_THUNK_LIST *ThunkList;
994 EBC_THUNK_LIST *NextThunkList;
995 EBC_IMAGE_LIST *ImageList;
996 EBC_IMAGE_LIST *PrevImageList;
997 //
998 // First go through our list of known image handles and see if we've already
999 // created an image list element for this image handle.
1000 //
1001 ReturnEBCStackByHandle(ImageHandle);
1002 PrevImageList = NULL;
1003 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
1004 if (ImageList->ImageHandle == ImageHandle) {
1005 break;
1006 }
1007 //
1008 // Save the previous so we can connect the lists when we remove this one
1009 //
1010 PrevImageList = ImageList;
1011 }
1012
1013 if (ImageList == NULL) {
1014 return EFI_INVALID_PARAMETER;
1015 }
1016 //
1017 // Free up all the thunk buffers and thunks list elements for this image
1018 // handle.
1019 //
1020 ThunkList = ImageList->ThunkList;
1021 while (ThunkList != NULL) {
1022 NextThunkList = ThunkList->Next;
1023 FreePool (ThunkList->ThunkBuffer);
1024 FreePool (ThunkList);
1025 ThunkList = NextThunkList;
1026 }
1027 //
1028 // Now remove this image list element from the chain
1029 //
1030 if (PrevImageList == NULL) {
1031 //
1032 // Remove from head
1033 //
1034 mEbcImageList = ImageList->Next;
1035 } else {
1036 PrevImageList->Next = ImageList->Next;
1037 }
1038 //
1039 // Now free up the image list element
1040 //
1041 FreePool (ImageList);
1042 return EFI_SUCCESS;
1043 }
1044
1045
1046 /**
1047 Add a thunk to our list of thunks for a given image handle.
1048 Also flush the instruction cache since we've written thunk code
1049 to memory that will be executed eventually.
1050
1051 @param ImageHandle The image handle to which the thunk is tied.
1052 @param ThunkBuffer The buffer that has been created/allocated.
1053 @param ThunkSize The size of the thunk memory allocated.
1054
1055 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1056 @retval EFI_SUCCESS The function completed successfully.
1057
1058 **/
1059 EFI_STATUS
1060 EbcAddImageThunk (
1061 IN EFI_HANDLE ImageHandle,
1062 IN VOID *ThunkBuffer,
1063 IN UINT32 ThunkSize
1064 )
1065 {
1066 EBC_THUNK_LIST *ThunkList;
1067 EBC_IMAGE_LIST *ImageList;
1068 EFI_STATUS Status;
1069
1070 //
1071 // It so far so good, then flush the instruction cache
1072 //
1073 if (mEbcICacheFlush != NULL) {
1074 Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);
1075 if (EFI_ERROR (Status)) {
1076 return Status;
1077 }
1078 }
1079 //
1080 // Go through our list of known image handles and see if we've already
1081 // created a image list element for this image handle.
1082 //
1083 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
1084 if (ImageList->ImageHandle == ImageHandle) {
1085 break;
1086 }
1087 }
1088
1089 if (ImageList == NULL) {
1090 //
1091 // Allocate a new one
1092 //
1093 ImageList = AllocatePool (sizeof (EBC_IMAGE_LIST));
1094
1095 if (ImageList == NULL) {
1096 return EFI_OUT_OF_RESOURCES;
1097 }
1098
1099 ImageList->ThunkList = NULL;
1100 ImageList->ImageHandle = ImageHandle;
1101 ImageList->Next = mEbcImageList;
1102 mEbcImageList = ImageList;
1103 }
1104 //
1105 // Ok, now create a new thunk element to add to the list
1106 //
1107 ThunkList = AllocatePool (sizeof (EBC_THUNK_LIST));
1108
1109 if (ThunkList == NULL) {
1110 return EFI_OUT_OF_RESOURCES;
1111 }
1112 //
1113 // Add it to the head of the list
1114 //
1115 ThunkList->Next = ImageList->ThunkList;
1116 ThunkList->ThunkBuffer = ThunkBuffer;
1117 ImageList->ThunkList = ThunkList;
1118 return EFI_SUCCESS;
1119 }
1120
1121 /**
1122 Registers a callback function that the EBC interpreter calls to flush the
1123 processor instruction cache following creation of thunks.
1124
1125 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1126 @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
1127
1128 @retval EFI_SUCCESS The function completed successfully.
1129
1130 **/
1131 EFI_STATUS
1132 EFIAPI
1133 EbcRegisterICacheFlush (
1134 IN EFI_EBC_PROTOCOL *This,
1135 IN EBC_ICACHE_FLUSH Flush
1136 )
1137 {
1138 mEbcICacheFlush = Flush;
1139 return EFI_SUCCESS;
1140 }
1141
1142 /**
1143 Called to get the version of the interpreter.
1144
1145 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1146 @param Version Pointer to where to store the returned version
1147 of the interpreter.
1148
1149 @retval EFI_SUCCESS The function completed successfully.
1150 @retval EFI_INVALID_PARAMETER Version pointer is NULL.
1151
1152 **/
1153 EFI_STATUS
1154 EFIAPI
1155 EbcGetVersion (
1156 IN EFI_EBC_PROTOCOL *This,
1157 IN OUT UINT64 *Version
1158 )
1159 {
1160 if (Version == NULL) {
1161 return EFI_INVALID_PARAMETER;
1162 }
1163
1164 *Version = GetVmVersion ();
1165 return EFI_SUCCESS;
1166 }
1167
1168 /**
1169 Returns the stack index and buffer assosicated with the Handle parameter.
1170
1171 @param Handle The EFI handle as the index to the EBC stack.
1172 @param StackBuffer A pointer to hold the returned stack buffer.
1173 @param BufferIndex A pointer to hold the returned stack index.
1174
1175 @retval EFI_OUT_OF_RESOURCES The Handle parameter does not correspond to any
1176 existing EBC stack.
1177 @retval EFI_SUCCESS The stack index and buffer were found and
1178 returned to the caller.
1179
1180 **/
1181 EFI_STATUS
1182 GetEBCStack(
1183 IN EFI_HANDLE Handle,
1184 OUT VOID **StackBuffer,
1185 OUT UINTN *BufferIndex
1186 )
1187 {
1188 UINTN Index;
1189 EFI_TPL OldTpl;
1190 OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);
1191 for (Index = 0; Index < mStackNum; Index ++) {
1192 if (mStackBufferIndex[Index] == NULL) {
1193 mStackBufferIndex[Index] = Handle;
1194 break;
1195 }
1196 }
1197 gBS->RestoreTPL(OldTpl);
1198 if (Index == mStackNum) {
1199 return EFI_OUT_OF_RESOURCES;
1200 }
1201 *BufferIndex = Index;
1202 *StackBuffer = mStackBuffer[Index];
1203 return EFI_SUCCESS;
1204 }
1205
1206 /**
1207 Returns from the EBC stack by stack Index.
1208
1209 @param Index Specifies which EBC stack to return from.
1210
1211 @retval EFI_SUCCESS The function completed successfully.
1212
1213 **/
1214 EFI_STATUS
1215 ReturnEBCStack(
1216 IN UINTN Index
1217 )
1218 {
1219 mStackBufferIndex[Index] = NULL;
1220 return EFI_SUCCESS;
1221 }
1222
1223 /**
1224 Returns from the EBC stack associated with the Handle parameter.
1225
1226 @param Handle Specifies the EFI handle to find the EBC stack with.
1227
1228 @retval EFI_SUCCESS The function completed successfully.
1229
1230 **/
1231 EFI_STATUS
1232 ReturnEBCStackByHandle(
1233 IN EFI_HANDLE Handle
1234 )
1235 {
1236 UINTN Index;
1237 for (Index = 0; Index < mStackNum; Index ++) {
1238 if (mStackBufferIndex[Index] == Handle) {
1239 break;
1240 }
1241 }
1242 if (Index == mStackNum) {
1243 return EFI_NOT_FOUND;
1244 }
1245 mStackBufferIndex[Index] = NULL;
1246 return EFI_SUCCESS;
1247 }
1248
1249 /**
1250 Allocates memory to hold all the EBC stacks.
1251
1252 @retval EFI_SUCCESS The EBC stacks were allocated successfully.
1253 @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks.
1254
1255 **/
1256 EFI_STATUS
1257 InitEBCStack (
1258 VOID
1259 )
1260 {
1261 for (mStackNum = 0; mStackNum < MAX_STACK_NUM; mStackNum ++) {
1262 mStackBuffer[mStackNum] = AllocatePool(STACK_POOL_SIZE);
1263 mStackBufferIndex[mStackNum] = NULL;
1264 if (mStackBuffer[mStackNum] == NULL) {
1265 break;
1266 }
1267 }
1268 if (mStackNum == 0) {
1269 return EFI_OUT_OF_RESOURCES;
1270 }
1271 return EFI_SUCCESS;
1272 }
1273
1274
1275 /**
1276 Free all EBC stacks allocated before.
1277
1278 @retval EFI_SUCCESS All the EBC stacks were freed.
1279
1280 **/
1281 EFI_STATUS
1282 FreeEBCStack(
1283 VOID
1284 )
1285 {
1286 UINTN Index;
1287 for (Index = 0; Index < mStackNum; Index ++) {
1288 FreePool(mStackBuffer[Index]);
1289 }
1290 return EFI_SUCCESS;
1291 }
1292
1293 /**
1294 Produces an EBC VM test protocol that can be used for regression tests.
1295
1296 @param IHandle Handle on which to install the protocol.
1297
1298 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1299 @retval EFI_SUCCESS The function completed successfully.
1300
1301 **/
1302 EFI_STATUS
1303 InitEbcVmTestProtocol (
1304 IN EFI_HANDLE *IHandle
1305 )
1306 {
1307 EFI_HANDLE Handle;
1308 EFI_STATUS Status;
1309 EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;
1310
1311 //
1312 // Allocate memory for the protocol, then fill in the fields
1313 //
1314 EbcVmTestProtocol = AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL));
1315 if (EbcVmTestProtocol == NULL) {
1316 return EFI_OUT_OF_RESOURCES;
1317 }
1318 EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
1319
1320 DEBUG_CODE_BEGIN ();
1321 EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
1322 EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
1323 DEBUG_CODE_END ();
1324
1325 //
1326 // Publish the protocol
1327 //
1328 Handle = NULL;
1329 Status = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
1330 if (EFI_ERROR (Status)) {
1331 FreePool (EbcVmTestProtocol);
1332 }
1333 return Status;
1334 }
1335
1336
1337 /**
1338 Returns the EFI_UNSUPPORTED Status.
1339
1340 @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
1341
1342 **/
1343 EFI_STATUS
1344 EbcVmTestUnsupported (
1345 VOID
1346 )
1347 {
1348 return EFI_UNSUPPORTED;
1349 }
1350