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