]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EbcDxe/EbcInt.c
MdeModulePkg/EbcDxe: rebase to ARRAY_SIZE()
[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 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 EBC_THUNK_LIST;
27 struct _EBC_THUNK_LIST {
28 VOID *ThunkBuffer;
29 EBC_THUNK_LIST *Next;
30 };
31
32 typedef struct _EBC_IMAGE_LIST EBC_IMAGE_LIST;
33 struct _EBC_IMAGE_LIST {
34 EBC_IMAGE_LIST *Next;
35 EFI_HANDLE ImageHandle;
36 EBC_THUNK_LIST *ThunkList;
37 };
38
39 /**
40 This routine is called by the core when an image is being unloaded from
41 memory. Basically we now have the opportunity to do any necessary cleanup.
42 Typically this will include freeing any memory allocated for thunk-creation.
43
44 @param This A pointer to the EFI_EBC_PROTOCOL instance.
45 @param ImageHandle Handle of image for which the thunk is being
46 created.
47
48 @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
49 internal list of EBC image handles.
50 @retval EFI_SUCCESS The function completed successfully.
51
52 **/
53 EFI_STATUS
54 EFIAPI
55 EbcUnloadImage (
56 IN EFI_EBC_PROTOCOL *This,
57 IN EFI_HANDLE ImageHandle
58 );
59
60 /**
61 This is the top-level routine plugged into the EBC protocol. Since thunks
62 are very processor-specific, from here we dispatch directly to the very
63 processor-specific routine EbcCreateThunks().
64
65 @param This A pointer to the EFI_EBC_PROTOCOL instance.
66 @param ImageHandle Handle of image for which the thunk is being
67 created. The EBC interpreter may use this to
68 keep track of any resource allocations
69 performed in loading and executing the image.
70 @param EbcEntryPoint Address of the actual EBC entry point or
71 protocol service the thunk should call.
72 @param Thunk Returned pointer to a thunk created.
73
74 @retval EFI_SUCCESS The function completed successfully.
75 @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
76 @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
77
78 **/
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 EFI_STATUS
100 EFIAPI
101 EbcGetVersion (
102 IN EFI_EBC_PROTOCOL *This,
103 IN OUT UINT64 *Version
104 );
105
106 /**
107 To install default Callback function for the VM interpreter.
108
109 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
110 instance.
111
112 @retval EFI_SUCCESS The function completed successfully.
113 @retval Others Some error occurs when creating periodic event.
114
115 **/
116 EFI_STATUS
117 EFIAPI
118 InitializeEbcCallback (
119 IN EFI_DEBUG_SUPPORT_PROTOCOL *This
120 );
121
122 /**
123 The default Exception Callback for the VM interpreter.
124 In this function, we report status code, and print debug information
125 about EBC_CONTEXT, then dead loop.
126
127 @param InterruptType Interrupt type.
128 @param SystemContext EBC system context.
129
130 **/
131 VOID
132 EFIAPI
133 CommonEbcExceptionHandler (
134 IN EFI_EXCEPTION_TYPE InterruptType,
135 IN EFI_SYSTEM_CONTEXT SystemContext
136 );
137
138 /**
139 The periodic callback function for EBC VM interpreter, which is used
140 to support the EFI debug support protocol.
141
142 @param Event The Periodic Callback Event.
143 @param Context It should be the address of VM_CONTEXT pointer.
144
145 **/
146 VOID
147 EFIAPI
148 EbcPeriodicNotifyFunction (
149 IN EFI_EVENT Event,
150 IN VOID *Context
151 );
152
153 /**
154 The VM interpreter calls this function on a periodic basis to support
155 the EFI debug support protocol.
156
157 @param VmPtr Pointer to a VM context for passing info to the
158 debugger.
159
160 @retval EFI_SUCCESS The function completed successfully.
161
162 **/
163 EFI_STATUS
164 EFIAPI
165 EbcDebugPeriodic (
166 IN VM_CONTEXT *VmPtr
167 );
168
169 //
170 // These two functions and the GUID are used to produce an EBC test protocol.
171 // This functionality is definitely not required for execution.
172 //
173 /**
174 Produces an EBC VM test protocol that can be used for regression tests.
175
176 @param IHandle Handle on which to install the protocol.
177
178 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
179 @retval EFI_SUCCESS The function completed successfully.
180
181 **/
182 EFI_STATUS
183 InitEbcVmTestProtocol (
184 IN EFI_HANDLE *IHandle
185 );
186
187 /**
188 Returns the EFI_UNSUPPORTED Status.
189
190 @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
191
192 **/
193 EFI_STATUS
194 EFIAPI
195 EbcVmTestUnsupported (
196 VOID
197 );
198
199 /**
200 Registers a callback function that the EBC interpreter calls to flush the
201 processor instruction cache following creation of thunks.
202
203 @param This A pointer to the EFI_EBC_PROTOCOL instance.
204 @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
205
206 @retval EFI_SUCCESS The function completed successfully.
207
208 **/
209 EFI_STATUS
210 EFIAPI
211 EbcRegisterICacheFlush (
212 IN EFI_EBC_PROTOCOL *This,
213 IN EBC_ICACHE_FLUSH Flush
214 );
215
216 /**
217 This EBC debugger protocol service is called by the debug agent
218
219 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
220 instance.
221 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
222 maximum supported processor index is returned.
223
224 @retval EFI_SUCCESS The function completed successfully.
225
226 **/
227 EFI_STATUS
228 EFIAPI
229 EbcDebugGetMaximumProcessorIndex (
230 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
231 OUT UINTN *MaxProcessorIndex
232 );
233
234 /**
235 This protocol service is called by the debug agent to register a function
236 for us to call on a periodic basis.
237
238 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
239 instance.
240 @param ProcessorIndex Specifies which processor the callback function
241 applies to.
242 @param PeriodicCallback A pointer to a function of type
243 PERIODIC_CALLBACK that is the main periodic
244 entry point of the debug agent. It receives as a
245 parameter a pointer to the full context of the
246 interrupted execution thread.
247
248 @retval EFI_SUCCESS The function completed successfully.
249 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
250 callback function was previously registered.
251 @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
252 callback function was previously registered.
253
254 **/
255 EFI_STATUS
256 EFIAPI
257 EbcDebugRegisterPeriodicCallback (
258 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
259 IN UINTN ProcessorIndex,
260 IN EFI_PERIODIC_CALLBACK PeriodicCallback
261 );
262
263 /**
264 This protocol service is called by the debug agent to register a function
265 for us to call when we detect an exception.
266
267 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
268 instance.
269 @param ProcessorIndex Specifies which processor the callback function
270 applies to.
271 @param ExceptionCallback A pointer to a function of type
272 EXCEPTION_CALLBACK that is called when the
273 processor exception specified by ExceptionType
274 occurs. Passing NULL unregisters any previously
275 registered function associated with
276 ExceptionType.
277 @param ExceptionType Specifies which processor exception to hook.
278
279 @retval EFI_SUCCESS The function completed successfully.
280 @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
281 callback function was previously registered.
282 @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
283 MAX_EBC_EXCEPTION.
284 @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
285 callback function was previously registered.
286
287 **/
288 EFI_STATUS
289 EFIAPI
290 EbcDebugRegisterExceptionCallback (
291 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
292 IN UINTN ProcessorIndex,
293 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
294 IN EFI_EXCEPTION_TYPE ExceptionType
295 );
296
297 /**
298 This EBC debugger protocol service is called by the debug agent. Required
299 for DebugSupport compliance but is only stubbed out for EBC.
300
301 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
302 instance.
303 @param ProcessorIndex Specifies which processor the callback function
304 applies to.
305 @param Start StartSpecifies the physical base of the memory
306 range to be invalidated.
307 @param Length Specifies the minimum number of bytes in the
308 processor's instruction cache to invalidate.
309
310 @retval EFI_SUCCESS The function completed successfully.
311
312 **/
313 EFI_STATUS
314 EFIAPI
315 EbcDebugInvalidateInstructionCache (
316 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
317 IN UINTN ProcessorIndex,
318 IN VOID *Start,
319 IN UINT64 Length
320 );
321
322 //
323 // We have one linked list of image handles for the whole world. Since
324 // there should only be one interpreter, make them global. They must
325 // also be global since the execution of an EBC image does not provide
326 // a This pointer.
327 //
328 EBC_IMAGE_LIST *mEbcImageList = NULL;
329
330 //
331 // Callback function to flush the icache after thunk creation
332 //
333 EBC_ICACHE_FLUSH mEbcICacheFlush;
334
335 //
336 // These get set via calls by the debug agent
337 //
338 EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;
339 EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};
340
341 VOID *mStackBuffer[MAX_STACK_NUM];
342 EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];
343 UINTN mStackNum = 0;
344
345 //
346 // Event for Periodic callback
347 //
348 EFI_EVENT mEbcPeriodicEvent;
349 VM_CONTEXT *mVmPtr = NULL;
350
351
352 /**
353 Initializes the VM EFI interface. Allocates memory for the VM interface
354 and registers the VM protocol.
355
356 @param ImageHandle EFI image handle.
357 @param SystemTable Pointer to the EFI system table.
358
359 @return Standard EFI status code.
360
361 **/
362 EFI_STATUS
363 EFIAPI
364 InitializeEbcDriver (
365 IN EFI_HANDLE ImageHandle,
366 IN EFI_SYSTEM_TABLE *SystemTable
367 )
368 {
369 EFI_EBC_PROTOCOL *EbcProtocol;
370 EFI_EBC_PROTOCOL *OldEbcProtocol;
371 EFI_STATUS Status;
372 EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol;
373 EFI_HANDLE *HandleBuffer;
374 UINTN NumHandles;
375 UINTN Index;
376 BOOLEAN Installed;
377
378 EbcProtocol = NULL;
379 EbcDebugProtocol = NULL;
380
381 //
382 // Allocate memory for our protocol. Then fill in the blanks.
383 //
384 EbcProtocol = AllocatePool (sizeof (EFI_EBC_PROTOCOL));
385
386 if (EbcProtocol == NULL) {
387 return EFI_OUT_OF_RESOURCES;
388 }
389
390 EbcProtocol->CreateThunk = EbcCreateThunk;
391 EbcProtocol->UnloadImage = EbcUnloadImage;
392 EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush;
393 EbcProtocol->GetVersion = EbcGetVersion;
394 mEbcICacheFlush = NULL;
395
396 //
397 // Find any already-installed EBC protocols and uninstall them
398 //
399 Installed = FALSE;
400 HandleBuffer = NULL;
401 Status = gBS->LocateHandleBuffer (
402 ByProtocol,
403 &gEfiEbcProtocolGuid,
404 NULL,
405 &NumHandles,
406 &HandleBuffer
407 );
408 if (Status == EFI_SUCCESS) {
409 //
410 // Loop through the handles
411 //
412 for (Index = 0; Index < NumHandles; Index++) {
413 Status = gBS->HandleProtocol (
414 HandleBuffer[Index],
415 &gEfiEbcProtocolGuid,
416 (VOID **) &OldEbcProtocol
417 );
418 if (Status == EFI_SUCCESS) {
419 if (gBS->ReinstallProtocolInterface (
420 HandleBuffer[Index],
421 &gEfiEbcProtocolGuid,
422 OldEbcProtocol,
423 EbcProtocol
424 ) == EFI_SUCCESS) {
425 Installed = TRUE;
426 }
427 }
428 }
429 }
430
431 if (HandleBuffer != NULL) {
432 FreePool (HandleBuffer);
433 HandleBuffer = NULL;
434 }
435 //
436 // Add the protocol so someone can locate us if we haven't already.
437 //
438 if (!Installed) {
439 Status = gBS->InstallProtocolInterface (
440 &ImageHandle,
441 &gEfiEbcProtocolGuid,
442 EFI_NATIVE_INTERFACE,
443 EbcProtocol
444 );
445 if (EFI_ERROR (Status)) {
446 FreePool (EbcProtocol);
447 return Status;
448 }
449 }
450
451 Status = InitEBCStack();
452 if (EFI_ERROR(Status)) {
453 goto ErrorExit;
454 }
455
456 //
457 // Allocate memory for our debug protocol. Then fill in the blanks.
458 //
459 EbcDebugProtocol = AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL));
460
461 if (EbcDebugProtocol == NULL) {
462 goto ErrorExit;
463 }
464
465 EbcDebugProtocol->Isa = IsaEbc;
466 EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex;
467 EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback;
468 EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback;
469 EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache;
470
471 //
472 // Add the protocol so the debug agent can find us
473 //
474 Status = gBS->InstallProtocolInterface (
475 &ImageHandle,
476 &gEfiDebugSupportProtocolGuid,
477 EFI_NATIVE_INTERFACE,
478 EbcDebugProtocol
479 );
480 //
481 // This is recoverable, so free the memory and continue.
482 //
483 if (EFI_ERROR (Status)) {
484 FreePool (EbcDebugProtocol);
485 goto ErrorExit;
486 }
487 //
488 // Install EbcDebugSupport Protocol Successfully
489 // Now we need to initialize the Ebc default Callback
490 //
491 Status = InitializeEbcCallback (EbcDebugProtocol);
492
493 //
494 // Produce a VM test interface protocol. Not required for execution.
495 //
496 DEBUG_CODE_BEGIN ();
497 InitEbcVmTestProtocol (&ImageHandle);
498 DEBUG_CODE_END ();
499
500 return EFI_SUCCESS;
501
502 ErrorExit:
503 FreeEBCStack();
504 HandleBuffer = NULL;
505 Status = gBS->LocateHandleBuffer (
506 ByProtocol,
507 &gEfiEbcProtocolGuid,
508 NULL,
509 &NumHandles,
510 &HandleBuffer
511 );
512 if (Status == EFI_SUCCESS) {
513 //
514 // Loop through the handles
515 //
516 for (Index = 0; Index < NumHandles; Index++) {
517 Status = gBS->HandleProtocol (
518 HandleBuffer[Index],
519 &gEfiEbcProtocolGuid,
520 (VOID **) &OldEbcProtocol
521 );
522 if (Status == EFI_SUCCESS) {
523 gBS->UninstallProtocolInterface (
524 HandleBuffer[Index],
525 &gEfiEbcProtocolGuid,
526 OldEbcProtocol
527 );
528 }
529 }
530 }
531
532 if (HandleBuffer != NULL) {
533 FreePool (HandleBuffer);
534 HandleBuffer = NULL;
535 }
536
537 FreePool (EbcProtocol);
538
539 return Status;
540 }
541
542
543 /**
544 This is the top-level routine plugged into the EBC protocol. Since thunks
545 are very processor-specific, from here we dispatch directly to the very
546 processor-specific routine EbcCreateThunks().
547
548 @param This A pointer to the EFI_EBC_PROTOCOL instance.
549 @param ImageHandle Handle of image for which the thunk is being
550 created. The EBC interpreter may use this to
551 keep track of any resource allocations
552 performed in loading and executing the image.
553 @param EbcEntryPoint Address of the actual EBC entry point or
554 protocol service the thunk should call.
555 @param Thunk Returned pointer to a thunk created.
556
557 @retval EFI_SUCCESS The function completed successfully.
558 @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
559 @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
560
561 **/
562 EFI_STATUS
563 EFIAPI
564 EbcCreateThunk (
565 IN EFI_EBC_PROTOCOL *This,
566 IN EFI_HANDLE ImageHandle,
567 IN VOID *EbcEntryPoint,
568 OUT VOID **Thunk
569 )
570 {
571 EFI_STATUS Status;
572
573 Status = EbcCreateThunks (
574 ImageHandle,
575 EbcEntryPoint,
576 Thunk,
577 FLAG_THUNK_ENTRY_POINT
578 );
579 return Status;
580 }
581
582
583 /**
584 This EBC debugger protocol service is called by the debug agent
585
586 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
587 instance.
588 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
589 maximum supported processor index is returned.
590
591 @retval EFI_SUCCESS The function completed successfully.
592
593 **/
594 EFI_STATUS
595 EFIAPI
596 EbcDebugGetMaximumProcessorIndex (
597 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
598 OUT UINTN *MaxProcessorIndex
599 )
600 {
601 *MaxProcessorIndex = 0;
602 return EFI_SUCCESS;
603 }
604
605
606 /**
607 This protocol service is called by the debug agent to register a function
608 for us to call on a periodic basis.
609
610 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
611 instance.
612 @param ProcessorIndex Specifies which processor the callback function
613 applies to.
614 @param PeriodicCallback A pointer to a function of type
615 PERIODIC_CALLBACK that is the main periodic
616 entry point of the debug agent. It receives as a
617 parameter a pointer to the full context of the
618 interrupted execution thread.
619
620 @retval EFI_SUCCESS The function completed successfully.
621 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
622 callback function was previously registered.
623 @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
624 callback function was previously registered.
625
626 **/
627 EFI_STATUS
628 EFIAPI
629 EbcDebugRegisterPeriodicCallback (
630 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
631 IN UINTN ProcessorIndex,
632 IN EFI_PERIODIC_CALLBACK PeriodicCallback
633 )
634 {
635 if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {
636 return EFI_INVALID_PARAMETER;
637 }
638 if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {
639 return EFI_ALREADY_STARTED;
640 }
641
642 mDebugPeriodicCallback = PeriodicCallback;
643 return EFI_SUCCESS;
644 }
645
646
647 /**
648 This protocol service is called by the debug agent to register a function
649 for us to call when we detect an exception.
650
651 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
652 instance.
653 @param ProcessorIndex Specifies which processor the callback function
654 applies to.
655 @param ExceptionCallback A pointer to a function of type
656 EXCEPTION_CALLBACK that is called when the
657 processor exception specified by ExceptionType
658 occurs. Passing NULL unregisters any previously
659 registered function associated with
660 ExceptionType.
661 @param ExceptionType Specifies which processor exception to hook.
662
663 @retval EFI_SUCCESS The function completed successfully.
664 @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
665 callback function was previously registered.
666 @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
667 MAX_EBC_EXCEPTION.
668 @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
669 callback function was previously registered.
670
671 **/
672 EFI_STATUS
673 EFIAPI
674 EbcDebugRegisterExceptionCallback (
675 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
676 IN UINTN ProcessorIndex,
677 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
678 IN EFI_EXCEPTION_TYPE ExceptionType
679 )
680 {
681 if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {
682 return EFI_INVALID_PARAMETER;
683 }
684 if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {
685 return EFI_INVALID_PARAMETER;
686 }
687 if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {
688 return EFI_ALREADY_STARTED;
689 }
690 mDebugExceptionCallback[ExceptionType] = ExceptionCallback;
691 return EFI_SUCCESS;
692 }
693
694
695 /**
696 This EBC debugger protocol service is called by the debug agent. Required
697 for DebugSupport compliance but is only stubbed out for EBC.
698
699 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
700 instance.
701 @param ProcessorIndex Specifies which processor the callback function
702 applies to.
703 @param Start StartSpecifies the physical base of the memory
704 range to be invalidated.
705 @param Length Specifies the minimum number of bytes in the
706 processor's instruction cache to invalidate.
707
708 @retval EFI_SUCCESS The function completed successfully.
709
710 **/
711 EFI_STATUS
712 EFIAPI
713 EbcDebugInvalidateInstructionCache (
714 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
715 IN UINTN ProcessorIndex,
716 IN VOID *Start,
717 IN UINT64 Length
718 )
719 {
720 return EFI_SUCCESS;
721 }
722
723
724 /**
725 The VM interpreter calls this function when an exception is detected.
726
727 @param ExceptionType Specifies the processor exception detected.
728 @param ExceptionFlags Specifies the exception context.
729 @param VmPtr Pointer to a VM context for passing info to the
730 EFI debugger.
731
732 @retval EFI_SUCCESS This function completed successfully.
733
734 **/
735 EFI_STATUS
736 EbcDebugSignalException (
737 IN EFI_EXCEPTION_TYPE ExceptionType,
738 IN EXCEPTION_FLAGS ExceptionFlags,
739 IN VM_CONTEXT *VmPtr
740 )
741 {
742 EFI_SYSTEM_CONTEXT_EBC EbcContext;
743 EFI_SYSTEM_CONTEXT SystemContext;
744
745 ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));
746 //
747 // Save the exception in the context passed in
748 //
749 VmPtr->ExceptionFlags |= ExceptionFlags;
750 VmPtr->LastException = (UINTN) ExceptionType;
751 //
752 // If it's a fatal exception, then flag it in the VM context in case an
753 // attached debugger tries to return from it.
754 //
755 if ((ExceptionFlags & EXCEPTION_FLAG_FATAL) != 0) {
756 VmPtr->StopFlags |= STOPFLAG_APP_DONE;
757 }
758
759 //
760 // If someone's registered for exception callbacks, then call them.
761 //
762 // EBC driver will register default exception callback to report the
763 // status code via the status code API
764 //
765 if (mDebugExceptionCallback[ExceptionType] != NULL) {
766
767 //
768 // Initialize the context structure
769 //
770 EbcContext.R0 = (UINT64) VmPtr->Gpr[0];
771 EbcContext.R1 = (UINT64) VmPtr->Gpr[1];
772 EbcContext.R2 = (UINT64) VmPtr->Gpr[2];
773 EbcContext.R3 = (UINT64) VmPtr->Gpr[3];
774 EbcContext.R4 = (UINT64) VmPtr->Gpr[4];
775 EbcContext.R5 = (UINT64) VmPtr->Gpr[5];
776 EbcContext.R6 = (UINT64) VmPtr->Gpr[6];
777 EbcContext.R7 = (UINT64) VmPtr->Gpr[7];
778 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
779 EbcContext.Flags = VmPtr->Flags;
780 EbcContext.ControlFlags = 0;
781 SystemContext.SystemContextEbc = &EbcContext;
782
783 mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);
784 //
785 // Restore the context structure and continue to execute
786 //
787 VmPtr->Gpr[0] = EbcContext.R0;
788 VmPtr->Gpr[1] = EbcContext.R1;
789 VmPtr->Gpr[2] = EbcContext.R2;
790 VmPtr->Gpr[3] = EbcContext.R3;
791 VmPtr->Gpr[4] = EbcContext.R4;
792 VmPtr->Gpr[5] = EbcContext.R5;
793 VmPtr->Gpr[6] = EbcContext.R6;
794 VmPtr->Gpr[7] = EbcContext.R7;
795 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
796 VmPtr->Flags = EbcContext.Flags;
797 }
798
799 return EFI_SUCCESS;
800 }
801
802
803 /**
804 To install default Callback function for the VM interpreter.
805
806 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
807 instance.
808
809 @retval EFI_SUCCESS The function completed successfully.
810 @retval Others Some error occurs when creating periodic event.
811
812 **/
813 EFI_STATUS
814 EFIAPI
815 InitializeEbcCallback (
816 IN EFI_DEBUG_SUPPORT_PROTOCOL *This
817 )
818 {
819 INTN Index;
820 EFI_STATUS Status;
821
822 //
823 // For ExceptionCallback
824 //
825 for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {
826 EbcDebugRegisterExceptionCallback (
827 This,
828 0,
829 CommonEbcExceptionHandler,
830 Index
831 );
832 }
833
834 //
835 // For PeriodicCallback
836 //
837 Status = gBS->CreateEvent (
838 EVT_TIMER | EVT_NOTIFY_SIGNAL,
839 TPL_NOTIFY,
840 EbcPeriodicNotifyFunction,
841 &mVmPtr,
842 &mEbcPeriodicEvent
843 );
844 if (EFI_ERROR(Status)) {
845 return Status;
846 }
847
848 Status = gBS->SetTimer (
849 mEbcPeriodicEvent,
850 TimerPeriodic,
851 EBC_VM_PERIODIC_CALLBACK_RATE
852 );
853 if (EFI_ERROR(Status)) {
854 return Status;
855 }
856
857 return EFI_SUCCESS;
858 }
859
860
861 /**
862 The default Exception Callback for the VM interpreter.
863 In this function, we report status code, and print debug information
864 about EBC_CONTEXT, then dead loop.
865
866 @param InterruptType Interrupt type.
867 @param SystemContext EBC system context.
868
869 **/
870 VOID
871 EFIAPI
872 CommonEbcExceptionHandler (
873 IN EFI_EXCEPTION_TYPE InterruptType,
874 IN EFI_SYSTEM_CONTEXT SystemContext
875 )
876 {
877 //
878 // We print debug information to let user know what happen.
879 //
880 DEBUG ((
881 EFI_D_ERROR,
882 "EBC Interrupter Version - 0x%016lx\n",
883 (UINT64) (((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)))
884 ));
885 DEBUG ((
886 EFI_D_ERROR,
887 "Exception Type - 0x%016lx\n",
888 (UINT64)(UINTN)InterruptType
889 ));
890 DEBUG ((
891 EFI_D_ERROR,
892 " R0 - 0x%016lx, R1 - 0x%016lx\n",
893 SystemContext.SystemContextEbc->R0,
894 SystemContext.SystemContextEbc->R1
895 ));
896 DEBUG ((
897 EFI_D_ERROR,
898 " R2 - 0x%016lx, R3 - 0x%016lx\n",
899 SystemContext.SystemContextEbc->R2,
900 SystemContext.SystemContextEbc->R3
901 ));
902 DEBUG ((
903 EFI_D_ERROR,
904 " R4 - 0x%016lx, R5 - 0x%016lx\n",
905 SystemContext.SystemContextEbc->R4,
906 SystemContext.SystemContextEbc->R5
907 ));
908 DEBUG ((
909 EFI_D_ERROR,
910 " R6 - 0x%016lx, R7 - 0x%016lx\n",
911 SystemContext.SystemContextEbc->R6,
912 SystemContext.SystemContextEbc->R7
913 ));
914 DEBUG ((
915 EFI_D_ERROR,
916 " Flags - 0x%016lx\n",
917 SystemContext.SystemContextEbc->Flags
918 ));
919 DEBUG ((
920 EFI_D_ERROR,
921 " ControlFlags - 0x%016lx\n",
922 SystemContext.SystemContextEbc->ControlFlags
923 ));
924 DEBUG ((
925 EFI_D_ERROR,
926 " Ip - 0x%016lx\n\n",
927 SystemContext.SystemContextEbc->Ip
928 ));
929
930 //
931 // We deadloop here to make it easy to debug this issue.
932 //
933 CpuDeadLoop ();
934
935 return ;
936 }
937
938
939 /**
940 The periodic callback function for EBC VM interpreter, which is used
941 to support the EFI debug support protocol.
942
943 @param Event The Periodic Callback Event.
944 @param Context It should be the address of VM_CONTEXT pointer.
945
946 **/
947 VOID
948 EFIAPI
949 EbcPeriodicNotifyFunction (
950 IN EFI_EVENT Event,
951 IN VOID *Context
952 )
953 {
954 VM_CONTEXT *VmPtr;
955
956 VmPtr = *(VM_CONTEXT **)Context;
957
958 if (VmPtr != NULL) {
959 EbcDebugPeriodic (VmPtr);
960 }
961
962 return ;
963 }
964
965
966 /**
967 The VM interpreter calls this function on a periodic basis to support
968 the EFI debug support protocol.
969
970 @param VmPtr Pointer to a VM context for passing info to the
971 debugger.
972
973 @retval EFI_SUCCESS The function completed successfully.
974
975 **/
976 EFI_STATUS
977 EFIAPI
978 EbcDebugPeriodic (
979 IN VM_CONTEXT *VmPtr
980 )
981 {
982 EFI_SYSTEM_CONTEXT_EBC EbcContext;
983 EFI_SYSTEM_CONTEXT SystemContext;
984
985 //
986 // If someone's registered for periodic callbacks, then call them.
987 //
988 if (mDebugPeriodicCallback != NULL) {
989
990 //
991 // Initialize the context structure
992 //
993 EbcContext.R0 = (UINT64) VmPtr->Gpr[0];
994 EbcContext.R1 = (UINT64) VmPtr->Gpr[1];
995 EbcContext.R2 = (UINT64) VmPtr->Gpr[2];
996 EbcContext.R3 = (UINT64) VmPtr->Gpr[3];
997 EbcContext.R4 = (UINT64) VmPtr->Gpr[4];
998 EbcContext.R5 = (UINT64) VmPtr->Gpr[5];
999 EbcContext.R6 = (UINT64) VmPtr->Gpr[6];
1000 EbcContext.R7 = (UINT64) VmPtr->Gpr[7];
1001 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
1002 EbcContext.Flags = VmPtr->Flags;
1003 EbcContext.ControlFlags = 0;
1004 SystemContext.SystemContextEbc = &EbcContext;
1005
1006 mDebugPeriodicCallback (SystemContext);
1007
1008 //
1009 // Restore the context structure and continue to execute
1010 //
1011 VmPtr->Gpr[0] = EbcContext.R0;
1012 VmPtr->Gpr[1] = EbcContext.R1;
1013 VmPtr->Gpr[2] = EbcContext.R2;
1014 VmPtr->Gpr[3] = EbcContext.R3;
1015 VmPtr->Gpr[4] = EbcContext.R4;
1016 VmPtr->Gpr[5] = EbcContext.R5;
1017 VmPtr->Gpr[6] = EbcContext.R6;
1018 VmPtr->Gpr[7] = EbcContext.R7;
1019 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
1020 VmPtr->Flags = EbcContext.Flags;
1021 }
1022
1023 return EFI_SUCCESS;
1024 }
1025
1026
1027 /**
1028 This routine is called by the core when an image is being unloaded from
1029 memory. Basically we now have the opportunity to do any necessary cleanup.
1030 Typically this will include freeing any memory allocated for thunk-creation.
1031
1032 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1033 @param ImageHandle Handle of image for which the thunk is being
1034 created.
1035
1036 @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
1037 internal list of EBC image handles.
1038 @retval EFI_SUCCESS The function completed successfully.
1039
1040 **/
1041 EFI_STATUS
1042 EFIAPI
1043 EbcUnloadImage (
1044 IN EFI_EBC_PROTOCOL *This,
1045 IN EFI_HANDLE ImageHandle
1046 )
1047 {
1048 EBC_THUNK_LIST *ThunkList;
1049 EBC_THUNK_LIST *NextThunkList;
1050 EBC_IMAGE_LIST *ImageList;
1051 EBC_IMAGE_LIST *PrevImageList;
1052 //
1053 // First go through our list of known image handles and see if we've already
1054 // created an image list element for this image handle.
1055 //
1056 ReturnEBCStackByHandle(ImageHandle);
1057 PrevImageList = NULL;
1058 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
1059 if (ImageList->ImageHandle == ImageHandle) {
1060 break;
1061 }
1062 //
1063 // Save the previous so we can connect the lists when we remove this one
1064 //
1065 PrevImageList = ImageList;
1066 }
1067
1068 if (ImageList == NULL) {
1069 return EFI_INVALID_PARAMETER;
1070 }
1071 //
1072 // Free up all the thunk buffers and thunks list elements for this image
1073 // handle.
1074 //
1075 ThunkList = ImageList->ThunkList;
1076 while (ThunkList != NULL) {
1077 NextThunkList = ThunkList->Next;
1078 FreePool (ThunkList->ThunkBuffer);
1079 FreePool (ThunkList);
1080 ThunkList = NextThunkList;
1081 }
1082 //
1083 // Now remove this image list element from the chain
1084 //
1085 if (PrevImageList == NULL) {
1086 //
1087 // Remove from head
1088 //
1089 mEbcImageList = ImageList->Next;
1090 } else {
1091 PrevImageList->Next = ImageList->Next;
1092 }
1093 //
1094 // Now free up the image list element
1095 //
1096 FreePool (ImageList);
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