summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c
new file mode 100644
index 00000000..93eeff84
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c
@@ -0,0 +1,303 @@
+/** @file
+ PE/Coff Extra Action library instances.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PeCoffExtraActionLib.h>
+
+#ifdef VBOX
+#include "VBoxPkg.h"
+#include "../../../../DevEFI.h"
+
+
+
+static void vboxImageEvtU64(uint32_t uCmd, uint64_t uValue)
+{
+ RTUINT64U u; /* 64-bit shift builtins. */
+ u.u = uValue;
+ ASMOutU32(EFI_PORT_IMAGE_EVENT, EFI_IMAGE_EVT_MAKE(uCmd, u.au16[3]));
+ ASMOutU32(EFI_PORT_IMAGE_EVENT, EFI_IMAGE_EVT_MAKE(uCmd, u.au16[2]));
+ ASMOutU32(EFI_PORT_IMAGE_EVENT, EFI_IMAGE_EVT_MAKE(uCmd, u.au16[1]));
+ ASMOutU32(EFI_PORT_IMAGE_EVENT, EFI_IMAGE_EVT_MAKE(uCmd, u.au16[0]));
+}
+
+static void vboxImageEvtString(uint32_t uCmd, const char *pszName)
+{
+ unsigned char uch;
+ while ((uch = *pszName++) != '\0')
+ ASMOutU32(EFI_PORT_IMAGE_EVENT, EFI_IMAGE_EVT_MAKE(uCmd, uch));
+}
+
+static void vboxImageEvtEmitOne(PE_COFF_LOADER_IMAGE_CONTEXT const *pImageCtx, uint32_t uEvt)
+{
+ ASMOutU32(EFI_PORT_IMAGE_EVENT, uEvt);
+ if (pImageCtx->DestinationAddress)
+ vboxImageEvtU64(EFI_IMAGE_EVT_CMD_ADDR0, pImageCtx->DestinationAddress);
+ else
+ vboxImageEvtU64(EFI_IMAGE_EVT_CMD_ADDR0, pImageCtx->ImageAddress);
+ vboxImageEvtU64(EFI_IMAGE_EVT_CMD_SIZE0, pImageCtx->ImageSize);
+ if (pImageCtx->PdbPointer)
+ vboxImageEvtString(EFI_IMAGE_EVT_CMD_NAME, pImageCtx->PdbPointer);
+ ASMOutU32(EFI_PORT_IMAGE_EVENT, EFI_IMAGE_EVT_CMD_COMPLETE);
+}
+#endif
+
+
+#ifdef VBOX_SOURCE_DEBUG_ENABLE
+/**
+ Check if the hardware breakpoint in Drx is enabled by checking the Lx and Gx bit in Dr7.
+
+ It assumes that DebugAgent will set both Lx and Gx bit when setting up the hardware breakpoint.
+
+
+ @param RegisterIndex Index of Dr register. The value range is from 0 to 3.
+ @param Dr7 Value of Dr7 register.
+
+ @return TRUE The hardware breakpoint specified in the Drx is enabled.
+ @return FALSE The hardware breakpoint specified in the Drx is disabled.
+
+**/
+BOOLEAN
+IsDrxEnabled (
+ IN UINT8 RegisterIndex,
+ IN UINTN Dr7
+ )
+{
+ return (BOOLEAN) (((Dr7 >> (RegisterIndex * 2)) & (BIT0 | BIT1)) == (BIT0 | BIT1));
+}
+
+/**
+ Common routine to report the PE/COFF image loading/relocating or unloading event.
+
+ If ImageContext is NULL, then ASSERT().
+
+ @param ImageContext Pointer to the image context structure that describes the
+ PE/COFF image.
+ @param Signature IMAGE_LOAD_SIGNATURE or IMAGE_UNLOAD_SIGNATURE.
+
+**/
+VOID
+PeCoffLoaderExtraActionCommon (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN UINTN Signature
+ )
+{
+ BOOLEAN InterruptState;
+ UINTN Dr0;
+ UINTN Dr1;
+ UINTN Dr2;
+ UINTN Dr3;
+ UINTN Dr7;
+ UINTN Cr4;
+ UINTN NewDr7;
+ UINT8 LoadImageMethod;
+ UINT8 DebugAgentStatus;
+ IA32_DESCRIPTOR IdtDescriptor;
+ IA32_IDT_GATE_DESCRIPTOR OriginalIdtEntry;
+ BOOLEAN IdtEntryHooked;
+ UINT32 RegEdx;
+
+ ASSERT (ImageContext != NULL);
+
+ if (ImageContext->PdbPointer != NULL) {
+ DEBUG((EFI_D_ERROR, " PDB = %a\n", ImageContext->PdbPointer));
+ }
+
+ //
+ // Disable interrupts and save the current interrupt state
+ //
+ InterruptState = SaveAndDisableInterrupts ();
+
+ IdtEntryHooked = FALSE;
+ LoadImageMethod = PcdGet8 (PcdDebugLoadImageMethod);
+ if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) {
+ //
+ // If the CPU does not support Debug Extensions(CPUID:01 EDX:BIT2)
+ // then force use of DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3
+ //
+ AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT2) == 0) {
+ LoadImageMethod = DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3;
+ }
+ }
+ AsmReadIdtr (&IdtDescriptor);
+ if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) {
+ if (!CheckDebugAgentHandler (&IdtDescriptor, SOFT_INT_VECTOR_NUM)) {
+ //
+ // Do not trigger INT3 if Debug Agent did not setup IDT entries.
+ //
+ return;
+ }
+ } else {
+ if (!CheckDebugAgentHandler (&IdtDescriptor, IO_HW_BREAKPOINT_VECTOR_NUM)) {
+ //
+ // Save and update IDT entry for INT1
+ //
+ SaveAndUpdateIdtEntry1 (&IdtDescriptor, &OriginalIdtEntry);
+ IdtEntryHooked = TRUE;
+ }
+ }
+
+ //
+ // Save Debug Register State
+ //
+ Dr0 = AsmReadDr0 ();
+ Dr1 = AsmReadDr1 ();
+ Dr2 = AsmReadDr2 ();
+ Dr3 = AsmReadDr3 ();
+ Dr7 = AsmReadDr7 () | BIT10; // H/w sets bit 10, some simulators don't
+ Cr4 = AsmReadCr4 ();
+
+ //
+ // DR0 = Signature
+ // DR1 = The address of the Null-terminated ASCII string for the PE/COFF image's PDB file name
+ // DR2 = The pointer to the ImageContext structure
+ // DR3 = IO_PORT_BREAKPOINT_ADDRESS
+ // DR7 = Disables all HW breakpoints except for DR3 I/O port access of length 1 byte
+ // CR4 = Make sure DE(BIT3) is set
+ //
+ AsmWriteDr7 (BIT10);
+ AsmWriteDr0 (Signature);
+ AsmWriteDr1 ((UINTN) ImageContext->PdbPointer);
+ AsmWriteDr2 ((UINTN) ImageContext);
+ AsmWriteDr3 (IO_PORT_BREAKPOINT_ADDRESS);
+
+ if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) {
+ AsmWriteDr7 (0x20000480);
+ AsmWriteCr4 (Cr4 | BIT3);
+ //
+ // Do an IN from IO_PORT_BREAKPOINT_ADDRESS to generate a HW breakpoint until the port
+ // returns a read value other than DEBUG_AGENT_IMAGE_WAIT
+ //
+ do {
+ DebugAgentStatus = IoRead8 (IO_PORT_BREAKPOINT_ADDRESS);
+ } while (DebugAgentStatus == DEBUG_AGENT_IMAGE_WAIT);
+
+ } else if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) {
+ //
+ // Generate a software break point.
+ //
+ CpuBreakpoint ();
+ }
+
+ //
+ // Restore Debug Register State only when Host didn't change it inside exception handler.
+ // E.g.: User halts the target and sets the HW breakpoint while target is
+ // in the above exception handler
+ //
+ NewDr7 = AsmReadDr7 () | BIT10; // H/w sets bit 10, some simulators don't
+ if (!IsDrxEnabled (0, NewDr7) && (AsmReadDr0 () == 0 || AsmReadDr0 () == Signature)) {
+ //
+ // If user changed Dr3 (by setting HW bp in the above exception handler,
+ // we will not set Dr0 to 0 in GO/STEP handler because the break cause is not IMAGE_LOAD/_UNLOAD.
+ //
+ AsmWriteDr0 (Dr0);
+ }
+ if (!IsDrxEnabled (1, NewDr7) && (AsmReadDr1 () == (UINTN) ImageContext->PdbPointer)) {
+ AsmWriteDr1 (Dr1);
+ }
+ if (!IsDrxEnabled (2, NewDr7) && (AsmReadDr2 () == (UINTN) ImageContext)) {
+ AsmWriteDr2 (Dr2);
+ }
+ if (!IsDrxEnabled (3, NewDr7) && (AsmReadDr3 () == IO_PORT_BREAKPOINT_ADDRESS)) {
+ AsmWriteDr3 (Dr3);
+ }
+ if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) {
+ if (AsmReadCr4 () == (Cr4 | BIT3)) {
+ AsmWriteCr4 (Cr4);
+ }
+ if (NewDr7 == 0x20000480) {
+ AsmWriteDr7 (Dr7);
+ }
+ } else if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) {
+ if (NewDr7 == BIT10) {
+ AsmWriteDr7 (Dr7);
+ }
+ }
+ //
+ // Restore original IDT entry for INT1 if it was hooked.
+ //
+ if (IdtEntryHooked) {
+ RestoreIdtEntry1 (&IdtDescriptor, &OriginalIdtEntry);
+ }
+ //
+ // Restore the interrupt state
+ //
+ SetInterruptState (InterruptState);
+}
+#endif
+
+/**
+ Performs additional actions after a PE/COFF image has been loaded and relocated.
+
+ @param ImageContext Pointer to the image context structure that describes the
+ PE/COFF image that has already been loaded and relocated.
+
+**/
+VOID
+EFIAPI
+PeCoffLoaderRelocateImageExtraAction (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+#ifdef VBOX_SOURCE_DEBUG_ENABLE
+ PeCoffLoaderExtraActionCommon (ImageContext, IMAGE_LOAD_SIGNATURE);
+#endif
+
+#ifdef VBOX
+# if ARCH_BITS == 32
+ vboxImageEvtEmitOne(ImageContext, EFI_IMAGE_EVT_CMD_START_LOAD32);
+# else
+ vboxImageEvtEmitOne(ImageContext, EFI_IMAGE_EVT_CMD_START_LOAD64);
+# endif
+#endif
+}
+
+/**
+ Performs additional actions just before a PE/COFF image is unloaded. Any resources
+ that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
+
+ @param ImageContext Pointer to the image context structure that describes the
+ PE/COFF image that is being unloaded.
+
+**/
+VOID
+EFIAPI
+PeCoffLoaderUnloadImageExtraAction (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+#ifdef VBOX_SOURCE_DEBUG_ENABLE
+ PeCoffLoaderExtraActionCommon (ImageContext, IMAGE_UNLOAD_SIGNATURE);
+#endif
+
+#ifdef VBOX
+# if ARCH_BITS == 32
+ vboxImageEvtEmitOne(ImageContext, EFI_IMAGE_EVT_CMD_START_UNLOAD32);
+# else
+ vboxImageEvtEmitOne(ImageContext, EFI_IMAGE_EVT_CMD_START_UNLOAD64);
+# endif
+#endif
+}
+
+#ifdef VBOX
+VOID
+EFIAPI
+VBoxPeCoffLoaderMoveImageExtraAction(
+ IN PHYSICAL_ADDRESS OldBase,
+ IN PHYSICAL_ADDRESS NewBase
+ )
+{
+#if ARCH_BITS == 32
+ ASMOutU32(EFI_PORT_IMAGE_EVENT, EFI_IMAGE_EVT_CMD_START_RELOC32);
+#else
+ ASMOutU32(EFI_PORT_IMAGE_EVENT, EFI_IMAGE_EVT_CMD_START_RELOC64);
+#endif
+ vboxImageEvtU64(EFI_IMAGE_EVT_CMD_ADDR0, NewBase);
+ vboxImageEvtU64(EFI_IMAGE_EVT_CMD_ADDR1, OldBase);
+ ASMOutU32(EFI_PORT_IMAGE_EVENT, EFI_IMAGE_EVT_CMD_COMPLETE);
+}
+#endif