ebcint.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,191 行 · 第 1/2 页

C
1,191
字号
}

EFI_STATUS
EbcDebugSignalException (
  IN EFI_EXCEPTION_TYPE                   ExceptionType,
  IN EXCEPTION_FLAGS                      ExceptionFlags,
  IN VM_CONTEXT                           *VmPtr
  )
/*++

Routine Description:

  The VM interpreter calls this function when an exception is detected.
  
Arguments:

  VmPtr - pointer to a VM context for passing info to the EFI debugger.

Returns:

  EFI_SUCCESS if it returns at all
  
--*/
{
  EFI_SYSTEM_CONTEXT_EBC  EbcContext;
  EFI_SYSTEM_CONTEXT      SystemContext;

  ASSERT ((ExceptionType >= 0) && (ExceptionType < EFI_EBC_EXCEPTION_NUMBER));

  //
  // Save the exception in the context passed in
  //
  VmPtr->ExceptionFlags |= ExceptionFlags;
  VmPtr->LastException = ExceptionType;
  //
  // If it's a fatal exception, then flag it in the VM context in case an
  // attached debugger tries to return from it.
  //
  if (ExceptionFlags & EXCEPTION_FLAG_FATAL) {
    VmPtr->StopFlags |= STOPFLAG_APP_DONE;
  }

  //
  // If someone's registered for exception callbacks, then call them.
  //
  // EBC driver will register default exception callback to report the
  // status code via the status code API
  //
  if (mDebugExceptionCallback[ExceptionType] != NULL) {

    //
    // Initialize the context structure
    //
    EbcContext.R0                   = VmPtr->R[0];
    EbcContext.R1                   = VmPtr->R[1];
    EbcContext.R2                   = VmPtr->R[2];
    EbcContext.R3                   = VmPtr->R[3];
    EbcContext.R4                   = VmPtr->R[4];
    EbcContext.R5                   = VmPtr->R[5];
    EbcContext.R6                   = VmPtr->R[6];
    EbcContext.R7                   = VmPtr->R[7];
    EbcContext.Ip                   = (UINT64)(UINTN)VmPtr->Ip;
    EbcContext.Flags                = VmPtr->Flags;
    EbcContext.ControlFlags         = 0;
    SystemContext.SystemContextEbc  = &EbcContext;

    mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);

    //
    // Restore the context structure and continue to execute
    //
    VmPtr->R[0]  = EbcContext.R0;
    VmPtr->R[1]  = EbcContext.R1;
    VmPtr->R[2]  = EbcContext.R2;
    VmPtr->R[3]  = EbcContext.R3;
    VmPtr->R[4]  = EbcContext.R4;
    VmPtr->R[5]  = EbcContext.R5;
    VmPtr->R[6]  = EbcContext.R6;
    VmPtr->R[7]  = EbcContext.R7;
    VmPtr->Ip    = (VMIP)(UINTN)EbcContext.Ip;
    VmPtr->Flags = EbcContext.Flags;
  }
  
  return EFI_SUCCESS;
}

EFI_STATUS
InitializeEbcCallback (
  IN EFI_DEBUG_SUPPORT_PROTOCOL  *This
  )
/*++

Routine Description:

  To install default Callback function for the VM interpreter.
  
Arguments:

  This - pointer to the instance of DebugSupport protocol

Returns:

  None
  
--*/
{
  INTN       Index;
  EFI_STATUS Status;

  //
  // For ExceptionCallback
  //
  for (Index = 0; Index < EFI_EBC_EXCEPTION_NUMBER; Index++) {
    EbcDebugRegisterExceptionCallback (
      This,
      0,
      CommonEbcExceptionHandler,
      Index
      );
  }

  //
  // For PeriodicCallback
  //
  Status = gBS->CreateEvent (
                  EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
                  EFI_TPL_NOTIFY,
                  EbcPeriodicNotifyFunction,
                  &mVmPtr,
                  &mEbcPeriodicEvent
                  );
  if (EFI_ERROR(Status)) {
    return Status;
  }

  Status = gBS->SetTimer (
                  mEbcPeriodicEvent,
                  TimerPeriodic,
                  EBC_VM_PERIODIC_CALLBACK_RATE
                  );
  if (EFI_ERROR(Status)) {
    return Status;
  }

  return EFI_SUCCESS;
}

