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