From e260ba3fef9fededa9c9c5119d7555cc106c9261 Mon Sep 17 00:00:00 2001 From: Oliver Smith-Denny Date: Wed, 2 Oct 2024 15:16:59 -0700 Subject: [PATCH] Enable Debugger By Default in Q35/SBSA (#1036) ## Description This PR turns mu_feature_debugger on by default in Q35/SBSA. It sets no initial breakpoint, but will break in on an exception. As part of this, QemuRunner defaults to having `SERIAL_PORT=50001` if this is not overridden, so that on a regular boot of Q35 the debugger can easily be used. On SBSA, the serial port is not added by default, as it will prevent writing to stdout, making it hard to tell progress. An additional command line flag is added `BLD_*_DXE_DBG_BRK` to control whether the initial breakpoint is set. Passing `BLD_*_DXE_DBG_BRK=TRUE` on the commandline will set an unlimited initial breakpoint on DxeCore entrance. The other caveat in SBSA is that with a single serial port, debugger polling is disabled, otherwise the debugger can eat user keystrokes at the shell. Once supervised StMM support is added to mu_feature_debugger (https://github.com/microsoft/mu_feature_debugger/issues/59), it will be added here with a corresponding flag to force breaking in to the MM debugger. - [ ] Impacts functionality? - [ ] Impacts security? - [ ] Breaking change? - [ ] Includes tests? - [ ] Includes documentation? ## How This Was Tested Tested by booting Q35 with no exceptions, with an exception and breaking in, and with the force flag and breaking in on initial breakpoint. ## Integration Instructions See above. --- Features/DEBUGGER | 2 +- Platforms/Docs/Common/debugging.md | 23 +++++----- .../Plugins/QemuRunner/QemuRunner.py | 2 +- Platforms/QemuQ35Pkg/QemuQ35Pkg.dsc | 38 +++++++++++----- .../Plugins/QemuRunner/QemuRunner.py | 2 +- Platforms/QemuSbsaPkg/QemuSbsaPkg.dsc | 44 +++++++++++++------ 6 files changed, 74 insertions(+), 37 deletions(-) diff --git a/Features/DEBUGGER b/Features/DEBUGGER index 08e01ab5c..81a516e8f 160000 --- a/Features/DEBUGGER +++ b/Features/DEBUGGER @@ -1 +1 @@ -Subproject commit 08e01ab5c51b41f8dd1aa35328c1227b8a3047ac +Subproject commit 81a516e8f636e65ebed0efa2456eb2963cfb6667 diff --git a/Platforms/Docs/Common/debugging.md b/Platforms/Docs/Common/debugging.md index 47f6b1367..ebdc29f40 100644 --- a/Platforms/Docs/Common/debugging.md +++ b/Platforms/Docs/Common/debugging.md @@ -8,22 +8,25 @@ This document described different ways to debug on the QEMU platforms. Both Q35 and SBSA are setup to debug debugged using the MU debugger package. for more details on using this debugger, see the [FeatureDebuggerPkg Readme](https://github.com/microsoft/mu_feature_debugger/blob/main/DebuggerFeaturePkg/Readme.md). -By default the debugger is disabled, to enable you must both enable the debugger -build flag to enable the source debug device state flag and specify a serial port -TCP port. - +By default the debugger is enabled to break in on exceptions, but not to break in +on an initial breakpoint. To enable the initial breakpoint in DXE, you must pass: ``` -stuart_build -c Platforms\QemuQ35Pkg\PlatformBuild.py BLD_*_DEBUGGER_ENABLED=TRUE SERIAL_PORT=5555 --flashrom +stuart_build -c Platforms\QemuQ35Pkg\PlatformBuild.py BLD_*_DXE_DBG_BRK=TRUE --FlashRom ``` On Q35 this allows for debugging over a different port then the usual debug output because Q35 has a seperate serial port available to it. On SBSA the serial port -will be shared with the logging output. +will be shared with the logging output. As a result, on Q35, if `SERIAL_PORT=` +is not passed on the cmdline, a default serial port at 50001 will be created. On SBSA, +no default port is set because it will prevent output from occuring on stdout, which +makes even telling if an exception occurred difficult. + +Currently this will only enable the DXE debugger. The MM debugger will be added to Q35 +once it support supervised Standalone MM. -Currently this will only enable the DXE debugger. The MM debugger must be manually -enabled using the PcdForceEnableDebugger if the DebugAgent has been configured. -By default, the DXE debugger will stall for 30 seconds on the initial breakpoint -before attempting to continue execution. +When an exception occurs, the debugger will break in and wait for a debugger client to +connect. This makes Q35 and SBSA very debuggable, because they will break in on +exceptions always, meaning a reboot is not required. ## Debugging using QEMU GDB Server diff --git a/Platforms/QemuQ35Pkg/Plugins/QemuRunner/QemuRunner.py b/Platforms/QemuQ35Pkg/Plugins/QemuRunner/QemuRunner.py index 4b074ba1c..ef0e356dd 100644 --- a/Platforms/QemuQ35Pkg/Plugins/QemuRunner/QemuRunner.py +++ b/Platforms/QemuQ35Pkg/Plugins/QemuRunner/QemuRunner.py @@ -222,7 +222,7 @@ def Runner(env): args += " -gdb tcp::" + gdb_port # write ConOut messages to telnet localhost port - serial_port = env.GetValue("SERIAL_PORT") + serial_port = env.GetValue("SERIAL_PORT", "50001") if serial_port != None: args += " -serial tcp:127.0.0.1:" + serial_port + ",server,nowait" diff --git a/Platforms/QemuQ35Pkg/QemuQ35Pkg.dsc b/Platforms/QemuQ35Pkg/QemuQ35Pkg.dsc index 243b3b5c8..52d62b1df 100644 --- a/Platforms/QemuQ35Pkg/QemuQ35Pkg.dsc +++ b/Platforms/QemuQ35Pkg/QemuQ35Pkg.dsc @@ -29,8 +29,12 @@ # Defines for default states. These can be changed on the command line. # -D FLAG=VALUE # -!ifndef DEBUGGER_ENABLED - DEFINE DEBUGGER_ENABLED = FALSE + + # + # DXE_DBG_BRK will force the DXE debugger to break in as early as possible and wait indefinitely + # +!ifndef DXE_DBG_BRK + DEFINE DXE_DBG_BRK = FALSE !endif !ifndef TPM_ENABLE DEFINE TPM_ENABLE = FALSE @@ -604,11 +608,7 @@ !endif [PcdsPatchableInModule] -!if $(DEBUGGER_ENABLED) == TRUE gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x17 -!else - gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F -!endif [PcdsFixedAtBuild] !include QemuPkg/AutoGen/SecurebootPcds.inc @@ -732,6 +732,23 @@ # CMOS region is 128 bytes gMsWheaPkgTokenSpaceGuid.PcdMsWheaReportEarlyStorageCapacity|0x80 + ## Controls the debug configuration flags. + # Bit 0 - Controls whether the debugger will break in on initialization. + # Bit 1 - Controls whether the DXE debugger is enabled. + # Bit 2 - Controls whether the MM debugger is enabled. + # Bit 3 - Disables the debuggers periodic polling for a requested break-in. + # if BLD_*_DXE_DBG_BRK=TRUE, the debugger will have an initial break in, but will break in, otherwise it only will + # on exceptions +!if $(DXE_DBG_BRK) == TRUE + DebuggerFeaturePkgTokenSpaceGuid.PcdDebugConfigFlags|0x3 +!else + DebuggerFeaturePkgTokenSpaceGuid.PcdDebugConfigFlags|0x2 +!endif + + # Set the debugger timeout to wait forever. This only takes effect if Bit 0 of PcdDebugConfigFlags is set + # to 1, which by default it is not. Using BLD_*_DXE_DBG_BRK=TRUE will set this to 1. + DebuggerFeaturePkgTokenSpaceGuid.PcdInitialBreakpointTimeoutMs|0 + [PcdsFixedAtBuild.IA32] # # The NumberOfPages values below are ad-hoc. They are updated sporadically at @@ -831,12 +848,11 @@ gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr|0 # Add DEVICE_STATE_UNIT_TEST_MODE to the device state bitmask if BUILD_UNIT_TESTS=TRUE (default) + # in addition to debugger enabled !if $(BUILD_UNIT_TESTS) == TRUE - gEfiMdeModulePkgTokenSpaceGuid.PcdDeviceStateBitmask|0x20 - !endif - - # Set to debug if debugger is enabled. - !if $(DEBUGGER_ENABLED) == TRUE + gEfiMdeModulePkgTokenSpaceGuid.PcdDeviceStateBitmask|0x28 + !else + # Set to debug as debugger is enabled. gEfiMdeModulePkgTokenSpaceGuid.PcdDeviceStateBitmask|0x08 !endif diff --git a/Platforms/QemuSbsaPkg/Plugins/QemuRunner/QemuRunner.py b/Platforms/QemuSbsaPkg/Plugins/QemuRunner/QemuRunner.py index eadadd62b..01e56751d 100644 --- a/Platforms/QemuSbsaPkg/Plugins/QemuRunner/QemuRunner.py +++ b/Platforms/QemuSbsaPkg/Plugins/QemuRunner/QemuRunner.py @@ -132,7 +132,7 @@ def Runner(env): args += " -gdb tcp::" + gdb_port # write ConOut messages to telnet localhost port - serial_port = env.GetValue("SERIAL_PORT") + serial_port = env.GetValue("SERIAL_PORT", "50001") if serial_port != None: args += " -serial tcp:127.0.0.1:" + serial_port + ",server,nowait" else: diff --git a/Platforms/QemuSbsaPkg/QemuSbsaPkg.dsc b/Platforms/QemuSbsaPkg/QemuSbsaPkg.dsc index 6757374d5..66bd1bb98 100644 --- a/Platforms/QemuSbsaPkg/QemuSbsaPkg.dsc +++ b/Platforms/QemuSbsaPkg/QemuSbsaPkg.dsc @@ -50,9 +50,14 @@ # Defines for default states. These can be changed on the command line. # -D FLAG=VALUE # - !ifndef DEBUGGER_ENABLED - DEFINE DEBUGGER_ENABLED = FALSE - !endif + + # + # DXE_DBG_BRK will force the DXE debugger to break in as early as possible and wait indefinitely + # +!ifndef DXE_DBG_BRK + DEFINE DXE_DBG_BRK = FALSE +!endif + DEFINE TTY_TERMINAL = FALSE DEFINE TPM2_ENABLE = FALSE DEFINE TPM2_CONFIG_ENABLE = FALSE @@ -587,11 +592,7 @@ # CLEAR_MEMORY_ENABLED 0x08 # ASSERT_BREAKPOINT_ENABLED 0x10 # ASSERT_DEADLOOP_ENABLED 0x20 -!if $(TARGET) == RELEASE - gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x21 -!else - gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xff -!endif + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x17 [PcdsFixedAtBuild.common] !include QemuPkg/AutoGen/SecurebootPcds.inc @@ -794,6 +795,24 @@ # Set this to be gOemConfigPolicyGuid gSetupDataPkgTokenSpaceGuid.PcdConfigurationPolicyGuid|{GUID("ba320ade-e132-4c99-a3df-74d673ea6f76")} + ## Controls the debug configuration flags. + # Bit 0 - Controls whether the debugger will break in on initialization. + # Bit 1 - Controls whether the DXE debugger is enabled. + # Bit 2 - Controls whether the MM debugger is enabled. + # Bit 3 - Disables the debuggers periodic polling for a requested break-in. + # For SBSA, we have to disable the periodic polling, because there is only one one serial port and the debug agent + # may eat console input if let poll on it. If BLD_*_DXE_DBG_BRK is set to TRUE, then the debugger will break in on + # initialization. Otherwise, the debugger will not break in on initialization. + !if $(DXE_DBG_BRK) == TRUE + DebuggerFeaturePkgTokenSpaceGuid.PcdDebugConfigFlags|0xB + !else + DebuggerFeaturePkgTokenSpaceGuid.PcdDebugConfigFlags|0xA + !endif + + # Set the debugger timeout to wait forever. This only takes effect if Bit 0 of PcdDebugConfigFlags is set + # to 1, which by default it is not. Using BLD_*_DXE_DBG_BRK=TRUE will set this to 1. + DebuggerFeaturePkgTokenSpaceGuid.PcdInitialBreakpointTimeoutMs|0 + [PcdsFixedAtBuild.common] gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId|"Palindrome" gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId|0x756D6551754D #MuQemuArm @@ -863,12 +882,11 @@ gEfiNetworkPkgTokenSpaceGuid.PcdIPv6PXESupport|0x01 # Add DEVICE_STATE_UNIT_TEST_MODE to the device state bitmask if BUILD_UNIT_TESTS=TRUE (default) + # in addition to debugger enabled !if $(BUILD_UNIT_TESTS) == TRUE - gEfiMdeModulePkgTokenSpaceGuid.PcdDeviceStateBitmask|0x20 - !endif - - # Set to debug if debugger is enabled. - !if $(DEBUGGER_ENABLED) == TRUE + gEfiMdeModulePkgTokenSpaceGuid.PcdDeviceStateBitmask|0x28 + !else + # Set to debug as debugger is enabled. gEfiMdeModulePkgTokenSpaceGuid.PcdDeviceStateBitmask|0x08 !endif