VOID
CommonEbcExceptionHandler (
  IN EFI_EXCEPTION_TYPE   InterruptType,
  IN EFI_SYSTEM_CONTEXT   SystemContext
  )
/*++

Routine Description:

  The default Exception Callback for the VM interpreter.
  In this function, we report status code, and print debug information
  about EBC_CONTEXT, then dead loop.
  
Arguments:

  InterruptType - Interrupt type.
  SystemContext - EBC system context.

Returns:

  None
  
--*/
{
  //
  // We report all of exception by default,
  //
  EfiLibReportStatusCode (
    EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
    (EFI_STATUS_CODE_VALUE)(EFI_SOFTWARE_EBC_EXCEPTION | InterruptType),
    0,
    &gEfiEbcProtocolGuid,
    NULL
    );

  //
  // We print debug information to let user know what happen.
  //
  DEBUG ((
    EFI_D_ERROR,
    "EBC Interrupter Version - 0x%016lx\n",
    (UINT64) (((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)))
    ));
  DEBUG ((
    EFI_D_ERROR,
    "Exception Type - 0x%016lx\n",
    (UINT64)(UINTN)InterruptType
    ));
  DEBUG ((
    EFI_D_ERROR,
    "  R0 - 0x%016lx, R1 - 0x%016lx\n",
    SystemContext.SystemContextEbc->R0,
    SystemContext.SystemContextEbc->R1
    ));
  DEBUG ((
    EFI_D_ERROR,
    "  R2 - 0x%016lx, R3 - 0x%016lx\n",
    SystemContext.SystemContextEbc->R2,
    SystemContext.SystemContextEbc->R3
    ));
  DEBUG ((
    EFI_D_ERROR,
    "  R4 - 0x%016lx, R5 - 0x%016lx\n",
    SystemContext.SystemContextEbc->R4,
    SystemContext.SystemContextEbc->R5
    ));
  DEBUG ((
    EFI_D_ERROR,
    "  R6 - 0x%016lx, R7 - 0x%016lx\n",
    SystemContext.SystemContextEbc->R6,
    SystemContext.SystemContextEbc->R7
    ));
  DEBUG ((
    EFI_D_ERROR,
    "  Flags - 0x%016lx\n",
    SystemContext.SystemContextEbc->Flags
    ));
  DEBUG ((
    EFI_D_ERROR,
    "  ControlFlags - 0x%016lx\n",
    SystemContext.SystemContextEbc->ControlFlags
    ));
  DEBUG ((
    EFI_D_ERROR,
    "  Ip - 0x%016lx\n\n",
    SystemContext.SystemContextEbc->Ip
    ));

  //
  // We deadloop here to make it easy to debug this issue.
  //
  EFI_DEADLOOP ();

  return ;
}

VOID
EFIAPI
EbcPeriodicNotifyFunction (
  IN EFI_EVENT     Event,
  IN VOID          *Context
  )
/*++

Routine Description:

  The periodic callback function for EBC VM interpreter, which is used
  to support the EFI debug support protocol.
  
Arguments:

  Event   - The Periodic Callback Event.
  Context - It should be the address of VM_CONTEXT pointer.

Returns:

  None.
  
--*/
{
  VM_CONTEXT *VmPtr;

  VmPtr = *(VM_CONTEXT **)Context;

  if (VmPtr != NULL) {
    EbcDebugPeriodic (VmPtr);
  }

  return ;
}

EFI_STATUS
EbcDebugPeriodic (
  IN VM_CONTEXT *VmPtr
  )
