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