]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EbcDxe/EbcInt.c
Improve coding style in MdeModulePkg.
[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 - 2010, Intel Corporation. <BR>
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "EbcInt.h"
18 #include "EbcExecute.h"
19
20 //
21 // We'll keep track of all thunks we create in a linked list. Each
22 // thunk is tied to an image handle, so we have a linked list of
23 // image handles, with each having a linked list of thunks allocated
24 // to that image handle.
25 //
26 typedef struct _EBC_THUNK_LIST 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 EbcVmTestUnsupported (
195 VOID
196 );
197
198 /**
199 Registers a callback function that the EBC interpreter calls to flush the
200 processor instruction cache following creation of thunks.
201
202 @param This A pointer to the EFI_EBC_PROTOCOL instance.
203 @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
204
205 @retval EFI_SUCCESS The function completed successfully.
206
207 **/
208 EFI_STATUS
209 EFIAPI
210 EbcRegisterICacheFlush (
211 IN EFI_EBC_PROTOCOL *This,
212 IN EBC_ICACHE_FLUSH Flush
213 );
214
215 /**
216 This EBC debugger protocol service is called by the debug agent
217
218 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
219 instance.
220 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
221 maximum supported processor index is returned.
222
223 @retval EFI_SUCCESS The function completed successfully.
224
225 **/
226 EFI_STATUS
227 EFIAPI
228 EbcDebugGetMaximumProcessorIndex (
229 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
230 OUT UINTN *MaxProcessorIndex
231 );
232
233 /**
234 This protocol service is called by the debug agent to register a function
235 for us to call on a periodic basis.
236
237 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
238 instance.
239 @param ProcessorIndex Specifies which processor the callback function
240 applies to.
241 @param PeriodicCallback A pointer to a function of type
242 PERIODIC_CALLBACK that is the main periodic
243 entry point of the debug agent. It receives as a
244 parameter a pointer to the full context of the
245 interrupted execution thread.
246
247 @retval EFI_SUCCESS The function completed successfully.
248 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
249 callback function was previously registered.
250 @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
251 callback function was previously registered.
252
253 **/
254 EFI_STATUS
255 EFIAPI
256 EbcDebugRegisterPeriodicCallback (
257 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
258 IN UINTN ProcessorIndex,
259 IN EFI_PERIODIC_CALLBACK PeriodicCallback
260 );
261
262 /**
263 This protocol service is called by the debug agent to register a function
264 for us to call when we detect an exception.
265
266 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
267 instance.
268 @param ProcessorIndex Specifies which processor the callback function
269 applies to.
270 @param ExceptionCallback A pointer to a function of type
271 EXCEPTION_CALLBACK that is called when the
272 processor exception specified by ExceptionType
273 occurs. Passing NULL unregisters any previously
274 registered function associated with
275 ExceptionType.
276 @param ExceptionType Specifies which processor exception to hook.
277
278 @retval EFI_SUCCESS The function completed successfully.
279 @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
280 callback function was previously registered.
281 @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
282 MAX_EBC_EXCEPTION.
283 @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
284 callback function was previously registered.
285
286 **/
287 EFI_STATUS
288 EFIAPI
289 EbcDebugRegisterExceptionCallback (
290 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
291 IN UINTN ProcessorIndex,
292 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
293 IN EFI_EXCEPTION_TYPE ExceptionType
294 );
295
296 /**
297 This EBC debugger protocol service is called by the debug agent. Required
298 for DebugSupport compliance but is only stubbed out for EBC.
299
300 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
301 instance.
302 @param ProcessorIndex Specifies which processor the callback function
303 applies to.
304 @param Start StartSpecifies the physical base of the memory
305 range to be invalidated.
306 @param Length Specifies the minimum number of bytes in the
307 processor's instruction cache to invalidate.
308
309 @retval EFI_SUCCESS The function completed successfully.
310
311 **/
312 EFI_STATUS
313 EFIAPI
314 EbcDebugInvalidateInstructionCache (
315 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
316 IN UINTN ProcessorIndex,
317 IN VOID *Start,
318 IN UINT64 Length
319 );
320
321 //
322 // We have one linked list of image handles for the whole world. Since
323 // there should only be one interpreter, make them global. They must
324 // also be global since the execution of an EBC image does not provide
325 // a This pointer.
326 //
327 EBC_IMAGE_LIST *mEbcImageList = NULL;
328
329 //
330 // Callback function to flush the icache after thunk creation
331 //
332 EBC_ICACHE_FLUSH mEbcICacheFlush;
333
334 //
335 // These get set via calls by the debug agent
336 //
337 EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;
338 EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};
339 EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;
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 = 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 = VmPtr->Gpr[0];
771 EbcContext.R1 = VmPtr->Gpr[1];
772 EbcContext.R2 = VmPtr->Gpr[2];
773 EbcContext.R3 = VmPtr->Gpr[3];
774 EbcContext.R4 = VmPtr->Gpr[4];
775 EbcContext.R5 = VmPtr->Gpr[5];
776 EbcContext.R6 = VmPtr->Gpr[6];
777 EbcContext.R7 = 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 deadloop here to make it easy to debug this issue.
879 //
880 ASSERT (FALSE);
881
882 return ;
883 }
884
885
886 /**
887 The periodic callback function for EBC VM interpreter, which is used
888 to support the EFI debug support protocol.
889
890 @param Event The Periodic Callback Event.
891 @param Context It should be the address of VM_CONTEXT pointer.
892
893 **/
894 VOID
895 EFIAPI
896 EbcPeriodicNotifyFunction (
897 IN EFI_EVENT Event,
898 IN VOID *Context
899 )
900 {
901 VM_CONTEXT *VmPtr;
902
903 VmPtr = *(VM_CONTEXT **)Context;
904
905 if (VmPtr != NULL) {
906 EbcDebugPeriodic (VmPtr);
907 }
908
909 return ;
910 }
911
912
913 /**
914 The VM interpreter calls this function on a periodic basis to support
915 the EFI debug support protocol.
916
917 @param VmPtr Pointer to a VM context for passing info to the
918 debugger.
919
920 @retval EFI_SUCCESS The function completed successfully.
921
922 **/
923 EFI_STATUS
924 EFIAPI
925 EbcDebugPeriodic (
926 IN VM_CONTEXT *VmPtr
927 )
928 {
929 EFI_SYSTEM_CONTEXT_EBC EbcContext;
930 EFI_SYSTEM_CONTEXT SystemContext;
931
932 //
933 // If someone's registered for periodic callbacks, then call them.
934 //
935 if (mDebugPeriodicCallback != NULL) {
936
937 //
938 // Initialize the context structure
939 //
940 EbcContext.R0 = VmPtr->Gpr[0];
941 EbcContext.R1 = VmPtr->Gpr[1];
942 EbcContext.R2 = VmPtr->Gpr[2];
943 EbcContext.R3 = VmPtr->Gpr[3];
944 EbcContext.R4 = VmPtr->Gpr[4];
945 EbcContext.R5 = VmPtr->Gpr[5];
946 EbcContext.R6 = VmPtr->Gpr[6];
947 EbcContext.R7 = VmPtr->Gpr[7];
948 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
949 EbcContext.Flags = VmPtr->Flags;
950 EbcContext.ControlFlags = 0;
951 SystemContext.SystemContextEbc = &EbcContext;
952
953 mDebugPeriodicCallback (SystemContext);
954
955 //
956 // Restore the context structure and continue to execute
957 //
958 VmPtr->Gpr[0] = EbcContext.R0;
959 VmPtr->Gpr[1] = EbcContext.R1;
960 VmPtr->Gpr[2] = EbcContext.R2;
961 VmPtr->Gpr[3] = EbcContext.R3;
962 VmPtr->Gpr[4] = EbcContext.R4;
963 VmPtr->Gpr[5] = EbcContext.R5;
964 VmPtr->Gpr[6] = EbcContext.R6;
965 VmPtr->Gpr[7] = EbcContext.R7;
966 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
967 VmPtr->Flags = EbcContext.Flags;
968 }
969
970 return EFI_SUCCESS;
971 }
972
973
974 /**
975 This routine is called by the core when an image is being unloaded from
976 memory. Basically we now have the opportunity to do any necessary cleanup.
977 Typically this will include freeing any memory allocated for thunk-creation.
978
979 @param This A pointer to the EFI_EBC_PROTOCOL instance.
980 @param ImageHandle Handle of image for which the thunk is being
981 created.
982
983 @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
984 internal list of EBC image handles.
985 @retval EFI_SUCCESS The function completed successfully.
986
987 **/
988 EFI_STATUS
989 EFIAPI
990 EbcUnloadImage (
991 IN EFI_EBC_PROTOCOL *This,
992 IN EFI_HANDLE ImageHandle
993 )
994 {
995 EBC_THUNK_LIST *ThunkList;
996 EBC_THUNK_LIST *NextThunkList;
997 EBC_IMAGE_LIST *ImageList;
998 EBC_IMAGE_LIST *PrevImageList;
999 //
1000 // First go through our list of known image handles and see if we've already
1001 // created an image list element for this image handle.
1002 //
1003 ReturnEBCStackByHandle(ImageHandle);
1004 PrevImageList = NULL;
1005 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
1006 if (ImageList->ImageHandle == ImageHandle) {
1007 break;
1008 }
1009 //
1010 // Save the previous so we can connect the lists when we remove this one
1011 //
1012 PrevImageList = ImageList;
1013 }
1014
1015 if (ImageList == NULL) {
1016 return EFI_INVALID_PARAMETER;
1017 }
1018 //
1019 // Free up all the thunk buffers and thunks list elements for this image
1020 // handle.
1021 //
1022 ThunkList = ImageList->ThunkList;
1023 while (ThunkList != NULL) {
1024 NextThunkList = ThunkList->Next;
1025 FreePool (ThunkList->ThunkBuffer);
1026 FreePool (ThunkList);
1027 ThunkList = NextThunkList;
1028 }
1029 //
1030 // Now remove this image list element from the chain
1031 //
1032 if (PrevImageList == NULL) {
1033 //
1034 // Remove from head
1035 //
1036 mEbcImageList = ImageList->Next;
1037 } else {
1038 PrevImageList->Next = ImageList->Next;
1039 }
1040 //
1041 // Now free up the image list element
1042 //
1043 FreePool (ImageList);
1044 return EFI_SUCCESS;
1045 }
1046
1047
1048 /**
1049 Add a thunk to our list of thunks for a given image handle.
1050 Also flush the instruction cache since we've written thunk code
1051 to memory that will be executed eventually.
1052
1053 @param ImageHandle The image handle to which the thunk is tied.
1054 @param ThunkBuffer The buffer that has been created/allocated.
1055 @param ThunkSize The size of the thunk memory allocated.
1056
1057 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1058 @retval EFI_SUCCESS The function completed successfully.
1059
1060 **/
1061 EFI_STATUS
1062 EbcAddImageThunk (
1063 IN EFI_HANDLE ImageHandle,
1064 IN VOID *ThunkBuffer,
1065 IN UINT32 ThunkSize
1066 )
1067 {
1068 EBC_THUNK_LIST *ThunkList;
1069 EBC_IMAGE_LIST *ImageList;
1070 EFI_STATUS Status;
1071
1072 //
1073 // It so far so good, then flush the instruction cache
1074 //
1075 if (mEbcICacheFlush != NULL) {
1076 Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);
1077 if (EFI_ERROR (Status)) {
1078 return Status;
1079 }
1080 }
1081 //
1082 // Go through our list of known image handles and see if we've already
1083 // created a image list element for this image handle.
1084 //
1085 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
1086 if (ImageList->ImageHandle == ImageHandle) {
1087 break;
1088 }
1089 }
1090
1091 if (ImageList == NULL) {
1092 //
1093 // Allocate a new one
1094 //
1095 ImageList = AllocatePool (sizeof (EBC_IMAGE_LIST));
1096
1097 if (ImageList == NULL) {
1098 return EFI_OUT_OF_RESOURCES;
1099 }
1100
1101 ImageList->ThunkList = NULL;
1102 ImageList->ImageHandle = ImageHandle;
1103 ImageList->Next = mEbcImageList;
1104 mEbcImageList = ImageList;
1105 }
1106 //
1107 // Ok, now create a new thunk element to add to the list
1108 //
1109 ThunkList = AllocatePool (sizeof (EBC_THUNK_LIST));
1110
1111 if (ThunkList == NULL) {
1112 return EFI_OUT_OF_RESOURCES;
1113 }
1114 //
1115 // Add it to the head of the list
1116 //
1117 ThunkList->Next = ImageList->ThunkList;
1118 ThunkList->ThunkBuffer = ThunkBuffer;
1119 ImageList->ThunkList = ThunkList;
1120 return EFI_SUCCESS;
1121 }
1122
1123 /**
1124 Registers a callback function that the EBC interpreter calls to flush the
1125 processor instruction cache following creation of thunks.
1126
1127 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1128 @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
1129
1130 @retval EFI_SUCCESS The function completed successfully.
1131
1132 **/
1133 EFI_STATUS
1134 EFIAPI
1135 EbcRegisterICacheFlush (
1136 IN EFI_EBC_PROTOCOL *This,
1137 IN EBC_ICACHE_FLUSH Flush
1138 )
1139 {
1140 mEbcICacheFlush = Flush;
1141 return EFI_SUCCESS;
1142 }
1143
1144 /**
1145 Called to get the version of the interpreter.
1146
1147 @param This A pointer to the EFI_EBC_PROTOCOL instance.
1148 @param Version Pointer to where to store the returned version
1149 of the interpreter.
1150
1151 @retval EFI_SUCCESS The function completed successfully.
1152 @retval EFI_INVALID_PARAMETER Version pointer is NULL.
1153
1154 **/
1155 EFI_STATUS
1156 EFIAPI
1157 EbcGetVersion (
1158 IN EFI_EBC_PROTOCOL *This,
1159 IN OUT UINT64 *Version
1160 )
1161 {
1162 if (Version == NULL) {
1163 return EFI_INVALID_PARAMETER;
1164 }
1165
1166 *Version = GetVmVersion ();
1167 return EFI_SUCCESS;
1168 }
1169
1170 /**
1171 Returns the stack index and buffer assosicated with the Handle parameter.
1172
1173 @param Handle The EFI handle as the index to the EBC stack.
1174 @param StackBuffer A pointer to hold the returned stack buffer.
1175 @param BufferIndex A pointer to hold the returned stack index.
1176
1177 @retval EFI_OUT_OF_RESOURCES The Handle parameter does not correspond to any
1178 existing EBC stack.
1179 @retval EFI_SUCCESS The stack index and buffer were found and
1180 returned to the caller.
1181
1182 **/
1183 EFI_STATUS
1184 GetEBCStack(
1185 IN EFI_HANDLE Handle,
1186 OUT VOID **StackBuffer,
1187 OUT UINTN *BufferIndex
1188 )
1189 {
1190 UINTN Index;
1191 EFI_TPL OldTpl;
1192 OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);
1193 for (Index = 0; Index < mStackNum; Index ++) {
1194 if (mStackBufferIndex[Index] == NULL) {
1195 mStackBufferIndex[Index] = Handle;
1196 break;
1197 }
1198 }
1199 gBS->RestoreTPL(OldTpl);
1200 if (Index == mStackNum) {
1201 return EFI_OUT_OF_RESOURCES;
1202 }
1203 *BufferIndex = Index;
1204 *StackBuffer = mStackBuffer[Index];
1205 return EFI_SUCCESS;
1206 }
1207
1208 /**
1209 Returns from the EBC stack by stack Index.
1210
1211 @param Index Specifies which EBC stack to return from.
1212
1213 @retval EFI_SUCCESS The function completed successfully.
1214
1215 **/
1216 EFI_STATUS
1217 ReturnEBCStack(
1218 IN UINTN Index
1219 )
1220 {
1221 mStackBufferIndex[Index] = NULL;
1222 return EFI_SUCCESS;
1223 }
1224
1225 /**
1226 Returns from the EBC stack associated with the Handle parameter.
1227
1228 @param Handle Specifies the EFI handle to find the EBC stack with.
1229
1230 @retval EFI_SUCCESS The function completed successfully.
1231
1232 **/
1233 EFI_STATUS
1234 ReturnEBCStackByHandle(
1235 IN EFI_HANDLE Handle
1236 )
1237 {
1238 UINTN Index;
1239 for (Index = 0; Index < mStackNum; Index ++) {
1240 if (mStackBufferIndex[Index] == Handle) {
1241 break;
1242 }
1243 }
1244 if (Index == mStackNum) {
1245 return EFI_NOT_FOUND;
1246 }
1247 mStackBufferIndex[Index] = NULL;
1248 return EFI_SUCCESS;
1249 }
1250
1251 /**
1252 Allocates memory to hold all the EBC stacks.
1253
1254 @retval EFI_SUCCESS The EBC stacks were allocated successfully.
1255 @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks.
1256
1257 **/
1258 EFI_STATUS
1259 InitEBCStack (
1260 VOID
1261 )
1262 {
1263 for (mStackNum = 0; mStackNum < MAX_STACK_NUM; mStackNum ++) {
1264 mStackBuffer[mStackNum] = AllocatePool(STACK_POOL_SIZE);
1265 mStackBufferIndex[mStackNum] = NULL;
1266 if (mStackBuffer[mStackNum] == NULL) {
1267 break;
1268 }
1269 }
1270 if (mStackNum == 0) {
1271 return EFI_OUT_OF_RESOURCES;
1272 }
1273 return EFI_SUCCESS;
1274 }
1275
1276
1277 /**
1278 Free all EBC stacks allocated before.
1279
1280 @retval EFI_SUCCESS All the EBC stacks were freed.
1281
1282 **/
1283 EFI_STATUS
1284 FreeEBCStack(
1285 VOID
1286 )
1287 {
1288 UINTN Index;
1289 for (Index = 0; Index < mStackNum; Index ++) {
1290 FreePool(mStackBuffer[Index]);
1291 }
1292 return EFI_SUCCESS;
1293 }
1294
1295 /**
1296 Produces an EBC VM test protocol that can be used for regression tests.
1297
1298 @param IHandle Handle on which to install the protocol.
1299
1300 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1301 @retval EFI_SUCCESS The function completed successfully.
1302
1303 **/
1304 EFI_STATUS
1305 InitEbcVmTestProtocol (
1306 IN EFI_HANDLE *IHandle
1307 )
1308 {
1309 EFI_HANDLE Handle;
1310 EFI_STATUS Status;
1311 EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;
1312
1313 //
1314 // Allocate memory for the protocol, then fill in the fields
1315 //
1316 EbcVmTestProtocol = AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL));
1317 if (EbcVmTestProtocol == NULL) {
1318 return EFI_OUT_OF_RESOURCES;
1319 }
1320 EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
1321
1322 DEBUG_CODE_BEGIN ();
1323 EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
1324 EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
1325 DEBUG_CODE_END ();
1326
1327 //
1328 // Publish the protocol
1329 //
1330 Handle = NULL;
1331 Status = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
1332 if (EFI_ERROR (Status)) {
1333 FreePool (EbcVmTestProtocol);
1334 }
1335 return Status;
1336 }
1337
1338
1339 /**
1340 Returns the EFI_UNSUPPORTED Status.
1341
1342 @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
1343
1344 **/
1345 EFI_STATUS
1346 EbcVmTestUnsupported (
1347 VOID
1348 )
1349 {
1350 return EFI_UNSUPPORTED;
1351 }
1352