/*++

Routine Description:

  The VM interpreter calls this function on a periodic basis to support
  the EFI debug support protocol.
  
Arguments:

  VmPtr - pointer to a VM context for passing info to the debugger.

Returns:

  Standard EFI status.
  
--*/
{
  EFI_SYSTEM_CONTEXT_EBC   EbcContext;
  EFI_SYSTEM_CONTEXT       SystemContext;
  
  //
  // If someone's registered for periodic callbacks, then call them.
  //
  if (mDebugPeriodicCallback != NULL) {

    //
    // Initialize the context structure
    //
    EbcContext.R0                   = VmPtr->R[0];
    EbcContext.R1                   = VmPtr->R[1];
    EbcContext.R2                   = VmPtr->R[2];
    EbcContext.R3                   = VmPtr->R[3];
    EbcContext.R4                   = VmPtr->R[4];
    EbcContext.R5                   = VmPtr->R[5];
    EbcContext.R6                   = VmPtr->R[6];
    EbcContext.R7                   = VmPtr->R[7];
    EbcContext.Ip                   = (UINT64)(UINTN)VmPtr->Ip;
    EbcContext.Flags                = VmPtr->Flags;
    EbcContext.ControlFlags         = 0;
    SystemContext.SystemContextEbc  = &EbcContext;

    mDebugPeriodicCallback (SystemContext);

    //
    // Restore the context structure and continue to execute
    //
    VmPtr->R[0]  = EbcContext.R0;
    VmPtr->R[1]  = EbcContext.R1;
    VmPtr->R[2]  = EbcContext.R2;
    VmPtr->R[3]  = EbcContext.R3;
    VmPtr->R[4]  = EbcContext.R4;
    VmPtr->R[5]  = EbcContext.R5;
    VmPtr->R[6]  = EbcContext.R6;
    VmPtr->R[7]  = EbcContext.R7;
    VmPtr->Ip    = (VMIP)(UINTN)EbcContext.Ip;
    VmPtr->Flags = EbcContext.Flags;
  }
  
  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
EFIAPI
EbcUnloadImage (
  IN EFI_EBC_PROTOCOL   *This,
  IN EFI_HANDLE         ImageHandle
  )
/*++

Routine Description:
  
  This routine is called by the core when an image is being unloaded from 
  memory. Basically we now have the opportunity to do any necessary cleanup.
  Typically this will include freeing any memory allocated for thunk-creation.

Arguments:

  This          - protocol instance pointer
  ImageHandle   - handle to the image being unloaded.

Returns:

  EFI_INVALID_PARAMETER  - the ImageHandle passed in was not found in
                           the internal list of EBC image handles.
  EFI_STATUS             - completed successfully

--*/
{
  EBC_THUNK_LIST  *ThunkList;
  EBC_THUNK_LIST  *NextThunkList;
  EBC_IMAGE_LIST  *ImageList;
  EBC_IMAGE_LIST  *PrevImageList;
  //
  // First go through our list of known image handles and see if we've already
  // created an image list element for this image handle.
  //
  PrevImageList = NULL;
  for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
    if (ImageList->ImageHandle == ImageHandle) {
      break;
    }
    //
    // Save the previous so we can connect the lists when we remove this one
    //
    PrevImageList = ImageList;
  }

  if (ImageList == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // Free up all the thunk buffers and thunks list elements for this image
  // handle.
  //
  ThunkList = ImageList->ThunkList;
  while (ThunkList != NULL) {
    NextThunkList = ThunkList->Next;
    gBS->FreePool (ThunkList->ThunkBuffer);
    gBS->FreePool (ThunkList);
    ThunkList = NextThunkList;
  }
  //
  // Now remove this image list element from the chain
  //
  if (PrevImageList == NULL) {
    //
    // Remove from head
    //
    mEbcImageList = ImageList->Next;
  } else {
    PrevImageList->Next = ImageList->Next;
  }
  //
  // Now free up the image list element
  //
  gBS->FreePool (ImageList);
  return EFI_SUCCESS;
}

EFI_STATUS
EbcAddImageThunk (
  IN EFI_HANDLE      ImageHandle,
  IN VOID            *ThunkBuffer,
  IN UINT32          ThunkSize
  )
/*++

Routine Description:
  
  Add a thunk to our list of thunks for a given image handle. 
  Also flush the instruction cache since we've written thunk code
  to memory that will be executed eventually.

Arguments:

  ImageHandle - the image handle to which the thunk is tied
  ThunkBuffer - the buffer we've created/allocated
  ThunkSize    - the size of the thunk memory allocated

Returns:
 
  EFI_OUT_OF_RESOURCES    - memory allocation failed
  EFI_SUCCESS             - successful completion

--*/
{
  EBC_THUNK_LIST  *ThunkList;
  EBC_IMAGE_LIST  *ImageList;
  EFI_STATUS      Status;

  //
  // It so far so good, then flush the instruction cache
  //
  if (mEbcICacheFlush != NULL) {
    Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);
    if (EFI_ERROR (Status)) {
      return Status;
    }
  }
  //
  // Go through our list of known image handles and see if we've already
  // created a image list element for this image handle.
  //
  for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
    if (ImageList->ImageHandle == ImageHandle) {
      break;
    }
  }

  if (ImageList == NULL) {
    //
    // Allocate a new one
    //
    Status = gBS->AllocatePool (
                    EfiBootServicesData,
                    sizeof (EBC_IMAGE_LIST),
                    (VOID **) &ImageList
                    );
    if (Status != EFI_SUCCESS) {
      return EFI_OUT_OF_RESOURCES;
    }

    ImageList->ThunkList    = NULL;
    ImageList->ImageHandle  = ImageHandle;
    ImageList->Next         = mEbcImageList;
    mEbcImageList           = ImageList;
  }
  //
  // Ok, now create a new thunk element to add to the list
  //
  Status = gBS->AllocatePool (
                  EfiBootServicesData,
                  sizeof (EBC_THUNK_LIST),
                  (VOID **) &ThunkList
                  );
  if (Status != EFI_SUCCESS) {
    return EFI_OUT_OF_RESOURCES;
  }
  //
  // Add it to the head of the list
  //
  ThunkList->Next         = ImageList->ThunkList;
  ThunkList->ThunkBuffer  = ThunkBuffer;
  ImageList->ThunkList    = ThunkList;
  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
