summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
commit16f504a9dca3fe3b70568f67b7d41241ae485288 (patch)
treec60f36ada0496ba928b7161059ba5ab1ab224f9d /src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg
parentInitial commit. (diff)
downloadvirtualbox-upstream.tar.xz
virtualbox-upstream.zip
Adding upstream version 7.0.6-dfsg.upstream/7.0.6-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg')
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.c137
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.inf46
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxeExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.c40
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.inf42
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.uni17
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPeiExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Guid/DebugAgentGuid.h26
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Ia32/ProcessorContext.h304
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/ImageDebugSupport.h22
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Library/DebugCommunicationLib.h146
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/TransferProtocol.h370
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c2640
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h498
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c377
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h216
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c143
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h45
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c110
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h21
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm413
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h30
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c114
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h21
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm399
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h30
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c544
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h34
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c808
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf96
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c704
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.h59
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf86
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c386
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.h19
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf81
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.c154
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf33
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.c1106
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf51
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c1140
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c531
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf74
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h737
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c273
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf69
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c577
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm22
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandlerFuncs.c93
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c303
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.h73
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf51
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm23
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandlerFuncs.c95
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Readme.txt6
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.dec117
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.dsc112
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.uni94
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkgExtra.uni12
68 files changed, 14942 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.c
new file mode 100644
index 00000000..43ff327c
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.c
@@ -0,0 +1,137 @@
+/** @file
+ Initialize Debug Agent in DXE by invoking Debug Agent Library.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/EventGroup.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/UefiLib.h>
+
+EFI_EVENT mExitBootServiceEvent;
+
+/**
+ One notified function to disable Debug Timer interrupt when gBS->ExitBootServices() called.
+
+ @param[in] Event Pointer to this event
+ @param[in] Context Event handler private data
+
+**/
+VOID
+EFIAPI
+DisableDebugTimerExitBootService (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+
+{
+ SaveAndSetDebugTimerInterrupt (FALSE);
+}
+
+/**
+ The Entry Point for Debug Agent Dxe driver.
+
+ It will invoke Debug Agent Library to enable source debugging feature in DXE phase.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when initialized Debug Agent.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugAgentDxeInitialize(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ if (gST->ConOut != NULL) {
+ Print (L"If the Debug Port is serial port, please make sure this serial port isn't connected by");
+ Print (L" ISA Serial driver\r\n");
+ Print (L"You could do the following steps to disconnect the serial port:\r\n");
+ Print (L"1: Shell> drivers\r\n");
+ Print (L" ...\r\n");
+ Print (L" V VERSION E G G #D #C DRIVER NAME IMAGE NAME\r\n");
+ Print (L" == ======== = = = == == =================================== ===================\r\n");
+ Print (L" 8F 0000000A B - - 1 14 PCI Bus Driver PciBusDxe\r\n");
+ Print (L" 91 00000010 ? - - - - ATA Bus Driver AtaBusDxe\r\n");
+ Print (L" ...\r\n");
+ Print (L" A7 0000000A B - - 1 1 ISA Serial Driver IsaSerialDxe\r\n");
+ Print (L" ...\r\n");
+ Print (L"2: Shell> dh -d A7\r\n");
+ Print (L" A7: Image(IsaSerialDxe) ImageDevPath (..9FB3-11D4-9A3A-0090273FC14D))DriverBinding");
+ Print (L" ComponentName ComponentName2\r\n");
+ Print (L" Driver Name : ISA Serial Driver\r\n");
+ Print (L" Image Name : FvFile(93B80003-9FB3-11D4-9A3A-0090273FC14D)\r\n");
+ Print (L" Driver Version : 0000000A\r\n");
+ Print (L" Driver Type : BUS\r\n");
+ Print (L" Configuration : NO\r\n");
+ Print (L" Diagnostics : NO\r\n");
+ Print (L" Managing :\r\n");
+ Print (L" Ctrl[EA] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)\r\n");
+ Print (L" Child[EB] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)/Uart(115200,8,N,1)\r\n");
+ Print (L"3: Shell> disconnect EA\r\n");
+ Print (L"4: Shell> load -nc DebugAgentDxe.efi\r\n\r\n");
+ }
+ Status = EFI_UNSUPPORTED;
+ InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_LOAD, &Status, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (gST->ConOut != NULL) {
+ Print (L"Debug Agent: Initialized successfully!\r\n\r\n");
+ }
+ //
+ // Create event to disable Debug Timer interrupt when exit boot service.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ DisableDebugTimerExitBootService,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &mExitBootServiceEvent
+ );
+ return Status;
+}
+
+/**
+ This is the unload handle for Debug Agent Dxe driver.
+
+ It will invoke Debug Agent Library to disable source debugging feature.
+
+ @param[in] ImageHandle The drivers' driver image.
+
+ @retval EFI_SUCCESS The image is unloaded.
+ @retval Others Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugAgentDxeUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_UNSUPPORTED;
+ InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_UNLOAD, &Status, NULL);
+ switch (Status) {
+ case EFI_ACCESS_DENIED:
+ Print (L"Debug Agent: Host is still connected, please de-attach TARGET firstly!\r\n");
+ break;
+ case EFI_NOT_STARTED:
+ Print (L"Debug Agent: It hasn't been initialized, cannot unload it!\r\n");
+ break;
+ }
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.inf b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.inf
new file mode 100644
index 00000000..8eeb404e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.inf
@@ -0,0 +1,46 @@
+## @file
+# Initialized Debug Agent in one separated DXE driver.
+#
+# This DXE driver will invoke Debug Agent Library to initialize the debug agent.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugAgentDxe
+ MODULE_UNI_FILE = DebugAgentDxe.uni
+ FILE_GUID = 9727502C-034E-472b-8E1B-67BB28C6CFDB
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DebugAgentDxeInitialize
+ UNLOAD_IMAGE = DebugAgentDxeUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ DebugAgentDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ DebugAgentLib
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## SOMETIMES_CONSUMES ## Event
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DebugAgentDxeExtra.uni
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.uni
new file mode 100644
index 00000000..66a19e7c
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Initialized Debug Agent in one separated DXE driver.
+//
+// This DXE driver will invoke Debug Agent Library to initialize the debug agent.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Initialized Debug Agent in one separated DXE driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This DXE driver will invoke Debug Agent Library to initialize the debug agent."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxeExtra.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxeExtra.uni
new file mode 100644
index 00000000..8f7c343e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DebugAgentDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Debug Agent DXE Driver"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.c
new file mode 100644
index 00000000..bf409734
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.c
@@ -0,0 +1,40 @@
+/** @file
+ Initialize Debug Agent in PEI by invoking Debug Agent Library.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Library/DebugAgentLib.h>
+
+/**
+ The Entry Point for Debug Agent PEI driver.
+
+ It will invoke Debug Agent Library to enable source debugging feature in PEI phase.
+
+ This function is the Entry point of the CPU I/O PEIM which installs CpuIoPpi.
+
+ @param[in] FileHandle Pointer to image file handle.
+ @param[in] PeiServices Pointer to PEI Services Table
+
+ @retval EFI_SUCCESS Debug Agent successfully initialized.
+ @retval other Some error occurs when initialized Debug Agent.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugAgentPeiInitialize (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_UNSUPPORTED;
+ InitializeDebugAgent (DEBUG_AGENT_INIT_PEI, &Status, NULL);
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.inf b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.inf
new file mode 100644
index 00000000..07b99e1b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.inf
@@ -0,0 +1,42 @@
+## @file
+# Initialized Debug Agent in PEI phase.
+#
+# This PEIM will invoke Debug Agent Library to initialize the debug agent in
+# whole PEI phase.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugAgentPei
+ MODULE_UNI_FILE = DebugAgentPei.uni
+ FILE_GUID = D9D114EF-F40B-4d48-AAA0-A3DC99C9F5BD
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DebugAgentPeiInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ DebugAgentPei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ DebugAgentLib
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DebugAgentPeiExtra.uni
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.uni
new file mode 100644
index 00000000..67267e54
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Initialized Debug Agent in PEI phase.
+//
+// This PEIM will invoke Debug Agent Library to initialize the debug agent in
+// whole PEI phase.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Initialized Debug Agent in PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This PEIM will invoke Debug Agent Library to initialize the debug agent throughout the whole PEI phase."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPeiExtra.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPeiExtra.uni
new file mode 100644
index 00000000..131f0ad2
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/DebugAgentPei/DebugAgentPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DebugAgentPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Debug Agent PEI Module"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Guid/DebugAgentGuid.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Guid/DebugAgentGuid.h
new file mode 100644
index 00000000..2cb88116
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Guid/DebugAgentGuid.h
@@ -0,0 +1,26 @@
+/** @file
+ This file defines the debug agent GUID for HOB and configuration table.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EFI_DEBUG_AGENT_GUID_H__
+#define __EFI_DEBUG_AGENT_GUID_H__
+
+///
+/// This guid is used as a variable GUID for the capsule variable
+/// if the capsule pointer is passed through reset via a variable.
+///
+/// This guid is also used as a hob GUID for the capsule data
+/// when the capsule pointer is passed from PEI phase to DXE phase.
+///
+#define EFI_DEBUG_AGENT_GUID \
+ { \
+ 0x865a5a9b, 0xb85d, 0x474c, { 0x84, 0x55, 0x65, 0xd1, 0xbe, 0x84, 0x4b, 0xe2 } \
+ }
+
+extern EFI_GUID gEfiDebugAgentGuid;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Ia32/ProcessorContext.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Ia32/ProcessorContext.h
new file mode 100644
index 00000000..dc35dac5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Ia32/ProcessorContext.h
@@ -0,0 +1,304 @@
+/** @file
+ IA32/x64 architecture specific definitions needed by debug transfer protocol.It is only
+ intended to be used by Debug related module implementation.
+
+ Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PROCESSOR_CONTEXT_H__
+#define __PROCESSOR_CONTEXT_H__
+
+//
+// IA-32/x64 processor register index table
+//
+#define SOFT_DEBUGGER_REGISTER_DR0 0x00
+#define SOFT_DEBUGGER_REGISTER_DR1 0x01
+#define SOFT_DEBUGGER_REGISTER_DR2 0x02
+#define SOFT_DEBUGGER_REGISTER_DR3 0x03
+#define SOFT_DEBUGGER_REGISTER_DR6 0x04
+#define SOFT_DEBUGGER_REGISTER_DR7 0x05
+#define SOFT_DEBUGGER_REGISTER_EFLAGS 0x06
+#define SOFT_DEBUGGER_REGISTER_LDTR 0x07
+#define SOFT_DEBUGGER_REGISTER_TR 0x08
+#define SOFT_DEBUGGER_REGISTER_GDTR0 0x09 // the low 32bit of GDTR
+#define SOFT_DEBUGGER_REGISTER_GDTR1 0x0A // the high 32bit of GDTR
+#define SOFT_DEBUGGER_REGISTER_IDTR0 0x0B // the low 32bit of IDTR
+#define SOFT_DEBUGGER_REGISTER_IDTR1 0x0C // the high 32bot of IDTR
+#define SOFT_DEBUGGER_REGISTER_EIP 0x0D
+#define SOFT_DEBUGGER_REGISTER_GS 0x0E
+#define SOFT_DEBUGGER_REGISTER_FS 0x0F
+#define SOFT_DEBUGGER_REGISTER_ES 0x10
+#define SOFT_DEBUGGER_REGISTER_DS 0x11
+#define SOFT_DEBUGGER_REGISTER_CS 0x12
+#define SOFT_DEBUGGER_REGISTER_SS 0x13
+#define SOFT_DEBUGGER_REGISTER_CR0 0x14
+#define SOFT_DEBUGGER_REGISTER_CR1 0x15
+#define SOFT_DEBUGGER_REGISTER_CR2 0x16
+#define SOFT_DEBUGGER_REGISTER_CR3 0x17
+#define SOFT_DEBUGGER_REGISTER_CR4 0x18
+
+#define SOFT_DEBUGGER_REGISTER_DI 0x19
+#define SOFT_DEBUGGER_REGISTER_SI 0x1A
+#define SOFT_DEBUGGER_REGISTER_BP 0x1B
+#define SOFT_DEBUGGER_REGISTER_SP 0x1C
+#define SOFT_DEBUGGER_REGISTER_DX 0x1D
+#define SOFT_DEBUGGER_REGISTER_CX 0x1E
+#define SOFT_DEBUGGER_REGISTER_BX 0x1F
+#define SOFT_DEBUGGER_REGISTER_AX 0x20
+
+//
+// This below registers are only available for x64 (not valid for Ia32 mode)
+//
+#define SOFT_DEBUGGER_REGISTER_CR8 0x21
+#define SOFT_DEBUGGER_REGISTER_R8 0x22
+#define SOFT_DEBUGGER_REGISTER_R9 0x23
+#define SOFT_DEBUGGER_REGISTER_R10 0x24
+#define SOFT_DEBUGGER_REGISTER_R11 0x25
+#define SOFT_DEBUGGER_REGISTER_R12 0x26
+#define SOFT_DEBUGGER_REGISTER_R13 0x27
+#define SOFT_DEBUGGER_REGISTER_R14 0x28
+#define SOFT_DEBUGGER_REGISTER_R15 0x29
+
+//
+// This below registers are FP / MMX / XMM registers
+//
+#define SOFT_DEBUGGER_REGISTER_FP_BASE 0x30
+
+#define SOFT_DEBUGGER_REGISTER_FP_FCW (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x00)
+#define SOFT_DEBUGGER_REGISTER_FP_FSW (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x01)
+#define SOFT_DEBUGGER_REGISTER_FP_FTW (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x02)
+#define SOFT_DEBUGGER_REGISTER_FP_OPCODE (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x03)
+#define SOFT_DEBUGGER_REGISTER_FP_EIP (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x04)
+#define SOFT_DEBUGGER_REGISTER_FP_CS (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x05)
+#define SOFT_DEBUGGER_REGISTER_FP_DATAOFFSET (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x06)
+#define SOFT_DEBUGGER_REGISTER_FP_DS (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x07)
+#define SOFT_DEBUGGER_REGISTER_FP_MXCSR (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x08)
+#define SOFT_DEBUGGER_REGISTER_FP_MXCSR_MASK (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x09)
+#define SOFT_DEBUGGER_REGISTER_ST0 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x0A)
+#define SOFT_DEBUGGER_REGISTER_ST1 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x0B)
+#define SOFT_DEBUGGER_REGISTER_ST2 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x0C)
+#define SOFT_DEBUGGER_REGISTER_ST3 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x0D)
+#define SOFT_DEBUGGER_REGISTER_ST4 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x0E)
+#define SOFT_DEBUGGER_REGISTER_ST5 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x0F)
+#define SOFT_DEBUGGER_REGISTER_ST6 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x10)
+#define SOFT_DEBUGGER_REGISTER_ST7 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x11)
+#define SOFT_DEBUGGER_REGISTER_XMM0 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x12)
+#define SOFT_DEBUGGER_REGISTER_XMM1 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x13)
+#define SOFT_DEBUGGER_REGISTER_XMM2 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x14)
+#define SOFT_DEBUGGER_REGISTER_XMM3 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x15)
+#define SOFT_DEBUGGER_REGISTER_XMM4 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x16)
+#define SOFT_DEBUGGER_REGISTER_XMM5 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x17)
+#define SOFT_DEBUGGER_REGISTER_XMM6 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x18)
+#define SOFT_DEBUGGER_REGISTER_XMM7 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x19)
+#define SOFT_DEBUGGER_REGISTER_XMM8 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x1A)
+#define SOFT_DEBUGGER_REGISTER_XMM9 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x1B)
+#define SOFT_DEBUGGER_REGISTER_XMM10 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x1C)
+#define SOFT_DEBUGGER_REGISTER_XMM11 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x1D)
+#define SOFT_DEBUGGER_REGISTER_XMM12 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x1E)
+#define SOFT_DEBUGGER_REGISTER_XMM13 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x1F)
+#define SOFT_DEBUGGER_REGISTER_XMM14 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x20)
+#define SOFT_DEBUGGER_REGISTER_XMM15 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x21)
+#define SOFT_DEBUGGER_REGISTER_MM0 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x22)
+#define SOFT_DEBUGGER_REGISTER_MM1 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x23)
+#define SOFT_DEBUGGER_REGISTER_MM2 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x24)
+#define SOFT_DEBUGGER_REGISTER_MM3 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x25)
+#define SOFT_DEBUGGER_REGISTER_MM4 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x26)
+#define SOFT_DEBUGGER_REGISTER_MM5 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x27)
+#define SOFT_DEBUGGER_REGISTER_MM6 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x28)
+#define SOFT_DEBUGGER_REGISTER_MM7 (SOFT_DEBUGGER_REGISTER_FP_BASE + 0x29)
+
+#define SOFT_DEBUGGER_REGISTER_MAX SOFT_DEBUGGER_REGISTER_MM7
+
+#define SOFT_DEBUGGER_MSR_EFER (0xC0000080)
+
+#pragma pack(1)
+
+///
+/// FXSAVE_STATE
+/// FP / MMX / XMM registers (see fxrstor instruction definition)
+///
+typedef struct {
+ UINT16 Fcw;
+ UINT16 Fsw;
+ UINT16 Ftw;
+ UINT16 Opcode;
+ UINT32 Eip;
+ UINT16 Cs;
+ UINT16 Reserved1;
+ UINT32 DataOffset;
+ UINT16 Ds;
+ UINT8 Reserved2[2];
+ UINT32 Mxcsr;
+ UINT32 Mxcsr_Mask;
+ UINT8 St0Mm0[10];
+ UINT8 Reserved3[6];
+ UINT8 St1Mm1[10];
+ UINT8 Reserved4[6];
+ UINT8 St2Mm2[10];
+ UINT8 Reserved5[6];
+ UINT8 St3Mm3[10];
+ UINT8 Reserved6[6];
+ UINT8 St4Mm4[10];
+ UINT8 Reserved7[6];
+ UINT8 St5Mm5[10];
+ UINT8 Reserved8[6];
+ UINT8 St6Mm6[10];
+ UINT8 Reserved9[6];
+ UINT8 St7Mm7[10];
+ UINT8 Reserved10[6];
+ UINT8 Xmm0[16];
+ UINT8 Xmm1[16];
+ UINT8 Xmm2[16];
+ UINT8 Xmm3[16];
+ UINT8 Xmm4[16];
+ UINT8 Xmm5[16];
+ UINT8 Xmm6[16];
+ UINT8 Xmm7[16];
+ UINT8 Reserved11[14 * 16];
+} DEBUG_DATA_IA32_FX_SAVE_STATE;
+
+///
+/// IA-32 processor context definition
+///
+typedef struct {
+ UINT32 ExceptionData;
+ DEBUG_DATA_IA32_FX_SAVE_STATE FxSaveState;
+ UINT32 Dr0;
+ UINT32 Dr1;
+ UINT32 Dr2;
+ UINT32 Dr3;
+ UINT32 Dr6;
+ UINT32 Dr7;
+ UINT32 Eflags;
+ UINT32 Ldtr;
+ UINT32 Tr;
+ UINT32 Gdtr[2];
+ UINT32 Idtr[2];
+ UINT32 Eip;
+ UINT32 Gs;
+ UINT32 Fs;
+ UINT32 Es;
+ UINT32 Ds;
+ UINT32 Cs;
+ UINT32 Ss;
+ UINT32 Cr0;
+ UINT32 Cr1; ///< Reserved
+ UINT32 Cr2;
+ UINT32 Cr3;
+ UINT32 Cr4;
+ UINT32 Edi;
+ UINT32 Esi;
+ UINT32 Ebp;
+ UINT32 Esp;
+ UINT32 Edx;
+ UINT32 Ecx;
+ UINT32 Ebx;
+ UINT32 Eax;
+} DEBUG_DATA_IA32_SYSTEM_CONTEXT;
+
+///
+/// FXSAVE_STATE
+/// FP / MMX / XMM registers (see fxrstor instruction definition)
+///
+typedef struct {
+ UINT16 Fcw;
+ UINT16 Fsw;
+ UINT16 Ftw;
+ UINT16 Opcode;
+ UINT32 Eip;
+ UINT16 Cs;
+ UINT16 Reserved1;
+ UINT32 DataOffset;
+ UINT16 Ds;
+ UINT8 Reserved2[2];
+ UINT32 Mxcsr;
+ UINT32 Mxcsr_Mask;
+ UINT8 St0Mm0[10];
+ UINT8 Reserved3[6];
+ UINT8 St1Mm1[10];
+ UINT8 Reserved4[6];
+ UINT8 St2Mm2[10];
+ UINT8 Reserved5[6];
+ UINT8 St3Mm3[10];
+ UINT8 Reserved6[6];
+ UINT8 St4Mm4[10];
+ UINT8 Reserved7[6];
+ UINT8 St5Mm5[10];
+ UINT8 Reserved8[6];
+ UINT8 St6Mm6[10];
+ UINT8 Reserved9[6];
+ UINT8 St7Mm7[10];
+ UINT8 Reserved10[6];
+ UINT8 Xmm0[16];
+ UINT8 Xmm1[16];
+ UINT8 Xmm2[16];
+ UINT8 Xmm3[16];
+ UINT8 Xmm4[16];
+ UINT8 Xmm5[16];
+ UINT8 Xmm6[16];
+ UINT8 Xmm7[16];
+ UINT8 Xmm8[16];
+ UINT8 Xmm9[16];
+ UINT8 Xmm10[16];
+ UINT8 Xmm11[16];
+ UINT8 Xmm12[16];
+ UINT8 Xmm13[16];
+ UINT8 Xmm14[16];
+ UINT8 Xmm15[16];
+ UINT8 Reserved11[6 * 16];
+} DEBUG_DATA_X64_FX_SAVE_STATE;
+
+///
+/// x64 processor context definition
+///
+typedef struct {
+ UINT64 ExceptionData;
+ DEBUG_DATA_X64_FX_SAVE_STATE FxSaveState;
+ UINT64 Dr0;
+ UINT64 Dr1;
+ UINT64 Dr2;
+ UINT64 Dr3;
+ UINT64 Dr6;
+ UINT64 Dr7;
+ UINT64 Eflags;
+ UINT64 Ldtr;
+ UINT64 Tr;
+ UINT64 Gdtr[2];
+ UINT64 Idtr[2];
+ UINT64 Eip;
+ UINT64 Gs;
+ UINT64 Fs;
+ UINT64 Es;
+ UINT64 Ds;
+ UINT64 Cs;
+ UINT64 Ss;
+ UINT64 Cr0;
+ UINT64 Cr1; ///< Reserved
+ UINT64 Cr2;
+ UINT64 Cr3;
+ UINT64 Cr4;
+ UINT64 Rdi;
+ UINT64 Rsi;
+ UINT64 Rbp;
+ UINT64 Rsp;
+ UINT64 Rdx;
+ UINT64 Rcx;
+ UINT64 Rbx;
+ UINT64 Rax;
+ UINT64 Cr8;
+ UINT64 R8;
+ UINT64 R9;
+ UINT64 R10;
+ UINT64 R11;
+ UINT64 R12;
+ UINT64 R13;
+ UINT64 R14;
+ UINT64 R15;
+} DEBUG_DATA_X64_SYSTEM_CONTEXT;
+
+#pragma pack()
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/ImageDebugSupport.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/ImageDebugSupport.h
new file mode 100644
index 00000000..9df4ec1a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/ImageDebugSupport.h
@@ -0,0 +1,22 @@
+/** @file
+ Public include file for Debug Agent Library instance and PE/COFF Extra
+ Action Library instance.
+
+ Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __IMAGE_DEBUG_SUPPORT_H__
+#define __IMAGE_DEBUG_SUPPORT_H__
+
+#define IO_PORT_BREAKPOINT_ADDRESS 0x84
+#define IMAGE_LOAD_SIGNATURE SIGNATURE_32('L','O','A','D')
+#define IMAGE_UNLOAD_SIGNATURE SIGNATURE_32('U','N','L','O')
+#define AGENT_HANDLER_SIGNATURE SIGNATURE_32('A','G','T','H')
+
+#define DEBUG_AGENT_IMAGE_WAIT 0x00
+#define DEBUG_AGENT_IMAGE_CONTINUE 0x01
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Library/DebugCommunicationLib.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Library/DebugCommunicationLib.h
new file mode 100644
index 00000000..b550115d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/Library/DebugCommunicationLib.h
@@ -0,0 +1,146 @@
+/** @file
+ Debug Communication Library definitions.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __DEBUG_COMMUNICATION_LIB_H__
+#define __DEBUG_COMMUNICATION_LIB_H__
+
+typedef VOID * DEBUG_PORT_HANDLE;
+
+/**
+ Caller provided function to be invoked at the end of DebugPortInitialize().
+
+ Refer to the description for DebugPortInitialize() for more details.
+
+ @param[in] Context The first input argument of DebugPortInitialize().
+ @param[in] DebugPortHandle Debug port handle created by Debug Communication Library.
+
+**/
+typedef
+VOID
+(EFIAPI * DEBUG_PORT_CONTINUE)(
+ IN VOID *Context,
+ IN DEBUG_PORT_HANDLE DebugPortHandle
+ );
+
+/**
+ Initialize the debug port.
+
+ This function will initialize debug port to get it ready for data transmission. If
+ certain Debug Communication Library instance has to save some private data in the
+ stack, this function must work on the mode that doesn't return to the caller, then
+ the caller needs to wrap up all rest of logic after DebugPortInitialize() into one
+ function and pass it into DebugPortInitialize(). DebugPortInitialize() is
+ responsible to invoke the passing-in function at the end of DebugPortInitialize().
+
+ If the parameter Function is not NULL, Debug Communication Library instance will
+ invoke it by passing in the Context to be the first parameter. Debug Communication
+ Library instance could create one debug port handle to be the second parameter
+ passing into the Function. Debug Communication Library instance also could pass
+ NULL to be the second parameter if it doesn't create the debug port handle.
+
+ If the parameter Function is NULL, and Context is not NULL. At this time, Context
+ is the debug port handle created by the previous Debug Communication Library
+ instance.
+ a) If the instance can understand and continue use the private data of the previous
+ instance, it could return the same handle as passed in (as Context parameter).
+ b) If the instance does not understand, or does not want to continue use the
+ private data of the previous instance, it could ignore the input Context parameter
+ and create the new handle to be returned.
+
+ If Function() is NULL and Context is NULL, Debug Communication Library could create a
+ new handle and return it. NULL is also a valid handle to be returned.
+
+ @param[in] Context Context needed by callback function; it was optional.
+ @param[in] Function Continue function called by Debug Communication library;
+ it was optional.
+
+ @return The debug port handle created by Debug Communication Library if Function
+ is not NULL.
+
+**/
+DEBUG_PORT_HANDLE
+EFIAPI
+DebugPortInitialize (
+ IN VOID *Context,
+ IN DEBUG_PORT_CONTINUE Function
+ );
+
+
+/**
+ Read data from debug device and save the datas in buffer.
+
+ Reads NumberOfBytes data bytes from a debug device into the buffer
+ specified by Buffer. The number of bytes actually read is returned.
+ If the return value is less than NumberOfBytes, then the rest operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to store the data read from the debug device.
+ @param NumberOfBytes Number of bytes which will be read.
+ @param Timeout Timeout value for reading from debug device. Its unit is Microsecond.
+
+ @retval 0 Read data failed, no data is to be read.
+ @retval >0 Actual number of bytes read from debug device.
+
+**/
+UINTN
+EFIAPI
+DebugPortReadBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes,
+ IN UINTN Timeout
+ );
+
+
+/**
+ Write data from buffer to debug device.
+
+ Writes NumberOfBytes data bytes from Buffer to the debug device.
+ The number of bytes actually written to the debug device is returned.
+ If the return value is less than NumberOfBytes, then the write operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to be written.
+ @param NumberOfBytes Number of bytes to written to the debug device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes written to the debug device.
+ If this value is less than NumberOfBytes, then the write operation failed.
+
+**/
+UINTN
+EFIAPI
+DebugPortWriteBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ );
+
+/**
+ Polls a debug device to see if there is any data waiting to be read.
+
+ Polls a debug device to see if there is any data waiting to be read.
+ If there is data waiting to be read from the debug device, then TRUE is returned.
+ If there is no data waiting to be read from the debug device, then FALSE is returned.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE Data is waiting to be read from the debug device.
+ @retval FALSE There is no data waiting to be read from the debug device.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPortPollBuffer (
+ IN DEBUG_PORT_HANDLE Handle
+ );
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/TransferProtocol.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/TransferProtocol.h
new file mode 100644
index 00000000..daf65dec
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Include/TransferProtocol.h
@@ -0,0 +1,370 @@
+/** @file
+ Transfer protocol definitions used by debug agent and host. It is only
+ intended to be used by Debug related module implementation.
+
+ Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __TRANSFER_PROTOCOL_H__
+#define __TRANSFER_PROTOCOL_H__
+
+#include "ProcessorContext.h"
+
+//
+// Current revision of transfer protocol
+// 0.4: Packet compression and decompression.
+//
+#define DEBUG_AGENT_REVISION_03 ((0 << 16) | 03)
+#define DEBUG_AGENT_REVISION_04 ((0 << 16) | 04)
+#define DEBUG_AGENT_CAPABILITIES 0
+
+//
+// Definitions for the (A)ttach command
+//
+#define DEBUG_STARTING_SYMBOL_ATTACH (0xFA)
+
+//
+// Definition for starting symbol of a normal debug packet. Choose a non-ASCII to avoid conflict with other serial output.
+//
+#define DEBUG_STARTING_SYMBOL_NORMAL (0xFE)
+
+//
+// Definition for starting symbol of a (C)ompressed debug packet. Choose a non-ASCII to avoid conflict with other serial output.
+//
+#define DEBUG_STARTING_SYMBOL_COMPRESS (0xFC)
+
+#pragma pack(1)
+
+//
+// Definition for debug packet header for debug packets (not including attach command)
+//
+typedef struct {
+ UINT8 StartSymbol;
+ UINT8 Command;
+ UINT8 Length; // Length of Debug Packet including header and payload in byte
+ UINT8 SequenceNo;
+ UINT16 Crc;
+} DEBUG_PACKET_HEADER;
+
+//
+// Definition for Command field for debug packets
+//
+#define DEBUG_COMMAND_REQUEST (0 << 7)
+#define DEBUG_COMMAND_RESPONSE (1 << 7)
+
+#define IS_REQUEST(x) (((x)->Command & DEBUG_COMMAND_RESPONSE) == 0)
+
+//
+// HOST initiated commands
+//
+#define DEBUG_COMMAND_RESET (DEBUG_COMMAND_REQUEST | 0x00)
+#define DEBUG_COMMAND_GO (DEBUG_COMMAND_REQUEST | 0x01)
+#define DEBUG_COMMAND_BREAK_CAUSE (DEBUG_COMMAND_REQUEST | 0x02)
+#define DEBUG_COMMAND_SET_HW_BREAKPOINT (DEBUG_COMMAND_REQUEST | 0x03)
+#define DEBUG_COMMAND_CLEAR_HW_BREAKPOINT (DEBUG_COMMAND_REQUEST | 0x04)
+#define DEBUG_COMMAND_SINGLE_STEPPING (DEBUG_COMMAND_REQUEST | 0x05)
+#define DEBUG_COMMAND_SET_SW_BREAKPOINT (DEBUG_COMMAND_REQUEST | 0x06)
+#define DEBUG_COMMAND_READ_MEMORY (DEBUG_COMMAND_REQUEST | 0x07)
+#define DEBUG_COMMAND_WRITE_MEMORY (DEBUG_COMMAND_REQUEST | 0x08)
+#define DEBUG_COMMAND_READ_IO (DEBUG_COMMAND_REQUEST | 0x09)
+#define DEBUG_COMMAND_WRITE_IO (DEBUG_COMMAND_REQUEST | 0x0A)
+#define DEBUG_COMMAND_READ_REGISTER (DEBUG_COMMAND_REQUEST | 0x0B)
+#define DEBUG_COMMAND_WRITE_REGISTER (DEBUG_COMMAND_REQUEST | 0x0C)
+#define DEBUG_COMMAND_READ_ALL_REGISTERS (DEBUG_COMMAND_REQUEST | 0x0D)
+#define DEBUG_COMMAND_ARCH_MODE (DEBUG_COMMAND_REQUEST | 0x0E)
+#define DEBUG_COMMAND_READ_MSR (DEBUG_COMMAND_REQUEST | 0x0F)
+#define DEBUG_COMMAND_WRITE_MSR (DEBUG_COMMAND_REQUEST | 0x10)
+#define DEBUG_COMMAND_SET_DEBUG_SETTING (DEBUG_COMMAND_REQUEST | 0x11)
+#define DEBUG_COMMAND_GET_REVISION (DEBUG_COMMAND_REQUEST | 0x12)
+#define DEBUG_COMMAND_GET_EXCEPTION (DEBUG_COMMAND_REQUEST | 0x13)
+#define DEBUG_COMMAND_SET_VIEWPOINT (DEBUG_COMMAND_REQUEST | 0x14)
+#define DEBUG_COMMAND_GET_VIEWPOINT (DEBUG_COMMAND_REQUEST | 0x15)
+#define DEBUG_COMMAND_DETACH (DEBUG_COMMAND_REQUEST | 0x16)
+#define DEBUG_COMMAND_CPUID (DEBUG_COMMAND_REQUEST | 0x17)
+#define DEBUG_COMMAND_SEARCH_SIGNATURE (DEBUG_COMMAND_REQUEST | 0x18)
+#define DEBUG_COMMAND_HALT (DEBUG_COMMAND_REQUEST | 0x19)
+
+//
+// TARGET initiated commands
+//
+#define DEBUG_COMMAND_INIT_BREAK (DEBUG_COMMAND_REQUEST | 0x3F)
+#define DEBUG_COMMAND_BREAK_POINT (DEBUG_COMMAND_REQUEST | 0x3E)
+#define DEBUG_COMMAND_MEMORY_READY (DEBUG_COMMAND_REQUEST | 0x3D)
+#define DEBUG_COMMAND_PRINT_MESSAGE (DEBUG_COMMAND_REQUEST | 0x3C)
+#define DEBUG_COMMAND_ATTACH_BREAK (DEBUG_COMMAND_REQUEST | 0x3B)
+
+//
+// Response commands
+//
+#define DEBUG_COMMAND_OK (DEBUG_COMMAND_RESPONSE | 0x00)
+#define DEBUG_COMMAND_RESEND (DEBUG_COMMAND_RESPONSE | 0x01)
+#define DEBUG_COMMAND_ABORT (DEBUG_COMMAND_RESPONSE | 0x02)
+//
+// The below 2 commands are used when transferring big data (like > ~250 bytes).
+// The sequence is:
+// HOST TARGET
+// Request =>
+// <= IN_PROGRESS with partial data
+// CONTINUE =>
+// (could have multiple IN_PROGRESS and CONTINUE interactions)
+// <= OK with the last part of data
+// OK (no data as ACK) =>
+//
+#define DEBUG_COMMAND_IN_PROGRESS (DEBUG_COMMAND_RESPONSE | 0x03)
+#define DEBUG_COMMAND_CONTINUE (DEBUG_COMMAND_RESPONSE | 0x04)
+//
+// The below 2 commands are used to support deferred halt:
+// TARGET returns HALT_DEFERRED when it receives a HALT request in inter-active mode.
+// TARGET returns HALT_PROCESSED when it receives a GO request and has a pending HALT request.
+//
+#define DEBUG_COMMAND_HALT_DEFERRED (DEBUG_COMMAND_RESPONSE | 0x05)
+#define DEBUG_COMMAND_HALT_PROCESSED (DEBUG_COMMAND_RESPONSE | 0x06)
+
+#define DEBUG_COMMAND_TIMEOUT (DEBUG_COMMAND_RESPONSE | 0x07)
+#define DEBUG_COMMAND_NOT_SUPPORTED (DEBUG_COMMAND_RESPONSE | 0x0F)
+
+//
+// Definition for data field for debug packets
+//
+#define DEBUG_DATA_UPPER_LIMIT 0xff // Upper limit for the data size, by the limit of the packet header definition.
+
+#define DEBUG_DATA_MAXIMUM_REAL_DATA (DEBUG_DATA_UPPER_LIMIT - sizeof (DEBUG_PACKET_HEADER))
+
+//
+// Response data for DEBUG_COMMAND_BREAK_CAUSE
+//
+typedef struct {
+ UINT8 Cause;
+ UINT64 StopAddress;
+} DEBUG_DATA_RESPONSE_BREAK_CAUSE;
+//
+// Break type definitions for DEBUG_DATA_BREAK_CAUSE
+//
+#define DEBUG_DATA_BREAK_CAUSE_UNKNOWN 0
+#define DEBUG_DATA_BREAK_CAUSE_HW_BREAKPOINT 1
+#define DEBUG_DATA_BREAK_CAUSE_STEPPING 2
+#define DEBUG_DATA_BREAK_CAUSE_SW_BREAKPOINT 3
+#define DEBUG_DATA_BREAK_CAUSE_USER_HALT 4
+#define DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD 5
+#define DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD 6
+#define DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET 7
+#define DEBUG_DATA_BREAK_CAUSE_EXCEPTION 8
+#define DEBUG_DATA_BREAK_CAUSE_MEMORY_READY 9
+
+//
+// Response data for DEBUG_COMMAND_ARCH_MODE, defined as SOFT_DEBUGGER_PROCESSOR_...
+//
+typedef struct {
+ UINT8 CpuMode;
+} DEBUG_DATA_RESPONSE_ARCH_MODE;
+//
+// Cpu architecture definitions for DEBUG_DATA_RESPONSE_ARCH_MODE
+//
+#define DEBUG_DATA_BREAK_CPU_ARCH_IA16 0
+#define DEBUG_DATA_BREAK_CPU_ARCH_IA32 1
+#define DEBUG_DATA_BREAK_CPU_ARCH_X64 2
+
+typedef struct {
+ UINT8 Length:2; // Refer to below DEBUG_DATA_BREAKPOINT_LENGTH_XX macros
+ UINT8 Access:2; // Refer to below DEBUG_DATA_BREAKPOINT_ACCESS_XX macros
+ UINT8 Index:2; // Index of debug register
+ UINT8 Reserved:2;
+} DEBUG_DATA_BREAKPOINT_TYPE;
+#define DEBUG_DATA_BREAKPOINT_MEMORY_ACCESS (0x3)
+#define DEBUG_DATA_BREAKPOINT_IO_ACCESS (0x2)
+#define DEBUG_DATA_BREAKPOINT_MEMORY_WRITE (0x1)
+#define DEBUG_DATA_BREAKPOINT_MEMORY_EXECUTE (0x0)
+#define DEBUG_DATA_BREAKPOINT_LENGTH_32 (0x3)
+#define DEBUG_DATA_BREAKPOINT_LENGTH_64 (0x2)
+#define DEBUG_DATA_BREAKPOINT_LENGTH_16 (0x1)
+#define DEBUG_DATA_BREAKPOINT_LENGTH_8 (0x0)
+
+//
+// Request data for DEBUG_COMMAND_SET_HW_BREAKPOINT
+//
+typedef struct {
+ DEBUG_DATA_BREAKPOINT_TYPE Type;
+ UINT64 Address;
+} DEBUG_DATA_SET_HW_BREAKPOINT;
+
+//
+// Request data for DEBUG_COMMAND_CLEAR_HW_BREAKPOINT
+//
+typedef struct {
+ UINT8 IndexMask; // 0x0f will clear all hw breakpoints
+} DEBUG_DATA_CLEAR_HW_BREAKPOINT;
+
+//
+// Request and response data for DEBUG_COMMAND_SET_SW_BREAKPOINT
+//
+typedef struct {
+ UINT64 Address;
+} DEBUG_DATA_SET_SW_BREAKPOINT;
+
+typedef struct {
+ UINT8 OriginalData;
+} DEBUG_DATA_RESPONSE_SET_SW_BREAKPOINT;
+
+//
+// Request data for DEBUG_COMMAND_READ_MEMORY
+//
+typedef struct {
+ UINT64 Address;
+ UINT8 Width;
+ UINT16 Count;
+} DEBUG_DATA_READ_MEMORY;
+
+//
+// Request data for DEBUG_COMMAND_WRITE_MEMORY
+//
+typedef struct {
+ UINT64 Address;
+ UINT8 Width;
+ UINT16 Count;
+ UINT8 Data[1]; // The actual length is (Width * Count)
+} DEBUG_DATA_WRITE_MEMORY;
+
+//
+// Request and response data for DEBUG_COMMAND_READ_IO
+//
+typedef struct {
+ UINT64 Port;
+ UINT8 Width;
+} DEBUG_DATA_READ_IO;
+
+typedef struct {
+ UINT8 Data[1]; // The actual length depends on the packet header
+} DEBUG_DATA_RESPONSE_READ_IO;
+
+//
+// Request data for DEBUG_COMMAND_WRITE_IO
+//
+typedef struct {
+ UINT64 Port;
+ UINT8 Width;
+ UINT8 Data[1]; // The actual length is Width
+} DEBUG_DATA_WRITE_IO;
+
+//
+// Request data for DEBUG_COMMAND_READ_REGISTER
+//
+typedef struct {
+ UINT8 Index; // defined as SOFT_DEBUGGER_REGISTER_XX
+} DEBUG_DATA_READ_REGISTER;
+
+//
+// Request data for DEBUG_COMMAND_WRITE_REGISTER
+//
+typedef struct {
+ UINT8 Index; // defined as SOFT_DEBUGGER_REGISTER_XX
+ UINT8 Length;
+ UINT8 Data[1]; // The actual length is Length
+} DEBUG_DATA_WRITE_REGISTER;
+
+//
+// Request and response data for DEBUG_COMMAND_READ_MSR
+//
+typedef struct {
+ UINT32 Index;
+} DEBUG_DATA_READ_MSR;
+
+typedef struct {
+ UINT64 Value;
+} DEBUG_DATA_RESPONSE_READ_MSR;
+
+//
+// Request data for DEBUG_COMMAND_WRITE_MSR
+//
+typedef struct {
+ UINT32 Index;
+ UINT64 Value;
+} DEBUG_DATA_WRITE_MSR;
+
+//
+// Response data for DEBUG_COMMAND_GET_REVISION
+//
+typedef struct {
+ UINT32 Revision;
+ UINT32 Capabilities;
+} DEBUG_DATA_RESPONSE_GET_REVISION;
+
+//
+// Response data for DEBUG_COMMAND_GET_EXCEPTION
+//
+typedef struct {
+ UINT8 ExceptionNum;
+ UINT32 ExceptionData;
+} DEBUG_DATA_RESPONSE_GET_EXCEPTION;
+
+//
+// Request data for DEBUG_DATA_SET_DEBUG_SETTING
+//
+typedef struct {
+ UINT8 Key;
+ UINT8 Value;
+} DEBUG_DATA_SET_DEBUG_SETTING;
+//
+// Supported keys
+//
+#define DEBUG_AGENT_SETTING_SMM_ENTRY_BREAK 1
+#define DEBUG_AGENT_SETTING_PRINT_ERROR_LEVEL 2
+#define DEBUG_AGENT_SETTING_BOOT_SCRIPT_ENTRY_BREAK 3
+//
+// Bitmask of print error level for debug message
+//
+#define DEBUG_AGENT_ERROR BIT0
+#define DEBUG_AGENT_WARNING BIT1
+#define DEBUG_AGENT_INFO BIT2
+#define DEBUG_AGENT_VERBOSE BIT3
+
+//
+// Request data for DEBUG_COMMAND_SET_VIEWPOINT
+//
+typedef struct {
+ UINT32 ViewPoint; // The index of viewpoint will be set
+} DEBUG_DATA_SET_VIEWPOINT;
+
+//
+// Response data for DEBUG_COMMAND_GET_VIEWPOINT
+//
+typedef struct {
+ UINT32 ViewPoint; // The index of viewpoint will be returned
+} DEBUG_DATA_RESPONSE_GET_VIEWPOINT;
+
+//
+// Request and response data for DEBUG_COMMAND_CPUID
+//
+typedef struct {
+ UINT32 Eax; // The value of EAX prior to invoking the CPUID instruction
+ UINT32 Ecx; // The value of ECX prior to invoking the CPUID instruction
+} DEBUG_DATA_CPUID;
+
+typedef struct {
+ UINT32 Eax; // The value of EAX returned by the CPUID instruction
+ UINT32 Ebx; // The value of EBX returned by the CPUID instruction
+ UINT32 Ecx; // The value of ECX returned by the CPUID instruction
+ UINT32 Edx; // The value of EDX returned by the CPUID instruction
+} DEBUG_DATA_RESPONSE_CPUID;
+
+//
+// Request and response data for DEBUG_COMMAND_SEARCH_SIGNATURE
+//
+typedef struct {
+ UINT64 Start;
+ UINT32 Count;
+ UINT32 Alignment;
+ BOOLEAN Positive; // TRUE to search in higher address memory
+ UINT8 DataLength;
+ UINT8 Data[1];
+} DEBUG_DATA_SEARCH_SIGNATURE;
+
+typedef struct {
+ UINT64 Address; // -1 indicates not found
+} DEBUG_DATA_RESPONSE_SEARCH_SIGNATURE;
+
+#pragma pack()
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c
new file mode 100644
index 00000000..1ee01e02
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c
@@ -0,0 +1,2640 @@
+/** @file
+ Commond Debug Agent library implementation. It mainly includes
+ the first C function called by exception/interrupt handlers,
+ read/write debug packet to communication with HOST based on transfer
+ protocol.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugAgent.h"
+#include "Ia32/DebugException.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgVersionAlert[] = "\rThe SourceLevelDebugPkg you are using requires a newer version of the Intel(R) UDK Debugger Tool.\r\n";
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgSendInitPacket[] = "\rSend INIT break packet and try to connect the HOST (Intel(R) UDK Debugger Tool v1.5) ...\r\n";
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgConnectOK[] = "HOST connection is successful!\r\n";
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgConnectFail[] = "HOST connection is failed!\r\n";
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mWarningMsgIngoreBreakpoint[] = "Ignore break point in SMM for SMI issued during DXE debugging!\r\n";
+
+//
+// Vector Handoff Info list used by Debug Agent for persist
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_VECTOR_HANDOFF_INFO mVectorHandoffInfoDebugAgent[] = {
+ {
+ DEBUG_EXCEPT_DIVIDE_ERROR, // Vector 0
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_DEBUG, // Vector 1
+ EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_NMI, // Vector 2
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_BREAKPOINT, // Vector 3
+ EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_OVERFLOW, // Vector 4
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_BOUND, // Vector 5
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_INVALID_OPCODE, // Vector 6
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_DOUBLE_FAULT, // Vector 8
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_INVALID_TSS, // Vector 10
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_SEG_NOT_PRESENT, // Vector 11
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_STACK_FAULT, // Vector 12
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_GP_FAULT, // Vector 13
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_PAGE_FAULT, // Vector 14
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_FP_ERROR, // Vector 16
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_ALIGNMENT_CHECK, // Vector 17
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_MACHINE_CHECK, // Vector 18
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_SIMD, // Vector 19
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_TIMER_VECTOR, // Vector 32
+ EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_MAILBOX_VECTOR, // Vector 33
+ EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ 0,
+ EFI_VECTOR_HANDOFF_LAST_ENTRY,
+ { 0 }
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mVectorHandoffInfoCount = sizeof (mVectorHandoffInfoDebugAgent) / sizeof (EFI_VECTOR_HANDOFF_INFO);
+
+/**
+ Calculate CRC16 for target data.
+
+ @param[in] Data The target data.
+ @param[in] DataSize The target data size.
+ @param[in] Crc Initial CRC.
+
+ @return UINT16 The CRC16 value.
+
+**/
+UINT16
+CalculateCrc16 (
+ IN UINT8 *Data,
+ IN UINTN DataSize,
+ IN UINT16 Crc
+ )
+{
+ UINTN Index;
+ UINTN BitIndex;
+
+ for (Index = 0; Index < DataSize; Index++) {
+ Crc ^= (UINT16)Data[Index];
+ for (BitIndex = 0; BitIndex < 8; BitIndex++) {
+ if ((Crc & 0x8000) != 0) {
+ Crc <<= 1;
+ Crc ^= 0x1021;
+ } else {
+ Crc <<= 1;
+ }
+ }
+ }
+ return Crc;
+}
+
+
+/**
+ Read IDT entry to check if IDT entries are setup by Debug Agent.
+
+ @retval TRUE IDT entries were setup by Debug Agent.
+ @retval FALSE IDT entries were not setup by Debug Agent.
+
+**/
+BOOLEAN
+IsDebugAgentInitialzed (
+ VOID
+ )
+{
+ UINTN InterruptHandler;
+
+ InterruptHandler = (UINTN) GetExceptionHandlerInIdtEntry (0);
+ if (InterruptHandler >= 4 && *(UINT32 *)(InterruptHandler - 4) == AGENT_HANDLER_SIGNATURE) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Find and report module image info to HOST.
+
+ @param[in] AlignSize Image aligned size.
+
+**/
+VOID
+FindAndReportModuleImageInfo (
+ IN UINTN AlignSize
+ )
+{
+ UINTN Pe32Data;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ //
+ // Find Image Base
+ //
+ Pe32Data = PeCoffSearchImageBase ((UINTN) mErrorMsgVersionAlert);
+ if (Pe32Data != 0) {
+ ImageContext.ImageAddress = Pe32Data;
+ ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
+ PeCoffLoaderRelocateImageExtraAction (&ImageContext);
+ }
+}
+
+/**
+ Trigger one software interrupt to debug agent to handle it.
+
+ @param[in] Signature Software interrupt signature.
+
+**/
+VOID
+TriggerSoftInterrupt (
+ IN UINT32 Signature
+ )
+{
+ UINTN Dr0;
+ UINTN Dr1;
+
+ //
+ // Save Debug Register State
+ //
+ Dr0 = AsmReadDr0 ();
+ Dr1 = AsmReadDr1 ();
+
+ //
+ // DR0 = Signature
+ //
+ AsmWriteDr0 (SOFT_INTERRUPT_SIGNATURE);
+ AsmWriteDr1 (Signature);
+
+ //
+ // Do INT3 to communicate with HOST side
+ //
+ CpuBreakpoint ();
+
+ //
+ // Restore Debug Register State only when Host didn't change it inside exception handler.
+ // Dr registers can only be changed by setting the HW breakpoint.
+ //
+ AsmWriteDr0 (Dr0);
+ AsmWriteDr1 (Dr1);
+
+}
+
+/**
+ Calculate Mailbox checksum and update the checksum field.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+
+**/
+VOID
+UpdateMailboxChecksum (
+ IN DEBUG_AGENT_MAILBOX *Mailbox
+ )
+{
+ Mailbox->CheckSum = CalculateCheckSum8 ((UINT8 *)Mailbox, sizeof (DEBUG_AGENT_MAILBOX) - 2);
+}
+
+/**
+ Verify Mailbox checksum.
+
+ If checksum error, print debug message and run init dead loop.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+
+**/
+VOID
+VerifyMailboxChecksum (
+ IN DEBUG_AGENT_MAILBOX *Mailbox
+ )
+{
+ UINT8 CheckSum;
+
+ CheckSum = CalculateCheckSum8 ((UINT8 *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX) - 2);
+ //
+ // The checksum updating process may be disturbed by hardware SMI, we need to check CheckSum field
+ // and ToBeCheckSum field to validate the mail box.
+ //
+ if (CheckSum != Mailbox->CheckSum && CheckSum != Mailbox->ToBeCheckSum) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Mailbox checksum error, stack or heap crashed!\n"));
+ DEBUG ((EFI_D_ERROR, "DebugAgent: CheckSum = %x, Mailbox->CheckSum = %x, Mailbox->ToBeCheckSum = %x\n", CheckSum, Mailbox->CheckSum, Mailbox->ToBeCheckSum));
+ CpuDeadLoop ();
+ }
+}
+
+/**
+ Update Mailbox content by index.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+ @param[in] Index Mailbox content index.
+ @param[in] Value Value to be set into Mailbox.
+
+**/
+VOID
+UpdateMailboxContent (
+ IN DEBUG_AGENT_MAILBOX *Mailbox,
+ IN UINTN Index,
+ IN UINT64 Value
+ )
+{
+ AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock);
+ switch (Index) {
+ case DEBUG_MAILBOX_DEBUG_FLAG_INDEX:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugFlag.Uint64, sizeof(UINT64))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINT64));
+ Mailbox->DebugFlag.Uint64 = Value;
+ break;
+ case DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugPortHandle, sizeof(UINTN))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINTN));
+ Mailbox->DebugPortHandle = (UINTN) Value;
+ break;
+ case DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->ExceptionBufferPointer, sizeof(UINTN))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINTN));
+ Mailbox->ExceptionBufferPointer = (UINTN) Value;
+ break;
+ case DEBUG_MAILBOX_LAST_ACK:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->LastAck, sizeof(UINT8))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINT8));
+ Mailbox->LastAck = (UINT8) Value;
+ break;
+ case DEBUG_MAILBOX_SEQUENCE_NO_INDEX:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->SequenceNo, sizeof(UINT8))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINT8));
+ Mailbox->SequenceNo = (UINT8) Value;
+ break;
+ case DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->HostSequenceNo, sizeof(UINT8))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINT8));
+ Mailbox->HostSequenceNo = (UINT8) Value;
+ break;
+ case DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugTimerFrequency, sizeof(UINT32))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINT32));
+ Mailbox->DebugTimerFrequency = (UINT32) Value;
+ break;
+ }
+ UpdateMailboxChecksum (Mailbox);
+ ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock);
+}
+
+/**
+ Read data from debug device and save the data in buffer.
+
+ Reads NumberOfBytes data bytes from a debug device into the buffer
+ specified by Buffer. The number of bytes actually read is returned.
+ If the return value is less than NumberOfBytes, then the rest operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to store the data read from the debug device.
+ @param NumberOfBytes Number of bytes which will be read.
+ @param Timeout Timeout value for reading from debug device. It unit is Microsecond.
+
+ @retval 0 Read data failed, no data is to be read.
+ @retval >0 Actual number of bytes read from debug device.
+
+**/
+UINTN
+DebugAgentReadBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes,
+ IN UINTN Timeout
+ )
+{
+ UINTN Index;
+ UINT32 Begin;
+ UINT32 TimeoutTicker;
+ UINT32 TimerRound;
+ UINT32 TimerFrequency;
+ UINT32 TimerCycle;
+
+ Begin = 0;
+ TimeoutTicker = 0;
+ TimerRound = 0;
+ TimerFrequency = GetMailboxPointer()->DebugTimerFrequency;
+ TimerCycle = GetApicTimerInitCount ();
+
+ if (Timeout != 0) {
+ Begin = GetApicTimerCurrentCount ();
+ TimeoutTicker = (UINT32) DivU64x32 (
+ MultU64x64 (
+ TimerFrequency,
+ Timeout
+ ),
+ 1000000u
+ );
+ TimerRound = (UINT32) DivU64x32Remainder (TimeoutTicker, TimerCycle / 2, &TimeoutTicker);
+ }
+ Index = 0;
+ while (Index < NumberOfBytes) {
+ if (DebugPortPollBuffer (Handle)) {
+ DebugPortReadBuffer (Handle, Buffer + Index, 1, 0);
+ Index ++;
+ continue;
+ }
+ if (Timeout != 0) {
+ if (TimerRound == 0) {
+ if (IsDebugTimerTimeout (TimerCycle, Begin, TimeoutTicker)) {
+ //
+ // If time out occurs.
+ //
+ return 0;
+ }
+ } else {
+ if (IsDebugTimerTimeout (TimerCycle, Begin, TimerCycle / 2)) {
+ TimerRound --;
+ Begin = GetApicTimerCurrentCount ();
+ }
+ }
+ }
+ }
+
+ return Index;
+}
+
+/**
+ Set debug flag in mailbox.
+
+ @param[in] FlagMask Debug flag mask value.
+ @param[in] FlagValue Debug flag value.
+
+**/
+VOID
+SetDebugFlag (
+ IN UINT64 FlagMask,
+ IN UINT32 FlagValue
+ )
+{
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ UINT64 Data64;
+
+ Mailbox = GetMailboxPointer ();
+ Data64 = (Mailbox->DebugFlag.Uint64 & ~FlagMask) |
+ (LShiftU64 ((UINT64)FlagValue, LowBitSet64 (FlagMask)) & FlagMask);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_FLAG_INDEX, Data64);
+}
+
+/**
+ Get debug flag in mailbox.
+
+ @param[in] FlagMask Debug flag mask value.
+
+ @return Debug flag value.
+
+**/
+UINT32
+GetDebugFlag (
+ IN UINT64 FlagMask
+ )
+{
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ UINT32 DebugFlag;
+
+ Mailbox = GetMailboxPointer ();
+ DebugFlag = (UINT32) RShiftU64 (Mailbox->DebugFlag.Uint64 & FlagMask, LowBitSet64 (FlagMask));
+
+ return DebugFlag;
+}
+
+/**
+ Send a debug message packet to the debug port.
+
+ @param[in] Buffer The debug message.
+ @param[in] Length The length of debug message.
+
+**/
+VOID
+SendDebugMsgPacket (
+ IN CHAR8 *Buffer,
+ IN UINTN Length
+ )
+{
+ DEBUG_PACKET_HEADER DebugHeader;
+ DEBUG_PORT_HANDLE Handle;
+
+ Handle = GetDebugPortHandle();
+
+ DebugHeader.StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
+ DebugHeader.Command = DEBUG_COMMAND_PRINT_MESSAGE;
+ DebugHeader.Length = sizeof (DEBUG_PACKET_HEADER) + (UINT8) Length;
+ DebugHeader.SequenceNo = 0xEE;
+ DebugHeader.Crc = 0;
+ DebugHeader.Crc = CalculateCrc16 (
+ (UINT8 *)Buffer, Length,
+ CalculateCrc16 ((UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0)
+ );
+
+ DebugPortWriteBuffer (Handle, (UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER));
+ DebugPortWriteBuffer (Handle, (UINT8 *)Buffer, Length);
+}
+
+/**
+ Prints a debug message to the debug port if the specified error level is enabled.
+
+ If any bit in ErrorLevel is also set in Mainbox, then print the message specified
+ by Format and the associated variable argument list to the debug port.
+
+ @param[in] ErrorLevel The error level of the debug message.
+ @param[in] Format Format string for the debug message to print.
+ @param[in] ... Variable argument list whose contents are accessed
+ based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+DebugAgentMsgPrint (
+ IN UINT8 ErrorLevel,
+ IN CHAR8 *Format,
+ ...
+ )
+{
+ CHAR8 Buffer[DEBUG_DATA_MAXIMUM_REAL_DATA];
+ VA_LIST Marker;
+
+ //
+ // Check driver debug mask value and global mask
+ //
+ if ((ErrorLevel & GetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL)) == 0) {
+ return;
+ }
+
+ //
+ // Convert the DEBUG() message to an ASCII String
+ //
+ VA_START (Marker, Format);
+ AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
+ VA_END (Marker);
+
+ SendDebugMsgPacket (Buffer, AsciiStrLen (Buffer));
+}
+
+/**
+ Prints a debug message to the debug output device if the specified error level is enabled.
+
+ If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
+ GetDebugPrintErrorLevel (), then print the message specified by Format and the
+ associated variable argument list to the debug output device.
+
+ If Format is NULL, then ASSERT().
+
+ @param[in] ErrorLevel The error level of the debug message.
+ @param[in] IsSend Flag of debug message to declare that the data is being sent or being received.
+ @param[in] Data Variable argument list whose contents are accessed
+ @param[in] Length based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+DebugAgentDataMsgPrint (
+ IN UINT8 ErrorLevel,
+ IN BOOLEAN IsSend,
+ IN UINT8 *Data,
+ IN UINT8 Length
+ )
+{
+ CHAR8 Buffer[DEBUG_DATA_MAXIMUM_REAL_DATA];
+ CHAR8 *DestBuffer;
+ UINTN Index;
+
+ //
+ // Check driver debug mask value and global mask
+ //
+ if ((ErrorLevel & GetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL)) == 0) {
+ return;
+ }
+
+ DestBuffer = Buffer;
+ if (IsSend) {
+ DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA, "Sent data [ ");
+ } else {
+ DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA, "Received data [ ");
+ }
+
+ Index = 0;
+ while (TRUE) {
+ if (DestBuffer - Buffer > DEBUG_DATA_MAXIMUM_REAL_DATA - 6) {
+ //
+ // If there was no enough space in buffer, send out the debug message,
+ // reserving 6 bytes is for the last data and end characters "]\n".
+ //
+ SendDebugMsgPacket (Buffer, DestBuffer - Buffer);
+ DestBuffer = Buffer;
+ }
+ DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA - (DestBuffer - Buffer), "%02x ", Data[Index]);
+ Index ++;
+ if (Index >= Length) {
+ //
+ // The last character of debug message has been formatted in buffer
+ //
+ DestBuffer += AsciiSPrint(DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA - (DestBuffer - Buffer), "]\n");
+ SendDebugMsgPacket (Buffer, DestBuffer - Buffer);
+ break;
+ }
+ }
+}
+
+/**
+ Read remaing debug packet except for the start symbol
+
+ @param[in] Handle Pointer to Debug Port handle.
+ @param[in, out] DebugHeader Debug header buffer including start symbol.
+
+ @retval EFI_SUCCESS Read the symbol in BreakSymbol.
+ @retval EFI_CRC_ERROR CRC check fail.
+ @retval EFI_TIMEOUT Timeout occurs when reading debug packet.
+ @retval EFI_DEVICE_ERROR Receive the old or responsed packet.
+
+**/
+EFI_STATUS
+ReadRemainingBreakPacket (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN OUT DEBUG_PACKET_HEADER *DebugHeader
+ )
+{
+ UINT16 Crc;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+
+ //
+ // Has received start symbol, try to read the rest part
+ //
+ if (DebugAgentReadBuffer (Handle, (UINT8 *)DebugHeader + OFFSET_OF (DEBUG_PACKET_HEADER, Command), sizeof (DEBUG_PACKET_HEADER) - OFFSET_OF (DEBUG_PACKET_HEADER, Command), READ_PACKET_TIMEOUT) == 0) {
+ //
+ // Timeout occur, exit
+ //
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Timeout in Debug Timer interrupt\n");
+ return EFI_TIMEOUT;
+ }
+
+ Crc = DebugHeader->Crc;
+ DebugHeader->Crc = 0;
+ if (CalculateCrc16 ((UINT8 *)DebugHeader, DebugHeader->Length, 0) != Crc) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Debug Timer CRC (%x) against (%x)\n", Crc, CalculateCrc16 ((UINT8 *) &DebugHeader, DebugHeader->Length, 0));
+ DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *)DebugHeader, DebugHeader->Length);
+ return EFI_CRC_ERROR;
+ }
+ Mailbox = GetMailboxPointer();
+ if (IS_REQUEST (DebugHeader)) {
+ if (DebugHeader->SequenceNo == (UINT8) (Mailbox->HostSequenceNo + 1)) {
+ //
+ // Only updagte HostSequenceNo for new command packet
+ //
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, DebugHeader->SequenceNo);
+ return EFI_SUCCESS;
+ }
+ if (DebugHeader->SequenceNo == Mailbox->HostSequenceNo) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Check if HOST is attached based on Mailbox.
+
+ @retval TRUE HOST is attached.
+ @retval FALSE HOST is not attached.
+
+**/
+BOOLEAN
+IsHostAttached (
+ VOID
+ )
+{
+ return (BOOLEAN) (GetDebugFlag (DEBUG_AGENT_FLAG_HOST_ATTACHED) == 1);
+}
+
+/**
+ Set HOST connect flag in Mailbox.
+
+ @param[in] Attached Attach status.
+
+**/
+VOID
+SetHostAttached (
+ IN BOOLEAN Attached
+ )
+{
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Attach status is %d\n", Attached);
+ SetDebugFlag (DEBUG_AGENT_FLAG_HOST_ATTACHED, (UINT32)Attached);
+}
+
+/**
+ Set debug setting of Debug Agent in Mailbox.
+
+ @param DebugSetting Pointer to Debug Setting defined by transfer protocol.
+
+ @retval RETURN_SUCCESS The setting is set successfully.
+ @retval RETURN_UNSUPPORTED The Key value is not supported.
+
+**/
+RETURN_STATUS
+SetDebugSetting (
+ IN DEBUG_DATA_SET_DEBUG_SETTING *DebugSetting
+ )
+{
+ RETURN_STATUS Status;
+
+ Status = RETURN_SUCCESS;
+ switch (DebugSetting->Key) {
+ case DEBUG_AGENT_SETTING_SMM_ENTRY_BREAK:
+ SetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI, DebugSetting->Value);
+ break;
+ case DEBUG_AGENT_SETTING_PRINT_ERROR_LEVEL:
+ SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DebugSetting->Value);
+ break;
+ case DEBUG_AGENT_SETTING_BOOT_SCRIPT_ENTRY_BREAK:
+ SetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT, DebugSetting->Value);
+ break;
+ default:
+ Status = RETURN_UNSUPPORTED;
+ }
+ return Status;
+}
+
+/**
+ Execute GO command.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+
+**/
+VOID
+CommandGo (
+ IN DEBUG_CPU_CONTEXT *CpuContext
+ )
+{
+ IA32_EFLAGS32 *Eflags;
+
+ Eflags = (IA32_EFLAGS32 *) &CpuContext->Eflags;
+ Eflags->Bits.TF = 0;
+ Eflags->Bits.RF = 1;
+}
+
+/**
+ Execute Stepping command.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+
+**/
+VOID
+CommandStepping (
+ IN DEBUG_CPU_CONTEXT *CpuContext
+ )
+{
+ IA32_EFLAGS32 *Eflags;
+
+ Eflags = (IA32_EFLAGS32 *) &CpuContext->Eflags;
+ Eflags->Bits.TF = 1;
+ Eflags->Bits.RF = 1;
+ //
+ // Save and clear EFLAGS.IF to avoid interrupt happen when executing Stepping
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_INTERRUPT_FLAG, Eflags->Bits.IF);
+ Eflags->Bits.IF = 0;
+ //
+ // Set Stepping Flag
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_STEPPING, 1);
+}
+
+/**
+ Do some cleanup after Stepping command done.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+
+**/
+VOID
+CommandSteppingCleanup (
+ IN DEBUG_CPU_CONTEXT *CpuContext
+ )
+{
+ IA32_EFLAGS32 *Eflags;
+
+ Eflags = (IA32_EFLAGS32 *) &CpuContext->Eflags;
+ //
+ // Restore EFLAGS.IF
+ //
+ Eflags->Bits.IF = GetDebugFlag (DEBUG_AGENT_FLAG_INTERRUPT_FLAG);
+ //
+ // Clear Stepping flag
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_STEPPING, 0);
+}
+
+/**
+ Set debug register for hardware breakpoint.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+ @param[in] SetHwBreakpoint Hardware breakpoint to be set.
+
+**/
+VOID
+SetDebugRegister (
+ IN DEBUG_CPU_CONTEXT *CpuContext,
+ IN DEBUG_DATA_SET_HW_BREAKPOINT *SetHwBreakpoint
+ )
+{
+ UINT8 RegisterIndex;
+ UINTN Dr7Value;
+
+ RegisterIndex = SetHwBreakpoint->Type.Index;
+
+ //
+ // Set debug address
+ //
+ * ((UINTN *) &CpuContext->Dr0 + RegisterIndex) = (UINTN) SetHwBreakpoint->Address;
+
+ Dr7Value = CpuContext->Dr7;
+
+ //
+ // Enable Gx, Lx
+ //
+ Dr7Value |= (UINTN) (0x3 << (RegisterIndex * 2));
+ //
+ // Set RWx and Lenx
+ //
+ Dr7Value &= (UINTN) (~(0xf << (16 + RegisterIndex * 4)));
+ Dr7Value |= (UINTN) ((SetHwBreakpoint->Type.Length << 2) | SetHwBreakpoint->Type.Access) << (16 + RegisterIndex * 4);
+ //
+ // Enable GE, LE
+ //
+ Dr7Value |= 0x300;
+
+ CpuContext->Dr7 = Dr7Value;
+}
+
+/**
+ Clear debug register for hardware breakpoint.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+ @param[in] ClearHwBreakpoint Hardware breakpoint to be cleared.
+
+**/
+VOID
+ClearDebugRegister (
+ IN DEBUG_CPU_CONTEXT *CpuContext,
+ IN DEBUG_DATA_CLEAR_HW_BREAKPOINT *ClearHwBreakpoint
+ )
+{
+ if ((ClearHwBreakpoint->IndexMask & BIT0) != 0) {
+ CpuContext->Dr0 = 0;
+ CpuContext->Dr7 &= (UINTN)(~(0x3 << 0));
+ }
+ if ((ClearHwBreakpoint->IndexMask & BIT1) != 0) {
+ CpuContext->Dr1 = 0;
+ CpuContext->Dr7 &= (UINTN)(~(0x3 << 2));
+ }
+ if ((ClearHwBreakpoint->IndexMask & BIT2) != 0) {
+ CpuContext->Dr2 = 0;
+ CpuContext->Dr7 &= (UINTN)(~(0x3 << 4));
+ }
+ if ((ClearHwBreakpoint->IndexMask & BIT3) != 0) {
+ CpuContext->Dr3 = 0;
+ CpuContext->Dr7 &= (UINTN)(~(0x3 << 6));
+ }
+}
+
+
+/**
+ Return the offset of FP / MMX / XMM registers in the FPU saved state by register index.
+
+ @param[in] Index Register index.
+ @param[out] Width Register width returned.
+
+ @return Offset in the FPU Save State.
+
+**/
+UINT16
+ArchReadFxStatOffset (
+ IN UINT8 Index,
+ OUT UINT8 *Width
+ )
+{
+ if (Index < SOFT_DEBUGGER_REGISTER_ST0) {
+ switch (Index) {
+ case SOFT_DEBUGGER_REGISTER_FP_FCW:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Fcw);
+
+ case SOFT_DEBUGGER_REGISTER_FP_FSW:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Fsw);
+
+ case SOFT_DEBUGGER_REGISTER_FP_FTW:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Ftw);
+
+ case SOFT_DEBUGGER_REGISTER_FP_OPCODE:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Opcode);
+
+ case SOFT_DEBUGGER_REGISTER_FP_EIP:
+ *Width = (UINT8) sizeof (UINT32);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Eip);
+
+ case SOFT_DEBUGGER_REGISTER_FP_CS:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Cs);
+
+ case SOFT_DEBUGGER_REGISTER_FP_DATAOFFSET:
+ *Width = (UINT8) sizeof (UINT32);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, DataOffset);
+
+ case SOFT_DEBUGGER_REGISTER_FP_DS:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Ds);
+
+ case SOFT_DEBUGGER_REGISTER_FP_MXCSR:
+ *Width = (UINT8) sizeof (UINT32);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Mxcsr);
+
+ case SOFT_DEBUGGER_REGISTER_FP_MXCSR_MASK:
+ *Width = (UINT8) sizeof (UINT32);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Mxcsr_Mask);
+ }
+ }
+
+ if (Index <= SOFT_DEBUGGER_REGISTER_ST7) {
+ *Width = 10;
+ } else if (Index <= SOFT_DEBUGGER_REGISTER_XMM15) {
+ *Width = 16;
+ } else {
+ //
+ // MMX register
+ //
+ *Width = 8;
+ Index -= SOFT_DEBUGGER_REGISTER_MM0 - SOFT_DEBUGGER_REGISTER_ST0;
+ }
+
+ return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, St0Mm0) + (Index - SOFT_DEBUGGER_REGISTER_ST0) * 16;
+}
+
+/**
+ Return the pointer of the register value in the CPU saved context.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+ @param[in] Index Register index value.
+ @param[out] Width Data width to read.
+
+ @return The pointer in the CPU saved context.
+
+**/
+UINT8 *
+ArchReadRegisterBuffer (
+ IN DEBUG_CPU_CONTEXT *CpuContext,
+ IN UINT8 Index,
+ OUT UINT8 *Width
+ )
+{
+ UINT8 *Buffer;
+
+ if (Index < SOFT_DEBUGGER_REGISTER_FP_BASE) {
+ Buffer = (UINT8 *) CpuContext + OFFSET_OF (DEBUG_CPU_CONTEXT, Dr0) + Index * sizeof (UINTN);
+ *Width = (UINT8) sizeof (UINTN);
+ } else {
+ //
+ // FPU/MMX/XMM registers
+ //
+ Buffer = (UINT8 *) CpuContext + OFFSET_OF (DEBUG_CPU_CONTEXT, FxSaveState) + ArchReadFxStatOffset (Index, Width);
+ }
+
+ return Buffer;
+}
+
+/**
+ Send the packet without data to HOST.
+
+ @param[in] CommandType Type of Command.
+ @param[in] SequenceNo Sequence number.
+
+**/
+VOID
+SendPacketWithoutData (
+ IN UINT8 CommandType,
+ IN UINT8 SequenceNo
+ )
+{
+ DEBUG_PACKET_HEADER DebugHeader;
+ DEBUG_PORT_HANDLE Handle;
+
+ Handle = GetDebugPortHandle();
+
+ DebugHeader.StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
+ DebugHeader.Command = CommandType;
+ DebugHeader.Length = sizeof (DEBUG_PACKET_HEADER);
+ DebugHeader.SequenceNo = SequenceNo;
+ DebugHeader.Crc = 0;
+ DebugHeader.Crc = CalculateCrc16 ((UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0);
+
+ DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, TRUE, (UINT8 *) &DebugHeader, DebugHeader.Length);
+ DebugPortWriteBuffer (Handle, (UINT8 *) &DebugHeader, DebugHeader.Length);
+}
+
+/**
+ Send acknowledge packet to HOST.
+
+ @param[in] AckCommand Type of Acknowledge packet.
+
+**/
+VOID
+SendAckPacket (
+ IN UINT8 AckCommand
+ )
+{
+ UINT8 SequenceNo;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+
+ if (AckCommand != DEBUG_COMMAND_OK) {
+ //
+ // This is not ACK OK packet
+ //
+ DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "Send ACK(%d)\n", AckCommand);
+ }
+ Mailbox = GetMailboxPointer();
+ SequenceNo = Mailbox->HostSequenceNo;
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "SendAckPacket: SequenceNo = %x\n", SequenceNo);
+ SendPacketWithoutData (AckCommand, SequenceNo);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_LAST_ACK, AckCommand);
+}
+
+/**
+ Decompress the Data in place.
+
+ @param[in, out] Data The compressed data buffer.
+ The buffer is assumed large enough to hold the uncompressed data.
+ @param[in] Length The length of the compressed data buffer.
+
+ @return The length of the uncompressed data buffer.
+**/
+UINT8
+DecompressDataInPlace (
+ IN OUT UINT8 *Data,
+ IN UINTN Length
+ )
+{
+ UINTN Index;
+ UINT16 LastChar;
+ UINTN LastCharCount;
+ UINT8 CurrentChar;
+
+ LastChar = (UINT16) -1;
+ LastCharCount = 0;
+ for (Index = 0; Index < Length; Index++) {
+ CurrentChar = Data[Index];
+ if (LastCharCount == 2) {
+ LastCharCount = 0;
+ CopyMem (&Data[Index + CurrentChar], &Data[Index + 1], Length - Index - 1);
+ SetMem (&Data[Index], CurrentChar, (UINT8) LastChar);
+ LastChar = (UINT16) -1;
+ Index += CurrentChar - 1;
+ Length += CurrentChar - 1;
+ } else {
+ if (LastChar != CurrentChar) {
+ LastCharCount = 0;
+ }
+ LastCharCount++;
+ LastChar = CurrentChar;
+ }
+ }
+
+ ASSERT (Length <= DEBUG_DATA_MAXIMUM_REAL_DATA);
+
+ return (UINT8) Length;
+}
+
+/**
+ Receive valid packet from HOST.
+
+ @param[out] InputPacket Buffer to receive packet.
+ @param[out] BreakReceived TRUE means break-in symbol received.
+ FALSE means break-in symbol not received.
+ @param[out] IncompatibilityFlag If IncompatibilityFlag is not NULL, return
+ TRUE: Compatible packet received.
+ FALSE: Incompatible packet received.
+ @param[in] Timeout Time out value to wait for acknowledge from HOST.
+ The unit is microsecond.
+ @param[in] SkipStartSymbol TRUE: Skip time out when reading start symbol.
+ FALSE: Does not Skip time out when reading start symbol.
+
+ @retval RETURN_SUCCESS A valid package was received in InputPacket.
+ @retval RETURN_TIMEOUT Timeout occurs.
+
+**/
+RETURN_STATUS
+ReceivePacket (
+ OUT UINT8 *InputPacket,
+ OUT BOOLEAN *BreakReceived,
+ OUT BOOLEAN *IncompatibilityFlag, OPTIONAL
+ IN UINTN Timeout,
+ IN BOOLEAN SkipStartSymbol
+ )
+{
+ DEBUG_PACKET_HEADER *DebugHeader;
+ UINTN Received;
+ DEBUG_PORT_HANDLE Handle;
+ UINT16 Crc;
+ UINTN TimeoutForStartSymbol;
+
+ Handle = GetDebugPortHandle();
+ if (SkipStartSymbol) {
+ TimeoutForStartSymbol = 0;
+ } else {
+ TimeoutForStartSymbol = Timeout;
+ }
+
+ DebugHeader = (DEBUG_PACKET_HEADER *) InputPacket;
+ while (TRUE) {
+ //
+ // Find the valid start symbol
+ //
+ Received = DebugAgentReadBuffer (Handle, &DebugHeader->StartSymbol, sizeof (DebugHeader->StartSymbol), TimeoutForStartSymbol);
+ if (Received < sizeof (DebugHeader->StartSymbol)) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "DebugAgentReadBuffer(StartSymbol) timeout\n");
+ return RETURN_TIMEOUT;
+ }
+
+ if ((DebugHeader->StartSymbol != DEBUG_STARTING_SYMBOL_NORMAL) && (DebugHeader->StartSymbol != DEBUG_STARTING_SYMBOL_COMPRESS)) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Invalid start symbol received [%02x]\n", DebugHeader->StartSymbol);
+ continue;
+ }
+
+ //
+ // Read Package header till field Length
+ //
+ Received = DebugAgentReadBuffer (
+ Handle,
+ (UINT8 *) DebugHeader + OFFSET_OF (DEBUG_PACKET_HEADER, Command),
+ OFFSET_OF (DEBUG_PACKET_HEADER, Length) + sizeof (DebugHeader->Length) - sizeof (DebugHeader->StartSymbol),
+ Timeout
+ );
+ if (Received == 0) {
+ DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "DebugAgentReadBuffer(Command) timeout\n");
+ return RETURN_TIMEOUT;
+ }
+ if (DebugHeader->Length < sizeof (DEBUG_PACKET_HEADER)) {
+ if (IncompatibilityFlag != NULL) {
+ //
+ // This is one old version debug packet format, set Incompatibility flag
+ //
+ *IncompatibilityFlag = TRUE;
+ } else {
+ //
+ // Skip the bad small packet
+ //
+ continue;
+ }
+ } else {
+ //
+ // Read the payload data include the CRC field
+ //
+ Received = DebugAgentReadBuffer (Handle, &DebugHeader->SequenceNo, (UINT8) (DebugHeader->Length - OFFSET_OF (DEBUG_PACKET_HEADER, SequenceNo)), Timeout);
+ if (Received == 0) {
+ DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "DebugAgentReadBuffer(SequenceNo) timeout\n");
+ return RETURN_TIMEOUT;
+ }
+ //
+ // Calculate the CRC of Debug Packet
+ //
+ Crc = DebugHeader->Crc;
+ DebugHeader->Crc = 0;
+ if (Crc == CalculateCrc16 ((UINT8 *) DebugHeader, DebugHeader->Length, 0)) {
+ break;
+ }
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "CRC Error (received CRC is %x)\n", Crc);
+ DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *) DebugHeader, DebugHeader->Length);
+ }
+ }
+
+ DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *) DebugHeader, DebugHeader->Length);
+
+ if (DebugHeader->StartSymbol == DEBUG_STARTING_SYMBOL_COMPRESS) {
+ DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
+ DebugHeader->Length = DecompressDataInPlace (
+ (UINT8 *) (DebugHeader + 1), DebugHeader->Length - sizeof (DEBUG_PACKET_HEADER)
+ ) + sizeof (DEBUG_PACKET_HEADER);
+ }
+ return RETURN_SUCCESS;
+}
+
+/**
+ Receive acknowledge packet OK from HOST in specified time.
+
+ @param[in] Command The command type issued by TARGET.
+ @param[in] Timeout Time out value to wait for acknowledge from HOST.
+ The unit is microsecond.
+ @param[out] BreakReceived If BreakReceived is not NULL,
+ TRUE is returned if break-in symbol received.
+ FALSE is returned if break-in symbol not received.
+ @param[out] IncompatibilityFlag If IncompatibilityFlag is not NULL, return
+ TRUE: Compatible packet received.
+ FALSE: Incompatible packet received.
+
+ @retval RETURN_SUCCESS Succeed to receive acknowledge packet from HOST,
+ the type of acknowledge packet saved in Ack.
+ @retval RETURN_TIMEOUT Specified timeout value was up.
+
+**/
+RETURN_STATUS
+SendCommandAndWaitForAckOK (
+ IN UINT8 Command,
+ IN UINTN Timeout,
+ OUT BOOLEAN *BreakReceived, OPTIONAL
+ OUT BOOLEAN *IncompatibilityFlag OPTIONAL
+ )
+{
+ RETURN_STATUS Status;
+ UINT8 InputPacketBuffer[DEBUG_DATA_UPPER_LIMIT];
+ DEBUG_PACKET_HEADER *DebugHeader;
+ UINT8 SequenceNo;
+ UINT8 HostSequenceNo;
+ UINT8 RetryCount;
+
+ RetryCount = 3;
+ DebugHeader = (DEBUG_PACKET_HEADER *) InputPacketBuffer;
+ Status = RETURN_TIMEOUT;
+ while (RetryCount > 0) {
+ SequenceNo = GetMailboxPointer()->SequenceNo;
+ HostSequenceNo = GetMailboxPointer()->HostSequenceNo;
+ SendPacketWithoutData (Command, SequenceNo);
+ Status = ReceivePacket ((UINT8 *) DebugHeader, BreakReceived, IncompatibilityFlag, Timeout, FALSE);
+ if (Status == RETURN_TIMEOUT) {
+ if (Command == DEBUG_COMMAND_INIT_BREAK) {
+ RetryCount--;
+ } else {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Timeout when waiting for ACK packet.\n");
+ }
+ continue;
+ }
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Status == RETURN_SUCCESS
+ //
+ if (DebugHeader->Command == DEBUG_COMMAND_OK && DebugHeader->SequenceNo == SequenceNo) {
+ //
+ // Received Ack OK
+ //
+ UpdateMailboxContent (GetMailboxPointer(), DEBUG_MAILBOX_SEQUENCE_NO_INDEX, ++SequenceNo);
+ return Status;
+ }
+ if (DebugHeader->Command == DEBUG_COMMAND_GO && (DebugHeader->SequenceNo == HostSequenceNo || Command == DEBUG_COMMAND_INIT_BREAK)) {
+ //
+ // Received Old GO
+ //
+ if (Command == DEBUG_COMMAND_INIT_BREAK) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Receive GO() in last boot\n");
+ }
+ SendPacketWithoutData (DEBUG_COMMAND_OK, DebugHeader->SequenceNo);
+ }
+ }
+
+ ASSERT (Command == DEBUG_COMMAND_INIT_BREAK);
+ return Status;
+}
+
+/**
+ Get current break cause.
+
+ @param[in] Vector Vector value of exception or interrupt.
+ @param[in] CpuContext Pointer to save CPU context.
+
+ @return The type of break cause defined by XXXX
+
+**/
+UINT8
+GetBreakCause (
+ IN UINTN Vector,
+ IN DEBUG_CPU_CONTEXT *CpuContext
+ )
+{
+ UINT8 Cause;
+
+ Cause = DEBUG_DATA_BREAK_CAUSE_UNKNOWN;
+
+ switch (Vector) {
+ case DEBUG_INT1_VECTOR:
+ case DEBUG_INT3_VECTOR:
+
+ if (Vector == DEBUG_INT1_VECTOR) {
+ //
+ // INT 1
+ //
+ if ((CpuContext->Dr6 & BIT14) != 0) {
+ Cause = DEBUG_DATA_BREAK_CAUSE_STEPPING;
+ //
+ // DR6.BIT14 Indicates (when set) that the debug exception was
+ // triggered by the single step execution mode.
+ // The single-step mode is the highest priority debug exception.
+ // This is single step, no need to check DR0, to ensure single step
+ // work in PeCoffExtraActionLib (right after triggering a breakpoint
+ // to report image load/unload).
+ //
+ return Cause;
+
+ } else {
+ Cause = DEBUG_DATA_BREAK_CAUSE_HW_BREAKPOINT;
+ }
+ } else {
+ //
+ // INT 3
+ //
+ Cause = DEBUG_DATA_BREAK_CAUSE_SW_BREAKPOINT;
+ }
+
+ switch (CpuContext->Dr0) {
+ case IMAGE_LOAD_SIGNATURE:
+ case IMAGE_UNLOAD_SIGNATURE:
+
+ if (CpuContext->Dr3 == IO_PORT_BREAKPOINT_ADDRESS) {
+
+ Cause = (UINT8) ((CpuContext->Dr0 == IMAGE_LOAD_SIGNATURE) ?
+ DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD : DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD);
+ }
+ break;
+
+ case SOFT_INTERRUPT_SIGNATURE:
+
+ if (CpuContext->Dr1 == MEMORY_READY_SIGNATURE) {
+ Cause = DEBUG_DATA_BREAK_CAUSE_MEMORY_READY;
+ CpuContext->Dr0 = 0;
+ } else if (CpuContext->Dr1 == SYSTEM_RESET_SIGNATURE) {
+ Cause = DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET;
+ CpuContext->Dr0 = 0;
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ break;
+
+ case DEBUG_TIMER_VECTOR:
+ Cause = DEBUG_DATA_BREAK_CAUSE_USER_HALT;
+ break;
+
+ default:
+ if (Vector < 20) {
+ if (GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) == 1) {
+ //
+ // If stepping command is executing
+ //
+ Cause = DEBUG_DATA_BREAK_CAUSE_STEPPING;
+ } else {
+ Cause = DEBUG_DATA_BREAK_CAUSE_EXCEPTION;
+ }
+ }
+ break;
+ }
+
+ return Cause;
+}
+
+/**
+ Copy memory from source to destination with specified width.
+
+ @param[out] Dest A pointer to the destination buffer of the memory copy.
+ @param[in] Src A pointer to the source buffer of the memory copy.
+ @param[in] Count The number of data with specified width to copy from source to destination.
+ @param[in] Width Data width in byte.
+
+**/
+VOID
+CopyMemByWidth (
+ OUT UINT8 *Dest,
+ IN UINT8 *Src,
+ IN UINT16 Count,
+ IN UINT8 Width
+ )
+{
+ UINT8 *Destination;
+ UINT8 *Source;
+ INT8 Step;
+
+ if (Src > Dest) {
+ Destination = Dest;
+ Source = Src;
+ Step = Width;
+ } else {
+ //
+ // Copy memory from tail to avoid memory overlap
+ //
+ Destination = Dest + (Count - 1) * Width;
+ Source = Src + (Count - 1) * Width;
+ Step = -Width;
+ }
+
+ while (Count-- != 0) {
+ switch (Width) {
+ case 1:
+ *(UINT8 *) Destination = MmioRead8 ((UINTN) Source);
+ break;
+ case 2:
+ *(UINT16 *) Destination = MmioRead16 ((UINTN) Source);
+ break;
+ case 4:
+ *(UINT32 *) Destination = MmioRead32 ((UINTN) Source);
+ break;
+ case 8:
+ *(UINT64 *) Destination = MmioRead64 ((UINTN) Source);
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ Source += Step;
+ Destination += Step;
+ }
+}
+
+/**
+ Compress the data buffer but do not modify the original buffer.
+
+ The compressed data is directly send to the debug channel.
+ Compressing in place doesn't work because the data may become larger
+ during compressing phase. ("3 3 ..." --> "3 3 0 ...")
+ The routine is expected to be called three times:
+ 1. Compute the length of the compressed data buffer;
+ 2. Compute the CRC of the compressed data buffer;
+ 3. Compress the data and send to the debug channel.
+
+ @param[in] Handle The debug channel handle to send the compressed data buffer.
+ @param[in] Data The data buffer.
+ @param[in] Length The length of the data buffer.
+ @param[in] Send TRUE to send the compressed data buffer.
+ @param[out] CompressedLength Return the length of the compressed data buffer.
+ It may be larger than the Length in some cases.
+ @param[out] CompressedCrc Return the CRC of the compressed data buffer.
+**/
+VOID
+CompressData (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Data,
+ IN UINT8 Length,
+ IN BOOLEAN Send,
+ OUT UINTN *CompressedLength, OPTIONAL
+ OUT UINT16 *CompressedCrc OPTIONAL
+ )
+{
+ UINTN Index;
+ UINT8 LastChar;
+ UINT8 LastCharCount;
+ UINT8 CurrentChar;
+ UINTN CompressedIndex;
+
+ ASSERT (Length > 0);
+ LastChar = Data[0] + 1; // Just ensure it's different from the first byte.
+ LastCharCount = 0;
+
+ for (Index = 0, CompressedIndex = 0; Index <= Length; Index++) {
+ if (Index < Length) {
+ CurrentChar = Data[Index];
+ } else {
+ CurrentChar = (UINT8) LastChar + 1; // just ensure it's different from LastChar
+ }
+ if (LastChar != CurrentChar) {
+ if (LastCharCount == 1) {
+ CompressedIndex++;
+ if (CompressedCrc != NULL) {
+ *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);
+ }
+ if (Send) {
+ DebugPortWriteBuffer (Handle, &LastChar, 1);
+ }
+
+ } else if (LastCharCount >= 2) {
+ CompressedIndex += 3;
+ LastCharCount -= 2;
+ if (CompressedCrc != NULL) {
+ *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);
+ *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);
+ *CompressedCrc = CalculateCrc16 (&LastCharCount, 1, *CompressedCrc);
+ }
+ if (Send) {
+ DebugPortWriteBuffer (Handle, &LastChar, 1);
+ DebugPortWriteBuffer (Handle, &LastChar, 1);
+ DebugPortWriteBuffer (Handle, &LastCharCount, 1);
+ }
+ }
+ LastCharCount = 0;
+ }
+ LastCharCount++;
+ LastChar = CurrentChar;
+ }
+
+ if (CompressedLength != NULL) {
+ *CompressedLength = CompressedIndex;
+ }
+}
+
+/**
+ Read memory with specified width and send packet with response data to HOST.
+
+ @param[in] Data Pointer to response data buffer.
+ @param[in] Count The number of data with specified Width.
+ @param[in] Width Data width in byte.
+ @param[in] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet,
+ to minimize the stack usage.
+
+ @retval RETURN_SUCCESS Response data was sent successfully.
+
+**/
+RETURN_STATUS
+ReadMemoryAndSendResponsePacket (
+ IN UINT8 *Data,
+ IN UINT16 Count,
+ IN UINT8 Width,
+ IN DEBUG_PACKET_HEADER *DebugHeader
+ )
+{
+ RETURN_STATUS Status;
+ BOOLEAN LastPacket;
+ DEBUG_PORT_HANDLE Handle;
+ UINT8 SequenceNo;
+ UINTN RemainingDataSize;
+ UINT8 CurrentDataSize;
+ UINTN CompressedDataSize;
+
+ Handle = GetDebugPortHandle();
+
+ RemainingDataSize = Count * Width;
+ while (TRUE) {
+ SequenceNo = GetMailboxPointer()->HostSequenceNo;
+ if (RemainingDataSize <= DEBUG_DATA_MAXIMUM_REAL_DATA) {
+ //
+ // If the remaining data is less one real packet size, this is the last data packet
+ //
+ CurrentDataSize = (UINT8) RemainingDataSize;
+ LastPacket = TRUE;
+ DebugHeader->Command = DEBUG_COMMAND_OK;
+ } else {
+ //
+ // Data is too larger to be sent in one packet, calculate the actual data size could
+ // be sent in one Maximum data packet
+ //
+ CurrentDataSize = (DEBUG_DATA_MAXIMUM_REAL_DATA / Width) * Width;
+ LastPacket = FALSE;
+ DebugHeader->Command = DEBUG_COMMAND_IN_PROGRESS;
+ }
+ //
+ // Construct the rest Debug header
+ //
+ DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
+ DebugHeader->Length = CurrentDataSize + sizeof (DEBUG_PACKET_HEADER);
+ DebugHeader->SequenceNo = SequenceNo;
+ DebugHeader->Crc = 0;
+ CopyMemByWidth ((UINT8 *) (DebugHeader + 1), Data, CurrentDataSize / Width, Width);
+
+ //
+ // Compression/decompression support was added since revision 0.4.
+ // Revision 0.3 shouldn't compress the packet.
+ //
+ if (PcdGet32(PcdTransferProtocolRevision) >= DEBUG_AGENT_REVISION_04) {
+ //
+ // Get the compressed data size without modifying the packet.
+ //
+ CompressData (
+ Handle,
+ (UINT8 *) (DebugHeader + 1),
+ CurrentDataSize,
+ FALSE,
+ &CompressedDataSize,
+ NULL
+ );
+ } else {
+ CompressedDataSize = CurrentDataSize;
+ }
+ if (CompressedDataSize < CurrentDataSize) {
+ DebugHeader->Length = (UINT8) CompressedDataSize + sizeof (DEBUG_PACKET_HEADER);
+ DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_COMPRESS;
+ //
+ // Compute the CRC of the packet head without modifying the packet.
+ //
+ DebugHeader->Crc = CalculateCrc16 ((UINT8 *) DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0);
+ CompressData (
+ Handle,
+ (UINT8 *) (DebugHeader + 1),
+ CurrentDataSize,
+ FALSE,
+ NULL,
+ &DebugHeader->Crc
+ );
+ //
+ // Send out the packet head.
+ //
+ DebugPortWriteBuffer (Handle, (UINT8 *) DebugHeader, sizeof (DEBUG_PACKET_HEADER));
+ //
+ // Compress and send out the packet data.
+ //
+ CompressData (
+ Handle,
+ (UINT8 *) (DebugHeader + 1),
+ CurrentDataSize,
+ TRUE,
+ NULL,
+ NULL
+ );
+ } else {
+
+ //
+ // Calculate and fill the checksum, DebugHeader->Crc should be 0 before invoking CalculateCrc16 ()
+ //
+ DebugHeader->Crc = CalculateCrc16 ((UINT8 *) DebugHeader, DebugHeader->Length, 0);
+
+ DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, TRUE, (UINT8 *) DebugHeader, DebugHeader->Length);
+
+ DebugPortWriteBuffer (Handle, (UINT8 *) DebugHeader, DebugHeader->Length);
+ }
+
+ while (TRUE) {
+ Status = ReceivePacket ((UINT8 *) DebugHeader, NULL, NULL, READ_PACKET_TIMEOUT, FALSE);
+ if (Status == RETURN_TIMEOUT) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Timeout in SendDataResponsePacket()\n");
+ break;
+ }
+ if ((DebugHeader->Command == DEBUG_COMMAND_OK) && (DebugHeader->SequenceNo == SequenceNo) && LastPacket) {
+ //
+ // If this is the last packet, return RETURN_SUCCESS.
+ //
+ return RETURN_SUCCESS;
+ }
+ if ((DebugHeader->Command == DEBUG_COMMAND_CONTINUE) && (DebugHeader->SequenceNo == (UINT8) (SequenceNo + 1))) {
+ //
+ // Calculate the rest data size
+ //
+ Data += CurrentDataSize;
+ RemainingDataSize -= CurrentDataSize;
+ UpdateMailboxContent (GetMailboxPointer(), DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, DebugHeader->SequenceNo);
+ break;
+ }
+ if (DebugHeader->SequenceNo >= SequenceNo) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Received one old or new command(SequenceNo is %x, last SequenceNo is %x)\n", SequenceNo, DebugHeader->SequenceNo);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ Send packet with response data to HOST.
+
+ @param[in] Data Pointer to response data buffer.
+ @param[in] DataSize Size of response data in byte.
+ @param[in, out] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet,
+ to minimize the stack usage.
+
+ @retval RETURN_SUCCESS Response data was sent successfully.
+
+**/
+RETURN_STATUS
+SendDataResponsePacket (
+ IN UINT8 *Data,
+ IN UINT16 DataSize,
+ IN OUT DEBUG_PACKET_HEADER *DebugHeader
+ )
+{
+ return ReadMemoryAndSendResponsePacket (Data, DataSize, 1, DebugHeader);
+}
+
+/**
+ Try to attach the HOST.
+
+ Send init break packet to HOST:
+ If no acknowledge received in specified Timeout, return RETURN_TIMEOUT.
+ If received acknowledge, check the revision of HOST.
+ Set Attach Flag if attach successfully.
+
+ @param[in] BreakCause Break cause of this break event.
+ @param[in] Timeout Time out value to wait for acknowledge from HOST.
+ The unit is microsecond.
+ @param[out] BreakReceived If BreakReceived is not NULL,
+ TRUE is returned if break-in symbol received.
+ FALSE is returned if break-in symbol not received.
+**/
+RETURN_STATUS
+AttachHost (
+ IN UINT8 BreakCause,
+ IN UINTN Timeout,
+ OUT BOOLEAN *BreakReceived
+ )
+{
+ RETURN_STATUS Status;
+ DEBUG_PORT_HANDLE Handle;
+ BOOLEAN IncompatibilityFlag;
+
+ IncompatibilityFlag = FALSE;
+ Handle = GetDebugPortHandle();
+
+ //
+ // Send init break and wait ack in Timeout
+ //
+ DebugPortWriteBuffer (Handle, (UINT8 *) mErrorMsgSendInitPacket, AsciiStrLen (mErrorMsgSendInitPacket));
+ if (BreakCause == DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET) {
+ Status = SendCommandAndWaitForAckOK (DEBUG_COMMAND_INIT_BREAK, Timeout, BreakReceived, &IncompatibilityFlag);
+ } else {
+ Status = SendCommandAndWaitForAckOK (DEBUG_COMMAND_ATTACH_BREAK, Timeout, BreakReceived, &IncompatibilityFlag);
+ }
+ if (IncompatibilityFlag) {
+ //
+ // If the incompatible Debug Packet received, the HOST should be running transfer protocol before PcdTransferProtocolRevision.
+ // It could be UDK Debugger for Windows v1.1/v1.2 or for Linux v0.8/v1.2.
+ //
+ DebugPortWriteBuffer (Handle, (UINT8 *) mErrorMsgVersionAlert, AsciiStrLen (mErrorMsgVersionAlert));
+ CpuDeadLoop ();
+ }
+
+ if (RETURN_ERROR (Status)) {
+ DebugPortWriteBuffer (Handle, (UINT8 *) mErrorMsgConnectFail, AsciiStrLen (mErrorMsgConnectFail));
+ } else {
+ DebugPortWriteBuffer (Handle, (UINT8 *) mErrorMsgConnectOK, AsciiStrLen (mErrorMsgConnectOK));
+ //
+ // Set Attach flag
+ //
+ SetHostAttached (TRUE);
+ }
+ return Status;
+}
+
+/**
+ Send Break point packet to HOST.
+
+ Only the first breaking processor could sent BREAK_POINT packet.
+
+ @param[in] BreakCause Break cause of this break event.
+ @param[in] ProcessorIndex Processor index value.
+ @param[out] BreakReceived If BreakReceived is not NULL,
+ TRUE is returned if break-in symbol received.
+ FALSE is returned if break-in symbol not received.
+
+**/
+VOID
+SendBreakPacketToHost (
+ IN UINT8 BreakCause,
+ IN UINT32 ProcessorIndex,
+ OUT BOOLEAN *BreakReceived
+ )
+{
+ UINT8 InputCharacter;
+ DEBUG_PORT_HANDLE Handle;
+
+ Handle = GetDebugPortHandle();
+
+ if (IsHostAttached ()) {
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Send Break Packet to HOST.\n", ProcessorIndex);
+ SendCommandAndWaitForAckOK (DEBUG_COMMAND_BREAK_POINT, READ_PACKET_TIMEOUT, BreakReceived, NULL);
+ } else {
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Try to attach HOST.\n", ProcessorIndex);
+ //
+ // If HOST is not attached, try to attach it firstly.
+ //
+ //
+ // Poll Attach symbols from HOST and ack OK
+ //
+ do {
+ DebugAgentReadBuffer (Handle, &InputCharacter, 1, 0);
+ } while (InputCharacter != DEBUG_STARTING_SYMBOL_ATTACH);
+ SendAckPacket (DEBUG_COMMAND_OK);
+
+ //
+ // Try to attach HOST
+ //
+ while (AttachHost (BreakCause, 0, NULL) != RETURN_SUCCESS);
+
+ }
+}
+
+/**
+ The main function to process communication with HOST.
+
+ It received the command packet from HOST, and sent response data packet to HOST.
+
+ @param[in] Vector Vector value of exception or interrupt.
+ @param[in, out] CpuContext Pointer to saved CPU context.
+ @param[in] BreakReceived TRUE means break-in symbol received.
+ FALSE means break-in symbol not received.
+
+**/
+VOID
+CommandCommunication (
+ IN UINTN Vector,
+ IN OUT DEBUG_CPU_CONTEXT *CpuContext,
+ IN BOOLEAN BreakReceived
+ )
+{
+ RETURN_STATUS Status;
+ UINT8 InputPacketBuffer[DEBUG_DATA_UPPER_LIMIT + sizeof (UINT64) - 1];
+ DEBUG_PACKET_HEADER *DebugHeader;
+ UINT8 Width;
+ UINT8 Data8;
+ UINT32 Data32;
+ UINT64 Data64;
+ DEBUG_DATA_READ_MEMORY *MemoryRead;
+ DEBUG_DATA_WRITE_MEMORY *MemoryWrite;
+ DEBUG_DATA_READ_IO *IoRead;
+ DEBUG_DATA_WRITE_IO *IoWrite;
+ DEBUG_DATA_READ_REGISTER *RegisterRead;
+ DEBUG_DATA_WRITE_REGISTER *RegisterWrite;
+ UINT8 *RegisterBuffer;
+ DEBUG_DATA_READ_MSR *MsrRegisterRead;
+ DEBUG_DATA_WRITE_MSR *MsrRegisterWrite;
+ DEBUG_DATA_CPUID *Cpuid;
+ DEBUG_DATA_RESPONSE_BREAK_CAUSE BreakCause;
+ DEBUG_DATA_RESPONSE_CPUID CpuidResponse;
+ DEBUG_DATA_SEARCH_SIGNATURE *SearchSignature;
+ DEBUG_DATA_RESPONSE_GET_EXCEPTION Exception;
+ DEBUG_DATA_RESPONSE_GET_REVISION DebugAgentRevision;
+ DEBUG_DATA_SET_VIEWPOINT *SetViewPoint;
+ BOOLEAN HaltDeferred;
+ UINT32 ProcessorIndex;
+ DEBUG_AGENT_EXCEPTION_BUFFER AgentExceptionBuffer;
+ UINT32 IssuedViewPoint;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ UINT8 *AlignedDataPtr;
+
+ ProcessorIndex = 0;
+ IssuedViewPoint = 0;
+ HaltDeferred = BreakReceived;
+
+ if (MultiProcessorDebugSupport()) {
+ ProcessorIndex = GetProcessorIndex ();
+ SetCpuStopFlagByIndex (ProcessorIndex, TRUE);
+ if (mDebugMpContext.ViewPointIndex == ProcessorIndex) {
+ //
+ // Only the current view processor could set AgentInProgress Flag.
+ //
+ IssuedViewPoint = ProcessorIndex;
+ }
+ }
+
+ if (IssuedViewPoint == ProcessorIndex) {
+ //
+ // Set AgentInProgress Flag.
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS, 1);
+ }
+
+ while (TRUE) {
+
+ if (MultiProcessorDebugSupport()) {
+ //
+ // Check if the current processor is HOST view point
+ //
+ if (mDebugMpContext.ViewPointIndex != ProcessorIndex) {
+ if (mDebugMpContext.RunCommandSet) {
+ //
+ // If HOST view point sets RUN flag, run GO command to leave
+ //
+ SetCpuStopFlagByIndex (ProcessorIndex, FALSE);
+ CommandGo (CpuContext);
+ break;
+ } else {
+ //
+ // Run into loop again
+ //
+ CpuPause ();
+ continue;
+ }
+ }
+ }
+
+ AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ DebugHeader =(DEBUG_PACKET_HEADER *) InputPacketBuffer;
+
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "TARGET: Try to get command from HOST...\n");
+ Status = ReceivePacket ((UINT8 *) DebugHeader, &BreakReceived, NULL, READ_PACKET_TIMEOUT, TRUE);
+ if (Status != RETURN_SUCCESS || !IS_REQUEST (DebugHeader)) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Get command[%x] sequenceno[%x] returned status is [%x] \n", DebugHeader->Command, DebugHeader->SequenceNo, Status);
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Get command failed or it's response packet not expected! \n");
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ continue;
+ }
+
+ Mailbox = GetMailboxPointer ();
+ if (DebugHeader->SequenceNo == Mailbox->HostSequenceNo) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Receive one old command[%x] against command[%x]\n", DebugHeader->SequenceNo, Mailbox->HostSequenceNo);
+ SendAckPacket (Mailbox->LastAck);
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ continue;
+ } else if (DebugHeader->SequenceNo == (UINT8) (Mailbox->HostSequenceNo + 1)) {
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, (UINT8) DebugHeader->SequenceNo);
+ } else {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Receive one invalid command[%x] against command[%x]\n", DebugHeader->SequenceNo, Mailbox->HostSequenceNo);
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ continue;
+ }
+
+ //
+ // Save CPU content before executing HOST command
+ //
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX, (UINT64)(UINTN) &AgentExceptionBuffer.JumpBuffer);
+ if (SetJump (&AgentExceptionBuffer.JumpBuffer) != 0) {
+ //
+ // If HOST command failed, continue to wait for HOST's next command
+ // If needed, agent could send exception info to HOST.
+ //
+ SendAckPacket (DEBUG_COMMAND_ABORT);
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ continue;
+ }
+
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Processor[%x]:Received one command(%x)\n", mDebugMpContext.ViewPointIndex, DebugHeader->Command);
+
+ switch (DebugHeader->Command) {
+
+ case DEBUG_COMMAND_HALT:
+ SendAckPacket (DEBUG_COMMAND_HALT_DEFERRED);
+ HaltDeferred = TRUE;
+ BreakReceived = FALSE;
+ Status = RETURN_SUCCESS;
+ break;
+
+ case DEBUG_COMMAND_RESET:
+ SendAckPacket (DEBUG_COMMAND_OK);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ ResetCold ();
+ //
+ // Assume system resets in 2 seconds, otherwise send TIMEOUT packet.
+ // PCD can be used if 2 seconds isn't long enough for some platforms.
+ //
+ MicroSecondDelay (2000000);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, Mailbox->HostSequenceNo + 1);
+ SendAckPacket (DEBUG_COMMAND_TIMEOUT);
+ SendAckPacket (DEBUG_COMMAND_TIMEOUT);
+ SendAckPacket (DEBUG_COMMAND_TIMEOUT);
+ break;
+
+ case DEBUG_COMMAND_GO:
+ CommandGo (CpuContext);
+ //
+ // Clear Dr0 to avoid to be recognized as IMAGE_LOAD/_UNLOAD again when hitting a breakpoint after GO
+ // If HOST changed Dr0 before GO, we will not change Dr0 here
+ //
+ Data8 = GetBreakCause (Vector, CpuContext);
+ if (Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD || Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD) {
+ CpuContext->Dr0 = 0;
+ }
+
+ if (!HaltDeferred) {
+ //
+ // If no HALT command received when being in-active mode
+ //
+ if (MultiProcessorDebugSupport()) {
+ Data32 = FindNextPendingBreakCpu ();
+ if (Data32 != -1) {
+ //
+ // If there are still others processors being in break state,
+ // send OK packet to HOST to finish this go command
+ //
+ SendAckPacket (DEBUG_COMMAND_OK);
+ CpuPause ();
+ //
+ // Set current view to the next breaking processor
+ //
+ mDebugMpContext.ViewPointIndex = Data32;
+ mDebugMpContext.BreakAtCpuIndex = mDebugMpContext.ViewPointIndex;
+ SetCpuBreakFlagByIndex (mDebugMpContext.ViewPointIndex, FALSE);
+ //
+ // Send break packet to HOST to let HOST break again
+ //
+ SendBreakPacketToHost (DEBUG_DATA_BREAK_CAUSE_UNKNOWN, mDebugMpContext.BreakAtCpuIndex, &BreakReceived);
+ //
+ // Continue to run into loop to read command packet from HOST
+ //
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ break;
+ }
+
+ //
+ // If no else processor break, set stop bitmask,
+ // and set Running flag for all processors.
+ //
+ SetCpuStopFlagByIndex (ProcessorIndex, FALSE);
+ SetCpuRunningFlag (TRUE);
+ CpuPause ();
+ //
+ // Wait for all processors are in running state
+ //
+ while (TRUE) {
+ if (IsAllCpuRunning ()) {
+ break;
+ }
+ }
+ //
+ // Set BSP to be current view point.
+ //
+ SetDebugViewPoint (mDebugMpContext.BspIndex);
+ CpuPause ();
+ //
+ // Clear breaking processor index and running flag
+ //
+ mDebugMpContext.BreakAtCpuIndex = (UINT32) (-1);
+ SetCpuRunningFlag (FALSE);
+ }
+
+ //
+ // Send OK packet to HOST to finish this go command
+ //
+ SendAckPacket (DEBUG_COMMAND_OK);
+
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ if (!IsHostAttached()) {
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_SEQUENCE_NO_INDEX, 0);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, 0);
+ }
+ return;
+
+ } else {
+ //
+ // If received HALT command, need to defer the GO command
+ //
+ SendAckPacket (DEBUG_COMMAND_HALT_PROCESSED);
+ HaltDeferred = FALSE;
+
+ Vector = DEBUG_TIMER_VECTOR;
+ }
+ break;
+
+ case DEBUG_COMMAND_BREAK_CAUSE:
+ BreakCause.StopAddress = CpuContext->Eip;
+ if (MultiProcessorDebugSupport() && ProcessorIndex != mDebugMpContext.BreakAtCpuIndex) {
+ BreakCause.Cause = GetBreakCause (DEBUG_TIMER_VECTOR, CpuContext);
+ } else {
+ BreakCause.Cause = GetBreakCause (Vector, CpuContext);
+ }
+ SendDataResponsePacket ((UINT8 *) &BreakCause, (UINT16) sizeof (DEBUG_DATA_RESPONSE_BREAK_CAUSE), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_SET_HW_BREAKPOINT:
+ SetDebugRegister (CpuContext, (DEBUG_DATA_SET_HW_BREAKPOINT *) (DebugHeader + 1));
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_CLEAR_HW_BREAKPOINT:
+ ClearDebugRegister (CpuContext, (DEBUG_DATA_CLEAR_HW_BREAKPOINT *) (DebugHeader + 1));
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_SINGLE_STEPPING:
+ CommandStepping (CpuContext);
+ //
+ // Clear Dr0 to avoid to be recognized as IMAGE_LOAD/_UNLOAD again when hitting a breakpoint after GO
+ // If HOST changed Dr0 before GO, we will not change Dr0 here
+ //
+ Data8 = GetBreakCause (Vector, CpuContext);
+ if (Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD || Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD) {
+ CpuContext->Dr0 = 0;
+ }
+
+ mDebugMpContext.BreakAtCpuIndex = (UINT32) (-1);
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ //
+ // Executing stepping command directly without sending ACK packet,
+ // ACK packet will be sent after stepping done.
+ //
+ return;
+
+ case DEBUG_COMMAND_SET_SW_BREAKPOINT:
+ Data64 = (UINTN) (((DEBUG_DATA_SET_SW_BREAKPOINT *) (DebugHeader + 1))->Address);
+ Data8 = *(UINT8 *) (UINTN) Data64;
+ *(UINT8 *) (UINTN) Data64 = DEBUG_SW_BREAKPOINT_SYMBOL;
+ Status = SendDataResponsePacket ((UINT8 *) &Data8, (UINT16) sizeof (UINT8), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_READ_MEMORY:
+ MemoryRead = (DEBUG_DATA_READ_MEMORY *) (DebugHeader + 1);
+ Status = ReadMemoryAndSendResponsePacket ((UINT8 *) (UINTN) MemoryRead->Address, MemoryRead->Count, MemoryRead->Width, DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_WRITE_MEMORY:
+ MemoryWrite = (DEBUG_DATA_WRITE_MEMORY *) (DebugHeader + 1);
+ //
+ // Copy data into one memory with 8-byte alignment address
+ //
+ AlignedDataPtr = ALIGN_POINTER ((UINT8 *) &MemoryWrite->Data, sizeof (UINT64));
+ if (AlignedDataPtr != (UINT8 *) &MemoryWrite->Data) {
+ CopyMem (AlignedDataPtr, (UINT8 *) &MemoryWrite->Data, MemoryWrite->Count * MemoryWrite->Width);
+ }
+ CopyMemByWidth ((UINT8 *) (UINTN) MemoryWrite->Address, AlignedDataPtr, MemoryWrite->Count, MemoryWrite->Width);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_READ_IO:
+ IoRead = (DEBUG_DATA_READ_IO *) (DebugHeader + 1);
+ switch (IoRead->Width) {
+ case 1:
+ Data64 = IoRead8 ((UINTN) IoRead->Port);
+ break;
+ case 2:
+ Data64 = IoRead16 ((UINTN) IoRead->Port);
+ break;
+ case 4:
+ Data64 = IoRead32 ((UINTN) IoRead->Port);
+ break;
+ case 8:
+ Data64 = IoRead64 ((UINTN) IoRead->Port);
+ break;
+ default:
+ Data64 = (UINT64) -1;
+ }
+ Status = SendDataResponsePacket ((UINT8 *) &Data64, IoRead->Width, DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_WRITE_IO:
+ IoWrite = (DEBUG_DATA_WRITE_IO *) (DebugHeader + 1);
+ switch (IoWrite->Width) {
+ case 1:
+ Data64 = IoWrite8 ((UINTN) IoWrite->Port, *(UINT8 *) &IoWrite->Data);
+ break;
+ case 2:
+ Data64 = IoWrite16 ((UINTN) IoWrite->Port, *(UINT16 *) &IoWrite->Data);
+ break;
+ case 4:
+ Data64 = IoWrite32 ((UINTN) IoWrite->Port, *(UINT32 *) &IoWrite->Data);
+ break;
+ case 8:
+ Data64 = IoWrite64 ((UINTN) IoWrite->Port, *(UINT64 *) &IoWrite->Data);
+ break;
+ default:
+ Data64 = (UINT64) -1;
+ }
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_READ_ALL_REGISTERS:
+ Status = SendDataResponsePacket ((UINT8 *) CpuContext, sizeof (*CpuContext), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_READ_REGISTER:
+ RegisterRead = (DEBUG_DATA_READ_REGISTER *) (DebugHeader + 1);
+
+ if (RegisterRead->Index <= SOFT_DEBUGGER_REGISTER_MAX) {
+ RegisterBuffer = ArchReadRegisterBuffer (CpuContext, RegisterRead->Index, &Width);
+ Status = SendDataResponsePacket (RegisterBuffer, Width, DebugHeader);
+ } else {
+ Status = RETURN_UNSUPPORTED;
+ }
+ break;
+
+ case DEBUG_COMMAND_WRITE_REGISTER:
+ RegisterWrite = (DEBUG_DATA_WRITE_REGISTER *) (DebugHeader + 1);
+ if (RegisterWrite->Index <= SOFT_DEBUGGER_REGISTER_MAX) {
+ RegisterBuffer = ArchReadRegisterBuffer (CpuContext, RegisterWrite->Index, &Width);
+ ASSERT (Width == RegisterWrite->Length);
+ CopyMem (RegisterBuffer, RegisterWrite->Data, Width);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ } else {
+ Status = RETURN_UNSUPPORTED;
+ }
+ break;
+
+ case DEBUG_COMMAND_ARCH_MODE:
+ Data8 = DEBUG_ARCH_SYMBOL;
+ Status = SendDataResponsePacket ((UINT8 *) &Data8, (UINT16) sizeof (UINT8), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_READ_MSR:
+ MsrRegisterRead = (DEBUG_DATA_READ_MSR *) (DebugHeader + 1);
+ Data64 = AsmReadMsr64 (MsrRegisterRead->Index);
+ Status = SendDataResponsePacket ((UINT8 *) &Data64, (UINT16) sizeof (UINT64), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_WRITE_MSR:
+ MsrRegisterWrite = (DEBUG_DATA_WRITE_MSR *) (DebugHeader + 1);
+ AsmWriteMsr64 (MsrRegisterWrite->Index, MsrRegisterWrite->Value);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_SET_DEBUG_SETTING:
+ Status = SetDebugSetting ((DEBUG_DATA_SET_DEBUG_SETTING *)(DebugHeader + 1));
+ if (Status == RETURN_SUCCESS) {
+ SendAckPacket (DEBUG_COMMAND_OK);
+ }
+ break;
+
+ case DEBUG_COMMAND_GET_REVISION:
+ DebugAgentRevision.Revision = PcdGet32(PcdTransferProtocolRevision);
+ DebugAgentRevision.Capabilities = DEBUG_AGENT_CAPABILITIES;
+ Status = SendDataResponsePacket ((UINT8 *) &DebugAgentRevision, (UINT16) sizeof (DEBUG_DATA_RESPONSE_GET_REVISION), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_GET_EXCEPTION:
+ Exception.ExceptionNum = (UINT8) Vector;
+ Exception.ExceptionData = (UINT32) CpuContext->ExceptionData;
+ Status = SendDataResponsePacket ((UINT8 *) &Exception, (UINT16) sizeof (DEBUG_DATA_RESPONSE_GET_EXCEPTION), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_SET_VIEWPOINT:
+ SetViewPoint = (DEBUG_DATA_SET_VIEWPOINT *) (DebugHeader + 1);
+ if (MultiProcessorDebugSupport()) {
+ if (IsCpuStopped (SetViewPoint->ViewPoint)) {
+ SetDebugViewPoint (SetViewPoint->ViewPoint);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ } else {
+ //
+ // If CPU is not halted
+ //
+ SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
+ }
+ } else if (SetViewPoint->ViewPoint == 0) {
+ SendAckPacket (DEBUG_COMMAND_OK);
+
+ } else {
+ SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
+ }
+
+ break;
+
+ case DEBUG_COMMAND_GET_VIEWPOINT:
+ Data32 = mDebugMpContext.ViewPointIndex;
+ SendDataResponsePacket((UINT8 *) &Data32, (UINT16) sizeof (UINT32), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_MEMORY_READY:
+ Data8 = (UINT8) GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY);
+ SendDataResponsePacket (&Data8, (UINT16) sizeof (UINT8), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_DETACH:
+ SetHostAttached (FALSE);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_CPUID:
+ Cpuid = (DEBUG_DATA_CPUID *) (DebugHeader + 1);
+ AsmCpuidEx (
+ Cpuid->Eax, Cpuid->Ecx,
+ &CpuidResponse.Eax, &CpuidResponse.Ebx,
+ &CpuidResponse.Ecx, &CpuidResponse.Edx
+ );
+ SendDataResponsePacket ((UINT8 *) &CpuidResponse, (UINT16) sizeof (CpuidResponse), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_SEARCH_SIGNATURE:
+ SearchSignature = (DEBUG_DATA_SEARCH_SIGNATURE *) (DebugHeader + 1);
+ if ((SearchSignature->Alignment != 0) &&
+ (SearchSignature->Alignment == GetPowerOfTwo32 (SearchSignature->Alignment))
+ ) {
+ if (SearchSignature->Positive) {
+ for (
+ Data64 = ALIGN_VALUE ((UINTN) SearchSignature->Start, SearchSignature->Alignment);
+ Data64 <= SearchSignature->Start + SearchSignature->Count - SearchSignature->DataLength;
+ Data64 += SearchSignature->Alignment
+ ) {
+ if (CompareMem ((VOID *) (UINTN) Data64, &SearchSignature->Data, SearchSignature->DataLength) == 0) {
+ break;
+ }
+ }
+ if (Data64 > SearchSignature->Start + SearchSignature->Count - SearchSignature->DataLength) {
+ Data64 = (UINT64) -1;
+ }
+ } else {
+ for (
+ Data64 = ALIGN_VALUE ((UINTN) SearchSignature->Start - SearchSignature->Alignment, SearchSignature->Alignment);
+ Data64 >= SearchSignature->Start - SearchSignature->Count;
+ Data64 -= SearchSignature->Alignment
+ ) {
+ if (CompareMem ((VOID *) (UINTN) Data64, &SearchSignature->Data, SearchSignature->DataLength) == 0) {
+ break;
+ }
+ }
+ if (Data64 < SearchSignature->Start - SearchSignature->Count) {
+ Data64 = (UINT64) -1;
+ }
+ }
+ SendDataResponsePacket ((UINT8 *) &Data64, (UINT16) sizeof (Data64), DebugHeader);
+ } else {
+ Status = RETURN_UNSUPPORTED;
+ }
+ break;
+
+ default:
+ SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
+ break;
+ }
+
+ if (Status == RETURN_UNSUPPORTED) {
+ SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
+ } else if (Status != RETURN_SUCCESS) {
+ SendAckPacket (DEBUG_COMMAND_ABORT);
+ }
+
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ CpuPause ();
+ }
+}
+
+/**
+ C function called in interrupt handler.
+
+ @param[in] Vector Vector value of exception or interrupt.
+ @param[in] CpuContext Pointer to save CPU context.
+
+**/
+VOID
+EFIAPI
+InterruptProcess (
+ IN UINT32 Vector,
+ IN DEBUG_CPU_CONTEXT *CpuContext
+ )
+{
+ UINT8 InputCharacter;
+ UINT8 BreakCause;
+ UINTN SavedEip;
+ BOOLEAN BreakReceived;
+ UINT32 ProcessorIndex;
+ UINT32 CurrentDebugTimerInitCount;
+ DEBUG_PORT_HANDLE Handle;
+ UINT8 Data8;
+ UINT8 *Al;
+ UINT32 IssuedViewPoint;
+ DEBUG_AGENT_EXCEPTION_BUFFER *ExceptionBuffer;
+
+ InputCharacter = 0;
+ ProcessorIndex = 0;
+ IssuedViewPoint = 0;
+ BreakReceived = FALSE;
+
+ if (mSkipBreakpoint) {
+ //
+ // If Skip Breakpoint flag is set, means communication is disturbed by hardware SMI, we need to ignore the break points in SMM
+ //
+ if ((Vector == DEBUG_INT1_VECTOR) || (Vector == DEBUG_INT3_VECTOR)) {
+ DebugPortWriteBuffer (GetDebugPortHandle(), (UINT8 *) mWarningMsgIngoreBreakpoint, AsciiStrLen (mWarningMsgIngoreBreakpoint));
+ return;
+ }
+ }
+
+ if (MultiProcessorDebugSupport()) {
+ ProcessorIndex = GetProcessorIndex ();
+ //
+ // If this processor has already halted before, need to check it later
+ //
+ if (IsCpuStopped (ProcessorIndex)) {
+ IssuedViewPoint = ProcessorIndex;
+ }
+ }
+
+ if (IssuedViewPoint == ProcessorIndex && GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) != 1) {
+ //
+ // Check if this exception is issued by Debug Agent itself
+ // If yes, fill the debug agent exception buffer and LongJump() back to
+ // the saved CPU content in CommandCommunication()
+ // If exception is issued when executing Stepping, will be handled in
+ // exception handle procedure.
+ //
+ if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) {
+ DebugAgentMsgPrint (
+ DEBUG_AGENT_ERROR,
+ "Debug agent meet one Exception, ExceptionNum is %d, EIP = 0x%x.\n",
+ Vector,
+ (UINTN)CpuContext->Eip
+ );
+ ExceptionBuffer = (DEBUG_AGENT_EXCEPTION_BUFFER *) (UINTN) GetMailboxPointer()->ExceptionBufferPointer;
+ ExceptionBuffer->ExceptionContent.ExceptionNum = (UINT8) Vector;
+ ExceptionBuffer->ExceptionContent.ExceptionData = (UINT32) CpuContext->ExceptionData;
+ LongJump ((BASE_LIBRARY_JUMP_BUFFER *)(UINTN)(ExceptionBuffer), 1);
+ }
+ }
+
+ if (MultiProcessorDebugSupport()) {
+ //
+ // If RUN command is executing, wait for it done.
+ //
+ while (mDebugMpContext.RunCommandSet) {
+ CpuPause ();
+ }
+ }
+
+ Handle = GetDebugPortHandle();
+ BreakCause = GetBreakCause (Vector, CpuContext);
+ switch (Vector) {
+ case DEBUG_INT1_VECTOR:
+ case DEBUG_INT3_VECTOR:
+ switch (BreakCause) {
+ case DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET:
+ if (AttachHost (BreakCause, READ_PACKET_TIMEOUT, &BreakReceived) != RETURN_SUCCESS) {
+ //
+ // Try to connect HOST, return if fails
+ //
+ break;
+ }
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ break;
+
+ case DEBUG_DATA_BREAK_CAUSE_STEPPING:
+ //
+ // Stepping is finished, send Ack package.
+ //
+ if (MultiProcessorDebugSupport()) {
+ mDebugMpContext.BreakAtCpuIndex = ProcessorIndex;
+ }
+ //
+ // Clear Stepping Flag and restore EFLAGS.IF
+ //
+ CommandSteppingCleanup (CpuContext);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ break;
+
+ case DEBUG_DATA_BREAK_CAUSE_MEMORY_READY:
+ //
+ // Memory is ready
+ //
+ SendCommandAndWaitForAckOK (DEBUG_COMMAND_MEMORY_READY, READ_PACKET_TIMEOUT, &BreakReceived, NULL);
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ break;
+
+ case DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD:
+ case DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD:
+ //
+ // Set AL to DEBUG_AGENT_IMAGE_CONTINUE
+ //
+ Al = ArchReadRegisterBuffer (CpuContext, SOFT_DEBUGGER_REGISTER_AX, &Data8);
+ *Al = DEBUG_AGENT_IMAGE_CONTINUE;
+
+ if (!IsHostAttached ()) {
+ //
+ // If HOST is not connected for image load/unload, return
+ //
+ break;
+ }
+ //
+ // Continue to run the following common code
+ //
+
+ case DEBUG_DATA_BREAK_CAUSE_HW_BREAKPOINT:
+ case DEBUG_DATA_BREAK_CAUSE_SW_BREAKPOINT:
+ default:
+ //
+ // Send Break packet to HOST
+ //
+ AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ //
+ // Only the first breaking processor could send BREAK_POINT to HOST
+ //
+ if (IsFirstBreakProcessor (ProcessorIndex)) {
+ SendBreakPacketToHost (BreakCause, ProcessorIndex, &BreakReceived);
+ }
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ if (Vector == DEBUG_INT3_VECTOR) {
+ //
+ // go back address located "0xCC"
+ //
+ CpuContext->Eip--;
+ SavedEip = CpuContext->Eip;
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ if ((SavedEip == CpuContext->Eip) &&
+ (*(UINT8 *) (UINTN) CpuContext->Eip == DEBUG_SW_BREAKPOINT_SYMBOL)) {
+ //
+ // If this is not a software breakpoint set by HOST,
+ // restore EIP
+ //
+ CpuContext->Eip++;
+ }
+ } else {
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ }
+ break;
+ }
+
+ break;
+
+ case DEBUG_TIMER_VECTOR:
+
+ AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ if (MultiProcessorDebugSupport()) {
+ if (DebugAgentIsBsp (ProcessorIndex)) {
+ //
+ // If current processor is BSP, check Apic timer's init count if changed,
+ // it may be re-written when switching BSP.
+ // If it changed, re-initialize debug timer
+ //
+ CurrentDebugTimerInitCount = GetApicTimerInitCount ();
+ if (mDebugMpContext.DebugTimerInitCount != CurrentDebugTimerInitCount) {
+ InitializeDebugTimer (NULL, FALSE);
+ SaveAndSetDebugTimerInterrupt (TRUE);
+ }
+ }
+
+ if (!DebugAgentIsBsp (ProcessorIndex) || mDebugMpContext.IpiSentByAp) {
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ //
+ // If current processor is not BSP or this is one IPI sent by AP
+ //
+ if (mDebugMpContext.BreakAtCpuIndex != (UINT32) (-1)) {
+ CommandCommunication (Vector, CpuContext, FALSE);
+ }
+
+ //
+ // Clear EOI before exiting interrupt process routine.
+ //
+ SendApicEoi ();
+ break;
+ }
+ }
+
+ //
+ // Only BSP could run here
+ //
+ while (TRUE) {
+ //
+ // If there is data in debug port, will check whether it is break(attach/break-in) symbol,
+ // If yes, go into communication mode with HOST.
+ // If no, exit interrupt process.
+ //
+ if (DebugReadBreakSymbol (Handle, &InputCharacter) == EFI_NOT_FOUND) {
+ break;
+ }
+
+ if ((!IsHostAttached () && (InputCharacter == DEBUG_STARTING_SYMBOL_ATTACH)) ||
+ (IsHostAttached () && (InputCharacter == DEBUG_COMMAND_HALT)) ||
+ (IsHostAttached () && (InputCharacter == DEBUG_COMMAND_GO))
+ ) {
+ DebugAgentMsgPrint (DEBUG_AGENT_VERBOSE, "Received data [%02x]\n", InputCharacter);
+ //
+ // Ack OK for break-in symbol
+ //
+ SendAckPacket (DEBUG_COMMAND_OK);
+
+ //
+ // If receive GO command in Debug Timer, means HOST may lost ACK packet before.
+ //
+ if (InputCharacter == DEBUG_COMMAND_GO) {
+ break;
+ }
+
+ if (!IsHostAttached ()) {
+ //
+ // Try to attach HOST, if no ack received after 200ms, return
+ //
+ if (AttachHost (BreakCause, READ_PACKET_TIMEOUT, &BreakReceived) != RETURN_SUCCESS) {
+ break;
+ }
+ }
+
+ if (MultiProcessorDebugSupport()) {
+ if(FindNextPendingBreakCpu () != -1) {
+ SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
+ } else {
+ HaltOtherProcessors (ProcessorIndex);
+ }
+ }
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ break;
+ }
+ }
+
+ //
+ // Clear EOI before exiting interrupt process routine.
+ //
+ SendApicEoi ();
+
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ break;
+
+ default:
+ if (Vector <= DEBUG_EXCEPT_SIMD) {
+ DebugAgentMsgPrint (
+ DEBUG_AGENT_ERROR,
+ "Exception happened, ExceptionNum is %d, EIP = 0x%x.\n",
+ Vector,
+ (UINTN) CpuContext->Eip
+ );
+ if (BreakCause == DEBUG_DATA_BREAK_CAUSE_STEPPING) {
+ //
+ // If exception happened when executing Stepping, send Ack package.
+ // HOST consider Stepping command was finished.
+ //
+ if (MultiProcessorDebugSupport()) {
+ mDebugMpContext.BreakAtCpuIndex = ProcessorIndex;
+ }
+ //
+ // Clear Stepping flag and restore EFLAGS.IF
+ //
+ CommandSteppingCleanup (CpuContext);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ } else {
+ //
+ // Exception occurs, send Break packet to HOST
+ //
+ AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ //
+ // Only the first breaking processor could send BREAK_POINT to HOST
+ //
+ if (IsFirstBreakProcessor (ProcessorIndex)) {
+ SendBreakPacketToHost (BreakCause, ProcessorIndex, &BreakReceived);
+ }
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ }
+
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ }
+ break;
+ }
+
+ if (MultiProcessorDebugSupport()) {
+ //
+ // Clear flag and wait for all processors run here
+ //
+ SetIpiSentByApFlag (FALSE);
+ while (mDebugMpContext.RunCommandSet) {
+ CpuPause ();
+ }
+
+ //
+ // Only current (view) processor could clean up AgentInProgress flag.
+ //
+ if (mDebugMpContext.ViewPointIndex == ProcessorIndex) {
+ IssuedViewPoint = mDebugMpContext.ViewPointIndex;
+ }
+ }
+
+ if (IssuedViewPoint == ProcessorIndex && GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) != 1) {
+ //
+ // If the command is not stepping, clean up AgentInProgress flag
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS, 0);
+ }
+
+ return;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h
new file mode 100644
index 00000000..672794bb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h
@@ -0,0 +1,498 @@
+/** @file
+ Command header of for Debug Agent library instance.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEBUG_AGENT_H_
+#define _DEBUG_AGENT_H_
+
+#include <Register/LocalApic.h>
+#include <Guid/DebugAgentGuid.h>
+#include <Guid/VectorHandoffTable.h>
+#include <Ppi/VectorHandoffInfo.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ResetSystemLib.h>
+#include <Library/IoLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugCommunicationLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Register/ArchitecturalMsr.h>
+
+#include <TransferProtocol.h>
+#include <ImageDebugSupport.h>
+
+#include "DebugMp.h"
+#include "DebugTimer.h"
+#include "ArchDebugSupport.h"
+#include "DebugException.h"
+
+//
+// These macros may be already defined in DebugAgentLib.h
+//
+#define DEBUG_AGENT_INIT_PEI 9
+#define DEBUG_AGENT_INIT_DXE_LOAD 10
+#define DEBUG_AGENT_INIT_DXE_UNLOAD 11
+#define DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64 12
+
+#define DEBUG_INT1_VECTOR DEBUG_EXCEPT_DEBUG
+#define DEBUG_INT3_VECTOR DEBUG_EXCEPT_BREAKPOINT
+#define DEBUG_TIMER_VECTOR 32
+#define DEBUG_MAILBOX_VECTOR 33
+
+//
+// Timeout value for reading packet (unit is microsecond)
+//
+#define READ_PACKET_TIMEOUT (500 * 1000)
+#define DEBUG_TIMER_INTERVAL (100 * 1000)
+
+#define SOFT_INTERRUPT_SIGNATURE SIGNATURE_32('S','O','F','T')
+#define SYSTEM_RESET_SIGNATURE SIGNATURE_32('S','Y','S','R')
+#define MEMORY_READY_SIGNATURE SIGNATURE_32('M','E','M','R')
+
+extern UINTN Exception0Handle;
+extern UINTN TimerInterruptHandle;
+extern UINT32 ExceptionStubHeaderSize;
+extern BOOLEAN mSkipBreakpoint;
+extern EFI_VECTOR_HANDOFF_INFO mVectorHandoffInfoDebugAgent[];
+extern UINTN mVectorHandoffInfoCount;
+
+//
+// CPU exception information issued by debug agent
+//
+typedef struct {
+ //
+ // This field is used to save CPU content before executing HOST command
+ //
+ BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
+ //
+ // This field returns the exception information issued by the HOST command
+ //
+ DEBUG_DATA_RESPONSE_GET_EXCEPTION ExceptionContent;
+} DEBUG_AGENT_EXCEPTION_BUFFER;
+
+#define DEBUG_AGENT_FLAG_HOST_ATTACHED BIT0
+#define DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS BIT1
+#define DEBUG_AGENT_FLAG_MEMORY_READY BIT2
+#define DEBUG_AGENT_FLAG_STEPPING BIT3
+#define DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB BIT4
+#define DEBUG_AGENT_FLAG_INIT_ARCH BIT5|BIT6
+#define DEBUG_AGENT_FLAG_INTERRUPT_FLAG BIT7
+#define DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI BIT32
+#define DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL (BIT33|BIT34|BIT35|BIT36)
+#define DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT BIT37
+
+#define DEBUG_MAILBOX_DEBUG_FLAG_INDEX 1
+#define DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX 2
+#define DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX 3
+#define DEBUG_MAILBOX_LAST_ACK 4
+#define DEBUG_MAILBOX_SEQUENCE_NO_INDEX 5
+#define DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX 6
+#define DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY 7
+
+#pragma pack(1)
+typedef union {
+ struct {
+ //
+ // Lower 32 bits to store the status of DebugAgent
+ //
+ UINT32 HostAttached : 1; // 1: HOST is attached
+ UINT32 AgentInProgress : 1; // 1: Debug Agent is communicating with HOST
+ UINT32 MemoryReady : 1; // 1: Memory is ready
+ UINT32 SteppingFlag : 1; // 1: Agent is running stepping command
+ UINT32 CheckMailboxInHob : 1; // 1: Need to check mailbox saved in HOB
+ UINT32 InitArch : 2; // value of DEBUG_DATA_RESPONSE_ARCH_MODE
+ UINT32 InterruptFlag : 1; // 1: EFLAGS.IF is set
+ UINT32 Reserved1 : 24;
+ //
+ // Higher 32bits to control the behavior of DebugAgent
+ //
+ UINT32 BreakOnNextSmi : 1; // 1: Break on next SMI
+ UINT32 PrintErrorLevel : 4; // Bitmask of print error level for debug message
+ UINT32 BreakOnBootScript : 1; // 1: Break before executing boot script
+ UINT32 Reserved2 : 26;
+ } Bits;
+ UINT64 Uint64;
+} DEBUG_AGENT_FLAG;
+
+typedef struct {
+ DEBUG_AGENT_FLAG DebugFlag;
+ UINT64 DebugPortHandle;
+ //
+ // Pointer to DEBUG_AGENT_EXCEPTION_BUFFER
+ //
+ UINT64 ExceptionBufferPointer;
+ UINT8 LastAck; // The last ack packet type
+ UINT8 SequenceNo;
+ UINT8 HostSequenceNo;
+ UINT32 DebugTimerFrequency;
+ UINT8 CheckSum; // Mailbox checksum
+ UINT8 ToBeCheckSum; // To be Mailbox checksum at the next
+} DEBUG_AGENT_MAILBOX;
+#pragma pack()
+
+///
+/// Byte packed structure for an IA-32 Interrupt Gate Descriptor.
+///
+typedef union {
+ struct {
+ UINT32 OffsetLow:16; ///< Offset bits 15..0.
+ UINT32 Selector:16; ///< Selector.
+ UINT32 Reserved_0:8; ///< Reserved.
+ UINT32 GateType:8; ///< Gate Type. See #defines above.
+ UINT32 OffsetHigh:16; ///< Offset bits 31..16.
+ } Bits;
+ UINT64 Uint64;
+} IA32_IDT_ENTRY;
+
+
+typedef union {
+ struct {
+ UINT32 LimitLow : 16;
+ UINT32 BaseLow : 16;
+ UINT32 BaseMid : 8;
+ UINT32 Type : 4;
+ UINT32 System : 1;
+ UINT32 Dpl : 2;
+ UINT32 Present : 1;
+ UINT32 LimitHigh : 4;
+ UINT32 Software : 1;
+ UINT32 Reserved : 1;
+ UINT32 DefaultSize : 1;
+ UINT32 Granularity : 1;
+ UINT32 BaseHigh : 8;
+ } Bits;
+ UINT64 Uint64;
+} IA32_GDT;
+
+/**
+ Initialize IDT entries to support source level debug.
+
+**/
+VOID
+InitializeDebugIdt (
+ VOID
+ );
+
+/**
+ Read register value from saved CPU context.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+ @param[in] Index Register index value.
+ @param[in] Width Data width to read.
+
+ @return The address of register value.
+
+**/
+UINT8 *
+ArchReadRegisterBuffer (
+ IN DEBUG_CPU_CONTEXT *CpuContext,
+ IN UINT8 Index,
+ IN UINT8 *Width
+ );
+
+/**
+ Send packet with response data to HOST.
+
+ @param[in] Data Pointer to response data buffer.
+ @param[in] DataSize Size of response data in byte.
+ @param[in, out] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet,
+ to minimize the stack usage.
+
+ @retval RETURN_SUCCESS Response data was sent successfully.
+ @retval RETURN_DEVICE_ERROR Cannot receive DEBUG_COMMAND_OK from HOST.
+
+**/
+RETURN_STATUS
+SendDataResponsePacket (
+ IN UINT8 *Data,
+ IN UINT16 DataSize,
+ IN OUT DEBUG_PACKET_HEADER *DebugHeader
+ );
+
+/**
+ Check if HOST is attached based on Mailbox.
+
+ @retval TRUE HOST is attached.
+ @retval FALSE HOST is not attached.
+
+**/
+BOOLEAN
+IsHostAttached (
+ VOID
+ );
+
+/**
+ Get Debug Agent Mailbox pointer.
+
+ @return Mailbox pointer.
+
+**/
+DEBUG_AGENT_MAILBOX *
+GetMailboxPointer (
+ VOID
+ );
+
+/**
+ Get debug port handle.
+
+ @return Debug port handle.
+
+**/
+DEBUG_PORT_HANDLE
+GetDebugPortHandle (
+ VOID
+ );
+
+/**
+ Read the Attach/Break-in symbols from the debug port.
+
+ @param[in] Handle Pointer to Debug Port handle.
+ @param[out] BreakSymbol Returned break symbol.
+
+ @retval EFI_SUCCESS Read the symbol in BreakSymbol.
+ @retval EFI_NOT_FOUND No read the break symbol.
+
+**/
+EFI_STATUS
+DebugReadBreakSymbol (
+ IN DEBUG_PORT_HANDLE Handle,
+ OUT UINT8 *BreakSymbol
+ );
+
+/**
+ Prints a debug message to the debug port if the specified error level is enabled.
+
+ If any bit in ErrorLevel is also set in Mainbox, then print the message specified
+ by Format and the associated variable argument list to the debug port.
+
+ @param[in] ErrorLevel The error level of the debug message.
+ @param[in] Format Format string for the debug message to print.
+ @param[in] ... Variable argument list whose contents are accessed
+ based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+DebugAgentMsgPrint (
+ IN UINT8 ErrorLevel,
+ IN CHAR8 *Format,
+ ...
+ );
+
+/**
+ Trigger one software interrupt to debug agent to handle it.
+
+ @param[in] Signature Software interrupt signature.
+
+**/
+VOID
+TriggerSoftInterrupt (
+ IN UINT32 Signature
+ );
+
+/**
+ Check if debug agent support multi-processor.
+
+ @retval TRUE Multi-processor is supported.
+ @retval FALSE Multi-processor is not supported.
+
+**/
+BOOLEAN
+MultiProcessorDebugSupport (
+ VOID
+ );
+
+/**
+ Find and report module image info to HOST.
+
+ @param[in] AlignSize Image aligned size.
+
+**/
+VOID
+FindAndReportModuleImageInfo (
+ IN UINTN AlignSize
+ );
+
+/**
+ Read IDT entry to check if IDT entries are setup by Debug Agent.
+
+ @retval TRUE IDT entries were setup by Debug Agent.
+ @retval FALSE IDT entries were not setup by Debug Agent.
+
+**/
+BOOLEAN
+IsDebugAgentInitialzed (
+ VOID
+ );
+
+/**
+ Calculate Mailbox checksum and update the checksum field.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+
+**/
+VOID
+UpdateMailboxChecksum (
+ IN DEBUG_AGENT_MAILBOX *Mailbox
+ );
+
+/**
+ Verify Mailbox checksum.
+
+ If checksum error, print debug message and run init dead loop.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+
+**/
+VOID
+VerifyMailboxChecksum (
+ IN DEBUG_AGENT_MAILBOX *Mailbox
+ );
+
+/**
+ Set debug flag in mailbox.
+
+ @param[in] FlagMask Debug flag mask value.
+ @param[in] FlagValue Debug flag value.
+
+**/
+VOID
+SetDebugFlag (
+ IN UINT64 FlagMask,
+ IN UINT32 FlagValue
+ );
+
+/**
+ Get debug flag in mailbox.
+
+ @param[in] FlagMask Debug flag mask value.
+
+ @return Debug flag value.
+
+**/
+UINT32
+GetDebugFlag (
+ IN UINT64 FlagMask
+ );
+
+/**
+ Update Mailbox content by index.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+ @param[in] Index Mailbox content index.
+ @param[in] Value Value to be set into mail box.
+
+**/
+VOID
+UpdateMailboxContent (
+ IN DEBUG_AGENT_MAILBOX *Mailbox,
+ IN UINTN Index,
+ IN UINT64 Value
+ );
+
+/**
+ Retrieve exception handler from IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+
+ @return Exception handler
+
+**/
+VOID *
+GetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum
+ );
+
+/**
+ Set exception handler in IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+ @param[in] ExceptionHandler Exception Handler to be set
+
+**/
+VOID
+SetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum,
+ IN VOID *ExceptionHandler
+ );
+
+/**
+ Prints a debug message to the debug output device if the specified error level is enabled.
+
+ If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
+ GetDebugPrintErrorLevel (), then print the message specified by Format and the
+ associated variable argument list to the debug output device.
+
+ If Format is NULL, then ASSERT().
+
+ @param[in] ErrorLevel The error level of the debug message.
+ @param[in] IsSend Flag of debug message to declare that the data is being sent or being received.
+ @param[in] Data Variable argument list whose contents are accessed
+ @param[in] Length based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+DebugAgentDataMsgPrint (
+ IN UINT8 ErrorLevel,
+ IN BOOLEAN IsSend,
+ IN UINT8 *Data,
+ IN UINT8 Length
+ );
+
+/**
+ Read remaing debug packet except for the start symbol
+
+ @param[in] Handle Pointer to Debug Port handle.
+ @param[in, out] DebugHeader Debug header buffer including start symbol.
+
+ @retval EFI_SUCCESS Read the symbol in BreakSymbol.
+ @retval EFI_CRC_ERROR CRC check fail.
+ @retval EFI_TIMEOUT Timeout occurs when reading debug packet.
+
+**/
+EFI_STATUS
+ReadRemainingBreakPacket (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN OUT DEBUG_PACKET_HEADER *DebugHeader
+ );
+
+/**
+ Read data from debug channel and save the data in buffer.
+
+ Reads NumberOfBytes data bytes from a debug device into the buffer
+ specified by Buffer. The number of bytes actually read is returned.
+ If the return value is less than NumberOfBytes, then the rest operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to store the data read from the debug device.
+ @param NumberOfBytes Number of bytes which will be read.
+ @param Timeout Timeout value for reading from debug device. It unit is Microsecond.
+
+ @retval 0 Read data failed, no data is to be read.
+ @retval >0 Actual number of bytes read from debug device.
+
+**/
+UINTN
+DebugAgentReadBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN OUT UINT8 *Buffer,
+ IN UINTN NumberOfBytes,
+ IN UINTN Timeout
+ );
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c
new file mode 100644
index 00000000..30ee5205
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c
@@ -0,0 +1,377 @@
+/** @file
+ Multi-Processor support functions implementation.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugAgent.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_MP_CONTEXT volatile mDebugMpContext = {0,0,0,{0},{0},0,0,0,0,FALSE,FALSE};
+
+GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_CPU_DATA volatile mDebugCpuData = {0};
+
+/**
+ Acquire a spin lock when Multi-processor supported.
+
+ It will block in the function if cannot get the access control.
+ If Multi-processor is not supported, return directly.
+
+ @param[in, out] MpSpinLock A pointer to the spin lock.
+
+**/
+VOID
+AcquireMpSpinLock (
+ IN OUT SPIN_LOCK *MpSpinLock
+ )
+{
+ if (!MultiProcessorDebugSupport()) {
+ return;
+ }
+
+ while (TRUE) {
+ if (AcquireSpinLockOrFail (MpSpinLock)) {
+ break;
+ }
+ CpuPause ();
+ continue;
+ }
+}
+
+/**
+ Release a spin lock when Multi-processor supported.
+
+ @param[in, out] MpSpinLock A pointer to the spin lock.
+
+**/
+VOID
+ReleaseMpSpinLock (
+ IN OUT SPIN_LOCK *MpSpinLock
+ )
+{
+ if (!MultiProcessorDebugSupport()) {
+ return;
+ }
+
+ ReleaseSpinLock (MpSpinLock);
+}
+
+/**
+ Break the other processor by send IPI.
+
+ @param[in] CurrentProcessorIndex Current processor index value.
+
+**/
+VOID
+HaltOtherProcessors (
+ IN UINT32 CurrentProcessorIndex
+ )
+{
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Try to halt other processors.\n", CurrentProcessorIndex);
+ if (!DebugAgentIsBsp (CurrentProcessorIndex)) {
+ SetIpiSentByApFlag (TRUE);;
+ }
+
+ mDebugMpContext.BreakAtCpuIndex = CurrentProcessorIndex;
+
+ //
+ // Set the debug viewpoint to the current breaking CPU.
+ //
+ SetDebugViewPoint (CurrentProcessorIndex);
+
+ //
+ // Send fixed IPI to other processors.
+ //
+ SendFixedIpiAllExcludingSelf (DEBUG_TIMER_VECTOR);
+
+}
+
+/**
+ Get the current processor's index.
+
+ @return Processor index value.
+
+**/
+UINT32
+GetProcessorIndex (
+ VOID
+ )
+{
+ UINT32 Index;
+ UINT16 LocalApicID;
+
+ LocalApicID = (UINT16) GetApicId ();
+
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+
+ for (Index = 0; Index < mDebugCpuData.CpuCount; Index ++) {
+ if (mDebugCpuData.ApicID[Index] == LocalApicID) {
+ break;
+ }
+ }
+
+ if (Index == mDebugCpuData.CpuCount) {
+ mDebugCpuData.ApicID[Index] = LocalApicID;
+ mDebugCpuData.CpuCount ++ ;
+ }
+
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+
+ return Index;
+}
+
+/**
+ Check if the specified processor is BSP or not.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @retval TRUE It is BSP.
+ @retval FALSE It isn't BSP.
+
+**/
+BOOLEAN
+DebugAgentIsBsp (
+ IN UINT32 ProcessorIndex
+ )
+{
+ MSR_IA32_APIC_BASE_REGISTER MsrApicBase;
+
+ //
+ // If there are less than 2 CPUs detected, then the currently executing CPU
+ // must be the BSP. This avoids an access to an MSR that may not be supported
+ // on single core CPUs.
+ //
+ if (mDebugCpuData.CpuCount < 2) {
+ return TRUE;
+ }
+
+ MsrApicBase.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ if (MsrApicBase.Bits.BSP == 1) {
+ if (mDebugMpContext.BspIndex != ProcessorIndex) {
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+ mDebugMpContext.BspIndex = ProcessorIndex;
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Set processor stop flag bitmask in MP context.
+
+ @param[in] ProcessorIndex Processor index value.
+ @param[in] StopFlag TRUE means set stop flag.
+ FALSE means clean break flag.
+
+**/
+VOID
+SetCpuStopFlagByIndex (
+ IN UINT32 ProcessorIndex,
+ IN BOOLEAN StopFlag
+ )
+{
+ UINT8 Value;
+ UINTN Index;
+
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+
+ Value = mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8];
+ Index = ProcessorIndex % 8;
+ if (StopFlag) {
+ Value = BitFieldWrite8 (Value, Index, Index, 1);
+ } else {
+ Value = BitFieldWrite8 (Value, Index, Index, 0);
+ }
+ mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] = Value;
+
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+}
+
+/**
+ Set processor break flag bitmask in MP context.
+
+ @param[in] ProcessorIndex Processor index value.
+ @param[in] BreakFlag TRUE means set break flag.
+ FALSE means clean break flag.
+
+**/
+VOID
+SetCpuBreakFlagByIndex (
+ IN UINT32 ProcessorIndex,
+ IN BOOLEAN BreakFlag
+ )
+{
+ UINT8 Value;
+ UINTN Index;
+
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+
+ Value = mDebugMpContext.CpuBreakMask[ProcessorIndex / 8];
+ Index = ProcessorIndex % 8;
+ if (BreakFlag) {
+ Value = BitFieldWrite8 (Value, Index, Index, 1);
+ } else {
+ Value = BitFieldWrite8 (Value, Index, Index, 0);
+ }
+ mDebugMpContext.CpuBreakMask[ProcessorIndex / 8] = Value;
+
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+}
+
+/**
+ Check if processor is stopped already.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @retval TRUE Processor is stopped already.
+ @retval TRUE Processor isn't stopped.
+
+**/
+BOOLEAN
+IsCpuStopped (
+ IN UINT32 ProcessorIndex
+ )
+{
+ UINT8 CpuMask;
+
+ CpuMask = (UINT8) (1 << (ProcessorIndex % 8));
+
+ if ((mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] & CpuMask) != 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Set the run command flag.
+
+ @param[in] RunningFlag TRUE means run command flag is set.
+ FALSE means run command flag is cleared.
+
+**/
+VOID
+SetCpuRunningFlag (
+ IN BOOLEAN RunningFlag
+ )
+{
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+ mDebugMpContext.RunCommandSet = RunningFlag;
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+}
+
+/**
+ Set the current view point to be debugged.
+
+ @param[in] ProcessorIndex Processor index value.
+
+**/
+VOID
+SetDebugViewPoint (
+ IN UINT32 ProcessorIndex
+ )
+{
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+ mDebugMpContext.ViewPointIndex = ProcessorIndex;
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+}
+
+/**
+ Set the IPI send by BPS/AP flag.
+
+ @param[in] IpiSentByApFlag TRUE means this IPI is sent by AP.
+ FALSE means this IPI is sent by BSP.
+
+**/
+VOID
+SetIpiSentByApFlag (
+ IN BOOLEAN IpiSentByApFlag
+ )
+{
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+ mDebugMpContext.IpiSentByAp = IpiSentByApFlag;
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+}
+
+/**
+ Check the next pending breaking CPU.
+
+ @retval others There is at least one processor broken, the minimum
+ index number of Processor returned.
+ @retval -1 No any processor broken.
+
+**/
+UINT32
+FindNextPendingBreakCpu (
+ VOID
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index ++) {
+ if (mDebugMpContext.CpuBreakMask[Index] != 0) {
+ return (UINT32) LowBitSet32 (mDebugMpContext.CpuBreakMask[Index]) + Index * 8;
+ }
+ }
+ return (UINT32)-1;
+}
+
+/**
+ Check if all processors are in running status.
+
+ @retval TRUE All processors run.
+ @retval FALSE At least one processor does not run.
+
+**/
+BOOLEAN
+IsAllCpuRunning (
+ VOID
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index ++) {
+ if (mDebugMpContext.CpuStopStatusMask[Index] != 0) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ Check if the current processor is the first breaking processor.
+
+ If yes, halt other processors.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @return TRUE This processor is the first breaking processor.
+ @return FALSE This processor is not the first breaking processor.
+
+**/
+BOOLEAN
+IsFirstBreakProcessor (
+ IN UINT32 ProcessorIndex
+ )
+{
+ if (MultiProcessorDebugSupport()) {
+ if (mDebugMpContext.BreakAtCpuIndex != (UINT32) -1) {
+ //
+ // The current processor is not the first breaking one.
+ //
+ SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
+ return FALSE;
+ } else {
+ //
+ // If no any processor breaks, try to halt other processors
+ //
+ HaltOtherProcessors (ProcessorIndex);
+ return TRUE;
+ }
+ }
+ return TRUE;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h
new file mode 100644
index 00000000..a169edd0
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h
@@ -0,0 +1,216 @@
+/** @file
+ Header file for Multi-Processor support.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEBUG_MP_H_
+#define _DEBUG_MP_H_
+
+#define DEBUG_CPU_MAX_COUNT 256
+
+typedef struct {
+ UINT32 CpuCount; ///< Processor count
+ UINT16 ApicID[DEBUG_CPU_MAX_COUNT]; ///< Record the local apic id for each processor
+} DEBUG_CPU_DATA;
+
+typedef struct {
+ SPIN_LOCK MpContextSpinLock; ///< Lock for writing MP context
+ SPIN_LOCK DebugPortSpinLock; ///< Lock for access debug port
+ SPIN_LOCK MailboxSpinLock; ///< Lock for accessing mail box
+ UINT8 CpuBreakMask[DEBUG_CPU_MAX_COUNT/8]; ///< Bitmask of all breaking CPUs
+ UINT8 CpuStopStatusMask[DEBUG_CPU_MAX_COUNT/8]; ///< Bitmask of CPU stop status
+ UINT32 ViewPointIndex; ///< Current view point to be debugged
+ UINT32 BspIndex; ///< Processor index value of BSP
+ UINT32 BreakAtCpuIndex; ///< Processor index value of the current breaking CPU
+ UINT32 DebugTimerInitCount; ///< Record BSP's init timer count
+ BOOLEAN IpiSentByAp; ///< TRUE: IPI is sent by AP. FALSE: IPI is sent by BSP
+ BOOLEAN RunCommandSet; ///< TRUE: RUN command is executing. FALSE: RUN command has been executed.
+} DEBUG_MP_CONTEXT;
+
+extern DEBUG_MP_CONTEXT volatile mDebugMpContext;
+extern DEBUG_CPU_DATA volatile mDebugCpuData;
+
+/**
+ Break the other processor by send IPI.
+
+ @param[in] CurrentProcessorIndex Current processor index value.
+
+**/
+VOID
+HaltOtherProcessors (
+ IN UINT32 CurrentProcessorIndex
+ );
+
+/**
+ Get the current processor's index.
+
+ @return Processor index value.
+
+**/
+UINT32
+GetProcessorIndex (
+ VOID
+ );
+
+/**
+ Acquire a spin lock when Multi-processor supported.
+
+ It will block in the function if cannot get the access control.
+ If Multi-processor is not supported, return directly.
+
+ @param[in, out] MpSpinLock A pointer to the spin lock.
+
+**/
+VOID
+AcquireMpSpinLock (
+ IN OUT SPIN_LOCK *MpSpinLock
+ );
+
+/**
+ Release a spin lock when Multi-processor supported.
+
+ @param[in, out] MpSpinLock A pointer to the spin lock.
+
+**/
+VOID
+ReleaseMpSpinLock (
+ IN OUT SPIN_LOCK *MpSpinLock
+ );
+
+/**
+ Check if the specified processor is BSP or not.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @retval TRUE It is BSP.
+ @retval FALSE It isn't BSP.
+
+**/
+BOOLEAN
+DebugAgentIsBsp (
+ IN UINT32 ProcessorIndex
+ );
+
+/**
+ Set processor stop flag bitmask in MP context.
+
+ @param[in] ProcessorIndex Processor index value.
+ @param[in] StopFlag TRUE means set stop flag.
+ FALSE means clean break flag.
+
+**/
+VOID
+SetCpuStopFlagByIndex (
+ IN UINT32 ProcessorIndex,
+ IN BOOLEAN StopFlag
+ );
+
+/**
+ Set processor break flag bitmask in MP context.
+
+ @param[in] ProcessorIndex Processor index value.
+ @param[in] BreakFlag TRUE means set break flag.
+ FALSE means clean break flag.
+
+**/
+VOID
+SetCpuBreakFlagByIndex (
+ IN UINT32 ProcessorIndex,
+ IN BOOLEAN BreakFlag
+ );
+
+/**
+ Check if processor is stopped already.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @retval TRUE Processor is stopped already.
+ @retval FALSE Processor isn't stopped.
+
+**/
+BOOLEAN
+IsCpuStopped (
+ IN UINT32 ProcessorIndex
+ );
+
+/**
+ Set the run command flag.
+
+ @param[in] RunningFlag TRUE means run command flag is set.
+ FALSE means run command flag is cleared.
+
+**/
+VOID
+SetCpuRunningFlag (
+ IN BOOLEAN RunningFlag
+ );
+
+/**
+ Set the current view point to be debugged.
+
+ @param[in] ProcessorIndex Processor index value.
+
+**/
+VOID
+SetDebugViewPoint (
+ IN UINT32 ProcessorIndex
+ );
+
+/**
+ Set the IPI send by BPS/AP flag.
+
+ @param[in] IpiSentByApFlag TRUE means this IPI is sent by AP.
+ FALSE means this IPI is sent by BSP.
+
+**/
+VOID
+SetIpiSentByApFlag (
+ IN BOOLEAN IpiSentByApFlag
+ );
+
+/**
+ Check the next pending breaking CPU.
+
+ @retval others There is at least one processor broken, the minimum
+ index number of Processor returned.
+ @retval -1 No any processor broken.
+
+**/
+UINT32
+FindNextPendingBreakCpu (
+ VOID
+ );
+
+/**
+ Check if all processors are in running status.
+
+ @retval TRUE All processors run.
+ @retval FALSE At least one processor does not run.
+
+**/
+BOOLEAN
+IsAllCpuRunning (
+ VOID
+ );
+
+/**
+ Check if the current processor is the first breaking processor.
+
+ If yes, halt other processors.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @return TRUE This processor is the first breaking processor.
+ @return FALSE This processor is not the first breaking processor.
+
+**/
+BOOLEAN
+IsFirstBreakProcessor (
+ IN UINT32 ProcessorIndex
+ );
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c
new file mode 100644
index 00000000..19c2afe9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c
@@ -0,0 +1,143 @@
+/** @file
+ Code for debug timer to support debug agent library implementation.
+
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugAgent.h"
+
+/**
+ Initialize CPU local APIC timer.
+
+ @param[out] TimerFrequency Local APIC timer frequency returned.
+ @param[in] DumpFlag If TRUE, dump Local APIC timer's parameter.
+
+ @return 32-bit Local APIC timer init count.
+**/
+UINT32
+InitializeDebugTimer (
+ OUT UINT32 *TimerFrequency,
+ IN BOOLEAN DumpFlag
+ )
+{
+ UINTN ApicTimerDivisor;
+ UINT32 InitialCount;
+ UINT32 ApicTimerFrequency;
+
+ InitializeLocalApicSoftwareEnable (TRUE);
+ GetApicTimerState (&ApicTimerDivisor, NULL, NULL);
+ ApicTimerFrequency = PcdGet32(PcdFSBClock) / (UINT32)ApicTimerDivisor;
+ //
+ // Cpu Local Apic timer interrupt frequency, it is set to 0.1s
+ //
+ InitialCount = (UINT32)DivU64x32 (
+ MultU64x64 (
+ ApicTimerFrequency,
+ DEBUG_TIMER_INTERVAL
+ ),
+ 1000000u
+ );
+
+ InitializeApicTimer (ApicTimerDivisor, InitialCount, TRUE, DEBUG_TIMER_VECTOR);
+ //
+ // Disable Debug Timer interrupt to avoid it is delivered before Debug Port
+ // is initialized
+ //
+ DisableApicTimerInterrupt ();
+
+ if (DumpFlag) {
+ DEBUG ((EFI_D_INFO, "Debug Timer: FSB Clock = %d\n", PcdGet32(PcdFSBClock)));
+ DEBUG ((EFI_D_INFO, "Debug Timer: Divisor = %d\n", ApicTimerDivisor));
+ DEBUG ((EFI_D_INFO, "Debug Timer: Frequency = %d\n", ApicTimerFrequency));
+ DEBUG ((EFI_D_INFO, "Debug Timer: InitialCount = %d\n", InitialCount));
+ }
+ if (TimerFrequency != NULL) {
+ *TimerFrequency = ApicTimerFrequency;
+ }
+ return InitialCount;
+}
+
+/**
+ Enable/Disable the interrupt of debug timer and return the interrupt state
+ prior to the operation.
+
+ If EnableStatus is TRUE, enable the interrupt of debug timer.
+ If EnableStatus is FALSE, disable the interrupt of debug timer.
+
+ @param[in] EnableStatus Enable/Disable.
+
+ @retval TRUE Debug timer interrupt were enabled on entry to this call.
+ @retval FALSE Debug timer interrupt were disabled on entry to this call.
+
+**/
+BOOLEAN
+EFIAPI
+SaveAndSetDebugTimerInterrupt (
+ IN BOOLEAN EnableStatus
+ )
+{
+ BOOLEAN OldDebugTimerInterruptState;
+
+ OldDebugTimerInterruptState = GetApicTimerInterruptState ();
+
+ if (OldDebugTimerInterruptState != EnableStatus) {
+ if (EnableStatus) {
+ EnableApicTimerInterrupt ();
+ } else {
+ DisableApicTimerInterrupt ();
+ }
+ //
+ // Validate the Debug Timer interrupt state
+ // This will make additional delay after Local Apic Timer interrupt state is changed.
+ // Thus, CPU could handle the potential pending interrupt of Local Apic timer.
+ //
+ while (GetApicTimerInterruptState () != EnableStatus) {
+ CpuPause ();
+ }
+ }
+
+ return OldDebugTimerInterruptState;
+}
+
+/**
+ Check if the timer is time out.
+
+ @param[in] TimerCycle Timer initial count.
+ @param[in] Timer The start timer from the begin.
+ @param[in] TimeoutTicker Ticker number need time out.
+
+ @return TRUE Timer time out occurs.
+ @retval FALSE Timer does not time out.
+
+**/
+BOOLEAN
+IsDebugTimerTimeout (
+ IN UINT32 TimerCycle,
+ IN UINT32 Timer,
+ IN UINT32 TimeoutTicker
+ )
+{
+ UINT64 CurrentTimer;
+ UINT64 Delta;
+
+ CurrentTimer = GetApicTimerCurrentCount ();
+
+ //
+ // This timer counter counts down. Check for roll over condition.
+ // If CurrentTimer is equal to Timer, it does not mean that roll over
+ // happened.
+ //
+ if (CurrentTimer <= Timer) {
+ Delta = Timer - CurrentTimer;
+ } else {
+ //
+ // Handle one roll-over.
+ //
+ Delta = TimerCycle - (CurrentTimer - Timer) + 1;
+ }
+
+ return (BOOLEAN) (Delta >= TimeoutTicker);
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h
new file mode 100644
index 00000000..19192d26
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h
@@ -0,0 +1,45 @@
+/** @file
+ Header file for debug timer to support debug agent library implementation.
+
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEBUG_TIMER_H_
+#define _DEBUG_TIMER_H_
+
+/**
+ Initialize CPU local APIC timer.
+
+ @param[out] TimerFrequency Local APIC timer frequency returned.
+ @param[in] DumpFlag If TRUE, dump Local APIC timer's parameter.
+
+ @return 32-bit Local APIC timer init count.
+**/
+UINT32
+InitializeDebugTimer (
+ OUT UINT32 *TimerFrequency,
+ IN BOOLEAN DumpFlag
+ );
+
+/**
+ Check if the timer is time out.
+
+ @param[in] TimerCycle Timer initial count.
+ @param[in] Timer The start timer from the begin.
+ @param[in] TimeoutTicker Ticker number need time out.
+
+ @return TRUE Timer time out occurs.
+ @retval FALSE Timer does not time out.
+
+**/
+BOOLEAN
+IsDebugTimerTimeout (
+ IN UINT32 TimerCycle,
+ IN UINT32 Timer,
+ IN UINT32 TimeoutTicker
+ );
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c
new file mode 100644
index 00000000..97c3d2d5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c
@@ -0,0 +1,110 @@
+/** @file
+ Supporting functions for IA32 architecture.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugAgent.h"
+
+/**
+ Initialize IDT entries to support source level debug.
+
+**/
+VOID
+InitializeDebugIdt (
+ VOID
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ UINTN InterruptHandler;
+ IA32_DESCRIPTOR IdtDescriptor;
+ UINTN Index;
+ UINT16 CodeSegment;
+ UINT32 RegEdx;
+
+ AsmReadIdtr (&IdtDescriptor);
+
+ //
+ // Use current CS as the segment selector of interrupt gate in IDT
+ //
+ CodeSegment = AsmReadCs ();
+
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ for (Index = 0; Index < 20; Index ++) {
+ if (((PcdGet32 (PcdExceptionsIgnoredByDebugger) & ~(BIT1 | BIT3)) & (1 << Index)) != 0) {
+ //
+ // If the exception is masked to be reserved except for INT1 and INT3, skip it
+ //
+ continue;
+ }
+ InterruptHandler = (UINTN)&Exception0Handle + Index * ExceptionStubHeaderSize;
+ IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry[Index].Bits.Selector = CodeSegment;
+ IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ }
+
+ InterruptHandler = (UINTN) &TimerInterruptHandle;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.Selector = CodeSegment;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+
+ //
+ // If the CPU supports Debug Extensions(CPUID:01 EDX:BIT2), then
+ // Set DE flag in CR4 to enable IO breakpoint
+ //
+ AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT2) != 0) {
+ AsmWriteCr4 (AsmReadCr4 () | BIT3);
+ }
+}
+
+/**
+ Retrieve exception handler from IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+
+ @return Exception handler
+
+**/
+VOID *
+GetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR IdtDescriptor;
+
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ return (VOID *) (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetLow) |
+ (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetHigh) << 16));
+}
+
+/**
+ Set exception handler in IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+ @param[in] ExceptionHandler Exception Handler to be set
+
+**/
+VOID
+SetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum,
+ IN VOID *ExceptionHandler
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR IdtDescriptor;
+
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ IdtEntry[ExceptionNum].Bits.OffsetLow = (UINT16)(UINTN)ExceptionHandler;
+ IdtEntry[ExceptionNum].Bits.OffsetHigh = (UINT16)((UINTN)ExceptionHandler >> 16);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h
new file mode 100644
index 00000000..f3edd0bd
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h
@@ -0,0 +1,21 @@
+/** @file
+ IA32 specific definitions for debug agent library instance.
+
+ Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ARCH_DEBUG_SUPPORT_H_
+#define _ARCH_DEBUG_SUPPORT_H_
+
+#include "ProcessorContext.h"
+#include "TransferProtocol.h"
+
+#define DEBUG_SW_BREAKPOINT_SYMBOL 0xcc
+#define DEBUG_ARCH_SYMBOL DEBUG_DATA_BREAK_CPU_ARCH_IA32
+
+typedef DEBUG_DATA_IA32_FX_SAVE_STATE DEBUG_DATA_FX_SAVE_STATE;
+typedef DEBUG_DATA_IA32_SYSTEM_CONTEXT DEBUG_CPU_CONTEXT;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm
new file mode 100644
index 00000000..36ad0c2e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm
@@ -0,0 +1,413 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; AsmFuncs.nasm
+;
+; Abstract:
+;
+; Debug interrupt handle functions.
+;
+;------------------------------------------------------------------------------
+
+#include "DebugException.h"
+
+;
+; InterruptProcess()
+;
+extern ASM_PFX(InterruptProcess)
+
+global ASM_PFX(Exception0Handle)
+global ASM_PFX(TimerInterruptHandle)
+global ASM_PFX(ExceptionStubHeaderSize)
+
+%macro AGENT_HANDLER_SIGNATURE 0
+ db 0x41, 0x47, 0x54, 0x48 ; SIGNATURE_32('A','G','T','H')
+%endmacro
+
+SECTION .data
+
+ASM_PFX(ExceptionStubHeaderSize): DD Exception1Handle - ASM_PFX(Exception0Handle)
+CommonEntryAddr: DD CommonEntry
+
+SECTION .text
+
+AGENT_HANDLER_SIGNATURE
+ASM_PFX(Exception0Handle):
+ cli
+ push eax
+ mov eax, 0
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception1Handle:
+ cli
+ push eax
+ mov eax, 1
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception2Handle:
+ cli
+ push eax
+ mov eax, 2
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception3Handle:
+ cli
+ push eax
+ mov eax, 3
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception4Handle:
+ cli
+ push eax
+ mov eax, 4
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception5Handle:
+ cli
+ push eax
+ mov eax, 5
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception6Handle:
+ cli
+ push eax
+ mov eax, 6
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception7Handle:
+ cli
+ push eax
+ mov eax, 7
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception8Handle:
+ cli
+ push eax
+ mov eax, 8
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception9Handle:
+ cli
+ push eax
+ mov eax, 9
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception10Handle:
+ cli
+ push eax
+ mov eax, 10
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception11Handle:
+ cli
+ push eax
+ mov eax, 11
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception12Handle:
+ cli
+ push eax
+ mov eax, 12
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception13Handle:
+ cli
+ push eax
+ mov eax, 13
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception14Handle:
+ cli
+ push eax
+ mov eax, 14
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception15Handle:
+ cli
+ push eax
+ mov eax, 15
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception16Handle:
+ cli
+ push eax
+ mov eax, 16
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception17Handle:
+ cli
+ push eax
+ mov eax, 17
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception18Handle:
+ cli
+ push eax
+ mov eax, 18
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception19Handle:
+ cli
+ push eax
+ mov eax, 19
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+ASM_PFX(TimerInterruptHandle):
+ cli
+ push eax
+ mov eax, 32
+ jmp dword [CommonEntryAddr]
+
+CommonEntry:
+;
+; +---------------------+
+; + EFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + EIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + EAX / Vector Number +
+; +---------------------+
+; + EBP +
+; +---------------------+ <-- EBP
+;
+ cmp eax, DEBUG_EXCEPT_DOUBLE_FAULT
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_INVALID_TSS
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_SEG_NOT_PRESENT
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_STACK_FAULT
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_GP_FAULT
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_PAGE_FAULT
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_ALIGNMENT_CHECK
+ je NoExtrPush
+
+ push dword [esp]
+ mov dword [esp + 4], 0
+
+NoExtrPush:
+
+ push ebp
+ mov ebp, esp ; save esp in ebp
+ ;
+ ; Make stack 16-byte alignment to make sure save fxrstor later
+ ;
+ and esp, 0xfffffff0
+ sub esp, 12
+
+ ; store UINT32 Edi, Esi, Ebp, Ebx, Edx, Ecx, Eax;
+ push dword [ebp + 4] ; original eax
+ push ebx
+ push ecx
+ push edx
+ mov ebx, eax ; save vector in ebx
+ mov eax, ebp
+ add eax, 4 * 6
+ push eax ; original ESP
+ push dword [ebp] ; EBP
+ push esi
+ push edi
+
+ ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ ;; insure FXSAVE/FXRSTOR is enabled in CR4...
+ ;; ... while we're at it, make sure DE is also enabled...
+ mov eax, 1
+ push ebx ; temporarily save value of ebx on stack
+ cpuid ; use CPUID to determine if FXSAVE/FXRESTOR and
+ ; DE are supported
+ pop ebx ; restore value of ebx that was overwritten by CPUID
+ mov eax, cr4
+ push eax ; push cr4 firstly
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
+ jz .0
+ or eax, BIT9 ; Set CR4.OSFXSR
+.0:
+ test edx, BIT2 ; Test for Debugging Extensions support
+ jz .1
+ or eax, BIT3 ; Set CR4.DE
+.1:
+ mov cr4, eax
+ mov eax, cr3
+ push eax
+ mov eax, cr2
+ push eax
+ push 0 ; cr0 will not saved???
+ mov eax, cr0
+ push eax
+
+ xor ecx, ecx
+ mov ecx, Ss
+ push ecx
+ mov ecx, Cs
+ push ecx
+ mov ecx, Ds
+ push ecx
+ mov ecx, Es
+ push ecx
+ mov ecx, Fs
+ push ecx
+ mov ecx, Gs
+ push ecx
+
+ ;; EIP
+ mov ecx, [ebp + 4 * 3] ; EIP
+ push ecx
+
+ ;; UINT32 Gdtr[2], Idtr[2];
+ sub esp, 8
+ sidt [esp]
+ sub esp, 8
+ sgdt [esp]
+
+ ;; UINT32 Ldtr, Tr;
+ xor eax, eax
+ str ax
+ push eax
+ sldt ax
+ push eax
+
+ ;; EFlags
+ mov ecx, [ebp + 4 * 5]
+ push ecx
+
+ ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov eax, dr7
+ push eax
+
+ ;; clear Dr7 while executing debugger itself
+ xor eax, eax
+ mov dr7, eax
+
+ ;; Dr6
+ mov eax, dr6
+ push eax
+
+ ;; insure all status bits in dr6 are clear...
+ xor eax, eax
+ mov dr6, eax
+
+ mov eax, dr3
+ push eax
+ mov eax, dr2
+ push eax
+ mov eax, dr1
+ push eax
+ mov eax, dr0
+ push eax
+
+ ;; Clear Direction Flag
+ cld
+
+ ;; FX_SAVE_STATE_IA32 FxSaveState;
+ sub esp, 512
+ mov edi, esp
+ ;; Clear the buffer
+ xor eax, eax
+ mov ecx, 128 ;= 512 / 4
+ rep stosd
+ mov edi, esp
+
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.
+ ; edx still contains result from CPUID above
+ jz .2
+ db 0xf, 0xae, 00000111y ;fxsave [edi]
+.2:
+
+ ;; save the exception data
+ push dword [ebp + 8]
+
+ ; call the C interrupt process function
+ push esp ; Structure
+ push ebx ; vector
+ call ASM_PFX(InterruptProcess)
+ add esp, 8
+
+ ; skip the exception data
+ add esp, 4
+
+ ;; FX_SAVE_STATE_IA32 FxSaveState;
+ mov esi, esp
+ mov eax, 1
+ cpuid ; use CPUID to determine if FXSAVE/FXRESTOR are supported
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
+ jz .3
+ db 0xf, 0xae, 00001110y ; fxrstor [esi]
+.3:
+ add esp, 512
+
+ ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ pop eax
+ mov dr0, eax
+ pop eax
+ mov dr1, eax
+ pop eax
+ mov dr2, eax
+ pop eax
+ mov dr3, eax
+ ;; skip restore of dr6. We cleared dr6 during the context save.
+ add esp, 4
+ pop eax
+ mov dr7, eax
+
+ ;; set EFlags
+ pop dword [ebp + 4 * 5] ; set EFLAGS in stack
+
+ ;; UINT32 Ldtr, Tr;
+ ;; UINT32 Gdtr[2], Idtr[2];
+ ;; Best not let anyone mess with these particular registers...
+ add esp, 24
+
+ ;; UINT32 Eip;
+ pop dword [ebp + 4 * 3] ; set EIP in stack
+
+ ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+ ;; NOTE - modified segment registers could hang the debugger... We
+ ;; could attempt to insulate ourselves against this possibility,
+ ;; but that poses risks as well.
+ ;;
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop dword [ebp + 4 * 4] ; set CS in stack
+ pop ss
+
+ ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ pop eax
+ mov cr0, eax
+ add esp, 4 ; skip for Cr1
+ pop eax
+ mov cr2, eax
+ pop eax
+ mov cr3, eax
+ pop eax
+ mov cr4, eax
+
+ ;; restore general register
+ pop edi
+ pop esi
+ pop dword [ebp] ; save updated ebp
+ pop dword [ebp + 4] ; save updated esp
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+
+ mov esp, ebp
+ pop ebp ; restore ebp maybe updated
+ pop esp ; restore esp maybe updated
+ sub esp, 4 * 3 ; restore interrupt pushced stack
+
+ iretd
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h
new file mode 100644
index 00000000..1648b7c7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h
@@ -0,0 +1,30 @@
+/** @file
+ Exception definitions.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEBUG_EXCEPTION_H_
+#define _DEBUG_EXCEPTION_H_
+
+#define DEBUG_EXCEPT_DIVIDE_ERROR 0
+#define DEBUG_EXCEPT_DEBUG 1
+#define DEBUG_EXCEPT_NMI 2
+#define DEBUG_EXCEPT_BREAKPOINT 3
+#define DEBUG_EXCEPT_OVERFLOW 4
+#define DEBUG_EXCEPT_BOUND 5
+#define DEBUG_EXCEPT_INVALID_OPCODE 6
+#define DEBUG_EXCEPT_DOUBLE_FAULT 8
+#define DEBUG_EXCEPT_INVALID_TSS 10
+#define DEBUG_EXCEPT_SEG_NOT_PRESENT 11
+#define DEBUG_EXCEPT_STACK_FAULT 12
+#define DEBUG_EXCEPT_GP_FAULT 13
+#define DEBUG_EXCEPT_PAGE_FAULT 14
+#define DEBUG_EXCEPT_FP_ERROR 16
+#define DEBUG_EXCEPT_ALIGNMENT_CHECK 17
+#define DEBUG_EXCEPT_MACHINE_CHECK 18
+#define DEBUG_EXCEPT_SIMD 19
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c
new file mode 100644
index 00000000..eaf57521
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c
@@ -0,0 +1,114 @@
+/** @file
+ Supporting functions for X64 architecture.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugAgent.h"
+
+/**
+ Initialize IDT entries to support source level debug.
+
+**/
+VOID
+InitializeDebugIdt (
+ VOID
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ UINTN InterruptHandler;
+ IA32_DESCRIPTOR IdtDescriptor;
+ UINTN Index;
+ UINT16 CodeSegment;
+ UINT32 RegEdx;
+
+ AsmReadIdtr (&IdtDescriptor);
+
+ //
+ // Use current CS as the segment selector of interrupt gate in IDT
+ //
+ CodeSegment = AsmReadCs ();
+
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ for (Index = 0; Index < 20; Index ++) {
+ if (((PcdGet32 (PcdExceptionsIgnoredByDebugger) & ~(BIT1 | BIT3)) & (1 << Index)) != 0) {
+ //
+ // If the exception is masked to be reserved except for INT1 and INT3, skip it
+ //
+ continue;
+ }
+ InterruptHandler = (UINTN)&Exception0Handle + Index * ExceptionStubHeaderSize;
+ IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry[Index].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
+ IdtEntry[Index].Bits.Selector = CodeSegment;
+ IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ }
+
+ InterruptHandler = (UINTN) &TimerInterruptHandle;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.Selector = CodeSegment;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+
+ //
+ // If the CPU supports Debug Extensions(CPUID:01 EDX:BIT2), then
+ // Set DE flag in CR4 to enable IO breakpoint
+ //
+ AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT2) != 0) {
+ AsmWriteCr4 (AsmReadCr4 () | BIT3);
+ }
+}
+
+/**
+ Retrieve exception handler from IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+
+ @return Exception handler
+
+**/
+VOID *
+GetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR IdtDescriptor;
+
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ return (VOID *) (IdtEntry[ExceptionNum].Bits.OffsetLow |
+ (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetHigh) << 16) |
+ (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetUpper) << 32));
+}
+
+/**
+ Set exception handler in IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+ @param[in] ExceptionHandler Exception Handler to be set
+
+**/
+VOID
+SetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum,
+ IN VOID *ExceptionHandler
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR IdtDescriptor;
+
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ IdtEntry[ExceptionNum].Bits.OffsetLow = (UINT16)(UINTN)ExceptionHandler;
+ IdtEntry[ExceptionNum].Bits.OffsetHigh = (UINT16)((UINTN)ExceptionHandler >> 16);
+ IdtEntry[ExceptionNum].Bits.OffsetUpper = (UINT32)((UINTN)ExceptionHandler >> 32);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h
new file mode 100644
index 00000000..07eec01c
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h
@@ -0,0 +1,21 @@
+/** @file
+ X64 specific definitions for debug agent library instance.
+
+ Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ARCH_DEBUG_SUPPORT_H_
+#define _ARCH_DEBUG_SUPPORT_H_
+
+#include "ProcessorContext.h"
+#include "TransferProtocol.h"
+
+#define DEBUG_SW_BREAKPOINT_SYMBOL 0xcc
+#define DEBUG_ARCH_SYMBOL DEBUG_DATA_BREAK_CPU_ARCH_X64
+
+typedef DEBUG_DATA_X64_FX_SAVE_STATE DEBUG_DATA_FX_SAVE_STATE;
+typedef DEBUG_DATA_X64_SYSTEM_CONTEXT DEBUG_CPU_CONTEXT;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm
new file mode 100644
index 00000000..508c1116
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm
@@ -0,0 +1,399 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; AsmFuncs.nasm
+;
+; Abstract:
+;
+; Debug interrupt handle functions.
+;
+;------------------------------------------------------------------------------
+
+#include "DebugException.h"
+
+SECTION .data
+
+extern ASM_PFX(InterruptProcess)
+global ASM_PFX(Exception0Handle)
+global ASM_PFX(TimerInterruptHandle)
+global ASM_PFX(ExceptionStubHeaderSize)
+
+%macro AGENT_HANDLER_SIGNATURE 0
+ db 0x41, 0x47, 0x54, 0x48 ; SIGNATURE_32('A','G','T','H')
+%endmacro
+
+ASM_PFX(ExceptionStubHeaderSize): dd Exception1Handle - ASM_PFX(Exception0Handle) ;
+CommonEntryAddr: dq CommonEntry ;
+
+DEFAULT REL
+SECTION .text
+
+AGENT_HANDLER_SIGNATURE
+ASM_PFX(Exception0Handle):
+ cli
+ push rcx
+ mov rcx, dword 0
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception1Handle:
+ cli
+ push rcx
+ mov rcx, dword 1
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception2Handle:
+ cli
+ push rcx
+ mov rcx, dword 2
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception3Handle:
+ cli
+ push rcx
+ mov rcx, dword 3
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception4Handle:
+ cli
+ push rcx
+ mov rcx, dword 4
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception5Handle:
+ cli
+ push rcx
+ mov rcx, dword 5
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception6Handle:
+ cli
+ push rcx
+ mov rcx, dword 6
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception7Handle:
+ cli
+ push rcx
+ mov rcx, dword 7
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception8Handle:
+ cli
+ push rcx
+ mov rcx, dword 8
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception9Handle:
+ cli
+ push rcx
+ mov rcx, dword 9
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception10Handle:
+ cli
+ push rcx
+ mov rcx, dword 10
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception11Handle:
+ cli
+ push rcx
+ mov rcx, dword 11
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception12Handle:
+ cli
+ push rcx
+ mov rcx, dword 12
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception13Handle:
+ cli
+ push rcx
+ mov rcx, dword 13
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception14Handle:
+ cli
+ push rcx
+ mov rcx, dword 14
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception15Handle:
+ cli
+ push rcx
+ mov rcx, dword 15
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception16Handle:
+ cli
+ push rcx
+ mov rcx, dword 16
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception17Handle:
+ cli
+ push rcx
+ mov rcx, dword 17
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception18Handle:
+ cli
+ push rcx
+ mov rcx, dword 18
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception19Handle:
+ cli
+ push rcx
+ mov rcx, dword 19
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+ASM_PFX(TimerInterruptHandle):
+ cli
+ push rcx
+ mov rcx, dword 32
+ jmp qword [CommonEntryAddr]
+
+CommonEntry:
+ ; We need to determine if any extra data was pushed by the exception
+ cmp rcx, DEBUG_EXCEPT_DOUBLE_FAULT
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_INVALID_TSS
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_SEG_NOT_PRESENT
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_STACK_FAULT
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_GP_FAULT
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_PAGE_FAULT
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_ALIGNMENT_CHECK
+ je NoExtrPush
+
+ push qword [rsp]
+ mov qword [rsp + 8], 0
+
+NoExtrPush:
+ push rbp
+ mov rbp, rsp
+
+ ; store UINT64 r8, r9, r10, r11, r12, r13, r14, r15;
+ push r15
+ push r14
+ push r13
+ push r12
+ push r11
+ push r10
+ push r9
+ push r8
+
+ mov r8, cr8
+ push r8
+
+ ; store UINT64 Rdi, Rsi, Rbp, Rsp, Rdx, Rcx, Rbx, Rax;
+ push rax
+ push rbx
+ push qword [rbp + 8] ; original rcx
+ push rdx
+ push qword [rbp + 6 * 8] ; original rsp
+ push qword [rbp] ; original rbp
+ push rsi
+ push rdi
+
+ ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ ;; insure FXSAVE/FXRSTOR is enabled in CR4...
+ ;; ... while we're at it, make sure DE is also enabled...
+ mov rax, cr4
+ or rax, 0x208
+ mov cr4, rax
+ push rax
+ mov rax, cr3
+ push rax
+ mov rax, cr2
+ push rax
+ push 0
+ mov rax, cr0
+ push rax
+
+ xor rax, rax
+ mov rax, Ss
+ push rax
+ mov rax, Cs
+ push rax
+ mov rax, Ds
+ push rax
+ mov rax, Es
+ push rax
+ mov rax, Fs
+ push rax
+ mov rax, Gs
+ push rax
+
+ ;; EIP
+ mov rax, [rbp + 8 * 3] ; EIP
+ push rax
+
+ ;; UINT64 Gdtr[2], Idtr[2];
+ sub rsp, 16
+ sidt [rsp]
+ sub rsp, 16
+ sgdt [rsp]
+
+ ;; UINT64 Ldtr, Tr;
+ xor rax, rax
+ str ax
+ push rax
+ sldt ax
+ push rax
+
+ ;; EFlags
+ mov rax, [rbp + 8 * 5]
+ push rax
+
+ ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov rax, dr7
+ push rax
+
+ ;; clear Dr7 while executing debugger itself
+ xor rax, rax
+ mov dr7, rax
+
+ ;; Dr6
+ mov rax, dr6
+ push rax
+
+ ;; insure all status bits in dr6 are clear...
+ xor rax, rax
+ mov dr6, rax
+
+ mov rax, dr3
+ push rax
+ mov rax, dr2
+ push rax
+ mov rax, dr1
+ push rax
+ mov rax, dr0
+ push rax
+
+ ;; Clear Direction Flag
+ cld
+
+ sub rsp, 512
+ mov rdi, rsp
+ ;; Clear the buffer
+ xor rax, rax
+ push rcx
+ mov rcx, dword 64 ;= 512 / 8
+ rep stosq
+ pop rcx
+ mov rdi, rsp
+ db 0xf, 0xae, 00000111y ;fxsave [rdi]
+
+ ;; save the exception data
+ push qword [rbp + 16]
+
+ ; call the C interrupt process function
+ mov rdx, rsp ; Structure
+ mov r15, rcx ; save vector in r15
+
+ ;
+ ; Per X64 calling convention, allocate maximum parameter stack space
+ ; and make sure RSP is 16-byte aligned
+ ;
+ sub rsp, 32 + 8
+ call ASM_PFX(InterruptProcess)
+ add rsp, 32 + 8
+
+ ;; skip the exception data
+ add rsp, 8
+
+ mov rsi, rsp
+ db 0xf, 0xae, 00001110y ; fxrstor [rsi]
+ add rsp, 512
+
+ ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ pop rax
+ mov dr0, rax
+ pop rax
+ mov dr1, rax
+ pop rax
+ mov dr2, rax
+ pop rax
+ mov dr3, rax
+ ;; skip restore of dr6. We cleared dr6 during the context save.
+ add rsp, 8
+ pop rax
+ mov dr7, rax
+
+ ;; set EFlags
+ pop qword [rbp + 8 * 5]
+
+ ;; UINT64 Ldtr, Tr;
+ ;; UINT64 Gdtr[2], Idtr[2];
+ ;; Best not let anyone mess with these particular registers...
+ add rsp, 24 * 2
+
+ ;; UINT64 Eip;
+ pop qword [rbp + 8 * 3] ; set EIP in stack
+
+ ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
+ ;; NOTE - modified segment registers could hang the debugger... We
+ ;; could attempt to insulate ourselves against this possibility,
+ ;; but that poses risks as well.
+ ;;
+ pop rax
+ pop rax
+ pop rax
+ mov es, rax
+ pop rax
+ mov ds, rax
+ pop qword [rbp + 8 * 4] ; Set CS in stack
+ pop rax
+ mov ss, rax
+
+ ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4;
+ pop rax
+ mov cr0, rax
+ add rsp, 8 ; skip for Cr1
+ pop rax
+ mov cr2, rax
+ pop rax
+ mov cr3, rax
+ pop rax
+ mov cr4, rax
+
+ ;; restore general register
+ pop rdi
+ pop rsi
+ add rsp, 8 ; skip rbp
+ add rsp, 8 ; skip rsp
+ pop rdx
+ pop rcx
+ pop rbx
+ pop rax
+
+ pop r8
+ mov cr8, r8
+
+ ; store UINT64 r8, r9, r10, r11, r12, r13, r14, r15;
+ pop r8
+ pop r9
+ pop r10
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+
+ mov rsp, rbp
+ pop rbp
+ add rsp, 16 ; skip rcx and error code
+
+ iretq
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h
new file mode 100644
index 00000000..1648b7c7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h
@@ -0,0 +1,30 @@
+/** @file
+ Exception definitions.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEBUG_EXCEPTION_H_
+#define _DEBUG_EXCEPTION_H_
+
+#define DEBUG_EXCEPT_DIVIDE_ERROR 0
+#define DEBUG_EXCEPT_DEBUG 1
+#define DEBUG_EXCEPT_NMI 2
+#define DEBUG_EXCEPT_BREAKPOINT 3
+#define DEBUG_EXCEPT_OVERFLOW 4
+#define DEBUG_EXCEPT_BOUND 5
+#define DEBUG_EXCEPT_INVALID_OPCODE 6
+#define DEBUG_EXCEPT_DOUBLE_FAULT 8
+#define DEBUG_EXCEPT_INVALID_TSS 10
+#define DEBUG_EXCEPT_SEG_NOT_PRESENT 11
+#define DEBUG_EXCEPT_STACK_FAULT 12
+#define DEBUG_EXCEPT_GP_FAULT 13
+#define DEBUG_EXCEPT_PAGE_FAULT 14
+#define DEBUG_EXCEPT_FP_ERROR 16
+#define DEBUG_EXCEPT_ALIGNMENT_CHECK 17
+#define DEBUG_EXCEPT_MACHINE_CHECK 18
+#define DEBUG_EXCEPT_SIMD 19
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c
new file mode 100644
index 00000000..a298b284
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c
@@ -0,0 +1,544 @@
+/** @file
+ Debug Agent library implementation for Dxe Core and Dxr modules.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeDebugAgentLib.h"
+
+DEBUG_AGENT_MAILBOX mMailbox;
+DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL;
+IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33];
+BOOLEAN mDxeCoreFlag = FALSE;
+BOOLEAN mMultiProcessorDebugSupport = FALSE;
+VOID *mSavedIdtTable = NULL;
+UINTN mSaveIdtTableSize = 0;
+BOOLEAN mDebugAgentInitialized = FALSE;
+BOOLEAN mSkipBreakpoint = FALSE;
+
+/**
+ Check if debug agent support multi-processor.
+
+ @retval TRUE Multi-processor is supported.
+ @retval FALSE Multi-processor is not supported.
+
+**/
+BOOLEAN
+MultiProcessorDebugSupport (
+ VOID
+ )
+{
+ return mMultiProcessorDebugSupport;
+}
+
+/**
+ Internal constructor worker function.
+
+ It will register one callback function on EFI PCD Protocol.
+ It will allocate the NVS memory to store Mailbox and install configuration table
+ in system table to store its pointer.
+
+**/
+VOID
+InternalConstructorWorker (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Address;
+ BOOLEAN DebugTimerInterruptState;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ DEBUG_AGENT_MAILBOX *NewMailbox;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_VECTOR_HANDOFF_INFO *VectorHandoffInfo;
+
+ //
+ // Check persisted vector handoff info
+ //
+ Status = EFI_SUCCESS;
+ GuidHob = GetFirstGuidHob (&gEfiVectorHandoffInfoPpiGuid);
+ if (GuidHob != NULL && !mDxeCoreFlag) {
+ //
+ // Check if configuration table is installed or not if GUIDed HOB existed,
+ // only when Debug Agent is not linked by DXE Core
+ //
+ Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **) &VectorHandoffInfo);
+ }
+ if (GuidHob == NULL || Status != EFI_SUCCESS) {
+ //
+ // Install configuration table for persisted vector handoff info if GUIDed HOB cannot be found or
+ // configuration table does not exist
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *) &mVectorHandoffInfoDebugAgent[0]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
+ CpuDeadLoop ();
+ }
+ }
+
+ //
+ // Install EFI Serial IO protocol on debug port
+ //
+ InstallSerialIo ();
+
+ Address = 0;
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for mailbox!\n"));
+ CpuDeadLoop ();
+ }
+
+ DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
+
+ NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;
+ //
+ // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
+ // and Debug Port Handle buffer may be free at runtime, SMM debug agent needs to access them
+ //
+ Mailbox = GetMailboxPointer ();
+ CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
+ CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
+ //
+ // Update Debug Port Handle in new Mailbox
+ //
+ UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
+ mMailboxPointer = NewMailbox;
+
+ DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
+
+ Status = gBS->InstallConfigurationTable (&gEfiDebugAgentGuid, (VOID *) mMailboxPointer);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install configuration for mailbox!\n"));
+ CpuDeadLoop ();
+ }
+}
+
+/**
+ Debug Agent constructor function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval RETURN_SUCCESS When this function completed.
+
+**/
+RETURN_STATUS
+EFIAPI
+DxeDebugAgentLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ if (mDxeCoreFlag) {
+ //
+ // Invoke internal constructor function only when DXE core links this library instance
+ //
+ InternalConstructorWorker ();
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Get the pointer to Mailbox from the configuration table.
+
+ @return Pointer to Mailbox.
+
+**/
+DEBUG_AGENT_MAILBOX *
+GetMailboxFromConfigurationTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+
+ Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox);
+ if (Status == EFI_SUCCESS && Mailbox != NULL) {
+ VerifyMailboxChecksum (Mailbox);
+ return Mailbox;
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ Get the pointer to Mailbox from the GUIDed HOB.
+
+ @param[in] HobStart The starting HOB pointer to search from.
+
+ @return Pointer to Mailbox.
+
+**/
+DEBUG_AGENT_MAILBOX *
+GetMailboxFromHob (
+ IN VOID *HobStart
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINT64 *MailboxLocation;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+
+ GuidHob = GetNextGuidHob (&gEfiDebugAgentGuid, HobStart);
+ if (GuidHob == NULL) {
+ return NULL;
+ }
+ MailboxLocation = (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
+ Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
+ VerifyMailboxChecksum (Mailbox);
+
+ return Mailbox;
+}
+
+/**
+ Get Debug Agent Mailbox pointer.
+
+ @return Mailbox pointer.
+
+**/
+DEBUG_AGENT_MAILBOX *
+GetMailboxPointer (
+ VOID
+ )
+{
+ AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock);
+ VerifyMailboxChecksum (mMailboxPointer);
+ ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock);
+ return mMailboxPointer;
+}
+
+/**
+ Get debug port handle.
+
+ @return Debug port handle.
+
+**/
+DEBUG_PORT_HANDLE
+GetDebugPortHandle (
+ VOID
+ )
+{
+ return (DEBUG_PORT_HANDLE) (UINTN)(GetMailboxPointer ()->DebugPortHandle);
+}
+
+/**
+ Worker function to set up Debug Agent environment.
+
+ This function will set up IDT table and initialize the IDT entries and
+ initialize CPU LOCAL APIC timer.
+ It also tries to connect HOST if Debug Agent was not initialized before.
+
+ @param[in] Mailbox Pointer to Mailbox.
+
+**/
+VOID
+SetupDebugAgentEnvironment (
+ IN DEBUG_AGENT_MAILBOX *Mailbox
+ )
+{
+ IA32_DESCRIPTOR Idtr;
+ UINT16 IdtEntryCount;
+ UINT64 DebugPortHandle;
+ UINT32 DebugTimerFrequency;
+
+ if (mMultiProcessorDebugSupport) {
+ InitializeSpinLock (&mDebugMpContext.MpContextSpinLock);
+ InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ InitializeSpinLock (&mDebugMpContext.MailboxSpinLock);
+ //
+ // Clear Break CPU index value
+ //
+ mDebugMpContext.BreakAtCpuIndex = (UINT32) -1;
+ }
+
+ //
+ // Get original IDT address and size.
+ //
+ AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr);
+ IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
+ if (IdtEntryCount < 33) {
+ ZeroMem (&mIdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33);
+ //
+ // Copy original IDT table into new one
+ //
+ CopyMem (&mIdtEntryTable, (VOID *) Idtr.Base, Idtr.Limit + 1);
+ //
+ // Load new IDT table
+ //
+ Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
+ Idtr.Base = (UINTN) &mIdtEntryTable;
+ AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr);
+ }
+
+ //
+ // Initialize the IDT table entries to support source level debug.
+ //
+ InitializeDebugIdt ();
+
+ //
+ // If mMailboxPointer is not set before, set it
+ //
+ if (mMailboxPointer == NULL) {
+ if (Mailbox != NULL) {
+ //
+ // If Mailbox exists, copy it into one global variable
+ //
+ CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
+ } else {
+ ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX));
+ }
+ mMailboxPointer = &mMailbox;
+ }
+
+ //
+ // Initialize Debug Timer hardware and save its initial count and frequency
+ //
+ mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (&DebugTimerFrequency, TRUE);
+ UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
+ //
+ // Initialize debug communication port
+ //
+ DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL);
+ UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
+
+ if (Mailbox == NULL) {
+ //
+ // Trigger one software interrupt to inform HOST
+ //
+ TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
+ SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
+ //
+ // Memory has been ready
+ //
+ if (IsHostAttached ()) {
+ //
+ // Trigger one software interrupt to inform HOST
+ //
+ TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
+ }
+ }
+}
+
+
+/**
+ Initialize debug agent.
+
+ This function is used to set up debug environment for DXE phase.
+
+ If this function is called by DXE Core, Context must be the pointer
+ to HOB list which will be used to get GUIDed HOB. It will enable
+ interrupt to support break-in feature.
+ If this function is called by DXE module, Context must be NULL. It
+ will enable interrupt to support break-in feature.
+
+ @param[in] InitFlag Init flag is used to decide initialize process.
+ @param[in] Context Context needed according to InitFlag.
+ @param[in] Function Continue function called by debug agent library; it was
+ optional.
+
+**/
+VOID
+EFIAPI
+InitializeDebugAgent (
+ IN UINT32 InitFlag,
+ IN VOID *Context, OPTIONAL
+ IN DEBUG_AGENT_CONTINUE Function OPTIONAL
+ )
+{
+ UINT64 *MailboxLocation;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ BOOLEAN InterruptStatus;
+ VOID *HobList;
+ IA32_DESCRIPTOR IdtDescriptor;
+ IA32_DESCRIPTOR *Ia32Idtr;
+ IA32_IDT_ENTRY *Ia32IdtEntry;
+ BOOLEAN PeriodicMode;
+ UINTN TimerCycle;
+
+ if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) {
+ //
+ // Check if CPU APIC Timer is working, otherwise initialize it.
+ //
+ InitializeLocalApicSoftwareEnable (TRUE);
+ GetApicTimerState (NULL, &PeriodicMode, NULL);
+ TimerCycle = GetApicTimerInitCount ();
+ if (!PeriodicMode || TimerCycle == 0) {
+ InitializeDebugTimer (NULL, FALSE);
+ }
+ //
+ // Invoked by AP, enable interrupt to let AP could receive IPI from other processors
+ //
+ EnableInterrupts ();
+ return ;
+ }
+
+ //
+ // Disable Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+ //
+ // Save and disable original interrupt status
+ //
+ InterruptStatus = SaveAndDisableInterrupts ();
+
+ //
+ // Try to get mailbox firstly
+ //
+ HobList = NULL;
+ Mailbox = NULL;
+ MailboxLocation = NULL;
+
+ switch (InitFlag) {
+
+ case DEBUG_AGENT_INIT_DXE_LOAD:
+ //
+ // Check if Debug Agent has been initialized before
+ //
+ if (IsDebugAgentInitialzed ()) {
+ DEBUG ((EFI_D_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n"));
+ }
+
+ mMultiProcessorDebugSupport = TRUE;
+ //
+ // Save original IDT table
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ mSaveIdtTableSize = IdtDescriptor.Limit + 1;
+ mSavedIdtTable = AllocateCopyPool (mSaveIdtTableSize, (VOID *) IdtDescriptor.Base);
+ //
+ // Check if Debug Agent initialized in DXE phase
+ //
+ Mailbox = GetMailboxFromConfigurationTable ();
+ if (Mailbox == NULL) {
+ //
+ // Try to get mailbox from GUIDed HOB build in PEI
+ //
+ HobList = GetHobList ();
+ Mailbox = GetMailboxFromHob (HobList);
+ }
+ //
+ // Set up Debug Agent Environment and try to connect HOST if required
+ //
+ SetupDebugAgentEnvironment (Mailbox);
+ //
+ // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol
+ // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()
+ //
+ InternalConstructorWorker ();
+ //
+ // Enable Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (TRUE);
+ //
+ // Enable interrupt to receive Debug Timer interrupt
+ //
+ EnableInterrupts ();
+
+ mDebugAgentInitialized = TRUE;
+ FindAndReportModuleImageInfo (SIZE_4KB);
+
+ *(EFI_STATUS *)Context = EFI_SUCCESS;
+
+ break;
+
+ case DEBUG_AGENT_INIT_DXE_UNLOAD:
+ if (mDebugAgentInitialized) {
+ if (IsHostAttached ()) {
+ *(EFI_STATUS *)Context = EFI_ACCESS_DENIED;
+ //
+ // Enable Debug Timer interrupt again
+ //
+ SaveAndSetDebugTimerInterrupt (TRUE);
+ } else {
+ //
+ // Restore original IDT table
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ IdtDescriptor.Limit = (UINT16) (mSaveIdtTableSize - 1);
+ CopyMem ((VOID *) IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize);
+ AsmWriteIdtr (&IdtDescriptor);
+ FreePool (mSavedIdtTable);
+ mDebugAgentInitialized = FALSE;
+ *(EFI_STATUS *)Context = EFI_SUCCESS;
+ }
+ } else {
+ *(EFI_STATUS *)Context = EFI_NOT_STARTED;
+ }
+
+ //
+ // Restore interrupt state.
+ //
+ SetInterruptState (InterruptStatus);
+ break;
+
+ case DEBUG_AGENT_INIT_DXE_CORE:
+ mDxeCoreFlag = TRUE;
+ mMultiProcessorDebugSupport = TRUE;
+ //
+ // Try to get mailbox from GUIDed HOB build in PEI
+ //
+ HobList = Context;
+ Mailbox = GetMailboxFromHob (HobList);
+ //
+ // Set up Debug Agent Environment and try to connect HOST if required
+ //
+ SetupDebugAgentEnvironment (Mailbox);
+ //
+ // Enable Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (TRUE);
+ //
+ // Enable interrupt to receive Debug Timer interrupt
+ //
+ EnableInterrupts ();
+
+ break;
+
+ case DEBUG_AGENT_INIT_S3:
+
+ if (Context != NULL) {
+ Ia32Idtr = (IA32_DESCRIPTOR *) Context;
+ Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
+ MailboxLocation = (UINT64 *) ((UINTN) Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
+ ((UINTN) Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
+ Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
+ VerifyMailboxChecksum (Mailbox);
+ }
+ //
+ // Save Mailbox pointer in global variable
+ //
+ mMailboxPointer = Mailbox;
+ //
+ // Set up Debug Agent Environment and try to connect HOST if required
+ //
+ SetupDebugAgentEnvironment (Mailbox);
+ //
+ // Disable interrupt
+ //
+ DisableInterrupts ();
+ FindAndReportModuleImageInfo (SIZE_4KB);
+ if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) {
+ //
+ // If Boot Script entry break is set, code will be break at here.
+ //
+ CpuBreakpoint ();
+ }
+ break;
+
+ default:
+ //
+ // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
+ // Debug Agent library instance.
+ //
+ DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
+ CpuDeadLoop ();
+ break;
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h
new file mode 100644
index 00000000..8d1d917a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h
@@ -0,0 +1,34 @@
+/** @file
+ Header file for Dxe Core Debug Agent Library instance.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DXE_CORE_DEBUG_AGENT_LIB_H_
+#define _DXE_CORE_DEBUG_AGENT_LIB_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/SerialIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PiPcd.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "DebugAgent.h"
+
+/**
+ Install EFI Serial IO protocol based on Debug Communication Library.
+
+**/
+VOID
+InstallSerialIo (
+ VOID
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c
new file mode 100644
index 00000000..b5176ac9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c
@@ -0,0 +1,808 @@
+/** @file
+ Install Serial IO Protocol that layers on top of a Debug Communication Library instance.
+
+ Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeDebugAgentLib.h"
+
+//
+// Serial I/O Protocol Interface definitions.
+//
+
+/**
+ Reset serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+
+ @retval EFI_SUCCESS Reset successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialReset (
+ IN EFI_SERIAL_IO_PROTOCOL *This
+ );
+
+/**
+ Set new attributes to a serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in] BaudRate The baudrate of the serial device.
+ @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.
+ @param[in] Timeout The request timeout for a single char.
+ @param[in] Parity The type of parity used in serial device.
+ @param[in] DataBits Number of databits used in serial device.
+ @param[in] StopBits Number of stopbits used in serial device.
+
+ @retval EFI_SUCCESS The new attributes were set.
+ @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetAttributes (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT64 BaudRate,
+ IN UINT32 ReceiveFifoDepth,
+ IN UINT32 Timeout,
+ IN EFI_PARITY_TYPE Parity,
+ IN UINT8 DataBits,
+ IN EFI_STOP_BITS_TYPE StopBits
+ );
+
+/**
+ Set Control Bits.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in] Control Control bits that can be settable.
+
+ @retval EFI_SUCCESS New Control bits were set successfully.
+ @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT32 Control
+ );
+
+/**
+ Get ControlBits.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[out] Control Control signals of the serial device.
+
+ @retval EFI_SUCCESS Get Control signals successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialGetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ OUT UINT32 *Control
+ );
+
+/**
+ Write the specified number of bytes to serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of
+ data actually written.
+ @param[in] Buffer The buffer of data to write.
+
+ @retval EFI_SUCCESS The data were written successfully.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The write operation was stopped due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialWrite (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Read the specified number of bytes from serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of
+ data returned in buffer.
+ @param[out] Buffer The buffer to return the data into.
+
+ @retval EFI_SUCCESS The data were read successfully.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The read operation was stopped due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialRead (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+//
+// Serial Driver Defaults
+//
+#define SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH 1
+#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000
+#define SERIAL_PORT_DEFAULT_CONTROL_MASK 0
+#define SERIAL_PORT_LOOPBACK_BUFFER_FULL BIT8
+
+//
+// EFI_SERIAL_IO_MODE instance
+//
+EFI_SERIAL_IO_MODE mSerialIoMode = {
+ SERIAL_PORT_DEFAULT_CONTROL_MASK,
+ SERIAL_PORT_DEFAULT_TIMEOUT,
+ 0, // default BaudRate
+ SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,
+ 0, // default DataBits
+ 0, // default Parity
+ 0 // default StopBits
+};
+
+//
+// EFI_SERIAL_IO_PROTOCOL instance
+//
+EFI_SERIAL_IO_PROTOCOL mSerialIo = {
+ SERIAL_IO_INTERFACE_REVISION,
+ SerialReset,
+ SerialSetAttributes,
+ SerialSetControl,
+ SerialGetControl,
+ SerialWrite,
+ SerialRead,
+ &mSerialIoMode
+};
+
+//
+// Serial IO Device Path definition
+//
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ UART_DEVICE_PATH UartDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} SERIAL_IO_DEVICE_PATH;
+
+//
+// Serial IO Device Patch instance
+//
+SERIAL_IO_DEVICE_PATH mSerialIoDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ EFI_DEBUG_AGENT_GUID,
+ },
+ {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_UART_DP,
+ {
+ (UINT8) (sizeof (UART_DEVICE_PATH)),
+ (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0,
+ 0, // default BaudRate
+ 0, // default DataBits
+ 0, // default Parity
+ 0, // default StopBits
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+#define DEBGU_SERIAL_IO_FIFO_DEPTH 10
+//
+// Data buffer for Terminal input character and Debug Symbols.
+// The depth is DEBGU_SERIAL_IO_FIFO_DEPTH.
+// Fields:
+// First UINT8: The index of the first data in array Data[].
+// Last UINT8: The index, which you can put a new data into array Data[].
+// Surplus UINT8: Identify how many data you can put into array Data[].
+// Data[] UINT8: An array, which used to store data.
+//
+typedef struct {
+ UINT8 First;
+ UINT8 Last;
+ UINT8 Surplus;
+ UINT8 Data[DEBGU_SERIAL_IO_FIFO_DEPTH];
+} DEBUG_SERIAL_FIFO;
+
+//
+// Global Variables
+//
+EFI_HANDLE mSerialIoHandle = NULL;
+UINTN mLoopbackBuffer = 0;
+DEBUG_SERIAL_FIFO mSerialFifoForTerminal = {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH, { 0 }};
+DEBUG_SERIAL_FIFO mSerialFifoForDebug = {0, 0, DEBGU_SERIAL_IO_FIFO_DEPTH, { 0 }};
+
+/**
+ Detect whether specific FIFO is empty or not.
+
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
+
+ @return whether specific FIFO is empty or not.
+
+**/
+BOOLEAN
+IsDebugTermianlFifoEmpty (
+ IN DEBUG_SERIAL_FIFO *Fifo
+ )
+{
+ if (Fifo->Surplus == DEBGU_SERIAL_IO_FIFO_DEPTH) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Detect whether specific FIFO is full or not.
+
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
+
+ @return whether specific FIFO is full or not.
+
+**/
+BOOLEAN
+IsDebugTerminalFifoFull (
+ IN DEBUG_SERIAL_FIFO *Fifo
+ )
+
+{
+ if (Fifo->Surplus == 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Add data to specific FIFO.
+
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
+ @param[in] Data The data added to FIFO.
+
+ @retval EFI_SUCCESS Add data to specific FIFO successfully.
+ @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full.
+
+**/
+EFI_STATUS
+DebugTerminalFifoAdd (
+ IN DEBUG_SERIAL_FIFO *Fifo,
+ IN UINT8 Data
+ )
+
+{
+ //
+ // if FIFO full can not add data
+ //
+ if (IsDebugTerminalFifoFull (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // FIFO is not full can add data
+ //
+ Fifo->Data[Fifo->Last] = Data;
+ Fifo->Surplus--;
+ Fifo->Last++;
+ if (Fifo->Last == DEBGU_SERIAL_IO_FIFO_DEPTH) {
+ Fifo->Last = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove data from specific FIFO.
+
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
+ @param[out] Data The data removed from FIFO.
+
+ @retval EFI_SUCCESS Remove data from specific FIFO successfully.
+ @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty.
+
+**/
+EFI_STATUS
+DebugTerminalFifoRemove (
+ IN DEBUG_SERIAL_FIFO *Fifo,
+ OUT UINT8 *Data
+ )
+{
+ //
+ // if FIFO is empty, no data can remove
+ //
+ if (IsDebugTermianlFifoEmpty (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // FIFO is not empty, can remove data
+ //
+ *Data = Fifo->Data[Fifo->First];
+ Fifo->Surplus++;
+ Fifo->First++;
+ if (Fifo->First == DEBGU_SERIAL_IO_FIFO_DEPTH) {
+ Fifo->First = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Install EFI Serial IO protocol based on Debug Communication Library.
+
+**/
+VOID
+InstallSerialIo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mSerialIoHandle,
+ &gEfiDevicePathProtocolGuid, &mSerialIoDevicePath,
+ &gEfiSerialIoProtocolGuid, &mSerialIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n"));
+ }
+}
+
+/**
+ Reset serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+
+ @retval EFI_SUCCESS Reset successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialReset (
+ IN EFI_SERIAL_IO_PROTOCOL *This
+ )
+{
+ mSerialIoMode.ControlMask = SERIAL_PORT_DEFAULT_CONTROL_MASK;
+ mLoopbackBuffer = 0;
+ //
+ // Not reset serial device hardware indeed.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Set new attributes to a serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in] BaudRate The baudrate of the serial device.
+ @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.
+ @param[in] Timeout The request timeout for a single char.
+ @param[in] Parity The type of parity used in serial device.
+ @param[in] DataBits Number of databits used in serial device.
+ @param[in] StopBits Number of stopbits used in serial device.
+
+ @retval EFI_SUCCESS The new attributes were set.
+ @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetAttributes (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT64 BaudRate,
+ IN UINT32 ReceiveFifoDepth,
+ IN UINT32 Timeout,
+ IN EFI_PARITY_TYPE Parity,
+ IN UINT8 DataBits,
+ IN EFI_STOP_BITS_TYPE StopBits
+ )
+{
+ //
+ // The Debug Communication Library CAN NOT change communications parameters (if it has)
+ // actually. Because it also has no any idea on what parameters are based on, we cannot
+ // check the input parameters (like BaudRate, Parity, DataBits and StopBits).
+ //
+
+ //
+ // Update the Timeout value in the mode structure based on the request.
+ // The Debug Communication Library can not support a timeout on writes, but the timeout on
+ // reads can be provided by this module.
+ //
+ if (Timeout == 0) {
+ mSerialIoMode.Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
+ } else {
+ mSerialIoMode.Timeout = Timeout;
+ }
+
+ //
+ // Update the ReceiveFifoDepth value in the mode structure based on the request.
+ // This module assumes that the Debug Communication Library uses a FIFO depth of
+ // SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH. The Debug Communication Library may actually be
+ // using a larger FIFO, but there is no way to tell.
+ //
+ if (ReceiveFifoDepth == 0 || ReceiveFifoDepth >= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH) {
+ mSerialIoMode.ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set Control Bits.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in] Control Control bits that can be settable.
+
+ @retval EFI_SUCCESS New Control bits were set successfully.
+ @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT32 Control
+ )
+{
+ //
+ // The only control bit supported by this module is software loopback.
+ // If any other bit is set, then return an error
+ //
+ if ((Control & (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+ mSerialIoMode.ControlMask = Control;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get ControlBits.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[out] Control Control signals of the serial device.
+
+ @retval EFI_SUCCESS Get Control signals successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialGetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ OUT UINT32 *Control
+ )
+{
+ DEBUG_PORT_HANDLE Handle;
+ BOOLEAN DebugTimerInterruptState;
+ EFI_TPL Tpl;
+
+ //
+ // Raise TPL to prevent recursion from EFI timer interrupts
+ //
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Save and disable Debug Timer interrupt to avoid it to access Debug Port
+ //
+ DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
+ Handle = GetDebugPortHandle ();
+
+ //
+ // Always assume the output buffer is empty and the Debug Communication Library can process
+ // more write requests.
+ //
+ *Control = mSerialIoMode.ControlMask | EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
+
+ //
+ // Check to see if the Terminal FIFO is empty and
+ // check to see if the input buffer in the Debug Communication Library is empty
+ //
+ if (!IsDebugTermianlFifoEmpty (&mSerialFifoForTerminal) || DebugPortPollBuffer (Handle)) {
+ *Control &= ~EFI_SERIAL_INPUT_BUFFER_EMPTY;
+ }
+
+ //
+ // Restore Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
+
+ //
+ // Restore to original TPL
+ //
+ gBS->RestoreTPL (Tpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write the specified number of bytes to serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of
+ data actually written.
+ @param[in] Buffer The buffer of data to write.
+
+ @retval EFI_SUCCESS The data were written successfully.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The write operation was stopped due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialWrite (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ DEBUG_PORT_HANDLE Handle;
+ BOOLEAN DebugTimerInterruptState;
+ EFI_TPL Tpl;
+
+ //
+ // Raise TPL to prevent recursion from EFI timer interrupts
+ //
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Save and disable Debug Timer interrupt to avoid it to access Debug Port
+ //
+ DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
+ Handle = GetDebugPortHandle ();
+
+ if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) {
+ if (*BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+ if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) != 0) {
+ *BufferSize = 0;
+ return EFI_TIMEOUT;
+ }
+ mLoopbackBuffer = SERIAL_PORT_LOOPBACK_BUFFER_FULL | *(UINT8 *)Buffer;
+ *BufferSize = 1;
+ } else {
+ *BufferSize = DebugPortWriteBuffer (Handle, Buffer, *BufferSize);
+ }
+
+ //
+ // Restore Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
+
+ //
+ // Restore to original TPL
+ //
+ gBS->RestoreTPL (Tpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read the specified number of bytes from serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of
+ data returned in buffer.
+ @param[out] Buffer The buffer to return the data into.
+
+ @retval EFI_SUCCESS The data were read successfully.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The read operation was stopped due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialRead (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT8 *Uint8Buffer;
+ BOOLEAN DebugTimerInterruptState;
+ EFI_TPL Tpl;
+ DEBUG_PORT_HANDLE Handle;
+ DEBUG_PACKET_HEADER DebugHeader;
+ UINT8 *Data8;
+
+ //
+ // Raise TPL to prevent recursion from EFI timer interrupts
+ //
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Save and disable Debug Timer interrupt to avoid it to access Debug Port
+ //
+ DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
+ Handle = GetDebugPortHandle ();
+
+ Data8 = (UINT8 *) &DebugHeader;
+ Uint8Buffer = (UINT8 *)Buffer;
+ if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) {
+ if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) == 0) {
+ return EFI_TIMEOUT;
+ }
+ *Uint8Buffer = (UINT8)(mLoopbackBuffer & 0xff);
+ mLoopbackBuffer = 0;
+ *BufferSize = 1;
+ } else {
+ for (Index = 0; Index < *BufferSize; Index++) {
+ //
+ // Read input character from terminal FIFO firstly
+ //
+ Status = DebugTerminalFifoRemove (&mSerialFifoForTerminal, Data8);
+ if (Status == EFI_SUCCESS) {
+ *Uint8Buffer = *Data8;
+ Uint8Buffer ++;
+ continue;
+ }
+ //
+ // Read the input character from Debug Port
+ //
+ if (!DebugPortPollBuffer (Handle)) {
+ break;
+ }
+ DebugAgentReadBuffer (Handle, Data8, 1, 0);
+
+ if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
+ //
+ // Add the debug symbol into Debug FIFO
+ //
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer attach symbol received %x", *Data8);
+ DebugTerminalFifoAdd (&mSerialFifoForDebug, *Data8);
+ } else if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
+ Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
+ if (Status == EFI_SUCCESS) {
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer break symbol received %x", DebugHeader.Command);
+ DebugTerminalFifoAdd (&mSerialFifoForDebug, DebugHeader.Command);
+ }
+ if (Status == EFI_TIMEOUT) {
+ continue;
+ }
+ } else {
+ *Uint8Buffer = *Data8;
+ Uint8Buffer ++;
+ }
+ }
+ *BufferSize = (UINTN)Uint8Buffer - (UINTN)Buffer;
+ }
+
+ //
+ // Restore Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
+
+ //
+ // Restore to original TPL
+ //
+ gBS->RestoreTPL (Tpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read the Attach/Break-in symbols from the debug port.
+
+ @param[in] Handle Pointer to Debug Port handle.
+ @param[out] BreakSymbol Returned break symbol.
+
+ @retval EFI_SUCCESS Read the symbol in BreakSymbol.
+ @retval EFI_NOT_FOUND No read the break symbol.
+
+**/
+EFI_STATUS
+DebugReadBreakFromDebugPort (
+ IN DEBUG_PORT_HANDLE Handle,
+ OUT UINT8 *BreakSymbol
+ )
+{
+ EFI_STATUS Status;
+ DEBUG_PACKET_HEADER DebugHeader;
+ UINT8 *Data8;
+
+ *BreakSymbol = 0;
+ //
+ // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
+ //
+ Data8 = (UINT8 *) &DebugHeader;
+ while (TRUE) {
+ //
+ // If start symbol is not received
+ //
+ if (!DebugPortPollBuffer (Handle)) {
+ //
+ // If no data in Debug Port, exit
+ //
+ break;
+ }
+ //
+ // Try to read the start symbol
+ //
+ DebugAgentReadBuffer (Handle, Data8, 1, 0);
+ if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *Data8);
+ *BreakSymbol = *Data8;
+ return EFI_SUCCESS;
+ }
+ if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
+ Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
+ if (Status == EFI_SUCCESS) {
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", DebugHeader.Command);
+ *BreakSymbol = DebugHeader.Command;
+ return EFI_SUCCESS;
+ }
+ if (Status == EFI_TIMEOUT) {
+ break;
+ }
+ } else {
+ //
+ // Add to Terminal FIFO
+ //
+ DebugTerminalFifoAdd (&mSerialFifoForTerminal, *Data8);
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Read the Attach/Break-in symbols.
+
+ @param[in] Handle Pointer to Debug Port handle.
+ @param[out] BreakSymbol Returned break symbol.
+
+ @retval EFI_SUCCESS Read the symbol in BreakSymbol.
+ @retval EFI_NOT_FOUND No read the break symbol.
+
+**/
+EFI_STATUS
+DebugReadBreakSymbol (
+ IN DEBUG_PORT_HANDLE Handle,
+ OUT UINT8 *BreakSymbol
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data8;
+
+ //
+ // Read break symbol from debug FIFO firstly
+ //
+ Status = DebugTerminalFifoRemove (&mSerialFifoForDebug, &Data8);
+ if (Status == EFI_SUCCESS) {
+ *BreakSymbol = Data8;
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Read Break symbol from debug port
+ //
+ return DebugReadBreakFromDebugPort (Handle, BreakSymbol);
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
new file mode 100644
index 00000000..562a44f4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
@@ -0,0 +1,96 @@
+## @file
+# Debug Agent library instance for Dxe Core and Dxe modules.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeDebugAgentLib
+ MODULE_UNI_FILE = DxeDebugAgentLib.uni
+ FILE_GUID = BA6BAD25-B814-4747-B0B0-0FBB61D40B90
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 0.8
+ LIBRARY_CLASS = DebugAgentLib|DXE_CORE DXE_DRIVER
+
+ CONSTRUCTOR = DxeDebugAgentLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ DxeDebugAgent/DxeDebugAgentLib.c
+ DxeDebugAgent/DxeDebugAgentLib.h
+ DxeDebugAgent/SerialIo.c
+ DebugAgentCommon/DebugAgent.c
+ DebugAgentCommon/DebugAgent.h
+ DebugAgentCommon/DebugTimer.c
+ DebugAgentCommon/DebugTimer.h
+ DebugAgentCommon/DebugMp.c
+ DebugAgentCommon/DebugMp.h
+
+[Sources.Ia32]
+ DebugAgentCommon/Ia32/AsmFuncs.nasm
+ DebugAgentCommon/Ia32/ArchDebugSupport.h
+ DebugAgentCommon/Ia32/ArchDebugSupport.c
+ DebugAgentCommon/Ia32/DebugException.h
+
+[Sources.X64]
+ DebugAgentCommon/X64/AsmFuncs.nasm
+ DebugAgentCommon/X64/ArchDebugSupport.h
+ DebugAgentCommon/X64/ArchDebugSupport.c
+ DebugAgentCommon/X64/DebugException.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ ResetSystemLib
+ IoLib
+ HobLib
+ DebugCommunicationLib
+ UefiBootServicesTableLib
+ UefiLib
+ PcdLib
+ SynchronizationLib
+ MemoryAllocationLib
+ LocalApicLib
+ TimerLib
+ PrintLib
+ PeCoffGetEntryPointLib
+ PeCoffExtraActionLib
+ MemoryAllocationLib
+
+[Guids]
+ ## PRODUCES ## SystemTable
+ ## CONSUMES ## HOB
+ gEfiDebugAgentGuid
+ ## SOMETIMES_CONSUMES ## SystemTable
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiVectorHandoffTableGuid
+
+[Ppis]
+ gEfiVectorHandoffInfoPpiGuid ## UNDEFINED
+
+[Protocols]
+ gEfiSerialIoProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiDevicePathProtocolGuid ## SOMETIMES_PRODUCES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdFSBClock ## SOMETIMES_CONSUMES
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdExceptionsIgnoredByDebugger ## SOMETIMES_CONSUMES
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize ## CONSUMES
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdTransferProtocolRevision ## CONSUMES
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.uni
new file mode 100644
index 00000000..fef8dafd
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Debug Agent library instance for Dxe Core and Dxe modules.
+//
+// Debug Agent library instance for DXE Core and DXE modules.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Debug Agent library instance for DXE Core and DXE modules"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Debug Agent library instance for DXE Core and DXE modules."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c
new file mode 100644
index 00000000..11e94b29
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c
@@ -0,0 +1,704 @@
+/** @file
+ SEC Core Debug Agent Library instance implementation.
+
+ Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SecPeiDebugAgentLib.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSkipBreakpoint = FALSE;
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_VECTOR_HANDOFF_INFO_PPI mVectorHandoffInfoPpi = {
+ &mVectorHandoffInfoDebugAgent[0]
+};
+
+//
+// Ppis to be installed
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mVectorHandoffInfoPpiList[] = {
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiVectorHandoffInfoPpiGuid,
+ &mVectorHandoffInfoPpi
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mDebugAgentMemoryDiscoveredNotifyList[1] = {
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ DebugAgentCallbackMemoryDiscoveredPpi
+ }
+};
+
+/**
+ Check if debug agent support multi-processor.
+
+ @retval TRUE Multi-processor is supported.
+ @retval FALSE Multi-processor is not supported.
+
+**/
+BOOLEAN
+MultiProcessorDebugSupport (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ Read the Attach/Break-in symbols from the debug port.
+
+ @param[in] Handle Pointer to Debug Port handle.
+ @param[out] BreakSymbol Returned break symbol.
+
+ @retval EFI_SUCCESS Read the symbol in BreakSymbol.
+ @retval EFI_NOT_FOUND No read the break symbol.
+
+**/
+EFI_STATUS
+DebugReadBreakSymbol (
+ IN DEBUG_PORT_HANDLE Handle,
+ OUT UINT8 *BreakSymbol
+ )
+{
+ EFI_STATUS Status;
+ DEBUG_PACKET_HEADER DebugHeader;
+ UINT8 *Data8;
+
+ *BreakSymbol = 0;
+ //
+ // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
+ //
+ Data8 = (UINT8 *) &DebugHeader;
+ while (TRUE) {
+ //
+ // If start symbol is not received
+ //
+ if (!DebugPortPollBuffer (Handle)) {
+ //
+ // If no data in Debug Port, exit
+ //
+ break;
+ }
+ //
+ // Try to read the start symbol
+ //
+ DebugAgentReadBuffer (Handle, Data8, 1, 0);
+ if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
+ *BreakSymbol = *Data8;
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *BreakSymbol);
+ return EFI_SUCCESS;
+ }
+ if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
+ Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
+ if (Status == EFI_SUCCESS) {
+ *BreakSymbol = DebugHeader.Command;
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", *BreakSymbol);
+ return EFI_SUCCESS;
+ }
+ if (Status == EFI_TIMEOUT) {
+ break;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get the pointer to location saved Mailbox pointer from IDT entry.
+
+**/
+VOID *
+GetLocationSavedMailboxPointerInIdtEntry (
+ VOID
+ )
+{
+ UINTN *MailboxLocation;
+
+ MailboxLocation = (UINTN *) GetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR);
+ //
+ // *MailboxLocation is the pointer to Mailbox
+ //
+ VerifyMailboxChecksum ((DEBUG_AGENT_MAILBOX *) (*MailboxLocation));
+ return MailboxLocation;
+}
+
+/**
+ Set the pointer of Mailbox into IDT entry before memory is ready.
+
+ @param[in] MailboxLocation Pointer to location saved Mailbox pointer.
+
+**/
+VOID
+SetLocationSavedMailboxPointerInIdtEntry (
+ IN VOID *MailboxLocation
+ )
+{
+ SetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR, MailboxLocation);
+}
+
+/**
+ Get the location of Mailbox pointer from the GUIDed HOB.
+
+ @return Pointer to the location saved Mailbox pointer.
+
+**/
+UINT64 *
+GetMailboxLocationFromHob (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid);
+ if (GuidHob == NULL) {
+ return NULL;
+ }
+ return (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
+}
+
+/**
+ Get Debug Agent Mailbox pointer.
+
+ @return Mailbox pointer.
+
+**/
+DEBUG_AGENT_MAILBOX *
+GetMailboxPointer (
+ VOID
+ )
+{
+ UINT64 DebugPortHandle;
+ UINT64 *MailboxLocationInIdt;
+ UINT64 *MailboxLocationInHob;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+
+ //
+ // Get mailbox from IDT entry firstly
+ //
+ MailboxLocationInIdt = GetLocationSavedMailboxPointerInIdtEntry ();
+ Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInIdt);
+ //
+ // Cannot used GetDebugFlag() to get Debug Flag to avoid GetMailboxPointer() nested
+ //
+ if (Mailbox->DebugFlag.Bits.CheckMailboxInHob != 1 ||
+ Mailbox->DebugFlag.Bits.InitArch != DEBUG_ARCH_SYMBOL) {
+ //
+ // If mailbox was setup in SEC or the current CPU arch is different from the init arch
+ // Debug Agent initialized, return the mailbox from IDT entry directly.
+ // Otherwise, we need to check the mailbox location saved in GUIDed HOB further.
+ //
+ return Mailbox;
+ }
+
+ MailboxLocationInHob = GetMailboxLocationFromHob ();
+ //
+ // Compare mailbox in IDT entry with mailbox in HOB,
+ // need to fix mailbox location if HOB moved by PEI CORE
+ //
+ if (MailboxLocationInHob != MailboxLocationInIdt && MailboxLocationInHob != NULL) {
+ Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInHob);
+ //
+ // Fix up Debug Port handler and save new mailbox in IDT entry
+ //
+ Mailbox = (DEBUG_AGENT_MAILBOX *)((UINTN)Mailbox + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt));
+ DebugPortHandle = (UINTN)Mailbox->DebugPortHandle + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
+ *MailboxLocationInHob = (UINT64)(UINTN)Mailbox;
+ SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
+ //
+ // Clean CheckMailboxInHob flag
+ //
+ Mailbox->DebugFlag.Bits.CheckMailboxInHob = 0;
+ UpdateMailboxChecksum (Mailbox);
+ }
+
+ return Mailbox;
+}
+
+/**
+ Get debug port handle.
+
+ @return Debug port handle.
+
+**/
+DEBUG_PORT_HANDLE
+GetDebugPortHandle (
+ VOID
+ )
+{
+ DEBUG_AGENT_MAILBOX *DebugAgentMailbox;
+
+ DebugAgentMailbox = GetMailboxPointer ();
+
+ return (DEBUG_PORT_HANDLE) (UINTN)(DebugAgentMailbox->DebugPortHandle);
+}
+
+/**
+ Debug Agent provided notify callback function on Memory Discovered PPI.
+
+ @param[in] PeiServices Indirect reference to the PEI Services Table.
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS If the function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugAgentCallbackMemoryDiscoveredPpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_STATUS Status;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ BOOLEAN InterruptStatus;
+ EFI_PHYSICAL_ADDRESS Address;
+ DEBUG_AGENT_MAILBOX *NewMailbox;
+ UINT64 *MailboxLocationInHob;
+
+ //
+ // Save and disable original interrupt status
+ //
+ InterruptStatus = SaveAndDisableInterrupts ();
+
+ //
+ // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer
+ //
+ Status = PeiServicesAllocatePages (
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
+ &Address
+ );
+ ASSERT_EFI_ERROR (Status);
+ NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;
+ //
+ // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
+ // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core
+ // reallocates the HOB.
+ //
+ Mailbox = GetMailboxPointer ();
+ CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
+ CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
+ //
+ // Update Mailbox Location pointer in GUIDed HOB and IDT entry with new one
+ //
+ MailboxLocationInHob = GetMailboxLocationFromHob ();
+ ASSERT (MailboxLocationInHob != NULL);
+ *MailboxLocationInHob = (UINT64)(UINTN)NewMailbox;
+ SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
+ //
+ // Update Debug Port Handle in new Mailbox
+ //
+ UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
+ //
+ // Set physical memory ready flag
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
+
+ if (IsHostAttached ()) {
+ //
+ // Trigger one software interrupt to inform HOST
+ //
+ TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
+ }
+
+ //
+ // Restore interrupt state.
+ //
+ SetInterruptState (InterruptStatus);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize debug agent.
+
+ This function is used to set up debug environment for SEC and PEI phase.
+
+ If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will override IDT table entries
+ and initialize debug port. It will enable interrupt to support break-in feature.
+ It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
+ physical memory is ready.
+ If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
+ HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
+
+ This function is used to set up debug environment to support source level debugging.
+ If certain Debug Agent Library instance has to save some private data in the stack,
+ this function must work on the mode that doesn't return to the caller, then
+ the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
+ function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
+ responsible to invoke the passing-in function at the end of InitializeDebugAgent().
+
+ If the parameter Function is not NULL, Debug Agent Library instance will invoke it by
+ passing in the Context to be its parameter.
+
+ If Function() is NULL, Debug Agent Library instance will return after setup debug
+ environment.
+
+ @param[in] InitFlag Init flag is used to decide the initialize process.
+ @param[in] Context Context needed according to InitFlag; it was optional.
+ @param[in] Function Continue function called by debug agent library; it was
+ optional.
+
+**/
+VOID
+EFIAPI
+InitializeDebugAgent (
+ IN UINT32 InitFlag,
+ IN VOID *Context, OPTIONAL
+ IN DEBUG_AGENT_CONTINUE Function OPTIONAL
+ )
+{
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ DEBUG_AGENT_MAILBOX *NewMailbox;
+ DEBUG_AGENT_MAILBOX MailboxInStack;
+ DEBUG_AGENT_PHASE2_CONTEXT Phase2Context;
+ DEBUG_AGENT_CONTEXT_POSTMEM_SEC *DebugAgentContext;
+ EFI_STATUS Status;
+ IA32_DESCRIPTOR *Ia32Idtr;
+ IA32_IDT_ENTRY *Ia32IdtEntry;
+ UINT64 DebugPortHandle;
+ UINT64 MailboxLocation;
+ UINT64 *MailboxLocationPointer;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT32 DebugTimerFrequency;
+ BOOLEAN CpuInterruptState;
+
+ //
+ // Disable interrupts and save current interrupt state
+ //
+ CpuInterruptState = SaveAndDisableInterrupts();
+
+ switch (InitFlag) {
+
+ case DEBUG_AGENT_INIT_PREMEM_SEC:
+
+ InitializeDebugIdt ();
+
+ MailboxLocation = (UINT64)(UINTN)&MailboxInStack;
+ Mailbox = &MailboxInStack;
+ ZeroMem ((VOID *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
+ //
+ // Get and save debug port handle and set the length of memory block.
+ //
+ SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation);
+ //
+ // Force error message could be printed during the first shakehand between Target/HOST.
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DEBUG_AGENT_ERROR);
+ //
+ // Save init arch type when debug agent initialized
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL);
+ //
+ // Initialize Debug Timer hardware and save its frequency
+ //
+ InitializeDebugTimer (&DebugTimerFrequency, TRUE);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
+
+ Phase2Context.InitFlag = InitFlag;
+ Phase2Context.Context = Context;
+ Phase2Context.Function = Function;
+ DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
+ //
+ // If reaches here, it means Debug Port initialization failed.
+ //
+ DEBUG ((EFI_D_ERROR, "Debug Agent: Debug port initialization failed.\n"));
+
+ break;
+
+ case DEBUG_AGENT_INIT_POSTMEM_SEC:
+ Mailbox = GetMailboxPointer ();
+ //
+ // Memory has been ready
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
+ if (IsHostAttached ()) {
+ //
+ // Trigger one software interrupt to inform HOST
+ //
+ TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
+ }
+ //
+ // Install Vector Handoff Info PPI to persist vectors used by Debug Agent
+ //
+ Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n"));
+ CpuDeadLoop ();
+ }
+ //
+ // Fix up Debug Port handle address and mailbox address
+ //
+ DebugAgentContext = (DEBUG_AGENT_CONTEXT_POSTMEM_SEC *) Context;
+ if (DebugAgentContext != NULL) {
+ DebugPortHandle = (UINT64)(UINT32)(Mailbox->DebugPortHandle + DebugAgentContext->StackMigrateOffset);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
+ Mailbox = (DEBUG_AGENT_MAILBOX *) ((UINTN) Mailbox + DebugAgentContext->StackMigrateOffset);
+ MailboxLocation = (UINT64)(UINTN)Mailbox;
+ //
+ // Build mailbox location in HOB and fix-up its address
+ //
+ MailboxLocationPointer = BuildGuidDataHob (
+ &gEfiDebugAgentGuid,
+ &MailboxLocation,
+ sizeof (UINT64)
+ );
+ MailboxLocationPointer = (UINT64 *) ((UINTN) MailboxLocationPointer + DebugAgentContext->HeapMigrateOffset);
+ } else {
+ //
+ // DebugAgentContext is NULL. Then, Mailbox can directly be copied into memory.
+ // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer
+ //
+ Status = PeiServicesAllocatePages (
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to allocate pages!\n"));
+ CpuDeadLoop ();
+ }
+ NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;
+ //
+ // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
+ // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core
+ // reallocates the HOB.
+ //
+ CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
+ CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
+ UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
+ MailboxLocation = (UINT64)(UINTN)NewMailbox;
+ //
+ // Build mailbox location in HOB
+ //
+ MailboxLocationPointer = BuildGuidDataHob (
+ &gEfiDebugAgentGuid,
+ &MailboxLocation,
+ sizeof (UINT64)
+ );
+ }
+ //
+ // Update IDT entry to save the location saved mailbox pointer
+ //
+ SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
+ break;
+
+ case DEBUG_AGENT_INIT_PEI:
+ if (Context == NULL) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
+ CpuDeadLoop ();
+ }
+ //
+ // Check if Debug Agent has initialized before
+ //
+ if (IsDebugAgentInitialzed()) {
+ DEBUG ((EFI_D_WARN, "Debug Agent: It has already initialized in SEC Core!\n"));
+ break;
+ }
+ //
+ // Install Vector Handoff Info PPI to persist vectors used by Debug Agent
+ //
+ Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n"));
+ CpuDeadLoop ();
+ }
+ //
+ // Set up IDT entries
+ //
+ InitializeDebugIdt ();
+ //
+ // Build mailbox in HOB and setup Mailbox Set In Pei flag
+ //
+ Mailbox = AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX));
+ if (Mailbox == NULL) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to allocate memory!\n"));
+ CpuDeadLoop ();
+ } else {
+ MailboxLocation = (UINT64)(UINTN)Mailbox;
+ MailboxLocationPointer = BuildGuidDataHob (
+ &gEfiDebugAgentGuid,
+ &MailboxLocation,
+ sizeof (UINT64)
+ );
+ //
+ // Initialize Debug Timer hardware and save its frequency
+ //
+ InitializeDebugTimer (&DebugTimerFrequency, TRUE);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
+ //
+ // Update IDT entry to save the location pointer saved mailbox pointer
+ //
+ SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
+ }
+ //
+ // Save init arch type when debug agent initialized
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL);
+ //
+ // Register for a callback once memory has been initialized.
+ // If memory has been ready, the callback function will be invoked immediately
+ //
+ Status = PeiServicesNotifyPpi (&mDebugAgentMemoryDiscoveredNotifyList[0]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to register memory discovered callback function!\n"));
+ CpuDeadLoop ();
+ }
+ //
+ // Set HOB check flag if memory has not been ready yet
+ //
+ if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY) == 0) {
+ SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB, 1);
+ }
+
+ Phase2Context.InitFlag = InitFlag;
+ Phase2Context.Context = Context;
+ Phase2Context.Function = Function;
+ DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
+
+ FindAndReportModuleImageInfo (4);
+
+ break;
+
+ case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
+ if (Context == NULL) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
+ CpuDeadLoop ();
+ } else {
+ Ia32Idtr = (IA32_DESCRIPTOR *) Context;
+ Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
+ MailboxLocationPointer = (UINT64 *) ((UINTN) Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
+ ((UINTN) Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
+ Mailbox = (DEBUG_AGENT_MAILBOX *) (UINTN)(*MailboxLocationPointer);
+ //
+ // Mailbox should valid and setup before executing thunk code
+ //
+ VerifyMailboxChecksum (Mailbox);
+
+ DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)Mailbox->DebugPortHandle, NULL);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
+ //
+ // Set up IDT entries
+ //
+ InitializeDebugIdt ();
+ //
+ // Update IDT entry to save location pointer saved the mailbox pointer
+ //
+ SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
+
+ FindAndReportModuleImageInfo (4);
+ }
+ break;
+
+ default:
+ //
+ // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
+ // Debug Agent library instance.
+ //
+ DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
+ CpuDeadLoop ();
+ break;
+ }
+
+ if (InitFlag == DEBUG_AGENT_INIT_POSTMEM_SEC) {
+ //
+ // Restore CPU Interrupt state and keep debug timer interrupt state as is
+ // in DEBUG_AGENT_INIT_POSTMEM_SEC case
+ //
+ SetInterruptState (CpuInterruptState);
+ } else {
+ //
+ // Enable Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (TRUE);
+ //
+ // Enable CPU interrupts so debug timer interrupts can be delivered
+ //
+ EnableInterrupts ();
+ }
+ //
+ // If Function is not NULL, invoke it always whatever debug agent was initialized successfully or not.
+ //
+ if (Function != NULL) {
+ Function (Context);
+ }
+ //
+ // Set return status for DEBUG_AGENT_INIT_PEI
+ //
+ if (InitFlag == DEBUG_AGENT_INIT_PEI && Context != NULL) {
+ *(EFI_STATUS *)Context = EFI_SUCCESS;
+ }
+}
+
+/**
+ Caller provided function to be invoked at the end of DebugPortInitialize().
+
+ Refer to the description for DebugPortInitialize() for more details.
+
+ @param[in] Context The first input argument of DebugPortInitialize().
+ @param[in] DebugPortHandle Debug port handle created by Debug Communication Library.
+
+**/
+VOID
+EFIAPI
+InitializeDebugAgentPhase2 (
+ IN VOID *Context,
+ IN DEBUG_PORT_HANDLE DebugPortHandle
+ )
+{
+ DEBUG_AGENT_PHASE2_CONTEXT *Phase2Context;
+ UINT64 *MailboxLocation;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ EFI_SEC_PEI_HAND_OFF *SecCoreData;
+ UINT16 BufferSize;
+ UINT64 NewDebugPortHandle;
+
+ Phase2Context = (DEBUG_AGENT_PHASE2_CONTEXT *) Context;
+ MailboxLocation = GetLocationSavedMailboxPointerInIdtEntry ();
+ Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
+ BufferSize = PcdGet16(PcdDebugPortHandleBufferSize);
+ if (Phase2Context->InitFlag == DEBUG_AGENT_INIT_PEI && BufferSize != 0) {
+ NewDebugPortHandle = (UINT64)(UINTN)AllocateCopyPool (BufferSize, DebugPortHandle);
+ } else {
+ NewDebugPortHandle = (UINT64)(UINTN)DebugPortHandle;
+ }
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, NewDebugPortHandle);
+
+ //
+ // Trigger one software interrupt to inform HOST
+ //
+ TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
+
+ if (Phase2Context->InitFlag == DEBUG_AGENT_INIT_PREMEM_SEC) {
+ //
+ // If Temporary RAM region is below 128 MB, then send message to
+ // host to disable low memory filtering.
+ //
+ SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Phase2Context->Context;
+ if ((UINTN)SecCoreData->TemporaryRamBase < BASE_128MB && IsHostAttached ()) {
+ SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
+ TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
+ }
+ //
+ // Enable Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (TRUE);
+ //
+ // Enable CPU interrupts so debug timer interrupts can be delivered
+ //
+ EnableInterrupts ();
+ //
+ // Call continuation function if it is not NULL.
+ //
+ Phase2Context->Function (Phase2Context->Context);
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.h
new file mode 100644
index 00000000..e614b90f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.h
@@ -0,0 +1,59 @@
+/** @file
+ Header file for Sec Core Debug Agent Library instance.
+
+ Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SEC_CORE_DEBUG_AGENT_LIB_H_
+#define _SEC_CORE_DEBUG_AGENT_LIB_H_
+
+#include <PiPei.h>
+#include <Ppi/MemoryDiscovered.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include "DebugAgent.h"
+
+typedef struct {
+ UINT32 InitFlag;
+ VOID *Context;
+ DEBUG_AGENT_CONTINUE Function;
+} DEBUG_AGENT_PHASE2_CONTEXT;
+
+/**
+ Caller provided function to be invoked at the end of DebugPortInitialize().
+
+ Refer to the description for DebugPortInitialize() for more details.
+
+ @param[in] Context The first input argument of DebugPortInitialize().
+ @param[in] DebugPortHandle Debug port handle created by Debug Communication Library.
+
+**/
+VOID
+EFIAPI
+InitializeDebugAgentPhase2 (
+ IN VOID *Context,
+ IN DEBUG_PORT_HANDLE DebugPortHandle
+ );
+
+/**
+ Debug Agent provided notify callback function on Memory Discovered PPI.
+
+ @param[in] PeiServices Indirect reference to the PEI Services Table.
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS If the function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugAgentCallbackMemoryDiscoveredPpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf
new file mode 100644
index 00000000..423e2763
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf
@@ -0,0 +1,86 @@
+## @file
+# Debug Agent library instance for SEC Core and PEI modules.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SecPeiDebugAgentLib
+ MODULE_UNI_FILE = SecPeiDebugAgentLib.uni
+ FILE_GUID = 508B7D59-CD4E-4a6b-A45B-6D3B2D90111E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 0.8
+ LIBRARY_CLASS = DebugAgentLib|SEC PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ SecPeiDebugAgent/SecPeiDebugAgentLib.c
+ SecPeiDebugAgent/SecPeiDebugAgentLib.h
+ DebugAgentCommon/DebugAgent.c
+ DebugAgentCommon/DebugAgent.h
+ DebugAgentCommon/DebugTimer.c
+ DebugAgentCommon/DebugTimer.h
+ DebugAgentCommon/DebugMp.c
+ DebugAgentCommon/DebugMp.h
+
+[Sources.Ia32]
+ DebugAgentCommon/Ia32/AsmFuncs.nasm
+ DebugAgentCommon/Ia32/ArchDebugSupport.h
+ DebugAgentCommon/Ia32/ArchDebugSupport.c
+ DebugAgentCommon/Ia32/DebugException.h
+
+[Sources.X64]
+ DebugAgentCommon/X64/AsmFuncs.nasm
+ DebugAgentCommon/X64/ArchDebugSupport.h
+ DebugAgentCommon/X64/ArchDebugSupport.c
+ DebugAgentCommon/X64/DebugException.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ ResetSystemLib
+ IoLib
+ HobLib
+ PcdLib
+ DebugCommunicationLib
+ SynchronizationLib
+ LocalApicLib
+ DebugLib
+ TimerLib
+ PrintLib
+ PeiServicesLib
+ MemoryAllocationLib
+ PeCoffGetEntryPointLib
+ PeCoffExtraActionLib
+
+[Ppis]
+ gEfiPeiMemoryDiscoveredPpiGuid ## NOTIFY
+ gEfiVectorHandoffInfoPpiGuid ## PRODUCES
+
+[Guids]
+ ## PRODUCES ## HOB
+ ## CONSUMES ## HOB
+ gEfiDebugAgentGuid
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdFSBClock ## SOMETIMES_CONSUMES
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdExceptionsIgnoredByDebugger ## SOMETIMES_CONSUMES
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize ## SOMETIMES_CONSUMES
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdTransferProtocolRevision ## CONSUMES
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.uni
new file mode 100644
index 00000000..bc56e3cb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Debug Agent library instance for SEC Core and PEI modules.
+//
+// Debug Agent library instance for SEC Core and PEI modules.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Debug Agent library instance for SEC Core and PEI modules"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Debug Agent library instance for SEC Core and PEI modules."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c
new file mode 100644
index 00000000..9cac45ab
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c
@@ -0,0 +1,386 @@
+/** @file
+ Debug Agent library implementation.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SmmDebugAgentLib.h"
+
+DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL;
+DEBUG_AGENT_MAILBOX mLocalMailbox;
+UINTN mSavedDebugRegisters[6];
+IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33];
+BOOLEAN mSkipBreakpoint = FALSE;
+BOOLEAN mSmmDebugIdtInitFlag = FALSE;
+BOOLEAN mApicTimerRestore = FALSE;
+BOOLEAN mPeriodicMode;
+UINT32 mTimerCycle;
+UINTN mApicTimerDivisor;
+UINT8 mVector;
+
+CHAR8 mWarningMsgIgnoreSmmEntryBreak[] = "Ignore smmentrybreak setting for SMI issued during DXE debugging!\r\n";
+
+/**
+ Check if debug agent support multi-processor.
+
+ @retval TRUE Multi-processor is supported.
+ @retval FALSE Multi-processor is not supported.
+
+**/
+BOOLEAN
+MultiProcessorDebugSupport (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ Read the Attach/Break-in symbols from the debug port.
+
+ @param[in] Handle Pointer to Debug Port handle.
+ @param[out] BreakSymbol Returned break symbol.
+
+ @retval EFI_SUCCESS Read the symbol in BreakSymbol.
+ @retval EFI_NOT_FOUND No read the break symbol.
+
+**/
+EFI_STATUS
+DebugReadBreakSymbol (
+ IN DEBUG_PORT_HANDLE Handle,
+ OUT UINT8 *BreakSymbol
+ )
+{
+ //
+ // Smm instance has no debug timer to poll break symbol.
+ //
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get the pointer to Mailbox from the GUIDed HOB.
+
+ @return Pointer to Mailbox.
+
+**/
+DEBUG_AGENT_MAILBOX *
+GetMailboxFromHob (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINT64 *MailboxLocation;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+
+ GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid);
+ if (GuidHob == NULL) {
+ return NULL;
+ }
+ MailboxLocation = (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
+ Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
+ VerifyMailboxChecksum (Mailbox);
+
+ return Mailbox;
+}
+
+/**
+ Get Debug Agent Mailbox pointer.
+
+ @return Mailbox pointer.
+
+**/
+DEBUG_AGENT_MAILBOX *
+GetMailboxPointer (
+ VOID
+ )
+{
+ VerifyMailboxChecksum (mMailboxPointer);
+ return mMailboxPointer;
+}
+
+/**
+ Get debug port handle.
+
+ @return Debug port handle.
+
+**/
+DEBUG_PORT_HANDLE
+GetDebugPortHandle (
+ VOID
+ )
+{
+ return (DEBUG_PORT_HANDLE) (UINTN)(GetMailboxPointer()->DebugPortHandle);
+}
+
+/**
+ Store debug register when SMI exit.
+
+**/
+VOID
+SaveDebugRegister (
+ VOID
+ )
+{
+ mSavedDebugRegisters[0] = AsmReadDr0 ();
+ mSavedDebugRegisters[1] = AsmReadDr1 ();
+ mSavedDebugRegisters[2] = AsmReadDr2 ();
+ mSavedDebugRegisters[3] = AsmReadDr3 ();
+ mSavedDebugRegisters[4] = AsmReadDr6 ();
+ mSavedDebugRegisters[5] = AsmReadDr7 ();
+}
+
+/**
+ Restore debug register when SMI exit.
+
+**/
+VOID
+RestoreDebugRegister (
+ VOID
+ )
+{
+ AsmWriteDr7 (0);
+ AsmWriteDr0 (mSavedDebugRegisters[0]);
+ AsmWriteDr1 (mSavedDebugRegisters[1]);
+ AsmWriteDr2 (mSavedDebugRegisters[2]);
+ AsmWriteDr3 (mSavedDebugRegisters[3]);
+ AsmWriteDr6 (mSavedDebugRegisters[4]);
+ AsmWriteDr7 (mSavedDebugRegisters[5]);
+}
+
+/**
+ Initialize debug agent.
+
+ This function is used to set up debug environment for source level debug
+ in SMM code.
+
+ If InitFlag is DEBUG_AGENT_INIT_SMM, it will override IDT table entries
+ and initialize debug port. It will get debug agent Mailbox from GUIDed HOB,
+ it it exists, debug agent wiil copied it into the local Mailbox in SMM space.
+ it will override IDT table entries and initialize debug port. Context will be
+ NULL.
+ If InitFlag is DEBUG_AGENT_INIT_ENTER_SMI, debug agent will save Debug
+ Registers and get local Mailbox in SMM space. Context will be NULL.
+ If InitFlag is DEBUG_AGENT_INIT_EXIT_SMI, debug agent will restore Debug
+ Registers. Context will be NULL.
+
+ @param[in] InitFlag Init flag is used to decide initialize process.
+ @param[in] Context Context needed according to InitFlag.
+ @param[in] Function Continue function called by debug agent library; it was
+ optional.
+
+**/
+VOID
+EFIAPI
+InitializeDebugAgent (
+ IN UINT32 InitFlag,
+ IN VOID *Context, OPTIONAL
+ IN DEBUG_AGENT_CONTINUE Function OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINT64 DebugPortHandle;
+ IA32_IDT_GATE_DESCRIPTOR IdtEntry[33];
+ IA32_DESCRIPTOR IdtDescriptor;
+ IA32_DESCRIPTOR *Ia32Idtr;
+ IA32_IDT_ENTRY *Ia32IdtEntry;
+ IA32_DESCRIPTOR Idtr;
+ UINT16 IdtEntryCount;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ UINT64 *MailboxLocation;
+ UINT32 DebugTimerFrequency;
+
+ switch (InitFlag) {
+ case DEBUG_AGENT_INIT_SMM:
+ //
+ // Install configuration table for persisted vector handoff info
+ //
+ Status = gSmst->SmmInstallConfigurationTable (
+ gSmst,
+ &gEfiVectorHandoffTableGuid,
+ (VOID *) &mVectorHandoffInfoDebugAgent[0],
+ sizeof (EFI_VECTOR_HANDOFF_INFO) * mVectorHandoffInfoCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
+ CpuDeadLoop ();
+ }
+ //
+ // Check if Debug Agent initialized in DXE phase
+ //
+ Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox);
+ if (Status == EFI_SUCCESS && Mailbox != NULL) {
+ VerifyMailboxChecksum (Mailbox);
+ mMailboxPointer = Mailbox;
+ break;
+ }
+ //
+ // Check if Debug Agent initialized in SEC/PEI phase
+ //
+ Mailbox = GetMailboxFromHob ();
+ if (Mailbox != NULL) {
+ mMailboxPointer = Mailbox;
+ break;
+ }
+ //
+ // Debug Agent was not initialized before, use the local mailbox.
+ //
+ ZeroMem (&mLocalMailbox, sizeof (DEBUG_AGENT_MAILBOX));
+ Mailbox = &mLocalMailbox;
+ //
+ // Save original IDT entries
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ CopyMem (&IdtEntry, (VOID *)IdtDescriptor.Base, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR));
+ //
+ // Initialized Debug Agent
+ //
+ InitializeDebugIdt ();
+ //
+ // Initialize Debug Timer hardware and save its frequency
+ //
+ InitializeDebugTimer (&DebugTimerFrequency, TRUE);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
+
+ DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, NULL);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
+ mMailboxPointer = Mailbox;
+ //
+ // Trigger one software interrupt to inform HOST
+ //
+ TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
+
+ SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
+ //
+ // Memory has been ready
+ //
+ if (IsHostAttached ()) {
+ //
+ // Trigger one software interrupt to inform HOST
+ //
+ TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
+ }
+ //
+ // Find and report PE/COFF image info to HOST
+ //
+ FindAndReportModuleImageInfo (SIZE_4KB);
+ //
+ // Restore saved IDT entries
+ //
+ CopyMem ((VOID *)IdtDescriptor.Base, &IdtEntry, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR));
+
+ break;
+
+ case DEBUG_AGENT_INIT_ENTER_SMI:
+ SaveDebugRegister ();
+ if (!mSmmDebugIdtInitFlag) {
+ //
+ // We only need to initialize Debug IDT table at first SMI entry
+ // after SMM relocation.
+ //
+ InitializeDebugIdt ();
+ mSmmDebugIdtInitFlag = TRUE;
+ }
+ //
+ // Check if CPU APIC Timer is working, otherwise initialize it.
+ //
+ InitializeLocalApicSoftwareEnable (TRUE);
+ GetApicTimerState (&mApicTimerDivisor, &mPeriodicMode, &mVector);
+ mTimerCycle = GetApicTimerInitCount ();
+ if (!mPeriodicMode || mTimerCycle == 0) {
+ mApicTimerRestore = TRUE;
+ InitializeDebugTimer (NULL, FALSE);
+ }
+ Mailbox = GetMailboxPointer ();
+ if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) {
+ //
+ // If Debug Agent has been communication state with HOST, we need skip
+ // any break points set in SMM, set Skip Breakpoint flag
+ //
+ mSkipBreakpoint = TRUE;
+ }
+ if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI) == 1) {
+ if (mSkipBreakpoint) {
+ //
+ // Print warning message if ignore smm entry break
+ //
+ DebugPortWriteBuffer ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle,
+ (UINT8 *)mWarningMsgIgnoreSmmEntryBreak,
+ AsciiStrLen (mWarningMsgIgnoreSmmEntryBreak)
+ );
+ } else {
+ //
+ // If SMM entry break is set, SMM code will be break at here.
+ //
+ CpuBreakpoint ();
+ }
+ }
+ break;
+
+ case DEBUG_AGENT_INIT_EXIT_SMI:
+ Mailbox = GetMailboxPointer ();
+ //
+ // Clear Skip Breakpoint flag
+ //
+ mSkipBreakpoint = FALSE;
+ RestoreDebugRegister ();
+ //
+ // Restore APIC Timer
+ //
+ if (mApicTimerRestore) {
+ InitializeApicTimer (mApicTimerDivisor, mTimerCycle, mPeriodicMode, mVector);
+ mApicTimerRestore = FALSE;
+ }
+ break;
+
+ case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
+ if (Context == NULL) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
+ CpuDeadLoop ();
+ } else {
+ Ia32Idtr = (IA32_DESCRIPTOR *) Context;
+ Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
+ MailboxLocation = (UINT64 *) ((UINTN) Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
+ ((UINTN) Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
+ mMailboxPointer = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
+ VerifyMailboxChecksum (mMailboxPointer);
+ //
+ // Get original IDT address and size.
+ //
+ AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr);
+ IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
+ if (IdtEntryCount < 33) {
+ Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
+ Idtr.Base = (UINTN) &mIdtEntryTable;
+ ZeroMem (&mIdtEntryTable, Idtr.Limit + 1);
+ AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr);
+ }
+
+ InitializeDebugIdt ();
+ //
+ // Initialize Debug Timer hardware and save its frequency
+ //
+ InitializeDebugTimer (&DebugTimerFrequency, TRUE);
+ UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
+ //
+ // Enable Debug Timer interrupt and CPU interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (TRUE);
+ EnableInterrupts ();
+
+ FindAndReportModuleImageInfo (SIZE_4KB);
+ }
+ break;
+
+ default:
+ //
+ // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
+ // Debug Agent library instance.
+ //
+ DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
+ CpuDeadLoop ();
+ break;
+ }
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.h
new file mode 100644
index 00000000..00a8a37b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.h
@@ -0,0 +1,19 @@
+/** @file
+ Header file for Smm Debug Agent Library instance.
+
+ Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_DEBUG_AGENT_LIB_H_
+#define _SMM_DEBUG_AGENT_LIB_H_
+
+#include <PiDxe.h>
+
+#include <Library/UefiLib.h>
+#include <Library/SmmServicesTableLib.h>
+
+#include "DebugAgent.h"
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf
new file mode 100644
index 00000000..436862ea
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf
@@ -0,0 +1,81 @@
+## @file
+# Debug Agent library instance for SMM modules.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmDebugAgentLib
+ MODULE_UNI_FILE = SmmDebugAgentLib.uni
+ FILE_GUID = CB07D74C-598F-4268-A5D1-644FB4A481E8
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 0.8
+ LIBRARY_CLASS = DebugAgentLib|DXE_SMM_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ SmmDebugAgent/SmmDebugAgentLib.c
+ SmmDebugAgent/SmmDebugAgentLib.h
+ DebugAgentCommon/DebugAgent.c
+ DebugAgentCommon/DebugAgent.h
+ DebugAgentCommon/DebugTimer.c
+ DebugAgentCommon/DebugTimer.h
+ DebugAgentCommon/DebugMp.c
+ DebugAgentCommon/DebugMp.h
+
+[Sources.Ia32]
+ DebugAgentCommon/Ia32/AsmFuncs.nasm
+ DebugAgentCommon/Ia32/ArchDebugSupport.h
+ DebugAgentCommon/Ia32/ArchDebugSupport.c
+ DebugAgentCommon/Ia32/DebugException.h
+
+[Sources.X64]
+ DebugAgentCommon/X64/AsmFuncs.nasm
+ DebugAgentCommon/X64/ArchDebugSupport.h
+ DebugAgentCommon/X64/ArchDebugSupport.c
+ DebugAgentCommon/X64/DebugException.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ ResetSystemLib
+ IoLib
+ DebugCommunicationLib
+ UefiLib
+ PcdLib
+ SynchronizationLib
+ LocalApicLib
+ TimerLib
+ PrintLib
+ PeCoffExtraActionLib
+ PeCoffGetEntryPointLib
+ SmmServicesTableLib
+
+[Guids]
+ ## CONSUMES ## SystemTable
+ ## CONSUMES ## HOB
+ gEfiDebugAgentGuid
+ gEfiVectorHandoffTableGuid ## PRODUCES ## GUID # SMM Configuration Table
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdFSBClock ## SOMETIMES_CONSUMES
+ # Skip Page Fault exception (14) by default in SMM
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdExceptionsIgnoredByDebugger|0x00004000 ## SOMETIMES_CONSUMES
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdTransferProtocolRevision ## CONSUMES
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.uni
new file mode 100644
index 00000000..74770a30
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Debug Agent library instance for SMM modules.
+//
+// Debug Agent library instance for SMM modules.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Debug Agent library instance for SMM modules"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Debug Agent library instance for SMM modules."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.c
new file mode 100644
index 00000000..b1bd6a54
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.c
@@ -0,0 +1,154 @@
+/** @file
+ Debug Port Library implementation based on serial port.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+
+#include <Library/DebugCommunicationLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/DebugLib.h>
+
+/**
+ Initialize the debug port.
+
+ This function will initialize debug port to get it ready for data transmission. If
+ certain Debug Communication Library instance has to save some private data in the
+ stack, this function must work on the mode that doesn't return to the caller, then
+ the caller needs to wrap up all rest of logic after DebugPortInitialize() into one
+ function and pass it into DebugPortInitialize(). DebugPortInitialize() is
+ responsible to invoke the passing-in function at the end of DebugPortInitialize().
+
+ If the parameter Function is not NULL, Debug Communication Library instance will
+ invoke it by passing in the Context to be the first parameter. Debug Communication
+ Library instance could create one debug port handle to be the second parameter
+ passing into the Function. Debug Communication Library instance also could pass
+ NULL to be the second parameter if it doesn't create the debug port handle.
+
+ If the parameter Function is NULL, and Context is not NULL. At this time, Context
+ is the debug port handle created by the previous Debug Communication Library
+ instance.
+ a) If the instance can understand and continue use the private data of the previous
+ instance, it could return the same handle as passed in (as Context parameter).
+ b) If the instance does not understand, or does not want to continue use the
+ private data of the previous instance, it could ignore the input Context parameter
+ and create the new handle to be returned.
+
+ If Function() is NULL and Context is NULL, Debug Communication Library could create a
+ new handle and return it. NULL is also a valid handle to be returned.
+
+ @param[in] Context Context needed by callback function; it was optional.
+ @param[in] Function Continue function called by Debug Communication library;
+ it was optional.
+
+ @return The debug port handle created by Debug Communication Library if Function
+ is not NULL.
+
+**/
+DEBUG_PORT_HANDLE
+EFIAPI
+DebugPortInitialize (
+ IN VOID *Context,
+ IN DEBUG_PORT_CONTINUE Function
+ )
+{
+ RETURN_STATUS Status;
+
+ Status = SerialPortInitialize ();
+ if (RETURN_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "Debug Serial Port: Initialization failed!\n"));
+ }
+
+ if (Function != NULL) {
+ Function (Context, NULL);
+ }
+
+ return NULL;
+}
+
+/**
+ Read data from debug device and save the datas in buffer.
+
+ Reads NumberOfBytes data bytes from a debug device into the buffer
+ specified by Buffer. The number of bytes actually read is returned.
+ If the return value is less than NumberOfBytes, then the rest operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to store the data read from the debug device.
+ @param NumberOfBytes Number of bytes which will be read.
+ @param Timeout Timeout value for reading from debug device. It unit is Microsecond.
+
+ @retval 0 Read data failed, no data is to be read.
+ @retval >0 Actual number of bytes read from debug device.
+
+**/
+UINTN
+EFIAPI
+DebugPortReadBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes,
+ IN UINTN Timeout
+ )
+{
+ if (NumberOfBytes != 1 || Buffer == NULL || Timeout != 0) {
+ return 0;
+ }
+
+ return SerialPortRead (Buffer, 1);
+}
+
+/**
+ Write data from buffer to debug device.
+
+ Writes NumberOfBytes data bytes from Buffer to the debug device.
+ The number of bytes actually written to the debug device is returned.
+ If the return value is less than NumberOfBytes, then the write operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to be written.
+ @param NumberOfBytes Number of bytes to written to the debug device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes written to the debug device.
+ If this value is less than NumberOfBytes, then the read operation failed.
+
+**/
+UINTN
+EFIAPI
+DebugPortWriteBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ return SerialPortWrite (Buffer, NumberOfBytes);
+}
+
+/**
+ Polls a debug device to see if there is any data waiting to be read.
+
+ Polls a debug device to see if there is any data waiting to be read.
+ If there is data waiting to be read from the debug device, then TRUE is returned.
+ If there is no data waiting to be read from the debug device, then FALSE is returned.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE Data is waiting to be read from the debug device.
+ @retval FALSE There is no data waiting to be read from the serial device.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPortPollBuffer (
+ IN DEBUG_PORT_HANDLE Handle
+ )
+{
+ return SerialPortPoll ();
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf
new file mode 100644
index 00000000..143fa2ee
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf
@@ -0,0 +1,33 @@
+## @file
+# Debug Communication Library instance based on serial port.
+#
+# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugCommunicationLibSerialPort
+ MODULE_UNI_FILE = DebugCommunicationLibSerialPort.uni
+ FILE_GUID = 8CC435C5-6330-4269-B0C3-E3BD05C86FB8
+ MODULE_TYPE = BASE
+ VERSION_STRING = 0.7
+ LIBRARY_CLASS = DebugCommunicationLib
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ DebugCommunicationLibSerialPort.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+
+[LibraryClasses]
+ SerialPortLib
+ DebugLib
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.uni
new file mode 100644
index 00000000..4bea6d51
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Debug Communication Library instance based on serial port.
+//
+// Debug Communication Library instance based on serial port.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on serial port"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on serial port."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.c
new file mode 100644
index 00000000..1f9cfc3e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.c
@@ -0,0 +1,1106 @@
+/** @file
+ Debug Port Library implementation based on usb debug port.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Usb.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/DebugCommunicationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#define SETUP_PID 0x2D
+#define INPUT_PID 0x69
+#define OUTPUT_PID 0xE1
+#define ERROR_PID 0x55
+#define DATA0_PID 0xC3
+#define DATA1_PID 0x4B
+#define DATA2_PID 0x87
+#define MDATA_PID 0x0F
+#define ACK_PID 0xD2
+#define NAK_PID 0x5A
+#define STALL_PID 0x1E
+#define NYET_PID 0x96
+
+#define PCI_CAPABILITY_ID_DEBUG_PORT 0x0A
+#define USB_DEBUG_PORT_MAX_PACKET_SIZE 0x08
+
+#define USB_DEBUG_PORT_IN_USE BIT10
+#define USB_DEBUG_PORT_ENABLE BIT28
+#define USB_DEBUG_PORT_OWNER BIT30
+
+#define USB_PORT_LINE_STATUS_LS 0x400
+#define USB_PORT_LINE_STATUS_MASK 0xC00
+
+//
+// Usb debug device descriptor, which is defined at
+// USB2 Debug Device Specification.
+//
+typedef struct _USB_DEBUG_PORT_DESCRIPTOR {
+ UINT8 Length;
+ UINT8 DescriptorType;
+ UINT8 DebugInEndpoint;
+ UINT8 DebugOutEndpoint;
+}USB_DEBUG_PORT_DESCRIPTOR;
+
+USB_DEVICE_REQUEST mDebugCommunicationLibUsbGetDebugDescriptor = {
+ 0x80,
+ USB_REQ_GET_DESCRIPTOR,
+ (UINT16)(0x0A << 8),
+ 0x0000,
+ sizeof(USB_DEBUG_PORT_DESCRIPTOR)
+ };
+
+USB_DEVICE_REQUEST mDebugCommunicationLibUsbSetDebugFeature = {
+ 0x0,
+ USB_REQ_SET_FEATURE,
+ (UINT16)(0x06),
+ 0x0000,
+ 0x0
+ };
+
+USB_DEVICE_REQUEST mDebugCommunicationLibUsbSetDebugAddress = {
+ 0x0,
+ USB_REQ_SET_ADDRESS,
+ (UINT16)(0x7F),
+ 0x0000,
+ 0x0
+ };
+
+//
+// Usb debug port register file, which is defined at
+// EHCI Specification.
+//
+typedef struct _USB_DEBUG_PORT_REGISTER {
+ UINT32 ControlStatus;
+ UINT8 TokenPid;
+ UINT8 SendPid;
+ UINT8 ReceivedPid;
+ UINT8 Reserved1;
+ UINT8 DataBuffer[8];
+ UINT8 UsbEndPoint;
+ UINT8 UsbAddress;
+ UINT8 Reserved2;
+ UINT8 Reserved3;
+}USB_DEBUG_PORT_REGISTER;
+
+//
+// The state machine of usb debug port
+//
+#define USBDBG_NO_DEV 0 // No device present at debug port
+#define USBDBG_NO_DBG_CAB 1 // The device attached is not usb debug cable
+#define USBDBG_DBG_CAB 2 // The device attached is usb debug cable
+#define USBDBG_INIT_DONE 4 // The usb debug cable device is initialized
+#define USBDBG_RESET 8 // The system is reset
+
+#pragma pack(1)
+//
+// The internal data structure of DEBUG_PORT_HANDLE, which stores some
+// important datum which are used across various phases.
+//
+typedef struct _USB_DEBUG_PORT_HANDLE{
+ //
+ // The usb debug port memory BAR number in EHCI configuration space.
+ //
+ UINT8 DebugPortBarNumber;
+ UINT8 Initialized;
+ //
+ // The offset of usb debug port registers in EHCI memory range.
+ //
+ UINT16 DebugPortOffset;
+ //
+ // The usb debug port memory BAR address.
+ //
+ UINT32 UsbDebugPortMemoryBase;
+ //
+ // The EHCI memory BAR address.
+ //
+ UINT32 EhciMemoryBase;
+ //
+ // The usb debug device In endpoint.
+ //
+ UINT8 InEndpoint;
+ //
+ // The usb debug device Out endpoint.
+ //
+ UINT8 OutEndpoint;
+ //
+ // The Bulk In endpoint toggle bit.
+ //
+ UINT8 BulkInToggle;
+ //
+ // The Bulk Out endpoint toggle bit.
+ //
+ UINT8 BulkOutToggle;
+ //
+ // The available data length in the following data buffer.
+ //
+ UINT8 DataCount;
+ //
+ // The data buffer. Maximum length is 8 bytes.
+ //
+ UINT8 Data[8];
+} USB_DEBUG_PORT_HANDLE;
+#pragma pack()
+
+//
+// The global variable which can be used after memory is ready.
+//
+USB_DEBUG_PORT_HANDLE mDebugCommunicationLibUsbDebugPortHandle;
+
+/**
+ Calculate the usb debug port bar address.
+
+ @param DebugPortOffset Get usb debug port offset in the usb debug port memory space.
+ @param DebugPortBarNumbar Get the bar number at which usb debug port is located.
+
+ @retval RETURN_UNSUPPORTED The usb host controller does not supported usb debug port capability.
+ @retval RETURN_SUCCESS Get bar and offset successfully.
+
+**/
+RETURN_STATUS
+EFIAPI
+CalculateUsbDebugPortBar (
+ OUT UINT16 *DebugPortOffset,
+ OUT UINT8 *DebugPortBarNumbar
+ )
+{
+ UINT16 PciStatus;
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT8 ProgInterface;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+ UINT8 CapabilityPtr;
+ UINT8 CapabilityId;
+
+ VendorId = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_VENDOR_ID_OFFSET);
+ DeviceId = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_DEVICE_ID_OFFSET);
+
+ if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ ProgInterface = PciRead8 (PcdGet32(PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET);
+ SubClassCode = PciRead8 (PcdGet32(PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET + 1);
+ BaseCode = PciRead8 (PcdGet32(PcdUsbEhciPciAddress) + PCI_CLASSCODE_OFFSET + 2);
+
+ if ((ProgInterface != PCI_IF_EHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Enable Ehci Host Controller MMIO Space.
+ //
+ PciStatus = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_PRIMARY_STATUS_OFFSET);
+
+ if ((PciStatus & EFI_PCI_STATUS_CAPABILITY) == 0) {
+ //
+ // The Pci Device Doesn't Support Capability Pointer.
+ //
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Get Pointer To Capability List
+ //
+ CapabilityPtr = PciRead8(PcdGet32(PcdUsbEhciPciAddress) + PCI_CAPBILITY_POINTER_OFFSET);
+
+ //
+ // Find Capability ID 0xA, Which Is For Debug Port
+ //
+ while (CapabilityPtr != 0) {
+ CapabilityId = PciRead8(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr);
+ if (CapabilityId == PCI_CAPABILITY_ID_DEBUG_PORT) {
+ break;
+ }
+ CapabilityPtr = PciRead8(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr + 1);
+ }
+
+ //
+ // No Debug Port Capability Found
+ //
+ if (CapabilityPtr == 0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Get The Base Address Of Debug Port Register In Debug Port Capability Register
+ //
+ *DebugPortOffset = (UINT16)(PciRead16(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr + 2) & 0x1FFF);
+ *DebugPortBarNumbar = (UINT8)((PciRead16(PcdGet32(PcdUsbEhciPciAddress) + CapabilityPtr + 2) >> 13) - 1);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Do a usb IN transaction by usb debug port.
+
+ @param DebugPortRegister Pointer to the base address of usb debug port register interface.
+ @param Buffer Pointer to the buffer receiving data.
+ @param Length Number of bytes of the received data.
+ @param Token The token PID for each USB transaction.
+ @param Addr The usb device address for usb transaction.
+ @param Ep The endpoint for usb transaction.
+ @param DataToggle The toggle bit used at usb transaction.
+
+ @retval RETURN_SUCCESS The IN transaction is executed successfully.
+ @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid.
+ @retval RETURN_DEVICE_ERROR The IN transaction comes across error.
+
+**/
+RETURN_STATUS
+EFIAPI
+UsbDebugPortIn (
+ IN USB_DEBUG_PORT_REGISTER *DebugPortRegister,
+ IN OUT UINT8 *Buffer,
+ OUT UINT8 *Length,
+ IN UINT8 Token,
+ IN UINT8 Addr,
+ IN UINT8 Ep,
+ IN UINT8 DataToggle
+ )
+{
+ UINTN Index;
+
+ if (Length == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ *Length = 0;
+
+ DebugPortRegister->TokenPid = Token;
+ if (DataToggle != 0) {
+ DebugPortRegister->SendPid = DATA1_PID;
+ } else {
+ DebugPortRegister->SendPid = DATA0_PID;
+ }
+
+ DebugPortRegister->UsbAddress = (UINT8)(Addr & 0x7F);
+ DebugPortRegister->UsbEndPoint = (UINT8)(Ep & 0xF);
+
+ //
+ // Clearing W/R bit to indicate it's a READ operation
+ //
+ MmioAnd32((UINTN)&DebugPortRegister->ControlStatus, (UINT32)~BIT4);
+
+ //
+ // Setting GO bit as well as clearing DONE bit
+ //
+ MmioOr32((UINTN)&DebugPortRegister->ControlStatus, (UINT32)BIT5);
+
+ //
+ // Wait for completing the request
+ //
+ while ((MmioRead32((UINTN)&DebugPortRegister->ControlStatus) & (UINT32)BIT16) == 0) {
+ if ((MmioRead32((UINTN)&DebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE))
+ != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE)) {
+ return RETURN_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Clearing DONE bit by writing 1
+ //
+ MmioOr32((UINTN)&DebugPortRegister->ControlStatus, BIT16);
+
+ //
+ // Check if the request is executed successfully or not.
+ //
+ if ((MmioRead32((UINTN)&DebugPortRegister->ControlStatus)) & BIT6) {
+ return RETURN_DEVICE_ERROR;
+ }
+
+ //
+ // Make sure the received data are not beyond the allowable maximum length - 8 byte
+ //
+ if (((MmioRead32((UINTN)&DebugPortRegister->ControlStatus)) & 0xF) > USB_DEBUG_PORT_MAX_PACKET_SIZE) {
+ return RETURN_DEVICE_ERROR;
+ }
+
+ *Length = (UINT8)(MmioRead32((UINTN)&DebugPortRegister->ControlStatus) & 0xF);
+ if (*Length > 8) {
+ return RETURN_DEVICE_ERROR;
+ }
+
+ for (Index = 0; Index < *Length; Index++) {
+ Buffer[Index] = DebugPortRegister->DataBuffer[Index];
+ }
+ return RETURN_SUCCESS;
+}
+
+/**
+ Do a usb SETUP/OUT transaction by usb debug port.
+
+ @param DebugPortRegister Pointer to the base address of usb debug port register interface.
+ @param Buffer Pointer to the buffer receiving data.
+ @param Length Number of bytes of the received data.
+ @param Token The token PID for each USB transaction.
+ @param Addr The usb device address for usb transaction.
+ @param Ep The endpoint for usb transaction.
+ @param DataToggle The toggle bit used at usb transaction.
+
+ @retval RETURN_SUCCESS The IN transaction is executed successfully.
+ @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid.
+ @retval RETURN_DEVICE_ERROR The IN transaction comes across error.
+
+**/
+RETURN_STATUS
+EFIAPI
+UsbDebugPortOut (
+ IN USB_DEBUG_PORT_REGISTER *DebugPortRegister,
+ IN UINT8 *Buffer,
+ IN UINT8 Length,
+ IN UINT8 Token,
+ IN UINT8 Addr,
+ IN UINT8 Ep,
+ IN UINT8 DataToggle
+ )
+{
+ UINT8 Index;
+
+ if (Length > 8) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ DebugPortRegister->TokenPid = Token;
+ if (DataToggle != 0) {
+ DebugPortRegister->SendPid = DATA1_PID;
+ } else {
+ DebugPortRegister->SendPid = DATA0_PID;
+ }
+ DebugPortRegister->UsbAddress = (UINT8)(Addr & 0x7F);
+ DebugPortRegister->UsbEndPoint = (UINT8)(Ep & 0xF);
+
+ //
+ // Fill in the data length and corresponding data.
+ //
+ MmioAnd32((UINTN)&DebugPortRegister->ControlStatus, (UINT32)~0xF);
+ MmioOr32((UINTN)&DebugPortRegister->ControlStatus, Length & 0xF);
+ for (Index = 0; Index < Length; Index++) {
+ DebugPortRegister->DataBuffer[Index] = Buffer[Index];
+ }
+
+ //
+ // Setting W/R bit to indicate it's a WRITE operation
+ //
+ MmioOr32((UINTN)&DebugPortRegister->ControlStatus, BIT4);
+ //
+ // Setting GO bit as well as clearing DONE bit
+ //
+ MmioOr32((UINTN)&DebugPortRegister->ControlStatus, BIT5);
+
+ //
+ // Wait for completing the request
+ //
+ while ((MmioRead32((UINTN)&DebugPortRegister->ControlStatus) & BIT16) == 0) {
+ if ((MmioRead32((UINTN)&DebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE))
+ != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE)) {
+ return RETURN_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Clearing DONE bit by writing 1
+ //
+ MmioOr32((UINTN)&DebugPortRegister->ControlStatus, BIT16);
+
+ //
+ // Check if the request is executed successfully or not.
+ //
+ if ((MmioRead32((UINTN)&DebugPortRegister->ControlStatus)) & BIT6) {
+ return RETURN_DEVICE_ERROR;
+ }
+
+ //
+ // Make sure the sent data are not beyond the allowable maximum length - 8 byte
+ //
+ if (((MmioRead32((UINTN)&DebugPortRegister->ControlStatus)) & 0xF) > USB_DEBUG_PORT_MAX_PACKET_SIZE) {
+ return RETURN_DEVICE_ERROR;
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Do a usb control transfer by usb debug port.
+
+ @param DebugPortRegister Pointer to the base address of usb debug port register interface.
+ @param SetupPacket The token PID for each USB transaction.
+ @param Addr The usb device address for usb transaction.
+ @param Ep The endpoint for usb transaction.
+ @param Data Pointer to the buffer receiving data.
+ @param DataLength Number of bytes of the received data.
+
+ @retval RETURN_SUCCESS The IN transaction is executed successfully.
+ @retval RETURN_INVALID_PARAMETER The parameters passed in are invalid.
+ @retval RETURN_DEVICE_ERROR The IN transaction comes across error.
+
+**/
+RETURN_STATUS
+EFIAPI
+UsbDebugPortControlTransfer (
+ IN USB_DEBUG_PORT_REGISTER *DebugPortRegister,
+ IN USB_DEVICE_REQUEST *SetupPacket,
+ IN UINT8 Addr,
+ IN UINT8 Ep,
+ OUT UINT8 *Data,
+ IN OUT UINT8 *DataLength
+ )
+{
+ RETURN_STATUS Status;
+ UINT8 Temp;
+ UINT8 ReturnStatus[8];
+
+ //
+ // Setup Phase
+ //
+ Status = UsbDebugPortOut(DebugPortRegister, (UINT8 *)SetupPacket, (UINT8)sizeof(USB_DEVICE_REQUEST), SETUP_PID, Addr, Ep, 0);
+ if (RETURN_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Data Phase
+ //
+ if (DataLength != 0) {
+ if ((SetupPacket->RequestType & BIT7) != 0) {
+ //
+ // Get Data From Device
+ //
+ Status = UsbDebugPortIn(DebugPortRegister, Data, DataLength, INPUT_PID, Addr, Ep, 1);
+ if (RETURN_ERROR(Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Send Data To Device
+ //
+ Status = UsbDebugPortOut(DebugPortRegister, Data, *DataLength, OUTPUT_PID, Addr, Ep, 1);
+ if (RETURN_ERROR(Status)) {
+ return Status;
+ }
+ }
+ }
+
+ //
+ // Status Phase
+ //
+ if ((SetupPacket->RequestType & BIT7) != 0) {
+ //
+ // For READ operation, Data Toggle in Status Phase Should be 1.
+ //
+ Status = UsbDebugPortOut(DebugPortRegister, NULL, 0, OUTPUT_PID, Addr, Ep, 1);
+ } else {
+ //
+ // For WRITE operation, Data Toggle in Status Phase Should be 1.
+ //
+ Status = UsbDebugPortIn(DebugPortRegister, ReturnStatus, &Temp, INPUT_PID, Addr, Ep, 1);
+ }
+
+ return Status;
+}
+
+/**
+ Check if it needs to re-initialize usb debug port hardware.
+
+ During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check
+ whether the usb debug port hardware configuration is changed. Such case can be triggered by
+ Pci bus resource allocation and so on.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE The usb debug port hardware configuration is changed.
+ @retval FALSE The usb debug port hardware configuration is not changed.
+
+**/
+BOOLEAN
+EFIAPI
+NeedReinitializeHardware(
+ IN USB_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ UINT16 PciCmd;
+ UINT32 UsbDebugPortMemoryBase;
+ UINT32 EhciMemoryBase;
+ BOOLEAN Status;
+ USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;
+
+ Status = FALSE;
+
+ EhciMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);
+ if (EhciMemoryBase != Handle->EhciMemoryBase) {
+ Handle->EhciMemoryBase = EhciMemoryBase;
+ Status = TRUE;
+ }
+
+ UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle->DebugPortBarNumber * 4);
+ if (UsbDebugPortMemoryBase != Handle->UsbDebugPortMemoryBase) {
+ Handle->UsbDebugPortMemoryBase = UsbDebugPortMemoryBase;
+ Status = TRUE;
+ }
+
+ //
+ // Enable Ehci Memory Space Access
+ //
+ PciCmd = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET);
+ if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {
+ PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER;
+ PciWrite16(PcdGet32(PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd);
+ Status = TRUE;
+ }
+
+ //
+ // If the owner and in_use bit is not set, it means system is doing cold/warm boot or EHCI host controller is reset by system software.
+ //
+ UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)Handle->UsbDebugPortMemoryBase + Handle->DebugPortOffset);
+ if ((MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_ENABLE | USB_DEBUG_PORT_IN_USE))
+ != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_ENABLE | USB_DEBUG_PORT_IN_USE)) {
+ Status = TRUE;
+ }
+
+ if (Handle->Initialized == USBDBG_RESET) {
+ Status = TRUE;
+ } else if (Handle->Initialized != USBDBG_INIT_DONE) {
+ Status = TRUE;
+ }
+ return Status;
+}
+
+/**
+ Initialize usb debug port hardware.
+
+ 1. reset ehci host controller.
+ 2. set right port to debug port.
+ 3. find a usb debug device is attached by getting debug device descriptor.
+ 4. set address for the usb debug device.
+ 5. configure the usb debug device to debug mode.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE The usb debug port hardware configuration is changed.
+ @retval FALSE The usb debug port hardware configuration is not changed.
+
+**/
+RETURN_STATUS
+EFIAPI
+InitializeUsbDebugHardware (
+ IN USB_DEBUG_PORT_HANDLE *Handle
+)
+{
+ RETURN_STATUS Status;
+ USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;
+ USB_DEBUG_PORT_DESCRIPTOR UsbDebugPortDescriptor;
+ UINT32 *PortStatus;
+ UINT32 *UsbCmd;
+ UINT32 *UsbStatus;
+ UINT32 *UsbHCSParam;
+ UINT8 DebugPortNumber;
+ UINT8 Length;
+
+ UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)Handle->UsbDebugPortMemoryBase + Handle->DebugPortOffset);
+ UsbHCSParam = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x04);
+ UsbCmd = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x20);
+ UsbStatus = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x24);
+
+ //
+ // Check if the debug port is enabled and owned by myself.
+ //
+ if (((MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE))
+ != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE)) || (Handle->Initialized == USBDBG_RESET)) {
+ DEBUG ((
+ EFI_D_INFO,
+ "UsbDbg: Need to reset the host controller. ControlStatus = %08x\n",
+ MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus)
+ ));
+ //
+ // If the host controller is halted, then reset and restart it.
+ //
+ if ((MmioRead32((UINTN)UsbStatus) & BIT12) != 0) {
+ DEBUG ((EFI_D_INFO, "UsbDbg: Reset the host controller.\n"));
+ //
+ // reset the host controller.
+ //
+ MmioOr32((UINTN)UsbCmd, BIT1);
+ //
+ // ensure that the host controller is reset.
+ //
+ while ((MmioRead32((UINTN)UsbCmd) & BIT1) != 0);
+
+ MmioOr32((UINTN)UsbCmd, BIT0);
+ // ensure that the host controller is started (HALTED bit must be cleared)
+ while ((MmioRead32((UINTN)UsbStatus) & BIT12) != 0);
+ }
+
+ //
+ // First get the ownership of port 0.
+ //
+ MmioOr32((UINTN)&UsbDebugPortRegister->ControlStatus, USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE);
+
+ MicroSecondDelay (200000);
+ }
+ //
+ // Find out which port is used as debug port.
+ //
+ DebugPortNumber = (UINT8)((MmioRead32((UINTN)UsbHCSParam) & 0x00F00000) >> 20);
+ //
+ // Should find a device is connected at debug port
+ //
+ PortStatus = (UINT32 *)((UINTN)Handle->EhciMemoryBase + 0x64 + (DebugPortNumber - 1) * 4);
+ if (!(MmioRead32((UINTN)PortStatus) & BIT0)) {
+ Handle->Initialized = USBDBG_NO_DEV;
+ return RETURN_NOT_FOUND;
+ }
+
+ if (Handle->Initialized != USBDBG_INIT_DONE ||
+ (MmioRead32 ((UINTN) &UsbDebugPortRegister->ControlStatus) & USB_DEBUG_PORT_ENABLE) == 0) {
+ DEBUG ((EFI_D_INFO, "UsbDbg: Reset the debug port.\n"));
+ //
+ // Reset the debug port
+ //
+ MmioOr32((UINTN)PortStatus, BIT8);
+ MicroSecondDelay (500000);
+ MmioAnd32((UINTN)PortStatus, (UINT32)~BIT8);
+ while (MmioRead32((UINTN)PortStatus) & BIT8);
+
+ //
+ // The port enabled bit should be set by HW.
+ //
+ if ((MmioRead32((UINTN)PortStatus) & BIT2) == 0) {
+ Handle->Initialized = USBDBG_NO_DBG_CAB;
+ return RETURN_DEVICE_ERROR;
+ }
+
+ //
+ // Enable Usb Debug Port Capability
+ //
+ MmioOr32((UINTN)&UsbDebugPortRegister->ControlStatus, USB_DEBUG_PORT_ENABLE);
+
+ //
+ // initialize the data toggle used by bulk in/out endpoint.
+ //
+ Handle->BulkInToggle = 0;
+ Handle->BulkOutToggle = 0;
+
+ //
+ // set usb debug device address as 0x7F.
+ //
+ Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mDebugCommunicationLibUsbSetDebugAddress, 0x0, 0x0, NULL, NULL);
+ if (RETURN_ERROR(Status)) {
+ //
+ // The device can not work well.
+ //
+ Handle->Initialized = USBDBG_NO_DBG_CAB;
+ return Status;
+ }
+
+ //
+ // Start to communicate with Usb Debug Device to see if the attached device is usb debug device or not.
+ //
+ Length = (UINT8)sizeof (USB_DEBUG_PORT_DESCRIPTOR);
+
+ //
+ // Get debug descriptor.
+ //
+ Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mDebugCommunicationLibUsbGetDebugDescriptor, 0x7F, 0x0, (UINT8*)&UsbDebugPortDescriptor, &Length);
+ if (RETURN_ERROR(Status)) {
+ //
+ // The device is not a usb debug device.
+ //
+ Handle->Initialized = USBDBG_NO_DBG_CAB;
+ return Status;
+ }
+
+ if (Length != sizeof(USB_DEBUG_PORT_DESCRIPTOR)) {
+ Handle->Initialized = USBDBG_NO_DBG_CAB;
+ return RETURN_DEVICE_ERROR;
+ }
+
+ //
+ // Determine the usb debug device endpoints.
+ //
+ Handle->InEndpoint = UsbDebugPortDescriptor.DebugInEndpoint;
+ Handle->OutEndpoint = UsbDebugPortDescriptor.DebugOutEndpoint;
+
+ //
+ // enable the usb debug feature.
+ //
+ Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mDebugCommunicationLibUsbSetDebugFeature, 0x7F, 0x0, NULL, NULL);
+ if (RETURN_ERROR(Status)) {
+ //
+ // The device can not work well.
+ //
+ Handle->Initialized = USBDBG_NO_DBG_CAB;
+ return Status;
+ }
+
+ Handle->Initialized = USBDBG_DBG_CAB;
+ }
+
+ //
+ // Set initialized flag
+ //
+ Handle->Initialized = USBDBG_INIT_DONE;
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Read data from debug device and save the datas in buffer.
+
+ Reads NumberOfBytes data bytes from a debug device into the buffer
+ specified by Buffer. The number of bytes actually read is returned.
+ If the return value is less than NumberOfBytes, then the rest operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to store the data read from the debug device.
+ @param NumberOfBytes Number of bytes which will be read.
+ @param Timeout Timeout value for reading from debug device. It unit is Microsecond.
+
+ @retval 0 Read data failed, no data is to be read.
+ @retval >0 Actual number of bytes read from debug device.
+
+**/
+UINTN
+EFIAPI
+DebugPortReadBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes,
+ IN UINTN Timeout
+ )
+{
+ USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
+ RETURN_STATUS Status;
+ UINT8 Index;
+
+ if (NumberOfBytes != 1 || Buffer == NULL || Timeout != 0) {
+ return 0;
+ }
+
+ //
+ // If Handle is NULL, it means memory is ready for use.
+ // Use global variable to store handle value.
+ //
+ if (Handle == NULL) {
+ UsbDebugPortHandle = &mDebugCommunicationLibUsbDebugPortHandle;
+ } else {
+ UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle;
+ }
+
+ if (NeedReinitializeHardware(UsbDebugPortHandle)) {
+ Status = InitializeUsbDebugHardware (UsbDebugPortHandle);
+ if (RETURN_ERROR(Status)) {
+ return 0;
+ }
+ }
+
+ //
+ // Read data from buffer
+ //
+ if (UsbDebugPortHandle->DataCount < 1) {
+ return 0;
+ } else {
+ *Buffer = UsbDebugPortHandle->Data[0];
+ for (Index = 0; Index < UsbDebugPortHandle->DataCount - 1; Index++) {
+ if ((Index + 1) >= USB_DEBUG_PORT_MAX_PACKET_SIZE) {
+ return 0;
+ }
+ UsbDebugPortHandle->Data[Index] = UsbDebugPortHandle->Data[Index + 1];
+ }
+ UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - 1);
+ return 1;
+ }
+}
+
+/**
+ Write data from buffer to debug device.
+
+ Writes NumberOfBytes data bytes from Buffer to the debug device.
+ The number of bytes actually written to the debug device is returned.
+ If the return value is less than NumberOfBytes, then the write operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to be written.
+ @param NumberOfBytes Number of bytes to written to the debug device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes written to the debug device.
+ If this value is less than NumberOfBytes, then the read operation failed.
+
+**/
+UINTN
+EFIAPI
+DebugPortWriteBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
+ USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;
+ RETURN_STATUS Status;
+ UINT8 Sent;
+ UINTN Total;
+ UINT8 ReceivedPid;
+
+ if (NumberOfBytes == 0 || Buffer == NULL) {
+ return 0;
+ }
+
+ Sent = 0;
+ Total = 0;
+
+ //
+ // If Handle is NULL, it means memory is ready for use.
+ // Use global variable to store handle value.
+ //
+ if (Handle == NULL) {
+ UsbDebugPortHandle = &mDebugCommunicationLibUsbDebugPortHandle;
+ } else {
+ UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle;
+ }
+
+ if (NeedReinitializeHardware(UsbDebugPortHandle)) {
+ Status = InitializeUsbDebugHardware (UsbDebugPortHandle);
+ if (RETURN_ERROR(Status)) {
+ return 0;
+ }
+ }
+
+ UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)UsbDebugPortHandle->UsbDebugPortMemoryBase + UsbDebugPortHandle->DebugPortOffset);
+
+ while ((Total < NumberOfBytes)) {
+ if (NumberOfBytes - Total > USB_DEBUG_PORT_MAX_PACKET_SIZE) {
+ Sent = USB_DEBUG_PORT_MAX_PACKET_SIZE;
+ } else {
+ Sent = (UINT8)(NumberOfBytes - Total);
+ }
+
+ Status = UsbDebugPortOut(UsbDebugPortRegister, Buffer + Total, Sent, OUTPUT_PID, 0x7F, UsbDebugPortHandle->OutEndpoint, UsbDebugPortHandle->BulkOutToggle);
+
+ if (RETURN_ERROR(Status)) {
+ return Total;
+ }
+
+ ReceivedPid = (MmioRead8((UINTN)&UsbDebugPortRegister->ReceivedPid));
+ //
+ // If received a NAK_PID on write transaction, it means the usb debug device is busy and can not handle this transaction.
+ // should send the packet again.
+ //
+ if (ReceivedPid == NAK_PID) {
+ Sent = 0;
+ } else {
+ UsbDebugPortHandle->BulkOutToggle ^= 1;
+ }
+ Total += Sent;
+ }
+ return Total;
+}
+
+/**
+ Polls a debug device to see if there is any data waiting to be read.
+
+ Polls a debug device to see if there is any data waiting to be read.
+ If there is data waiting to be read from the debug device, then TRUE is returned.
+ If there is no data waiting to be read from the debug device, then FALSE is returned.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE Data is waiting to be read from the debug device.
+ @retval FALSE There is no data waiting to be read from the serial device.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPortPollBuffer (
+ IN DEBUG_PORT_HANDLE Handle
+ )
+{
+ USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
+ USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister;
+ UINT8 Length;
+ UINT8 Index;
+ RETURN_STATUS Status;
+
+ //
+ // If Handle is NULL, it means memory is ready for use.
+ // Use global variable to store handle value.
+ //
+ if (Handle == NULL) {
+ UsbDebugPortHandle = &mDebugCommunicationLibUsbDebugPortHandle;
+ } else {
+ UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Handle;
+ }
+
+ if (NeedReinitializeHardware(UsbDebugPortHandle)) {
+ Status = InitializeUsbDebugHardware(UsbDebugPortHandle);
+ if (RETURN_ERROR(Status)) {
+ return FALSE;
+ }
+ }
+
+ //
+ // If the data buffer is not empty, then return TRUE directly.
+ // else initialize a usb read transaction and read data to the data buffer.
+ //
+ if (UsbDebugPortHandle->DataCount != 0) {
+ return TRUE;
+ }
+
+ UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)((UINTN)UsbDebugPortHandle->UsbDebugPortMemoryBase + UsbDebugPortHandle->DebugPortOffset);
+
+ UsbDebugPortRegister->TokenPid = INPUT_PID;
+ if (UsbDebugPortHandle->BulkInToggle == 0) {
+ UsbDebugPortRegister->SendPid = DATA0_PID;
+ } else {
+ UsbDebugPortRegister->SendPid = DATA1_PID;
+ }
+ UsbDebugPortRegister->UsbAddress = 0x7F;
+ UsbDebugPortRegister->UsbEndPoint = UsbDebugPortHandle->InEndpoint & 0x0F;
+
+ //
+ // Clearing W/R bit to indicate it's a READ operation
+ //
+ MmioAnd32((UINTN)&UsbDebugPortRegister->ControlStatus, (UINT32)~BIT4);
+ //
+ // Setting GO bit as well as clearing DONE bit
+ //
+ MmioOr32((UINTN)&UsbDebugPortRegister->ControlStatus, (UINT32)BIT5);
+
+ //
+ // Wait for completing the request
+ //
+ while ((MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus) & (UINT32)BIT16) == 0) {
+ if ((MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE))
+ != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_ENABLE)) {
+ return FALSE;
+ }
+ }
+
+ if ((MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus)) & BIT6) {
+ return FALSE;
+ }
+
+ Length = (UINT8)(MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus) & 0xF);
+
+ if (Length > 8) {
+ return FALSE;
+ }
+
+ UsbDebugPortHandle->BulkInToggle ^= 1;
+
+ if (Length == 0) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index < Length; Index++) {
+ UsbDebugPortHandle->Data[Index] = UsbDebugPortRegister->DataBuffer[Index];
+ }
+ UsbDebugPortHandle->DataCount = Length;
+
+ return TRUE;
+}
+
+/**
+ Initialize the debug port.
+
+ If Function is not NULL, Debug Communication Library will call this function
+ by passing in the Context to be the first parameter. If needed, Debug Communication
+ Library will create one debug port handle to be the second argument passing in
+ calling the Function, otherwise it will pass NULL to be the second argument of
+ Function.
+
+ If Function is NULL, and Context is not NULL, the Debug Communication Library could
+ a) Return the same handle as passed in (as Context parameter).
+ b) Ignore the input Context parameter and create new handle to be returned.
+
+ If parameter Function is NULL and Context is NULL, Debug Communication Library could
+ created a new handle if needed and return it, otherwise it will return NULL.
+
+ @param[in] Context Context needed by callback function; it was optional.
+ @param[in] Function Continue function called by Debug Communication library;
+ it was optional.
+
+ @return The debug port handle created by Debug Communication Library if Function
+ is not NULL.
+
+**/
+DEBUG_PORT_HANDLE
+EFIAPI
+DebugPortInitialize (
+ IN VOID *Context,
+ IN DEBUG_PORT_CONTINUE Function
+ )
+{
+ RETURN_STATUS Status;
+ USB_DEBUG_PORT_HANDLE Handle;
+
+ //
+ // Validate the PCD PcdDebugPortHandleBufferSize value
+ //
+ ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB_DEBUG_PORT_HANDLE));
+
+ if (Function == NULL && Context != NULL) {
+ return (DEBUG_PORT_HANDLE *) Context;
+ }
+ ZeroMem(&Handle, sizeof (USB_DEBUG_PORT_HANDLE));
+
+ Status = CalculateUsbDebugPortBar(&Handle.DebugPortOffset, &Handle.DebugPortBarNumber);
+ if (RETURN_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbDbg: the pci device pointed by PcdUsbEhciPciAddress is not EHCI host controller or does not support debug port capability!\n"));
+ goto Exit;
+ }
+
+ Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);
+
+ if (Handle.EhciMemoryBase == 0) {
+ //
+ // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero
+ //
+ PciWrite32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, PcdGet32(PcdUsbEhciMemorySpaceBase));
+ Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);
+ }
+
+ Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4);
+
+ if (Handle.UsbDebugPortMemoryBase == 0) {
+ //
+ // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero
+ //
+ PciWrite32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4, PcdGet32(PcdUsbDebugPortMemorySpaceBase));
+ Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4);
+ }
+
+ Handle.Initialized = USBDBG_RESET;
+
+ if (NeedReinitializeHardware(&Handle)) {
+ DEBUG ((EFI_D_ERROR, "UsbDbg: Start EHCI debug port initialization!\n"));
+ Status = InitializeUsbDebugHardware (&Handle);
+ if (RETURN_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbDbg: Failed, please check if USB debug cable is plugged into EHCI debug port correctly!\n"));
+ goto Exit;
+ }
+ }
+
+Exit:
+
+ if (Function != NULL) {
+ Function (Context, &Handle);
+ } else {
+ CopyMem(&mDebugCommunicationLibUsbDebugPortHandle, &Handle, sizeof (USB_DEBUG_PORT_HANDLE));
+ }
+
+ return (DEBUG_PORT_HANDLE)(UINTN)&mDebugCommunicationLibUsbDebugPortHandle;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf
new file mode 100644
index 00000000..6af0fb1b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf
@@ -0,0 +1,51 @@
+## @file
+# Debug Communication Library instance based on usb debug port.
+#
+# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugCommunicationLibUsb
+ MODULE_UNI_FILE = DebugCommunicationLibUsb.uni
+ FILE_GUID = 87438836-AD8D-4e3e-9249-895120A67240
+ MODULE_TYPE = BASE
+ VERSION_STRING = 0.7
+ LIBRARY_CLASS = DebugCommunicationLib
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ DebugCommunicationLibUsb.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+
+[Pcd]
+ # The memory BAR of usb debug port, it may be different with the memory bar of ehci host controller.
+ # Note that the memory BAR address is only used before Pci bus resource allocation.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbDebugPortMemorySpaceBase ## SOMETIMES_CONSUMES
+ # The memory BAR of ehci host controller, in which usb debug feature is enabled.
+ # Note that the memory BAR address is only used before Pci bus resource allocation.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbEhciMemorySpaceBase ## SOMETIMES_CONSUMES
+ # The pci address of ehci host controller, in which usb debug feature is enabled.
+ # The format of pci address please refer to SourceLevelDebugPkg.dec
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbEhciPciAddress ## CONSUMES
+ # The value of data buffer size used for USB debug port handle.
+ # It should be equal to sizeof (USB_DEBUG_PORT_HANDLE).
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|25 ## SOMETIMES_CONSUMES
+
+[LibraryClasses]
+ TimerLib
+ IoLib
+ PciLib
+ PcdLib
+ DebugLib
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.uni
new file mode 100644
index 00000000..b7fb54d2
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Debug Communication Library instance based on usb debug port.
+//
+// Debug Communication Library instance based on USB debug port.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB debug port"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB debug port."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c
new file mode 100644
index 00000000..76f6707d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c
@@ -0,0 +1,1140 @@
+/** @file
+ Debug Port Library implementation based on usb3 debug port.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugCommunicationLibUsb3Internal.h"
+
+UINT16 mString0Desc[] = {
+ // String Descriptor Type + Length
+ ( USB_DESC_TYPE_STRING << 8 ) + STRING0_DESC_LEN,
+ 0x0409
+};
+
+UINT16 mManufacturerStrDesc[] = {
+ // String Descriptor Type + Length
+ ( USB_DESC_TYPE_STRING << 8 ) + MANU_DESC_LEN,
+ 'I', 'n', 't', 'e', 'l'
+};
+
+UINT16 mProductStrDesc[] = {
+ // String Descriptor Type + Length
+ ( USB_DESC_TYPE_STRING << 8 ) + PRODUCT_DESC_LEN,
+ 'U', 'S', 'B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e'
+};
+
+UINT16 mSerialNumberStrDesc[] = {
+ // String Descriptor Type + Length
+ ( USB_DESC_TYPE_STRING << 8 ) + SERIAL_DESC_LEN,
+ '1'
+};
+
+/**
+ Sets bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcSetR32Bit(
+ IN OUT UINTN Register,
+ IN UINT32 BitMask
+ )
+{
+ UINT32 RegisterValue;
+
+ RegisterValue = MmioRead32 (Register);
+ RegisterValue |= (UINT32)(BitMask);
+ MmioWrite32 (Register, RegisterValue);
+}
+
+/**
+ Clears bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcClearR32Bit(
+ IN OUT UINTN Register,
+ IN UINT32 BitMask
+ )
+{
+ UINT32 RegisterValue;
+
+ RegisterValue = MmioRead32 (Register);
+ RegisterValue &= ~BitMask;
+ MmioWrite32 (Register, RegisterValue);
+}
+
+/**
+ Write the data to the XHCI debug register.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteDebugReg (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
+
+ DebugCapabilityBase = Handle->DebugCapabilityBase;
+ MmioWrite32 ((UINTN)(DebugCapabilityBase + Offset), Data);
+
+ return;
+}
+
+/**
+ Read XHCI debug register.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the runtime register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadDebugReg (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
+
+ DebugCapabilityBase = Handle->DebugCapabilityBase;
+ Data = MmioRead32 ((UINTN)(DebugCapabilityBase + Offset));
+
+ return Data;
+}
+
+/**
+ Set one bit of the debug register while keeping other bits.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetDebugRegBit (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadDebugReg (Handle, Offset);
+ Data |= Bit;
+ XhcWriteDebugReg (Handle, Offset, Data);
+}
+
+/**
+ Clear one bit of the debug register while keeping other bits.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+ @param Bit The bit mask of the register to clear.
+
+**/
+VOID
+XhcClearDebugRegBit (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadDebugReg (Handle, Offset);
+ Data &= ~Bit;
+ XhcWriteDebugReg (Handle, Offset, Data);
+}
+
+/**
+ Program and enable XHCI MMIO base address.
+
+ @return XHCI MMIO base address.
+
+**/
+EFI_PHYSICAL_ADDRESS
+ProgramXhciBaseAddress (
+ VOID
+ )
+{
+ UINT16 PciCmd;
+ UINT32 Low;
+ UINT32 High;
+ EFI_PHYSICAL_ADDRESS XhciMmioBase;
+
+ Low = PciRead32 (PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);
+ High = PciRead32 (PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4);
+ XhciMmioBase = (EFI_PHYSICAL_ADDRESS) (LShiftU64 ((UINT64) High, 32) | Low);
+ XhciMmioBase &= XHCI_BASE_ADDRESS_64_BIT_MASK;
+
+ if ((XhciMmioBase == 0) || (XhciMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
+ XhciMmioBase = PcdGet64(PcdUsbXhciMemorySpaceBase);
+ PciWrite32(PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, XhciMmioBase & 0xFFFFFFFF);
+ PciWrite32(PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4, (RShiftU64 (XhciMmioBase, 32) & 0xFFFFFFFF));
+ }
+
+ PciCmd = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET);
+ if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {
+ PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER;
+ PciWrite16(PcdGet32(PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd);
+ }
+
+ return XhciMmioBase;
+}
+
+/**
+ Update XHC MMIO base address when MMIO base address is changed.
+
+ @param Handle Debug port handle.
+ @param XhciMmioBase XHCI MMIO base address.
+
+**/
+VOID
+UpdateXhcResource (
+ IN OUT USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EFI_PHYSICAL_ADDRESS XhciMmioBase
+ )
+{
+ if (Handle == NULL) {
+ return;
+ }
+
+ //
+ // Need fix Handle data according to new XHCI MMIO base address.
+ //
+ Handle->XhciMmioBase = XhciMmioBase;
+ Handle->DebugCapabilityBase = XhciMmioBase + Handle->DebugCapabilityOffset;
+ Handle->XhciOpRegister = XhciMmioBase + MmioRead8 ((UINTN)XhciMmioBase);
+}
+
+/**
+ Calculate the usb debug port bar address.
+
+ @param Handle Debug port handle.
+
+ @retval RETURN_UNSUPPORTED The usb host controller does not support usb debug port capability.
+ @retval RETURN_SUCCESS Get bar and offset successfully.
+
+**/
+RETURN_STATUS
+EFIAPI
+CalculateUsbDebugPortMmioBase (
+ USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT8 ProgInterface;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+ BOOLEAN Flag;
+ UINT32 Capability;
+ EFI_PHYSICAL_ADDRESS CapabilityPointer;
+ UINT8 CapLength;
+
+ if (Handle->Initialized != USB3DBG_UNINITIALIZED) {
+ if (Handle->Initialized == USB3DBG_NO_DBG_CAB) {
+ return RETURN_UNSUPPORTED;
+ } else {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ VendorId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_VENDOR_ID_OFFSET);
+ DeviceId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_DEVICE_ID_OFFSET);
+
+ if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) {
+ goto Done;
+ }
+
+ ProgInterface = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET);
+ SubClassCode = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 1);
+ BaseCode = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 2);
+
+ if ((ProgInterface != PCI_IF_XHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) {
+ goto Done;
+ }
+
+ CapLength = MmioRead8 ((UINTN) Handle->XhciMmioBase);
+
+ //
+ // Get capability pointer from HCCPARAMS at offset 0x10
+ //
+ CapabilityPointer = Handle->XhciMmioBase + (MmioRead32 ((UINTN)(Handle->XhciMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
+
+ //
+ // Search XHCI debug capability
+ //
+ Flag = FALSE;
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);
+ while (TRUE) {
+ if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
+ Flag = TRUE;
+ break;
+ }
+ if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
+ //
+ // Reach the end of capability list, quit
+ //
+ break;
+ }
+ CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);
+ }
+
+ if (!Flag) {
+ goto Done;
+ }
+
+ //
+ // USB3 debug capability is supported.
+ //
+ Handle->DebugCapabilityBase = CapabilityPointer;
+ Handle->DebugCapabilityOffset = CapabilityPointer - Handle->XhciMmioBase;
+ Handle->XhciOpRegister = Handle->XhciMmioBase + CapLength;
+ Handle->DebugSupport = TRUE;
+ Handle->Initialized = USB3DBG_DBG_CAB;
+ return RETURN_SUCCESS;
+
+Done:
+ Handle->Initialized = USB3DBG_NO_DBG_CAB;
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Check if it needs to re-initialize usb debug port hardware.
+
+ During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check
+ whether the usb debug port hardware configuration is changed. Such case can be triggered by
+ Pci bus resource allocation and so on.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE The usb debug port hardware configuration is changed.
+ @retval FALSE The usb debug port hardware configuration is not changed.
+
+**/
+BOOLEAN
+EFIAPI
+NeedReinitializeHardware(
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ BOOLEAN Result;
+ volatile UINT32 Dcctrl;
+
+ Result = FALSE;
+
+ //
+ // If DCE bit, it means USB3 debug is not enabled.
+ //
+ Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
+ if ((Dcctrl & BIT0) == 0) {
+ Result = TRUE;
+ } else if (!Handle->Ready) {
+ Handle->Ready = TRUE;
+ Handle->Initialized = USB3DBG_ENABLED;
+ }
+
+ return Result;
+}
+
+/**
+ Create XHCI event ring.
+
+ @param Handle Debug port handle.
+ @param EventRing The created event ring.
+
+**/
+EFI_STATUS
+CreateEventRing (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ OUT EVENT_RING *EventRing
+ )
+{
+ VOID *Buf;
+ EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;
+
+ ASSERT (EventRing != NULL);
+
+ //
+ // Allocate Event Ring
+ //
+ Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0x3F) == 0);
+ ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
+
+ EventRing->EventRingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;
+ EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
+ EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;
+ EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;
+
+ //
+ // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
+ // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
+ //
+ EventRing->EventRingCCS = 1;
+
+ //
+ // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table
+ //
+ Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0x3F) == 0);
+ ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
+
+ ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
+ EventRing->ERSTBase = (EFI_PHYSICAL_ADDRESS)(UINTN) ERSTBase;
+
+ //
+ // Fill Event Segment address
+ //
+ ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);
+ ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);
+ ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
+
+ //
+ // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)
+ //
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCERDP,
+ XHC_LOW_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
+ );
+
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCERDP + 4,
+ XHC_HIGH_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
+ );
+
+ //
+ // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)
+ //
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCERSTBA,
+ XHC_LOW_32BIT((UINT64)(UINTN)ERSTBase)
+ );
+
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCERSTBA + 4,
+ XHC_HIGH_32BIT((UINT64)(UINTN)ERSTBase)
+ );
+
+ //
+ // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)
+ //
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCERSTSZ,
+ ERST_NUMBER
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Create XHCI transfer ring.
+
+ @param Handle Debug port handle.
+ @param TrbNum The number of TRB in the ring.
+ @param TransferRing The created transfer ring.
+
+**/
+VOID
+CreateTransferRing (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 TrbNum,
+ OUT TRANSFER_RING *TransferRing
+ )
+{
+ VOID *Buf;
+ LINK_TRB *EndTrb;
+
+ Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0xF) == 0);
+ ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
+
+ TransferRing->RingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;
+ TransferRing->TrbNumber = TrbNum;
+ TransferRing->RingEnqueue = TransferRing->RingSeg0;
+ TransferRing->RingDequeue = TransferRing->RingSeg0;
+ TransferRing->RingPCS = 1;
+ //
+ // 4.9.2 Transfer Ring Management
+ // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
+ // point to the first TRB in the ring.
+ //
+ EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
+ EndTrb->Type = TRB_TYPE_LINK;
+ EndTrb->PtrLo = XHC_LOW_32BIT (Buf);
+ EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);
+ //
+ // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
+ //
+ EndTrb->TC = 1;
+ //
+ // Set Cycle bit as other TRB PCS init value
+ //
+ EndTrb->CycleBit = 0;
+}
+
+/**
+ Create debug capability context for XHC debug device.
+
+ @param Handle Debug port handle.
+
+ @retval EFI_SUCCESS The bit successfully changed by host controller.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+CreateDebugCapabilityContext (
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ VOID *Buf;
+ XHC_DC_CONTEXT *DebugCapabilityContext;
+ UINT8 *String0Desc;
+ UINT8 *ManufacturerStrDesc;
+ UINT8 *ProductStrDesc;
+ UINT8 *SerialNumberStrDesc;
+
+ //
+ // Allocate debug device context
+ //
+ Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT));
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0xF) == 0);
+ ZeroMem (Buf, sizeof (XHC_DC_CONTEXT));
+
+ DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN) Buf;
+ Handle->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN) DebugCapabilityContext;
+
+ //
+ // Initialize DbcInfoContext.
+ //
+ DebugCapabilityContext->DbcInfoContext.String0Length = STRING0_DESC_LEN;
+ DebugCapabilityContext->DbcInfoContext.ManufacturerStrLength = MANU_DESC_LEN;
+ DebugCapabilityContext->DbcInfoContext.ProductStrLength = PRODUCT_DESC_LEN;
+ DebugCapabilityContext->DbcInfoContext.SerialNumberStrLength = SERIAL_DESC_LEN;
+
+ //
+ // Initialize EpOutContext.
+ //
+ DebugCapabilityContext->EpOutContext.CErr = 0x3;
+ DebugCapabilityContext->EpOutContext.EPType = ED_BULK_OUT;
+ DebugCapabilityContext->EpOutContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
+ DebugCapabilityContext->EpOutContext.AverageTRBLength = 0x1000;
+
+ //
+ // Initialize EpInContext.
+ //
+ DebugCapabilityContext->EpInContext.CErr = 0x3;
+ DebugCapabilityContext->EpInContext.EPType = ED_BULK_IN;
+ DebugCapabilityContext->EpInContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
+ DebugCapabilityContext->EpInContext.AverageTRBLength = 0x1000;
+
+ //
+ // Update string descriptor address
+ //
+ String0Desc = (UINT8 *) AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
+ ASSERT (String0Desc != NULL);
+ ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
+ CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc;
+
+ ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN;
+ CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc;
+
+ ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN;
+ CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc;
+
+ SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN;
+ CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc;
+
+ //
+ // Allocate and initialize the Transfer Ring for the Input Endpoint Context.
+ //
+ ZeroMem (&Handle->TransferRingIn, sizeof (TRANSFER_RING));
+ CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingIn);
+ DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingIn.RingSeg0) | BIT0;
+ DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingIn.RingSeg0);
+
+ //
+ // Allocate and initialize the Transfer Ring for the Output Endpoint Context.
+ //
+ ZeroMem (&Handle->TransferRingOut, sizeof (TRANSFER_RING));
+ CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingOut);
+ DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingOut.RingSeg0) | BIT0;
+ DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingOut.RingSeg0);
+
+ //
+ // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)
+ //
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCCP,
+ XHC_LOW_32BIT((UINT64)(UINTN)DebugCapabilityContext)
+ );
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCCP + 4,
+ XHC_HIGH_32BIT((UINT64)(UINTN)DebugCapabilityContext)
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if debug device is running.
+
+ @param Handle Debug port handle.
+
+**/
+VOID
+XhcDetectDebugCapabilityReady (
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ UINT64 TimeOut;
+ volatile UINT32 Dcctrl;
+
+ TimeOut = 1;
+ if (Handle->Initialized == USB3DBG_DBG_CAB) {
+ //
+ // As detection is slow in seconds, wait for longer timeout for the first time.
+ // If first initialization is failed, we will try to enable debug device in the
+ // Poll function invoked by timer.
+ //
+ TimeOut = DivU64x32 (PcdGet64 (PcdUsbXhciDebugDetectTimeout), XHC_POLL_DELAY) + 1;
+ }
+
+ do {
+ //
+ // Check if debug device is in configured state
+ //
+ Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
+ if ((Dcctrl & BIT0) != 0) {
+ //
+ // Set the flag to indicate debug device is in configured state
+ //
+ Handle->Ready = TRUE;
+ break;
+ }
+ MicroSecondDelay (XHC_POLL_DELAY);
+ TimeOut--;
+ } while (TimeOut != 0);
+}
+
+/**
+ Initialize usb debug port hardware.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE The usb debug port hardware configuration is changed.
+ @retval FALSE The usb debug port hardware configuration is not changed.
+
+**/
+RETURN_STATUS
+EFIAPI
+InitializeUsbDebugHardware (
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ RETURN_STATUS Status;
+ UINT8 *Buffer;
+ UINTN Index;
+ UINT8 TotalUsb3Port;
+ EFI_PHYSICAL_ADDRESS XhciOpRegister;
+ UINT32 Dcddi1;
+
+ XhciOpRegister = Handle->XhciOpRegister;
+ TotalUsb3Port = MmioRead32 (((UINTN) Handle->XhciMmioBase + XHC_HCSPARAMS1_OFFSET)) >> 24;
+
+ if (Handle->Initialized == USB3DBG_NOT_ENABLED) {
+ Dcddi1 = XhcReadDebugReg (Handle,XHC_DC_DCDDI1);
+ if (Dcddi1 != (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)) {
+ //
+ // The debug capability has been reset by other code, return device error.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // If XHCI supports debug capability, hardware resource has been allocated,
+ // but it has not been enabled, try to enable again.
+ //
+ goto Enable;
+ }
+
+ //
+ // Initialize for PEI phase when AllocatePages can work.
+ // Allocate data buffer with max packet size for data read and data poll.
+ // Allocate data buffer for data write.
+ //
+ Buffer = AllocateAlignBuffer (XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE);
+ if (Buffer == NULL) {
+ //
+ // AllocatePages can not still work now, return fail and do not initialize now.
+ //
+ return RETURN_NOT_READY;
+ }
+
+ //
+ // Reset port to get debug device discovered
+ //
+ for (Index = 0; Index < TotalUsb3Port; Index++) {
+ XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT4);
+ MicroSecondDelay (10 * 1000);
+ }
+
+ //
+ // Clear DCE bit and LSE bit in DCCTRL
+ //
+ if ((XhcReadDebugReg (Handle, XHC_DC_DCCTRL) & (BIT1|BIT31)) == (BIT1|BIT31)) {
+ XhcClearDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);
+ }
+
+ //
+ // Construct the buffer for read, poll and write.
+ //
+ Handle->UrbIn.Data = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer;
+ Handle->Data = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
+ Handle->UrbOut.Data = Handle->UrbIn.Data + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2;
+
+ //
+ // Initialize event ring
+ //
+ ZeroMem (&Handle->EventRing, sizeof (EVENT_RING));
+ Status = CreateEventRing (Handle, &Handle->EventRing);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Init IN and OUT endpoint context
+ //
+ Status = CreateDebugCapabilityContext (Handle);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Init DCDDI1 and DCDDI2
+ //
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCDDI1,
+ (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)
+ );
+
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCDDI2,
+ (UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID)
+ );
+
+Enable:
+ if ((Handle->Initialized == USB3DBG_NOT_ENABLED) && (!Handle->ChangePortPower)) {
+ //
+ // If the first time detection is failed, turn port power off and on in order to
+ // reset port status this time, then try to check if debug device is ready again.
+ //
+ for (Index = 0; Index < TotalUsb3Port; Index++) {
+ XhcClearR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
+ MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
+ XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
+ MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
+ Handle->ChangePortPower = TRUE;
+ }
+ }
+
+ //
+ // Set DCE bit and LSE bit to "1" in DCCTRL in first initialization
+ //
+ XhcSetDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);
+
+ XhcDetectDebugCapabilityReady (Handle);
+
+ Status = RETURN_SUCCESS;
+ if (!Handle->Ready) {
+ Handle->Initialized = USB3DBG_NOT_ENABLED;
+ Status = RETURN_NOT_READY;
+ } else {
+ Handle->Initialized = USB3DBG_ENABLED;
+ }
+
+ return Status;
+}
+
+/**
+ Discover and initialize usb debug port.
+
+ @param Handle Debug port handle.
+
+**/
+VOID
+DiscoverInitializeUsbDebugPort (
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS XhciMmioBase;
+
+ //
+ // Read 64-bit MMIO base address
+ //
+ XhciMmioBase = ProgramXhciBaseAddress ();
+ Handle->XhciMmioBase = XhciMmioBase;
+
+ Status = CalculateUsbDebugPortMmioBase (Handle);
+ if (!RETURN_ERROR (Status)) {
+ UpdateXhcResource (Handle, XhciMmioBase);
+ if (NeedReinitializeHardware (Handle)) {
+ InitializeUsbDebugHardware (Handle);
+ }
+ }
+}
+
+/**
+ Set USB3 debug instance address.
+
+ @param[in] Instance Debug port instance.
+
+**/
+VOID
+SetUsb3DebugPortInstance (
+ IN USB3_DEBUG_PORT_HANDLE *Instance
+ )
+{
+ EFI_PHYSICAL_ADDRESS *AddrPtr;
+
+ AddrPtr = GetUsb3DebugPortInstanceAddrPtr ();
+ ASSERT (AddrPtr != NULL);
+ *AddrPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) Instance;
+}
+
+/**
+ Return USB3 debug instance address.
+
+**/
+USB3_DEBUG_PORT_HANDLE *
+GetUsb3DebugPortInstance (
+ VOID
+ )
+{
+ EFI_PHYSICAL_ADDRESS *AddrPtr;
+ USB3_DEBUG_PORT_HANDLE *Instance;
+
+ AddrPtr = GetUsb3DebugPortInstanceAddrPtr ();
+ ASSERT (AddrPtr != NULL);
+
+ Instance = (USB3_DEBUG_PORT_HANDLE *) (UINTN) *AddrPtr;
+
+ return Instance;
+}
+
+/**
+ Read data from debug device and save the data in buffer.
+
+ Reads NumberOfBytes data bytes from a debug device into the buffer
+ specified by Buffer. The number of bytes actually read is returned.
+ If the return value is less than NumberOfBytes, then the rest operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to store the data read from the debug device.
+ @param NumberOfBytes Number of bytes which will be read.
+ @param Timeout Timeout value for reading from debug device. Its unit is Microsecond.
+
+ @retval 0 Read data failed, no data is to be read.
+ @retval >0 Actual number of bytes read from debug device.
+
+**/
+UINTN
+EFIAPI
+DebugPortReadBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes,
+ IN UINTN Timeout
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
+ UINT8 Index;
+ UINT8 *Data;
+
+ if (NumberOfBytes != 1 || Buffer == NULL || Timeout != 0) {
+ return 0;
+ }
+
+ //
+ // If Handle is NULL, get own instance.
+ // If Handle is not NULL, use it and set the instance.
+ //
+ if (Handle != NULL) {
+ UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *) Handle;
+ SetUsb3DebugPortInstance (UsbDebugPortHandle);
+ } else {
+ UsbDebugPortHandle = GetUsb3DebugPortInstance ();
+ }
+ if (UsbDebugPortHandle == NULL) {
+ return 0;
+ }
+
+ if (UsbDebugPortHandle->InNotify) {
+ return 0;
+ }
+
+ DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
+
+ if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
+ return 0;
+ }
+
+ Data = (UINT8 *)(UINTN)UsbDebugPortHandle->Data;
+
+ //
+ // Read data from buffer
+ //
+ if (UsbDebugPortHandle->DataCount < 1) {
+ return 0;
+ } else {
+ *Buffer = Data[0];
+
+ for (Index = 0; Index < UsbDebugPortHandle->DataCount - 1; Index++) {
+ if ((Index + 1) >= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
+ return 0;
+ }
+ Data[Index] = Data[Index + 1];
+ }
+ UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - 1);
+ return 1;
+ }
+}
+
+/**
+ Write data from buffer to debug device.
+
+ Writes NumberOfBytes data bytes from Buffer to the debug device.
+ The number of bytes actually written to the debug device is returned.
+ If the return value is less than NumberOfBytes, then the write operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to be written.
+ @param NumberOfBytes Number of bytes to written to the debug device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes written to the debug device.
+ If this value is less than NumberOfBytes, then the write operation failed.
+
+**/
+UINTN
+EFIAPI
+DebugPortWriteBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
+ UINTN Sent;
+ UINTN Total;
+
+ if (NumberOfBytes == 0 || Buffer == NULL) {
+ return 0;
+ }
+
+ Sent = 0;
+ Total = 0;
+
+ //
+ // If Handle is NULL, get own instance.
+ // If Handle is not NULL, use it and set the instance.
+ //
+ if (Handle != NULL) {
+ UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *) Handle;
+ SetUsb3DebugPortInstance (UsbDebugPortHandle);
+ } else {
+ UsbDebugPortHandle = GetUsb3DebugPortInstance ();
+ }
+ if (UsbDebugPortHandle == NULL) {
+ return 0;
+ }
+
+ if (UsbDebugPortHandle->InNotify) {
+ return 0;
+ }
+
+ DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
+
+ if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
+ return 0;
+ }
+
+ //
+ // When host is trying to send data, write will be blocked.
+ // Poll to see if there is any data sent by host at first.
+ //
+ DebugPortPollBuffer (UsbDebugPortHandle);
+
+ while ((Total < NumberOfBytes)) {
+ if (NumberOfBytes - Total > USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE) {
+ Sent = USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE;
+ } else {
+ Sent = (UINT8)(NumberOfBytes - Total);
+ }
+ XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataOut, Buffer + Total, &Sent, DATA_TRANSFER_WRITE_TIMEOUT);
+ Total += Sent;
+ }
+
+ return Total;
+}
+
+/**
+ Polls a debug device to see if there is any data waiting to be read.
+
+ Polls a debug device to see if there is any data waiting to be read.
+ If there is data waiting to be read from the debug device, then TRUE is returned.
+ If there is no data waiting to be read from the debug device, then FALSE is returned.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE Data is waiting to be read from the debug device.
+ @retval FALSE There is no data waiting to be read from the debug device.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPortPollBuffer (
+ IN DEBUG_PORT_HANDLE Handle
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
+ UINTN Length;
+
+ //
+ // If Handle is NULL, get own instance.
+ // If Handle is not NULL, use it and set the instance.
+ //
+ if (Handle != NULL) {
+ UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *) Handle;
+ SetUsb3DebugPortInstance (UsbDebugPortHandle);
+ } else {
+ UsbDebugPortHandle = GetUsb3DebugPortInstance ();
+ }
+ if (UsbDebugPortHandle == NULL) {
+ return FALSE;
+ }
+
+ if (UsbDebugPortHandle->InNotify) {
+ return FALSE;
+ }
+
+ DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
+
+ if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
+ return FALSE;
+ }
+
+ //
+ // If the data buffer is not empty, then return TRUE directly.
+ // Otherwise initialize a usb read transaction and read data to internal data buffer.
+ //
+ if (UsbDebugPortHandle->DataCount != 0) {
+ return TRUE;
+ }
+
+ //
+ // Read data as much as we can
+ //
+ Length = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
+ XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, (VOID *)(UINTN)UsbDebugPortHandle->Data, &Length, DATA_TRANSFER_POLL_TIMEOUT);
+
+ if (Length > XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
+ return FALSE;
+ }
+
+ if (Length == 0) {
+ return FALSE;
+ }
+
+ //
+ // Store data into internal buffer for use later
+ //
+ UsbDebugPortHandle->DataCount = (UINT8) Length;
+ return TRUE;
+}
+
+/**
+ Initialize the debug port.
+
+ If Function is not NULL, Debug Communication Library will call this function
+ by passing in the Context to be the first parameter. If needed, Debug Communication
+ Library will create one debug port handle to be the second argument passing in
+ calling the Function, otherwise it will pass NULL to be the second argument of
+ Function.
+
+ If Function is NULL, and Context is not NULL, the Debug Communication Library could
+ a) Return the same handle as passed in (as Context parameter).
+ b) Ignore the input Context parameter and create new handle to be returned.
+
+ If parameter Function is NULL and Context is NULL, Debug Communication Library could
+ created a new handle if needed and return it, otherwise it will return NULL.
+
+ @param[in] Context Context needed by callback function; it was optional.
+ @param[in] Function Continue function called by Debug Communication library;
+ it was optional.
+
+ @return The debug port handle created by Debug Communication Library if Function
+ is not NULL.
+
+**/
+DEBUG_PORT_HANDLE
+EFIAPI
+DebugPortInitialize (
+ IN VOID *Context,
+ IN DEBUG_PORT_CONTINUE Function
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
+
+ //
+ // Validate the PCD PcdDebugPortHandleBufferSize value
+ //
+ ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB3_DEBUG_PORT_HANDLE));
+
+ if (Function == NULL && Context != NULL) {
+ SetUsb3DebugPortInstance ((USB3_DEBUG_PORT_HANDLE *) Context);
+ return (DEBUG_PORT_HANDLE) Context;
+ }
+ UsbDebugPortHandle = GetUsb3DebugPortInstance ();
+ if (UsbDebugPortHandle == NULL) {
+ return NULL;
+ }
+
+ DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
+
+ if (Function != NULL) {
+ Function (Context, (DEBUG_PORT_HANDLE) UsbDebugPortHandle);
+ }
+
+ return (DEBUG_PORT_HANDLE) UsbDebugPortHandle;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
new file mode 100644
index 00000000..29b83b15
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
@@ -0,0 +1,531 @@
+/** @file
+ Debug Port Library implementation based on usb3 debug port.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <PiDxe.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/IoMmu.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+#include "DebugCommunicationLibUsb3Internal.h"
+
+GUID gUsb3DbgGuid = USB3_DBG_GUID;
+
+USB3_DEBUG_PORT_HANDLE mUsb3Instance = {USB3DBG_UNINITIALIZED};
+EFI_PHYSICAL_ADDRESS mUsb3InstanceAddr = 0;
+EFI_PHYSICAL_ADDRESS *mUsb3InstanceAddrPtr = NULL;
+EFI_PCI_IO_PROTOCOL *mUsb3PciIo = NULL;
+
+/**
+ Creates a named event that can be signaled.
+
+ This function creates an event using NotifyTpl, NotifyFunction.
+ If Name is NULL, then ASSERT().
+ If NotifyTpl is not a legal TPL value, then ASSERT().
+ If NotifyFunction is NULL, then ASSERT().
+
+ @param Name Supplies the GUID name of the event.
+ @param NotifyTpl Supplies the task priority level of the event notifications.
+ @param NotifyFunction Supplies the function to notify when the event is signaled.
+ @param Event A pointer to the event created.
+
+ @retval EFI_SUCCESS A named event was created.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
+
+**/
+EFI_STATUS
+EFIAPI
+Usb3NamedEventListen (
+ IN CONST EFI_GUID *Name,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction,
+ IN EFI_EVENT *Event
+ )
+{
+ EFI_STATUS Status;
+ VOID *RegistrationLocal;
+
+ ASSERT (Name != NULL);
+ ASSERT (NotifyFunction != NULL);
+ ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
+
+ //
+ // Create event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ NotifyTpl,
+ NotifyFunction,
+ NULL,
+ Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for an installation of protocol interface
+ //
+ Status = gBS->RegisterProtocolNotify (
+ (EFI_GUID *) Name,
+ *Event,
+ &RegistrationLocal
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ USB3 map one DMA buffer.
+
+ @param PciIo Pointer to PciIo for USB3 debug port.
+ @param Address DMA buffer address to be mapped.
+ @param NumberOfBytes Number of bytes to be mapped.
+
+**/
+VOID
+Usb3MapOneDmaBuffer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfBytes
+ )
+{
+ EFI_STATUS Status;
+ VOID *HostAddress;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+ VOID *Mapping;
+
+ HostAddress = (VOID *) (UINTN) Address;
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ HostAddress,
+ &NumberOfBytes,
+ &DeviceAddress,
+ &Mapping
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress));
+}
+
+/**
+ USB3 map DMA buffers.
+
+ @param Instance Pointer to USB3 debug port instance.
+ @param PciIo Pointer to PciIo for USB3 debug port.
+
+**/
+VOID
+Usb3MapDmaBuffers (
+ IN USB3_DEBUG_PORT_HANDLE *Instance,
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->UrbIn.Data,
+ XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->TransferRingIn.RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->TransferRingOut.RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->EventRing.EventRingSeg0,
+ sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->EventRing.ERSTBase,
+ sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->DebugCapabilityContext,
+ sizeof (XHC_DC_CONTEXT)
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ ((XHC_DC_CONTEXT *) (UINTN) Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,
+ STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN
+ );
+}
+
+/**
+ Invoke a notification event
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+Usb3DxeSmmReadyToLockNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *Instance;
+
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+
+ Instance->InNotify = TRUE;
+
+ //
+ // For the case that the USB3 debug port instance and DMA buffers are
+ // from PEI HOB with IOMMU enabled.
+ // Reinitialize USB3 debug port with granted DXE DMA buffer accessible
+ // by SMM environment.
+ //
+ InitializeUsbDebugHardware (Instance);
+
+ //
+ // Wait some time for host to be ready after re-initialization.
+ //
+ MicroSecondDelay (1000000);
+
+ Instance->InNotify = FALSE;
+ gBS->CloseEvent (Event);
+}
+
+/**
+ USB3 get IOMMU protocol.
+
+ @return Pointer to IOMMU protocol.
+
+**/
+EDKII_IOMMU_PROTOCOL *
+Usb3GetIoMmu (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PROTOCOL *IoMmu;
+
+ IoMmu = NULL;
+ Status = gBS->LocateProtocol (
+ &gEdkiiIoMmuProtocolGuid,
+ NULL,
+ (VOID **) &IoMmu
+ );
+ if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
+ return IoMmu;
+ }
+
+ return NULL;
+}
+
+/**
+ Invoke a notification event
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+Usb3PciIoNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN PciIoHandleCount;
+ EFI_HANDLE *PciIoHandleBuffer;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN PciSegment;
+ UINTN PciBusNumber;
+ UINTN PciDeviceNumber;
+ UINTN PciFunctionNumber;
+ UINT32 PciAddress;
+ USB3_DEBUG_PORT_HANDLE *Instance;
+ EFI_EVENT SmmReadyToLockEvent;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &PciIoHandleCount,
+ &PciIoHandleBuffer
+ );
+ if (!EFI_ERROR (Status) &&
+ (PciIoHandleBuffer != NULL) &&
+ (PciIoHandleCount != 0)) {
+ for (Index = 0; Index < PciIoHandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ PciIoHandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);
+ ASSERT_EFI_ERROR (Status);
+ PciAddress = (UINT32) ((PciBusNumber << 20) | (PciDeviceNumber << 15) | (PciFunctionNumber << 12));
+ if (PciAddress == PcdGet32(PcdUsbXhciPciAddress)) {
+ //
+ // Found the PciIo for USB3 debug port.
+ //
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
+ if (Usb3GetIoMmu () != NULL) {
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+ if (Instance->Ready) {
+ Instance->InNotify = TRUE;
+ Usb3MapDmaBuffers (Instance, PciIo);
+ Instance->InNotify = FALSE;
+
+ if (Instance->FromHob) {
+ mUsb3PciIo = PciIo;
+ Usb3NamedEventListen (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ TPL_NOTIFY,
+ Usb3DxeSmmReadyToLockNotify,
+ &SmmReadyToLockEvent
+ );
+ }
+ }
+ }
+ gBS->CloseEvent (Event);
+ break;
+ }
+ }
+
+ gBS->FreePool (PciIoHandleBuffer);
+ }
+}
+
+/**
+ Return USB3 debug instance address pointer.
+
+**/
+EFI_PHYSICAL_ADDRESS *
+GetUsb3DebugPortInstanceAddrPtr (
+ VOID
+ )
+{
+ if (mUsb3InstanceAddrPtr == NULL) {
+ //
+ // Use the local variables temporarily.
+ //
+ mUsb3InstanceAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) &mUsb3Instance;
+ mUsb3InstanceAddrPtr = &mUsb3InstanceAddr;
+ }
+ return mUsb3InstanceAddrPtr;
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param PciIo Pointer to PciIo for USB3 debug port.
+ @param Pages The number of pages to allocate.
+ @param Address A pointer to store the base system memory address of the
+ allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+Usb3AllocateDmaBuffer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN Pages,
+ OUT VOID **Address
+ )
+{
+ EFI_STATUS Status;
+
+ *Address = NULL;
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ Pages,
+ Address,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) *Address,
+ EFI_PAGES_TO_SIZE (Pages)
+ );
+ }
+ return Status;
+}
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID*
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ )
+{
+ EFI_PHYSICAL_ADDRESS TmpAddr;
+ EFI_STATUS Status;
+ VOID *Buf;
+
+ Buf = NULL;
+
+ if (gBS != NULL) {
+ if (mUsb3PciIo != NULL) {
+ Usb3AllocateDmaBuffer (
+ mUsb3PciIo,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Buf
+ );
+ } else {
+ TmpAddr = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &TmpAddr
+ );
+ if (!EFI_ERROR (Status)) {
+ Buf = (VOID *) (UINTN) TmpAddr;
+ }
+ }
+ }
+
+ return Buf;
+}
+
+/**
+ The constructor function initialize USB3 debug port.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugCommunicationUsb3DxeConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_PHYSICAL_ADDRESS *AddrPtr;
+ USB3_DEBUG_PORT_HANDLE *Instance;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **) &AddrPtr);
+ if (EFI_ERROR (Status) || (AddrPtr == NULL)) {
+ //
+ // Instead of using local variables, install system configuration table for
+ // the local instance and the buffer to save instance address pointer.
+ //
+ Address = SIZE_4GB;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ AddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) Address;
+ ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
+ Instance = (USB3_DEBUG_PORT_HANDLE *) (AddrPtr + 1);
+ CopyMem (Instance, &mUsb3Instance, sizeof (USB3_DEBUG_PORT_HANDLE));
+ *AddrPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) Instance;
+
+ Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, AddrPtr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (mUsb3InstanceAddrPtr != NULL) {
+ *AddrPtr = *mUsb3InstanceAddrPtr;
+ }
+ mUsb3InstanceAddrPtr = AddrPtr;
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+
+ if (Instance->PciIoEvent == 0) {
+ Status = Usb3NamedEventListen (
+ &gEfiPciIoProtocolGuid,
+ TPL_NOTIFY,
+ Usb3PciIoNotify,
+ &Event
+ );
+ if (!EFI_ERROR (Status)) {
+ Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS) (UINTN) Event;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugCommunicationUsb3DxeDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *Instance;
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+
+ if (Instance->PciIoEvent != 0) {
+ //
+ // Close the event created.
+ //
+ gBS->CloseEvent ((EFI_EVENT) (UINTN) Instance->PciIoEvent);
+ Instance->PciIoEvent = 0;
+ }
+ return EFI_SUCCESS;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf
new file mode 100644
index 00000000..abe37acf
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf
@@ -0,0 +1,74 @@
+## @file
+# Debug Communication Library instance based on usb3 debug port.
+#
+# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugCommunicationLibUsb3Dxe
+ MODULE_UNI_FILE = DebugCommunicationLibUsb3Dxe.uni
+ FILE_GUID = C41F8C82-B3E6-47e0-A61D-0F9E429E6996
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugCommunicationLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
+ CONSTRUCTOR = DebugCommunicationUsb3DxeConstructor
+ DESTRUCTOR = DebugCommunicationUsb3DxeDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ DebugCommunicationLibUsb3Dxe.c
+ DebugCommunicationLibUsb3Transfer.c
+ DebugCommunicationLibUsb3Common.c
+ DebugCommunicationLibUsb3Internal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+
+[Pcd]
+ # The memory BAR of ehci host controller, in which usb debug feature is enabled.
+ # Note that the memory BAR address is only used before Pci bus resource allocation.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase ## SOMETIMES_CONSUMES
+
+ # The pci address of ehci host controller, in which usb debug feature is enabled.
+ # The format of pci address please refer to SourceLevelDebugPkg.dec
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress ## CONSUMES
+
+ # Per XHCI spec, software shall impose a timeout between the detection of the Debug Host
+ # connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout ## SOMETIMES_CONSUMES
+
+ # The value of data buffer size used for USB debug port handle.
+ # It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE).
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|249 ## SOMETIMES_CONSUMES
+
+[Protocols]
+ ## NOTIFY
+ ## SOMETIMES_CONSUMES
+ gEfiPciIoProtocolGuid
+ gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES
+ ## NOTIFY
+ ## SOMETIMES_CONSUMES
+ gEfiDxeSmmReadyToLockProtocolGuid
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ IoLib
+ PciLib
+ TimerLib
+ UefiBootServicesTableLib
+ UefiLib
+ BaseMemoryLib
+ HobLib
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni
new file mode 100644
index 00000000..244b25d7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Debug Communication Library instance based on USB3 debug port for DXE and SMM modules.
+//
+// Debug Communication Library instance based on USB3 debug port for DXE and SMM modules.
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB3 debug port for DXE and SMM modules"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB3 debug port for DXE and SMM modules."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h
new file mode 100644
index 00000000..44c6971e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h
@@ -0,0 +1,737 @@
+/** @file
+ Debug Port Library implementation based on usb3 debug port.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __USB3_DEBUG_PORT_LIB_INTERNAL__
+#define __USB3_DEBUG_PORT_LIB_INTERNAL__
+
+#include <Uefi.h>
+#include <Base.h>
+#include <IndustryStandard/Usb.h>
+#include <Library/IoLib.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/TimerLib.h>
+#include <Library/DebugCommunicationLib.h>
+#include <Library/PciLib.h>
+
+//
+// USB Debug GUID value
+//
+#define USB3_DBG_GUID \
+ { \
+ 0xb2a56f4d, 0x9177, 0x4fc8, { 0xa6, 0x77, 0xdd, 0x96, 0x3e, 0xb4, 0xcb, 0x1b } \
+ }
+
+//
+// The state machine of usb debug port
+//
+#define USB3DBG_NO_DBG_CAB 0 // The XHCI host controller does not support debug capability
+#define USB3DBG_DBG_CAB 1 // The XHCI host controller supports debug capability
+#define USB3DBG_ENABLED 2 // The XHCI debug device is enabled
+#define USB3DBG_NOT_ENABLED 4 // The XHCI debug device is not enabled
+#define USB3DBG_UNINITIALIZED 255 // The XHCI debug device is uninitialized
+
+#define USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE 0x08
+
+//
+// MaxPacketSize for DbC Endpoint Descriptor IN and OUT
+//
+#define XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE 0x400
+
+#define XHCI_DEBUG_DEVICE_VENDOR_ID 0x0525
+#define XHCI_DEBUG_DEVICE_PRODUCT_ID 0x127A
+#define XHCI_DEBUG_DEVICE_PROTOCOL 0xFF
+#define XHCI_DEBUG_DEVICE_REVISION 0x00
+
+#define XHCI_BASE_ADDRESS_64_BIT_MASK 0xFFFFFFFFFFFF0000ULL
+#define XHCI_BASE_ADDRESS_32_BIT_MASK 0xFFFF0000
+
+#define PCI_CAPABILITY_ID_DEBUG_PORT 0x0A
+#define XHC_HCCPARAMS_OFFSET 0x10
+#define XHC_CAPABILITY_ID_MASK 0xFF
+#define XHC_NEXT_CAPABILITY_MASK 0xFF00
+
+#define XHC_HCSPARAMS1_OFFSET 0x4 // Structural Parameters 1
+#define XHC_USBCMD_OFFSET 0x0 // USB Command Register Offset
+#define XHC_USBSTS_OFFSET 0x4 // USB Status Register Offset
+#define XHC_PORTSC_OFFSET 0x400 // Port Status and Control Register Offset
+
+#define XHC_USBCMD_RUN BIT0 // Run/Stop
+#define XHC_USBCMD_RESET BIT1 // Host Controller Reset
+
+#define XHC_USBSTS_HALT BIT0
+
+//
+// Indicate the timeout when data is transferred in microsecond. 0 means infinite timeout.
+//
+#define DATA_TRANSFER_WRITE_TIMEOUT 0
+#define DATA_TRANSFER_READ_TIMEOUT 50000
+#define DATA_TRANSFER_POLL_TIMEOUT 1000
+#define XHC_DEBUG_PORT_1_MILLISECOND 1000
+//
+// XHCI port power off/on delay
+//
+#define XHC_DEBUG_PORT_ON_OFF_DELAY 100000
+
+//
+// USB debug device string descriptor (header size + unicode string length)
+//
+#define STRING0_DESC_LEN 4
+#define MANU_DESC_LEN 12
+#define PRODUCT_DESC_LEN 40
+#define SERIAL_DESC_LEN 4
+
+//
+// Debug Capability Register Offset
+//
+#define XHC_DC_DCID 0x0
+#define XHC_DC_DCDB 0x4
+#define XHC_DC_DCERSTSZ 0x8
+#define XHC_DC_DCERSTBA 0x10
+#define XHC_DC_DCERDP 0x18
+#define XHC_DC_DCCTRL 0x20
+#define XHC_DC_DCST 0x24
+#define XHC_DC_DCPORTSC 0x28
+#define XHC_DC_DCCP 0x30
+#define XHC_DC_DCDDI1 0x38
+#define XHC_DC_DCDDI2 0x3C
+
+#define TRB_TYPE_LINK 6
+
+#define ERST_NUMBER 0x01
+#define TR_RING_TRB_NUMBER 0x100
+#define EVENT_RING_TRB_NUMBER 0x200
+
+#define ED_BULK_OUT 2
+#define ED_BULK_IN 6
+
+#define XHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0xFFFFFFFF))
+#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINT64)(UINTN)(Addr64), 32) & 0xFFFFFFFF))
+#define XHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
+
+//
+// Endpoint Type (EP Type).
+//
+#define ED_NOT_VALID 0
+#define ED_ISOCH_OUT 1
+#define ED_BULK_OUT 2
+#define ED_INTERRUPT_OUT 3
+#define ED_CONTROL_BIDIR 4
+#define ED_ISOCH_IN 5
+#define ED_BULK_IN 6
+#define ED_INTERRUPT_IN 7
+
+//
+// 6.4.5 TRB Completion Codes
+//
+#define TRB_COMPLETION_INVALID 0
+#define TRB_COMPLETION_SUCCESS 1
+#define TRB_COMPLETION_DATA_BUFFER_ERROR 2
+#define TRB_COMPLETION_BABBLE_ERROR 3
+#define TRB_COMPLETION_USB_TRANSACTION_ERROR 4
+#define TRB_COMPLETION_TRB_ERROR 5
+#define TRB_COMPLETION_STALL_ERROR 6
+#define TRB_COMPLETION_SHORT_PACKET 13
+
+//
+// 6.4.6 TRB Types
+//
+#define TRB_TYPE_NORMAL 1
+#define TRB_TYPE_SETUP_STAGE 2
+#define TRB_TYPE_DATA_STAGE 3
+#define TRB_TYPE_STATUS_STAGE 4
+#define TRB_TYPE_ISOCH 5
+#define TRB_TYPE_LINK 6
+#define TRB_TYPE_EVENT_DATA 7
+#define TRB_TYPE_NO_OP 8
+#define TRB_TYPE_EN_SLOT 9
+#define TRB_TYPE_DIS_SLOT 10
+#define TRB_TYPE_ADDRESS_DEV 11
+#define TRB_TYPE_CON_ENDPOINT 12
+#define TRB_TYPE_EVALU_CONTXT 13
+#define TRB_TYPE_RESET_ENDPOINT 14
+#define TRB_TYPE_STOP_ENDPOINT 15
+#define TRB_TYPE_SET_TR_DEQUE 16
+#define TRB_TYPE_RESET_DEV 17
+#define TRB_TYPE_GET_PORT_BANW 21
+#define TRB_TYPE_FORCE_HEADER 22
+#define TRB_TYPE_NO_OP_COMMAND 23
+#define TRB_TYPE_TRANS_EVENT 32
+#define TRB_TYPE_COMMAND_COMPLT_EVENT 33
+#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT 34
+#define TRB_TYPE_HOST_CONTROLLER_EVENT 37
+#define TRB_TYPE_DEVICE_NOTIFI_EVENT 38
+#define TRB_TYPE_MFINDEX_WRAP_EVENT 39
+
+//
+// Convert millisecond to microsecond.
+//
+#define XHC_1_MILLISECOND (1000)
+#define XHC_POLL_DELAY (1000)
+#define XHC_GENERIC_TIMEOUT (10 * 1000)
+
+#define EFI_USB_SPEED_FULL 0x0000 ///< 12 Mb/s, USB 1.1 OHCI and UHCI HC.
+#define EFI_USB_SPEED_LOW 0x0001 ///< 1 Mb/s, USB 1.1 OHCI and UHCI HC.
+#define EFI_USB_SPEED_HIGH 0x0002 ///< 480 Mb/s, USB 2.0 EHCI HC.
+#define EFI_USB_SPEED_SUPER 0x0003 ///< 4.8 Gb/s, USB 3.0 XHCI HC.
+
+//
+// Transfer types, used in URB to identify the transfer type
+//
+#define XHC_CTRL_TRANSFER 0x01
+#define XHC_BULK_TRANSFER 0x02
+#define XHC_INT_TRANSFER_SYNC 0x04
+#define XHC_INT_TRANSFER_ASYNC 0x08
+#define XHC_INT_ONLY_TRANSFER_ASYNC 0x10
+
+//
+// USB Transfer Results
+//
+#define EFI_USB_NOERROR 0x00
+#define EFI_USB_ERR_NOTEXECUTE 0x01
+#define EFI_USB_ERR_STALL 0x02
+#define EFI_USB_ERR_BUFFER 0x04
+#define EFI_USB_ERR_BABBLE 0x08
+#define EFI_USB_ERR_NAK 0x10
+#define EFI_USB_ERR_CRC 0x20
+#define EFI_USB_ERR_TIMEOUT 0x40
+#define EFI_USB_ERR_BITSTUFF 0x80
+#define EFI_USB_ERR_SYSTEM 0x100
+
+#pragma pack(1)
+
+//
+// 7.6.9 OUT/IN EP Context: 64 bytes
+// 7.6.9.2 When used by the DbC it is always a 64 byte data structure
+//
+typedef struct _ENDPOINT_CONTEXT_64 {
+ UINT32 EPState:3;
+ UINT32 RsvdZ1:5;
+ UINT32 Mult:2; // set to 0
+ UINT32 MaxPStreams:5; // set to 0
+ UINT32 LSA:1; // set to 0
+ UINT32 Interval:8; // set to 0
+ UINT32 RsvdZ2:8;
+
+ UINT32 RsvdZ3:1;
+ UINT32 CErr:2;
+ UINT32 EPType:3;
+ UINT32 RsvdZ4:1;
+ UINT32 HID:1; // set to 0
+ UINT32 MaxBurstSize:8;
+ UINT32 MaxPacketSize:16;
+
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 AverageTRBLength:16;
+ UINT32 MaxESITPayload:16; // set to 0
+
+ UINT32 RsvdZ5; // Reserved
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+
+ UINT32 RsvdZ8;
+ UINT32 RsvdZ9;
+ UINT32 RsvdZ10;
+ UINT32 RsvdZ11;
+
+ UINT32 RsvdZ12;
+ UINT32 RsvdZ13;
+ UINT32 RsvdZ14;
+ UINT32 RsvdZ15;
+} ENDPOINT_CONTEXT_64;
+
+//
+// 6.4.1.1 Normal TRB: 16 bytes
+// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and
+// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer
+// Rings, and to define the Data stage information for Control Transfer Rings.
+//
+typedef struct _TRANSFER_TRB_NORMAL {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length:17;
+ UINT32 TDSize:5;
+ UINT32 IntTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 ENT:1;
+ UINT32 ISP:1;
+ UINT32 NS:1;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 IDT:1;
+ UINT32 RsvdZ1:2;
+ UINT32 BEI:1;
+ UINT32 Type:6;
+ UINT32 RsvdZ2:16;
+} TRANSFER_TRB_NORMAL;
+
+//
+// 6.4.2.1 Transfer Event TRB: 16 bytes
+// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1
+// for more information on the use and operation of Transfer Events.
+//
+typedef struct _EVT_TRB_TRANSFER {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length:24;
+ UINT32 Completecode:8;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ1:1;
+ UINT32 ED:1;
+ UINT32 RsvdZ2:7;
+ UINT32 Type:6;
+ UINT32 EndpointId:5;
+ UINT32 RsvdZ3:3;
+ UINT32 SlotId:8;
+} EVT_TRB_TRANSFER;
+
+//
+// 6.4.4.1 Link TRB: 16 bytes
+// A Link TRB provides support for non-contiguous TRB Rings.
+//
+typedef struct _LINK_TRB {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1:22;
+ UINT32 InterTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 TC:1;
+ UINT32 RsvdZ2:2;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 RsvdZ3:4;
+ UINT32 Type:6;
+ UINT32 RsvdZ4:16;
+} LINK_TRB;
+
+//
+// TRB Template: 16 bytes
+//
+typedef struct _TRB_TEMPLATE {
+ UINT32 Parameter1;
+
+ UINT32 Parameter2;
+
+ UINT32 Status;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ1:9;
+ UINT32 Type:6;
+ UINT32 Control:16;
+} TRB_TEMPLATE;
+
+//
+// Refer to XHCI 6.5 Event Ring Segment Table: 16 bytes
+//
+typedef struct _EVENT_RING_SEG_TABLE_ENTRY {
+ UINT32 PtrLo;
+ UINT32 PtrHi;
+ UINT32 RingTrbSize:16;
+ UINT32 RsvdZ1:16;
+ UINT32 RsvdZ2;
+} EVENT_RING_SEG_TABLE_ENTRY;
+
+//
+// Size: 40 bytes
+//
+typedef struct _EVENT_RING {
+ EFI_PHYSICAL_ADDRESS ERSTBase;
+ EFI_PHYSICAL_ADDRESS EventRingSeg0;
+ UINT32 TrbNumber;
+ EFI_PHYSICAL_ADDRESS EventRingEnqueue;
+ EFI_PHYSICAL_ADDRESS EventRingDequeue;
+ UINT32 EventRingCCS;
+} EVENT_RING;
+
+// Size: 32 bytes
+typedef struct _TRANSFER_RING {
+ EFI_PHYSICAL_ADDRESS RingSeg0;
+ UINT32 TrbNumber;
+ EFI_PHYSICAL_ADDRESS RingEnqueue;
+ EFI_PHYSICAL_ADDRESS RingDequeue;
+ UINT32 RingPCS;
+} TRANSFER_RING;
+
+//
+// Size: 64 bytes
+//
+typedef struct _DBC_INFO_CONTEXT {
+ UINT64 String0DescAddress;
+ UINT64 ManufacturerStrDescAddress;
+ UINT64 ProductStrDescAddress;
+ UINT64 SerialNumberStrDescAddress;
+ UINT64 String0Length:8;
+ UINT64 ManufacturerStrLength:8;
+ UINT64 ProductStrLength:8;
+ UINT64 SerialNumberStrLength:8;
+ UINT64 RsvdZ1:32;
+ UINT64 RsvdZ2;
+ UINT64 RsvdZ3;
+ UINT64 RsvdZ4;
+} DBC_INFO_CONTEXT;
+
+//
+// Debug Capability Context Data Structure: 192 bytes
+//
+typedef struct _XHC_DC_CONTEXT {
+ DBC_INFO_CONTEXT DbcInfoContext;
+ ENDPOINT_CONTEXT_64 EpOutContext;
+ ENDPOINT_CONTEXT_64 EpInContext;
+} XHC_DC_CONTEXT;
+
+//
+// Size: 16 bytes
+//
+typedef union _TRB {
+ TRB_TEMPLATE TrbTemplate;
+ TRANSFER_TRB_NORMAL TrbNormal;
+} TRB;
+
+///
+/// USB data transfer direction
+///
+typedef enum {
+ EfiUsbDataIn,
+ EfiUsbDataOut,
+ EfiUsbNoData
+} EFI_USB_DATA_DIRECTION;
+
+//
+// URB (Usb Request Block) contains information for all kinds of
+// usb requests.
+//
+typedef struct _URB {
+ //
+ // Transfer data buffer
+ //
+ EFI_PHYSICAL_ADDRESS Data;
+ UINT32 DataLen;
+
+ //
+ // Execute result
+ //
+ UINT32 Result;
+ //
+ // Completed data length
+ //
+ UINT32 Completed;
+ //
+ // Tranfer Ring info
+ //
+ EFI_PHYSICAL_ADDRESS Ring;
+ EFI_PHYSICAL_ADDRESS Trb;
+ BOOLEAN Finished;
+ EFI_USB_DATA_DIRECTION Direction;
+} URB;
+
+typedef struct _USB3_DEBUG_PORT_INSTANCE {
+ UINT8 Initialized;
+
+ //
+ // The flag indicates debug capability is supported
+ //
+ BOOLEAN DebugSupport;
+
+ //
+ // The flag indicates debug device is ready
+ //
+ BOOLEAN Ready;
+
+ //
+ // The flag indicates the instance is from HOB
+ //
+ BOOLEAN FromHob;
+
+ //
+ // Prevent notification being interrupted by debug timer
+ //
+ BOOLEAN InNotify;
+
+ //
+ // PciIo protocol event
+ //
+ EFI_PHYSICAL_ADDRESS PciIoEvent;
+
+ //
+ // The flag indicates if USB 3.0 ports has been turn off/on power
+ //
+ BOOLEAN ChangePortPower;
+
+ //
+ // XHCI MMIO Base address
+ //
+ EFI_PHYSICAL_ADDRESS XhciMmioBase;
+
+ //
+ // XHCI OP RegisterBase address
+ //
+ EFI_PHYSICAL_ADDRESS XhciOpRegister;
+
+ //
+ // XHCI Debug Register Base Address
+ //
+ EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
+
+ //
+ // XHCI Debug Capability offset
+ //
+ UINT64 DebugCapabilityOffset;
+
+ //
+ // XHCI Debug Context Address
+ //
+ EFI_PHYSICAL_ADDRESS DebugCapabilityContext;
+
+ //
+ // Transfer Ring
+ //
+ TRANSFER_RING TransferRingOut;
+ TRANSFER_RING TransferRingIn;
+
+ //
+ // EventRing
+ //
+ EVENT_RING EventRing;
+
+ //
+ // URB - Read
+ //
+ URB UrbOut;
+
+ //
+ // URB - Write
+ //
+ URB UrbIn;
+
+ //
+ // The available data length in the following data buffer.
+ //
+ UINT8 DataCount;
+ //
+ // The data buffer address for data read and poll.
+ //
+ EFI_PHYSICAL_ADDRESS Data;
+} USB3_DEBUG_PORT_HANDLE;
+
+#pragma pack()
+
+/**
+ Read XHCI debug register.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadDebugReg (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset
+ );
+
+/**
+ Set one bit of the debug register while keeping other bits.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetDebugRegBit (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Write the data to the debug register.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteDebugReg (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+/**
+ Verifies if the bit positions specified by a mask are set in a register.
+
+ @param[in, out] Register UNITN register
+ @param[in] BitMask 32-bit mask
+
+ @return BOOLEAN - TRUE if all bits specified by the mask are enabled.
+ - FALSE even if one of the bits specified by the mask
+ is not enabled.
+**/
+BOOLEAN
+XhcIsBitSet(
+ UINTN Register,
+ UINT32 BitMask
+ );
+
+/**
+ Sets bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcSetR32Bit(
+ UINTN Register,
+ UINT32 BitMask
+ );
+
+/**
+ Clears bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcClearR32Bit(
+ IN OUT UINTN Register,
+ IN UINT32 BitMask
+ );
+
+/**
+ Initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3Initialize (
+ VOID
+ );
+
+/**
+ Return command register value in XHCI controller.
+
+**/
+UINT16
+GetXhciPciCommand (
+ VOID
+ );
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID*
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ );
+
+/**
+ The real function to initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3InitializeReal (
+ VOID
+ );
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param Handle The instance of debug device.
+ @param Direction The direction of data transfer.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The length of the data buffer.
+ @param Timeout Indicates the maximum time, in millisecond, which
+ the transfer is allowed to complete.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDataTransfer (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout
+ );
+
+/**
+ Initialize usb debug port hardware.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE The usb debug port hardware configuration is changed.
+ @retval FALSE The usb debug port hardware configuration is not changed.
+
+**/
+RETURN_STATUS
+EFIAPI
+InitializeUsbDebugHardware (
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ );
+
+/**
+ Return USB3 debug instance address pointer.
+
+**/
+EFI_PHYSICAL_ADDRESS *
+GetUsb3DebugPortInstanceAddrPtr (
+ VOID
+ );
+
+/**
+ Return USB3 debug instance address.
+
+**/
+USB3_DEBUG_PORT_HANDLE *
+GetUsb3DebugPortInstance (
+ VOID
+ );
+
+#endif //__SERIAL_PORT_LIB_USB__
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c
new file mode 100644
index 00000000..68c355ce
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c
@@ -0,0 +1,273 @@
+/** @file
+ Debug Port Library implementation based on usb3 debug port.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/HobLib.h>
+#include <Ppi/MemoryDiscovered.h>
+#include <Ppi/IoMmu.h>
+#include "DebugCommunicationLibUsb3Internal.h"
+
+GUID gUsb3DbgGuid = USB3_DBG_GUID;
+
+/**
+ USB3 IOMMU PPI notify.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_STATUS Always return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+Usb3IoMmuPpiNotify (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *Instance;
+
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+ if (!Instance->Ready) {
+ return EFI_SUCCESS;
+ }
+
+ Instance->InNotify = TRUE;
+
+ //
+ // Reinitialize USB3 debug port with granted DMA buffer from IOMMU PPI.
+ //
+ InitializeUsbDebugHardware (Instance);
+
+ //
+ // Wait some time for host to be ready after re-initialization.
+ //
+ MicroSecondDelay (1000000);
+
+ Instance->InNotify = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+EFI_PEI_NOTIFY_DESCRIPTOR mUsb3IoMmuPpiNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiIoMmuPpiGuid,
+ Usb3IoMmuPpiNotify
+};
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+ *Mapping = NULL;
+
+ Status = IoMmu->AllocateBuffer (
+ IoMmu,
+ EfiRuntimeServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
+ Status = IoMmu->Map (
+ IoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
+ *HostAddress = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = IoMmu->SetAttribute (
+ IoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->Unmap (IoMmu, *Mapping);
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
+ *Mapping = NULL;
+ *HostAddress = NULL;
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ USB3 get IOMMU PPI.
+
+ @return Pointer to IOMMU PPI.
+
+**/
+EDKII_IOMMU_PPI *
+Usb3GetIoMmu (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ IoMmu = NULL;
+ Status = PeiServicesLocatePpi (
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &IoMmu
+ );
+ if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
+ return IoMmu;
+ }
+
+ return NULL;
+}
+
+/**
+ Return USB3 debug instance address pointer.
+
+**/
+EFI_PHYSICAL_ADDRESS *
+GetUsb3DebugPortInstanceAddrPtr (
+ VOID
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *Instance;
+ EFI_PHYSICAL_ADDRESS *AddrPtr;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_STATUS Status;
+
+ Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid);
+ if (Hob.Raw == NULL) {
+ //
+ // Build HOB for the local instance and the buffer to save instance address pointer.
+ // Use the local instance in HOB temporarily.
+ //
+ AddrPtr = BuildGuidHob (
+ &gUsb3DbgGuid,
+ sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)
+ );
+ ASSERT (AddrPtr != NULL);
+ ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
+ Instance = (USB3_DEBUG_PORT_HANDLE *) (AddrPtr + 1);
+ *AddrPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) Instance;
+ Instance->FromHob = TRUE;
+ Instance->Initialized = USB3DBG_UNINITIALIZED;
+ if (Usb3GetIoMmu () == NULL) {
+ Status = PeiServicesNotifyPpi (&mUsb3IoMmuPpiNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ AddrPtr = GET_GUID_HOB_DATA (Hob.Guid);
+ }
+
+ return AddrPtr;
+}
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID*
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ )
+{
+ VOID *Buf;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+ VOID *MemoryDiscoveredPpi;
+ EDKII_IOMMU_PPI *IoMmu;
+ VOID *HostAddress;
+ VOID *Mapping;
+
+ Buf = NULL;
+
+ //
+ // Make sure the allocated memory is physical memory.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &MemoryDiscoveredPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ IoMmu = Usb3GetIoMmu ();
+ if (IoMmu != NULL) {
+ Status = IoMmuAllocateBuffer (
+ IoMmu,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &HostAddress,
+ &Address,
+ &Mapping
+ );
+ if (!EFI_ERROR (Status)) {
+ ASSERT (Address == ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress));
+ Buf = (VOID *)(UINTN) Address;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Address
+ );
+ if (!EFI_ERROR (Status)) {
+ Buf = (VOID *)(UINTN) Address;
+ }
+ }
+ }
+ return Buf;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf
new file mode 100644
index 00000000..02638804
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf
@@ -0,0 +1,69 @@
+## @file
+# Debug Communication Library instance based on usb3 debug port.
+#
+# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugCommunicationLibUsb3Pei
+ MODULE_UNI_FILE = DebugCommunicationLibUsb3Pei.uni
+ FILE_GUID = 106C877F-C2BA-4c46-876C-BDFE6171CD7E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugCommunicationLib|PEIM PEI_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ DebugCommunicationLibUsb3Pei.c
+ DebugCommunicationLibUsb3Transfer.c
+ DebugCommunicationLibUsb3Common.c
+ DebugCommunicationLibUsb3Internal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+
+[Ppis]
+ gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ # The memory BAR of ehci host controller, in which usb debug feature is enabled.
+ # Note that the memory BAR address is only used before Pci bus resource allocation.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase ## SOMETIMES_CONSUMES
+
+ # The pci address of ehci host controller, in which usb debug feature is enabled.
+ # The format of pci address please refer to SourceLevelDebugPkg.dec
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress ## CONSUMES
+
+ # Per XHCI spec, software shall impose a timeout between the detection of the Debug Host
+ # connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout ## SOMETIMES_CONSUMES
+
+ # The value of data buffer size used for USB debug port handle.
+ # It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE).
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|249 ## SOMETIMES_CONSUMES
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ IoLib
+ PciLib
+ TimerLib
+ BaseMemoryLib
+ PeiServicesLib
+ HobLib
+
+[Depex.common.PEIM]
+ gEfiPeiMemoryDiscoveredPpiGuid
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni
new file mode 100644
index 00000000..8252b660
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Debug Communication Library instance based on USB3 debug port for PEI modules.
+//
+// Debug Communication Library instance based on USB3 debug port for PEI modules.
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB3 debug port for PEI modules"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB3 debug port for PEI modules."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c
new file mode 100644
index 00000000..0d400315
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c
@@ -0,0 +1,577 @@
+/** @file
+ Debug Port Library implementation based on usb3 debug port.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "DebugCommunicationLibUsb3Internal.h"
+
+/**
+ Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
+
+ @param Handle Debug port handle.
+ @param TrsRing The transfer ring to sync.
+
+ @retval EFI_SUCCESS The transfer ring is synchronized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncTrsRing (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN TRANSFER_RING *TrsRing
+ )
+{
+ UINTN Index;
+ TRB_TEMPLATE *TrsTrb;
+ UINT32 CycleBit;
+
+ ASSERT (TrsRing != NULL);
+
+ //
+ // Calculate the latest RingEnqueue and RingPCS
+ //
+ TrsTrb = (TRB_TEMPLATE *)(UINTN) TrsRing->RingEnqueue;
+
+ ASSERT (TrsTrb != NULL);
+
+ for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
+ if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
+ break;
+ }
+ TrsTrb++;
+ if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
+ ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);
+ //
+ // set cycle bit in Link TRB as normal
+ //
+ ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
+ //
+ // Toggle PCS maintained by software
+ //
+ TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
+ TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F);
+ }
+ }
+ ASSERT (Index != TrsRing->TrbNumber);
+
+ if ((EFI_PHYSICAL_ADDRESS)(UINTN) TrsTrb != TrsRing->RingEnqueue) {
+ TrsRing->RingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) TrsTrb;
+ }
+
+ //
+ // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb.
+ //
+ CycleBit = TrsTrb->CycleBit;
+ ZeroMem (TrsTrb, sizeof (TRB_TEMPLATE));
+ TrsTrb->CycleBit = CycleBit;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Synchronize the specified event ring to update the enqueue and dequeue pointer.
+
+ @param Handle Debug port handle.
+ @param EvtRing The event ring to sync.
+
+ @retval EFI_SUCCESS The event ring is synchronized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncEventRing (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EVENT_RING *EvtRing
+ )
+{
+ UINTN Index;
+ TRB_TEMPLATE *EvtTrb1;
+
+ ASSERT (EvtRing != NULL);
+
+ //
+ // Calculate the EventRingEnqueue and EventRingCCS.
+ // Note: only support single Segment
+ //
+ EvtTrb1 = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;
+
+ for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
+ if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
+ break;
+ }
+
+ EvtTrb1++;
+
+ if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
+ EvtTrb1 = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingSeg0;
+ EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
+ }
+ }
+
+ if (Index < EvtRing->TrbNumber) {
+ EvtRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EvtTrb1;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if there is a new generated event.
+
+ @param Handle Debug port handle.
+ @param EvtRing The event ring to check.
+ @param NewEvtTrb The new event TRB found.
+
+ @retval EFI_SUCCESS Found a new event TRB at the event ring.
+ @retval EFI_NOT_READY The event ring has no new event.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcCheckNewEvent (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EVENT_RING *EvtRing,
+ OUT TRB_TEMPLATE **NewEvtTrb
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (EvtRing != NULL);
+
+ *NewEvtTrb = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;
+
+ if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
+ return EFI_NOT_READY;
+ }
+
+ Status = EFI_SUCCESS;
+
+ EvtRing->EventRingDequeue += sizeof (TRB_TEMPLATE);
+ //
+ // If the dequeue pointer is beyond the ring, then roll-back it to the beginning of the ring.
+ //
+ if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
+ EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
+ }
+
+ return Status;
+}
+
+/**
+ Check if the Trb is a transaction of the URB.
+
+ @param Ring The transfer ring to be checked.
+ @param Trb The TRB to be checked.
+
+ @retval TRUE It is a transaction of the URB.
+ @retval FALSE It is not any transaction of the URB.
+
+**/
+BOOLEAN
+IsTrbInTrsRing (
+ IN TRANSFER_RING *Ring,
+ IN TRB_TEMPLATE *Trb
+ )
+{
+ TRB_TEMPLATE *CheckedTrb;
+ UINTN Index;
+
+ CheckedTrb = (TRB_TEMPLATE *)(UINTN) Ring->RingSeg0;
+
+ ASSERT (Ring->TrbNumber == TR_RING_TRB_NUMBER);
+
+ for (Index = 0; Index < Ring->TrbNumber; Index++) {
+ if (Trb == CheckedTrb) {
+ return TRUE;
+ }
+ CheckedTrb++;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check the URB's execution result and update the URB's
+ result accordingly.
+
+ @param Handle Debug port handle.
+ @param Urb The URB to check result.
+
+**/
+VOID
+XhcCheckUrbResult (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN URB *Urb
+ )
+{
+ EVT_TRB_TRANSFER *EvtTrb;
+ TRB_TEMPLATE *TRBPtr;
+ UINTN Index;
+ EFI_STATUS Status;
+ URB *CheckedUrb;
+ UINT64 XhcDequeue;
+ UINT32 High;
+ UINT32 Low;
+
+ ASSERT ((Handle != NULL) && (Urb != NULL));
+
+ if (Urb->Finished) {
+ goto EXIT;
+ }
+
+ EvtTrb = NULL;
+
+ //
+ // Traverse the event ring to find out all new events from the previous check.
+ //
+ XhcSyncEventRing (Handle, &Handle->EventRing);
+
+ for (Index = 0; Index < Handle->EventRing.TrbNumber; Index++) {
+
+ Status = XhcCheckNewEvent (Handle, &Handle->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
+ if (Status == EFI_NOT_READY) {
+ //
+ // All new events are handled, return directly.
+ //
+ goto EXIT;
+ }
+
+ if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
+ continue;
+ }
+
+ TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
+
+ if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Urb->Ring), TRBPtr)) {
+ CheckedUrb = Urb;
+ } else if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Handle->UrbIn.Ring), TRBPtr)) {
+ //
+ // If it is read event and it should be generated by poll, and current operation is write, we need save data into internal buffer.
+ // Internal buffer is used by next read.
+ //
+ Handle->DataCount = (UINT8) (Handle->UrbIn.DataLen - EvtTrb->Length);
+ CopyMem ((VOID *)(UINTN)Handle->Data, (VOID *)(UINTN)Handle->UrbIn.Data, Handle->DataCount);
+ //
+ // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB.
+ //
+ TRBPtr->CycleBit = (TRBPtr->CycleBit & BIT0) ? 0 : 1;
+ continue;
+ } else {
+ continue;
+ }
+
+ if ((EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) ||
+ (EvtTrb->Completecode == TRB_COMPLETION_SUCCESS)) {
+ //
+ // The length of data which were transferred.
+ //
+ CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);
+ } else {
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
+ }
+ //
+ // This Urb has been processed
+ //
+ CheckedUrb->Finished = TRUE;
+ }
+
+EXIT:
+ //
+ // Advance event ring to last available entry
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ Low = XhcReadDebugReg (Handle, XHC_DC_DCERDP);
+ High = XhcReadDebugReg (Handle, XHC_DC_DCERDP + 4);
+ XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);
+
+ if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Handle->EventRing.EventRingDequeue & (~0x0F))) {
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ XhcWriteDebugReg (Handle, XHC_DC_DCERDP, XHC_LOW_32BIT (Handle->EventRing.EventRingDequeue));
+ XhcWriteDebugReg (Handle, XHC_DC_DCERDP + 4, XHC_HIGH_32BIT (Handle->EventRing.EventRingDequeue));
+ }
+}
+
+/**
+ Ring the door bell to notify XHCI there is a transaction to be executed.
+
+ @param Handle Debug port handle.
+ @param Urb The pointer to URB.
+
+ @retval EFI_SUCCESS Successfully ring the door bell.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcRingDoorBell (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN URB *Urb
+ )
+{
+ UINT32 Dcdb;
+
+ //
+ // 7.6.8.2 DCDB Register
+ //
+ Dcdb = (Urb->Direction == EfiUsbDataIn) ? 0x100 : 0x0;
+
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCDB,
+ Dcdb
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Execute the transfer by polling the URB. This is a synchronous operation.
+
+ @param Handle Debug port handle.
+ @param Urb The URB to execute.
+ @param Timeout The time to wait before abort, in microsecond.
+
+**/
+VOID
+XhcExecTransfer (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN URB *Urb,
+ IN UINTN Timeout
+ )
+{
+ TRANSFER_RING *Ring;
+ TRB_TEMPLATE *Trb;
+ UINTN Loop;
+ UINTN Index;
+
+ Loop = Timeout / XHC_DEBUG_PORT_1_MILLISECOND;
+ if (Timeout == 0) {
+ Loop = 0xFFFFFFFF;
+ }
+ XhcRingDoorBell (Handle, Urb);
+ //
+ // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.
+ //
+ for (Index = 0; Index < Loop; Index++) {
+ XhcCheckUrbResult (Handle, Urb);
+ if (Urb->Finished) {
+ break;
+ }
+ MicroSecondDelay (XHC_DEBUG_PORT_1_MILLISECOND);
+ }
+ if (Index == Loop) {
+ //
+ // If time out occurs.
+ //
+ Urb->Result |= EFI_USB_ERR_TIMEOUT;
+ }
+ //
+ // If URB transfer is error, restore transfer ring to original value before URB transfer
+ // This will make the current transfer TRB is always at the latest unused one in transfer ring.
+ //
+ Ring = (TRANSFER_RING *)(UINTN) Urb->Ring;
+ if ((Urb->Result != EFI_USB_NOERROR) && (Urb->Direction == EfiUsbDataIn)) {
+ //
+ // Adjust Enqueue pointer
+ //
+ Ring->RingEnqueue = Urb->Trb;
+ //
+ // Clear CCS flag for next use
+ //
+ Trb = (TRB_TEMPLATE *)(UINTN) Urb->Trb;
+ Trb->CycleBit = ((~Ring->RingPCS) & BIT0);
+ } else {
+ //
+ // Update transfer ring for next transfer.
+ //
+ XhcSyncTrsRing (Handle, Ring);
+ }
+}
+
+/**
+ Create a transfer TRB.
+
+ @param Handle Debug port handle.
+ @param Urb The urb used to construct the transfer TRB.
+
+ @return Created TRB or NULL
+
+**/
+EFI_STATUS
+XhcCreateTransferTrb (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN URB *Urb
+ )
+{
+ TRANSFER_RING *EPRing;
+ TRB *Trb;
+
+ if (Urb->Direction == EfiUsbDataIn) {
+ EPRing = &Handle->TransferRingIn;
+ } else {
+ EPRing = &Handle->TransferRingOut;
+ }
+
+ Urb->Ring = (EFI_PHYSICAL_ADDRESS)(UINTN) EPRing;
+ XhcSyncTrsRing (Handle, EPRing);
+
+ Urb->Trb = EPRing->RingEnqueue;
+ Trb = (TRB *)(UINTN)EPRing->RingEnqueue;
+ Trb->TrbNormal.TRBPtrLo = XHC_LOW_32BIT (Urb->Data);
+ Trb->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT (Urb->Data);
+ Trb->TrbNormal.Length = Urb->DataLen;
+ Trb->TrbNormal.TDSize = 0;
+ Trb->TrbNormal.IntTarget = 0;
+ Trb->TrbNormal.ISP = 1;
+ Trb->TrbNormal.IOC = 1;
+ Trb->TrbNormal.Type = TRB_TYPE_NORMAL;
+
+ //
+ // Update the cycle bit to indicate this TRB has been consumed.
+ //
+ Trb->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new URB for a new transaction.
+
+ @param Handle Debug port handle.
+ @param Direction The direction of data flow.
+ @param Data The user data to transfer
+ @param DataLen The length of data buffer
+
+ @return Created URB or NULL
+
+**/
+URB*
+XhcCreateUrb (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN VOID *Data,
+ IN UINTN DataLen
+ )
+{
+ EFI_STATUS Status;
+ URB *Urb;
+ EFI_PHYSICAL_ADDRESS UrbData;
+
+ if (Direction == EfiUsbDataIn) {
+ Urb = &Handle->UrbIn;
+ } else {
+ Urb = &Handle->UrbOut;
+ }
+
+ UrbData = Urb->Data;
+
+ ZeroMem (Urb, sizeof (URB));
+ Urb->Direction = Direction;
+
+ //
+ // Allocate memory to move data from CAR or SMRAM to normal memory
+ // to make XHCI DMA successfully
+ // re-use the pre-allocate buffer in PEI to avoid DXE memory service or gBS are not ready
+ //
+ Urb->Data = UrbData;
+
+ if (Direction == EfiUsbDataIn) {
+ //
+ // Do not break URB data in buffer as it may contain the data which were just put in via DMA by XHC
+ //
+ Urb->DataLen = (UINT32) DataLen;
+ } else {
+ //
+ // Put data into URB data out buffer which will create TRBs
+ //
+ ZeroMem ((VOID*)(UINTN) Urb->Data, DataLen);
+ CopyMem ((VOID*)(UINTN) Urb->Data, Data, DataLen);
+ Urb->DataLen = (UINT32) DataLen;
+ }
+
+ Status = XhcCreateTransferTrb (Handle, Urb);
+ ASSERT_EFI_ERROR (Status);
+
+ return Urb;
+}
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param Handle Debug port handle.
+ @param Direction The direction of data transfer.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The length of the data buffer.
+ @param Timeout Indicates the maximum time, in microsecond, which
+ the transfer is allowed to complete.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDataTransfer (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout
+ )
+{
+ URB *Urb;
+ EFI_STATUS Status;
+
+ //
+ // Validate the parameters
+ //
+ if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create a new URB, insert it into the asynchronous
+ // schedule list, then poll the execution status.
+ //
+ Urb = XhcCreateUrb (Handle, Direction, Data, *DataLength);
+ ASSERT (Urb != NULL);
+
+ XhcExecTransfer (Handle, Urb, Timeout);
+
+ //
+ // Make sure the data received from HW can fit in the received buffer.
+ //
+ if (Urb->Completed > *DataLength) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ *DataLength = Urb->Completed;
+
+ Status = EFI_TIMEOUT;
+ if (Urb->Result == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ }
+
+ if (Direction == EfiUsbDataIn) {
+ //
+ // Move data from internal buffer to outside buffer (outside buffer may be in SMRAM...)
+ // SMRAM does not allow to do DMA, so we create an internal buffer.
+ //
+ CopyMem (Data, (VOID *)(UINTN)Urb->Data, *DataLength);
+ }
+
+ return Status;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm
new file mode 100644
index 00000000..3ef8b4d8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm
@@ -0,0 +1,22 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; IntHandler.nasm
+;
+; Abstract:
+;
+; Assembly interrupt handler function.
+;
+;------------------------------------------------------------------------------
+
+global ASM_PFX(AsmInterruptHandle)
+
+SECTION .text
+ASM_PFX(AsmInterruptHandle):
+ cli
+ mov al, 1
+ iretd
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandlerFuncs.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandlerFuncs.c
new file mode 100644
index 00000000..37bed770
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandlerFuncs.c
@@ -0,0 +1,93 @@
+/** @file
+ Ia32 arch functions to access IDT vector.
+
+ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PeCoffExtraActionLib.h>
+
+/**
+ Read IDT entry to check if IDT entries are setup by Debug Agent.
+
+ @param[in] IdtDescriptor Pointer to IDT Descriptor.
+ @param[in] InterruptType Interrupt type.
+
+ @retval TRUE IDT entries were setup by Debug Agent.
+ @retval FALSE IDT entries were not setuo by Debug Agent.
+
+**/
+BOOLEAN
+CheckDebugAgentHandler (
+ IN IA32_DESCRIPTOR *IdtDescriptor,
+ IN UINTN InterruptType
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ UINTN InterruptHandler;
+
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor->Base;
+ if (IdtEntry == NULL) {
+ return FALSE;
+ }
+
+ InterruptHandler = IdtEntry[InterruptType].Bits.OffsetLow +
+ (IdtEntry[InterruptType].Bits.OffsetHigh << 16);
+ if (InterruptHandler >= sizeof (UINT32) && *(UINT32 *)(InterruptHandler - sizeof (UINT32)) == AGENT_HANDLER_SIGNATURE) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Save IDT entry for INT1 and update it.
+
+ @param[in] IdtDescriptor Pointer to IDT Descriptor.
+ @param[out] SavedIdtEntry Original IDT entry returned.
+
+**/
+VOID
+SaveAndUpdateIdtEntry1 (
+ IN IA32_DESCRIPTOR *IdtDescriptor,
+ OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ UINT16 CodeSegment;
+ UINTN InterruptHandler;
+
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor->Base;
+ CopyMem (SavedIdtEntry, &IdtEntry[1], sizeof (IA32_IDT_GATE_DESCRIPTOR));
+
+ //
+ // Use current CS as the segment selector of interrupt gate in IDT
+ //
+ CodeSegment = AsmReadCs ();
+
+ InterruptHandler = (UINTN) &AsmInterruptHandle;
+ IdtEntry[1].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry[1].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry[1].Bits.Selector = CodeSegment;
+ IdtEntry[1].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+}
+
+/**
+ Restore IDT entry for INT1.
+
+ @param[in] IdtDescriptor Pointer to IDT Descriptor.
+ @param[in] RestoredIdtEntry IDT entry to be restored.
+
+**/
+VOID
+RestoreIdtEntry1 (
+ IN IA32_DESCRIPTOR *IdtDescriptor,
+ IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor->Base;
+ CopyMem (&IdtEntry[1], RestoredIdtEntry, sizeof (IA32_IDT_GATE_DESCRIPTOR));
+}
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
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.h
new file mode 100644
index 00000000..8ba58fde
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.h
@@ -0,0 +1,73 @@
+/** @file
+ PE/Coff Extra Action library instances, it will report image debug info.
+
+ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PE_COFF_EXTRA_ACTION_LIB_H_
+#define _PE_COFF_EXTRA_ACTION_LIB_H_
+
+#include <Base.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include <ImageDebugSupport.h>
+
+#define DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT 1
+#define DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3 2
+
+#define IO_HW_BREAKPOINT_VECTOR_NUM 1
+#define SOFT_INT_VECTOR_NUM 3
+
+extern UINTN AsmInterruptHandle;
+
+/**
+ Read IDT entry to check if IDT entries are setup by Debug Agent.
+
+ @param[in] IdtDescriptor Pointer to IDT Descriptor.
+ @param[in] InterruptType Interrupt type.
+
+ @retval TRUE IDT entries were setup by Debug Agent.
+ @retval FALSE IDT entries were not setuo by Debug Agent.
+
+**/
+BOOLEAN
+CheckDebugAgentHandler (
+ IN IA32_DESCRIPTOR *IdtDescriptor,
+ IN UINTN InterruptType
+ );
+
+/**
+ Save IDT entry for INT1 and update it.
+
+ @param[in] IdtDescriptor Pointer to IDT Descriptor.
+ @param[out] SavedIdtEntry Original IDT entry returned.
+
+**/
+VOID
+SaveAndUpdateIdtEntry1 (
+ IN IA32_DESCRIPTOR *IdtDescriptor,
+ OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry
+ );
+
+/**
+ Restore IDT entry for INT1.
+
+ @param[in] IdtDescriptor Pointer to IDT Descriptor.
+ @param[in] RestoredIdtEntry IDT entry to be restored.
+
+**/
+VOID
+RestoreIdtEntry1 (
+ IN IA32_DESCRIPTOR *IdtDescriptor,
+ IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry
+ );
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.uni
new file mode 100644
index 00000000..965aa644
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// PeCoffExtraAction Library to support source level debug.
+//
+// PeCoffExtraAction Library to support source level debug.
+//
+// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PeCoffExtraAction Library to support source level debug"
+
+#string STR_MODULE_DESCRIPTION #language en-US "PeCoffExtraAction Library to support source level debug."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
new file mode 100644
index 00000000..815c6a98
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
@@ -0,0 +1,51 @@
+## @file
+# PeCoffExtraAction Library to support source level debug.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeCoffExtraActionLib
+ MODULE_UNI_FILE = PeCoffExtraActionLib.uni
+ FILE_GUID = 8F01CBD5-E069-44d7-90C9-35F0318603AD
+ MODULE_TYPE = BASE
+ VERSION_STRING = 0.8
+ LIBRARY_CLASS = PeCoffExtraActionLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ PeCoffExtraActionLib.h
+ PeCoffExtraActionLib.c
+
+[Sources.IA32]
+ Ia32/IntHandlerFuncs.c
+ Ia32/IntHandler.nasm
+
+[Sources.X64]
+ X64/IntHandlerFuncs.c
+ X64/IntHandler.nasm
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ IoLib
+ PcdLib
+
+[Pcd]
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod ## CONSUMES
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm
new file mode 100644
index 00000000..4e637749
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm
@@ -0,0 +1,23 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; IntHandler.nasm
+;
+; Abstract:
+;
+; Assembly interrupt handler function.
+;
+;------------------------------------------------------------------------------
+
+global ASM_PFX(AsmInterruptHandle)
+
+DEFAULT REL
+SECTION .text
+ASM_PFX(AsmInterruptHandle):
+ cli
+ mov al, 1
+ iretq
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandlerFuncs.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandlerFuncs.c
new file mode 100644
index 00000000..6d1f1063
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandlerFuncs.c
@@ -0,0 +1,95 @@
+/** @file
+ X64 arch function to access IDT vector.
+
+ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PeCoffExtraActionLib.h>
+
+/**
+ Read IDT entry to check if IDT entries are setup by Debug Agent.
+
+ @param[in] IdtDescriptor Pointer to IDT Descriptor.
+ @param[in] InterruptType Interrupt type.
+
+ @retval TRUE IDT entries were setup by Debug Agent.
+ @retval FALSE IDT entries were not setuo by Debug Agent.
+
+**/
+BOOLEAN
+CheckDebugAgentHandler (
+ IN IA32_DESCRIPTOR *IdtDescriptor,
+ IN UINTN InterruptType
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ UINTN InterruptHandler;
+
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor->Base;
+ if (IdtEntry == NULL) {
+ return FALSE;
+ }
+
+ InterruptHandler = IdtEntry[InterruptType].Bits.OffsetLow +
+ (((UINTN)IdtEntry[InterruptType].Bits.OffsetHigh) << 16) +
+ (((UINTN)IdtEntry[InterruptType].Bits.OffsetUpper) << 32);
+ if (InterruptHandler >= sizeof (UINT32) && *(UINT32 *)(InterruptHandler - sizeof (UINT32)) == AGENT_HANDLER_SIGNATURE) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Save IDT entry for INT1 and update it.
+
+ @param[in] IdtDescriptor Pointer to IDT Descriptor.
+ @param[out] SavedIdtEntry Original IDT entry returned.
+
+**/
+VOID
+SaveAndUpdateIdtEntry1 (
+ IN IA32_DESCRIPTOR *IdtDescriptor,
+ OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ UINT16 CodeSegment;
+ UINTN InterruptHandler;
+
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor->Base;
+ CopyMem (SavedIdtEntry, &IdtEntry[1], sizeof (IA32_IDT_GATE_DESCRIPTOR));
+
+ //
+ // Use current CS as the segment selector of interrupt gate in IDT
+ //
+ CodeSegment = AsmReadCs ();
+
+ InterruptHandler = (UINTN) &AsmInterruptHandle;
+ IdtEntry[1].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry[1].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry[1].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
+ IdtEntry[1].Bits.Selector = CodeSegment;
+ IdtEntry[1].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+}
+
+/**
+ Restore IDT entry for INT1.
+
+ @param[in] IdtDescriptor Pointer to IDT Descriptor.
+ @param[in] RestoredIdtEntry IDT entry to be restored.
+
+**/
+VOID
+RestoreIdtEntry1 (
+ IN IA32_DESCRIPTOR *IdtDescriptor,
+ IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor->Base;
+ CopyMem (&IdtEntry[1], RestoredIdtEntry, sizeof (IA32_IDT_GATE_DESCRIPTOR));
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Readme.txt b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Readme.txt
new file mode 100644
index 00000000..688ebb19
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Readme.txt
@@ -0,0 +1,6 @@
+UDK based firmware on UEFI IA-32 and UEFI x64 platforms can be debugged with
+SourceLevelDebugPkg in conjunction with Intel(R) UEFI Development Kit Debugger
+Tool (Intel (R) UDK Debugger Tool).
+
+The Intel(R) UDK Debugger Tool and its detailed user manual can be obtained
+from: https://firmware.intel.com/develop/intel-uefi-tools-and-utilities/intel-uefi-development-kit-debugger-tool.
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.dec b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.dec
new file mode 100644
index 00000000..7b66f646
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.dec
@@ -0,0 +1,117 @@
+## @file SourceLevelDebugPkg.dec
+# This package provides target side modules to support source level debug.
+# The target side components includes the Debug Agent Library instance
+# to communicate with host side modules, Debug Communication Library and
+# instances to provide the communication I/O functions between Debug Agent
+# and host, PeCoffExtraActionLib instance to report symbol path information,
+# etc.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = SourceLevelDebugPkg
+ PACKAGE_UNI_FILE = SourceLevelDebugPkg.uni
+ PACKAGE_GUID = DBF00C27-D8D7-443d-918B-4E85CDA1373B
+ PACKAGE_VERSION = 0.96
+
+[Includes]
+ Include
+
+[Includes.IA32]
+ Include/Ia32
+
+[Includes.X64]
+ Include/Ia32
+
+[LibraryClasses]
+ ## @libraryclass Provides communication I/O functions between Debug Agent and HOST.
+ ##
+ DebugCommunicationLib|Include/Library/DebugCommunicationLib.h
+
+[Guids]
+ ## MdeModule package token space guid
+ # Include/Guid/DebugAgentGuid.h
+ gEfiDebugAgentGuid = {0x865a5a9b, 0xb85d, 0x474c, { 0x84, 0x55, 0x65, 0xd1, 0xbe, 0x84, 0x4b, 0xe2 }}
+ gEfiSourceLevelDebugPkgTokenSpaceGuid = {0x865a5aab, 0xb85d, 0x474c, { 0x84, 0x55, 0x65, 0xd1, 0xbe, 0x84, 0x4b, 0xe2 }}
+
+#
+# [Error.gEfiSourceLevelDebugPkgTokenSpaceGuid]
+# 0x80000001 | Invalid value provided.
+#
+
+[PcdsFixedAtBuild, PcdsPatchableInModule]
+ ## The memory BAR of usb debug port, it may be different with the memory bar of ehci host controller.
+ # Note that the memory BAR address is only used before Pci bus resource allocation.
+ # @Prompt Configure usb debug port memory BAR.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbDebugPortMemorySpaceBase|0xd0000000|UINT32|0x00000001
+
+ ## The memory BAR of ehci host controller, in which usb debug feature is enabled.
+ # Note that the memory BAR address is only used before Pci bus resource allocation.
+ # @Prompt Configure ehci host controller memory BAR.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbEhciMemorySpaceBase|0xd0000000|UINT32|0x00000002
+
+ ## The pci address of ehci host controller, in which usb debug feature is enabled.
+ # The format of pci address is :<BR>
+ # -----------------------------------------------------------------------<BR>
+ # | Bits 28..31 | Bits 20..27 | Bits 15..19 | Bits 12..14 | Bits 00..11 |<BR>
+ # -----------------------------------------------------------------------<BR>
+ # | 0 | Bus | Device | Function | 0 |<BR>
+ # -----------------------------------------------------------------------<BR>
+ # For the value 0x000EF000, it means the pci address at bus 0x0, device 0x1D, function 0x7.
+ # @Prompt Configure ehci host controller pci address.
+ # @Expression 0x80000001 | (gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbEhciPciAddress & 0xF0000FFF) == 0
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbEhciPciAddress|0x000EF000|UINT32|0x00000003
+
+ ## The mask of exception numbers whose handlers would be ignored and cannot be replaced or
+ # hooked by Debug Agent Library. Masking INT1/INT3 is invalid.
+ # @Prompt Configure exception numbers not to be hooked by Debug Agent.
+ # @Expression 0x80000001 | (gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdExceptionsIgnoredByDebugger & 0xA) == 0
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdExceptionsIgnoredByDebugger|0x00000000|UINT32|0x00000004
+
+ ## The method to issue break point to Debug Agent Library when Loading/UnLoading image.<BR><BR>
+ # 1: Use I/O Port 84 to issue hardware break point<BR>
+ # 2: Use INT3 to issue software break point<BR>
+ # @Prompt Configure Loading/UnLoading image break method.
+ # @ValidRange 0x80000001 | 1 - 2
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod|0x1|UINT8|0x00000005
+
+ ## The data buffer size used by debug port in debug communication library instances.
+ # Its value is not suggested to be changed in platform DSC file.
+ # @Prompt Assign debug port buffer size.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|0x0|UINT16|0x00000006
+
+ ## The memory BAR of xhci host controller, in which usb debug feature is enabled.
+ ## Note that the memory BAR address is only used before Pci bus resource allocation.
+ # @Prompt Configure xhci host controller memory BAR.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase|0xD0000000|UINT64|0x00000007
+
+ ## The pci address of xhci host controller, in which usb debug feature is enabled.
+ # The format of pci address is :<BR>
+ # -----------------------------------------------------------------------<BR>
+ # | Bits 28..31 | Bits 20..27 | Bits 15..19 | Bits 12..14 | Bits 00..11 |<BR>
+ # -----------------------------------------------------------------------<BR>
+ # | 0 | Bus | Device | Function | 0 |<BR>
+ # -----------------------------------------------------------------------<BR>
+ # For the value 0x000A0000, it means the pci address at bus 0x0, device 0x14, function 0x0.
+ # @Prompt Configure xhci host controller pci address.
+ # @Expression 0x80000001 | (gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress & 0xF0000FFF) == 0
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress|0x000A0000|UINT32|0x00000008
+
+ ## Per XHCI spec, software shall impose a timeout between the detection of the Debug Host
+ ## connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.
+ # @Prompt Configure debug device detection timeout value.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout|3000000|UINT64|0x00000009
+
+ ## Default revision of the debug agent transfer protocol.
+ # The upper 16 bits indicate the major revision and the lower 16 bits indicate the minor revision.
+ # For example, a value of 0x00000004 stands for revision 0.4.
+ # Debug packet compression and decompression is supported since revision 0.4.
+ # @Prompt Default revision of the debug agent transfer protocol.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdTransferProtocolRevision|0x00000004|UINT32|0x0000000a
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SourceLevelDebugPkgExtra.uni
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.dsc b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.dsc
new file mode 100644
index 00000000..cbdaca24
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.dsc
@@ -0,0 +1,112 @@
+## @file
+# Source Level Debug Package.
+#
+# Copyright (c) 2010 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2020, AMD Incorporated. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ PLATFORM_NAME = SourceLevelDebugPkg
+ PLATFORM_GUID = 38C85805-883F-4ee8-A854-95B966ED73AA
+ PLATFORM_VERSION = 0.96
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/SourceLevelDebugPkg
+ SUPPORTED_ARCHITECTURES = IA32|X64
+ BUILD_TARGETS = DEBUG|RELEASE|NOOPT
+ SKUID_IDENTIFIER = DEFAULT
+
+!include MdePkg/MdeLibs.dsc.inc
+
+[LibraryClasses.common]
+ DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf
+ LocalApicLib|UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf
+ UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
+ PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+ SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
+ PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
+ TimerLib|UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf
+ ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
+ PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+ PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
+ PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
+
+!ifdef $(SOURCE_DEBUG_USE_USB)
+ DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf
+!else
+!ifndef $(SOURCE_DEBUG_USE_USB3)
+ DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf
+!endif
+!endif
+
+[LibraryClasses.common.PEIM]
+ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
+ PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+ PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf
+ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+ DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf
+!ifdef $(SOURCE_DEBUG_USE_USB3)
+ DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf
+!endif
+
+[LibraryClasses.common.DXE_DRIVER]
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
+!ifdef $(SOURCE_DEBUG_USE_USB3)
+ DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf
+!endif
+
+###################################################################################################
+#
+# Components Section - list of the modules and components that will be processed by compilation
+# tools and the EDK II tools to generate PE32/PE32+/Coff image files.
+#
+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed
+# into firmware volume images. This section is just a list of modules to compile from
+# source into UEFI-compliant binaries.
+# It is the FDF file that contains information on combining binary files into firmware
+# volume images, whose concept is beyond UEFI and is described in PI specification.
+# Binary modules do not need to be listed in this section, as they should be
+# specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),
+# Logo (Logo.bmp), and etc.
+# There may also be modules listed in this section that are not required in the FDF file,
+# When a module listed here is excluded from FDF file, then UEFI-compliant binary will be
+# generated for it, but the binary will not be put into any firmware volume.
+#
+###################################################################################################
+
+[Components.common]
+ SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf
+ SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf
+ SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf
+ SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf
+ SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
+ SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf
+ SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
+ SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf
+ SourceLevelDebugPkg/DebugAgentPei/DebugAgentPei.inf
+ SourceLevelDebugPkg/DebugAgentDxe/DebugAgentDxe.inf
+
+[BuildOptions]
+ *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.uni
new file mode 100644
index 00000000..8d2f06eb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkg.uni
@@ -0,0 +1,94 @@
+// /** @file
+// This package provides target side modules to support source level debug.
+//
+// This package provides target side modules to support source level debug.
+// The target side components includes the Debug Agent Library instance
+// to communicate with host side modules, Debug Communication Library and
+// instances to provide the communication I/O functions between Debug Agent
+// and host, PeCoffExtraActionLib instance to report symbol path information,
+// etc.
+//
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_PACKAGE_ABSTRACT #language en-US "This package provides target side modules to support source level debug."
+
+#string STR_PACKAGE_DESCRIPTION #language en-US "The target side components includes the Debug Agent Library instance\n"
+ "to communicate with host side modules, Debug Communication Library and\n"
+ "instances to provide the communication I/O functions between Debug Agent\n"
+ "and host, PeCoffExtraActionLib instance to report symbol path information,\n"
+ "etc."
+
+
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbDebugPortMemorySpaceBase_PROMPT #language en-US "Configure USB debug port memory BAR"
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbDebugPortMemorySpaceBase_HELP #language en-US "The memory BAR of USB debug port, it may be different from the memory BAR of EHCI host controller.<BR>\n"
+ "Note that the memory BAR address is only used before PCI bus resource allocation."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbEhciMemorySpaceBase_PROMPT #language en-US "Configure EHCI host controller memory BAR"
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbEhciMemorySpaceBase_HELP #language en-US "The memory BAR of EHCI host controller, in which USB debug feature is enabled.<BR>\n"
+ "Note that the memory BAR address is only used before PCI bus resource allocation."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbEhciPciAddress_PROMPT #language en-US "Configure EHCI host controller PCI address"
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbEhciPciAddress_HELP #language en-US "The PCI address of EHCI host controller, in which USB debug feature is enabled.<BR>\n"
+ "The format of PCI address is :<BR>\n"
+ "-----------------------------------------------------------------------<BR>\n"
+ "| Bits 28..31 | Bits 20..27 | Bits 15..19 | Bits 12..14 | Bits 00..11 |<BR>\n"
+ "-----------------------------------------------------------------------<BR>\n"
+ "| 0 | Bus | Device | Function | 0 |<BR>\n"
+ "-----------------------------------------------------------------------<BR>\n"
+ "For the value 0x000EF000, it means the PCI address at bus 0x0, device 0x1D, function 0x7."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_ERR_80000001 #language en-US "Invalid value provided."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdExceptionsIgnoredByDebugger_PROMPT #language en-US "Configure exception numbers not to be hooked by Debug Agent"
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdExceptionsIgnoredByDebugger_HELP #language en-US "The mask of exception numbers whose handlers would be ignored and cannot be replaced or\n"
+ "hooked by Debug Agent Library. Masking INT1/INT3 is invalid."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdDebugLoadImageMethod_PROMPT #language en-US "Select loading/unloading image break method"
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdDebugLoadImageMethod_HELP #language en-US "The method to issue break point to Debug Agent Library when loading/unloading image.<BR><BR>\n"
+ "1: Use I/O Port 84 to issue hardware break point<BR>\n"
+ "2: Use INT3 to issue software break point<BR>"
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdDebugPortHandleBufferSize_PROMPT #language en-US "Assign debug port buffer size"
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdDebugPortHandleBufferSize_HELP #language en-US "The data buffer size used by debug port in debug communication library instances.\n"
+ "Its value is not suggested to be changed in platform DSC file."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbXhciMemorySpaceBase_PROMPT #language en-US "Configure xhci host controller memory BAR."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbXhciMemorySpaceBase_HELP #language en-US "The memory BAR of xhci host controller, in which usb debug feature is enabled.\n"
+ "Note that the memory BAR address is only used before Pci bus resource allocation."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbXhciPciAddress_PROMPT #language en-US "Configure xhci host controller pci address."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbXhciPciAddress_HELP #language en-US "The pci address of xhci host controller, in which usb debug feature is enabled.\n"
+ "The format of pci address is :<BR>\n"
+ "-----------------------------------------------------------------------<BR>\n"
+ "| Bits 28..31 | Bits 20..27 | Bits 15..19 | Bits 12..14 | Bits 00..11 |<BR>\n"
+ "-----------------------------------------------------------------------<BR>\n"
+ "| 0 | Bus | Device | Function | 0 |<BR>\n"
+ "-----------------------------------------------------------------------<BR>\n"
+ "For the value 0x000A0000, it means the pci address at bus 0x0, device 0x14, function 0x0."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbXhciDebugDetectTimeout_PROMPT #language en-US "Configure debug device detection timeout value."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdUsbXhciDebugDetectTimeout_HELP #language en-US "Per XHCI spec, software shall impose a timeout between the detection of the Debug Host\n"
+ "connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdTransferProtocolRevision_PROMPT #language en-US "Default revision of the debug agent transfer protocol."
+
+#string STR_gEfiSourceLevelDebugPkgTokenSpaceGuid_PcdTransferProtocolRevision_HELP #language en-US "The upper 16 bits indicate the major revision and the lower 16 bits indicate\n"
+ "the minor revision.\n"
+ "For example, a value of 0x00000004 stands for revision 0.4.\n"
+ "Debug packet compression and decompression is supported since revision 0.4."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkgExtra.uni b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkgExtra.uni
new file mode 100644
index 00000000..560404d9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/SourceLevelDebugPkgExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// SourceLevelDebug Package Localized Strings and Content.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_PACKAGE_NAME
+#language en-US
+"SourceLevelDebug package"