EFIAPI
EbcRegisterICacheFlush (
  IN EFI_EBC_PROTOCOL   *This,
  IN EBC_ICACHE_FLUSH   Flush
  )
{
  mEbcICacheFlush = Flush;
  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
EFIAPI
EbcGetVersion (
  IN EFI_EBC_PROTOCOL   *This,
  IN OUT UINT64         *Version
  )
{
  if (Version == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  *Version = GetVmVersion ();
  return EFI_SUCCESS;
}

DEBUG_CODE (

STATIC
EFI_STATUS
InitEbcVmTestProtocol (
  IN EFI_HANDLE     *IHandle
  )
/*++

Routine Description:
  
  Produce an EBC VM test protocol that can be used for regression tests.

Arguments:

  IHandle - handle on which to install the protocol.

Returns:

  EFI_OUT_OF_RESOURCES  - memory allocation failed
  EFI_SUCCESS           - successful completion

--*/
{
  EFI_HANDLE Handle;
  EFI_STATUS Status;
  EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;

  //
  // Allocate memory for the protocol, then fill in the fields
  //
  Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_EBC_VM_TEST_PROTOCOL), (VOID **) &EbcVmTestProtocol);
  if (Status != EFI_SUCCESS) {
    return EFI_OUT_OF_RESOURCES;
  }
  EbcVmTestProtocol->Execute      = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
  EbcVmTestProtocol->Assemble     = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
  EbcVmTestProtocol->Disassemble  = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
  //
  // Publish the protocol
  //
  Handle  = NULL;
  Status  = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
  if (EFI_ERROR (Status)) {
    gBS->FreePool (EbcVmTestProtocol);
  }
  return Status;
}
STATIC
EFI_STATUS
EbcVmTestUnsupported ()
{
  return EFI_UNSUPPORTED;
}

) // end DEBUG_CODE

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?