Skip to content

ArmVirtPkg: allow runtime control of serial debug log level via DT#12277

Draft
luigix25 wants to merge 2 commits intotianocore:masterfrom
luigix25:arm_dt_level
Draft

ArmVirtPkg: allow runtime control of serial debug log level via DT#12277
luigix25 wants to merge 2 commits intotianocore:masterfrom
luigix25:arm_dt_level

Conversation

@luigix25
Copy link
Contributor

@luigix25 luigix25 commented Mar 11, 2026

Add support for a device-tree property "edk2,debug-level" on PL011 UART nodes. When present, this 32-bit cell overrides the compiled-in DebugPrintErrorLevel for serial port output, allowing the serial verbosity to be tuned at boot time without rebuilding the firmware.

When this property is not present, the original behavior (serial output follows DebugPrintErrorLevel) is preserved.

The memory debug log continues to use the compiled-in level.

Example DT snippet:

pl011@9000000 {
compatible = "arm,pl011";
edk2,debug-level = <0x80000000>;
...
};

Description

<Include a description of the change and why this change was made.>

<For each item, place an "x" in between [ and ] if true. Example: [x] (you can also check items in GitHub UI)>

<Create the PR as a Draft PR if it is only created to run CI checks.>

<Delete lines in <> tags before creating the PR.>

  • Breaking change?
    • Breaking change - Does this PR cause a break in build or boot behavior?
    • Examples: Does it add a new library class or move a module to a different repo.
  • Impacts security?
    • Security - Does this PR have a direct security impact?
    • Examples: Crypto algorithm change or buffer overflow fix.
  • Includes tests?
    • Tests - Does this PR include any explicit test code?
    • Examples: Unit tests or integration tests.

How This Was Tested

QEMU changes:

https://lore.kernel.org/qemu-devel/20260311-edk2_arm_serial-v1-1-c25e237116f3@redhat.com/

Integration Instructions

<Describe how these changes should be integrated. Use N/A if nothing is required.>

patchew-importer pushed a commit to patchew-project/qemu that referenced this pull request Mar 11, 2026
Add a machine property to pass a debug level to EDK2 firmware via the
device tree. The value is set as an "edk2,debug-level" property on all
pl011 UART nodes.

This is to create a runtime parameter to set the verbosity of the debug
log on the serial ports in edk2. Currently, the only way to set the
verbosity is a compile-time option.

DT is used because the fw_cfg interface is not yet initialized in early
boot phases.

Corresponding edk2 PR: tianocore/edk2#12277

Suggested-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
Message-Id: <20260311-edk2_arm_serial-v1-1-c25e237116f3@redhat.com>
p-b-o pushed a commit to p-b-o/qemu-ci that referenced this pull request Mar 11, 2026
Add a machine property to pass a debug level to EDK2 firmware via the
device tree. The value is set as an "edk2,debug-level" property on all
pl011 UART nodes.

This is to create a runtime parameter to set the verbosity of the debug
log on the serial ports in edk2. Currently, the only way to set the
verbosity is a compile-time option.

DT is used because the fw_cfg interface is not yet initialized in early
boot phases.

Corresponding edk2 PR: tianocore/edk2#12277

Suggested-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260311-edk2_arm_serial-v1-1-c25e237116f3@redhat.com
p-b-o pushed a commit to p-b-o/qemu-ci that referenced this pull request Mar 11, 2026
https://lore.kernel.org/qemu-devel/20260311-edk2_arm_serial-v1-1-c25e237116f3@redhat.com

---

From: Luigi Leonardi <leonardi@redhat.com>
Date: Wed, 11 Mar 2026 14:43:20 +0100
Subject: [PATCH] hw/arm/virt: add serial-debug-level property for EDK2 firmware
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
Message-Id: <20260311-edk2_arm_serial-v1-1-c25e237116f3@redhat.com>
X-B4-Tracking: v=1; b=H4sIAAAAAAAC/6tWKk4tykwtVrJSqFYqSi3LLM7MzwNyDHUUlJIzE
 vPSU3UzU4B8JSMDIzMDY0ND3dSUbKP4xKLceJDGxBzdVBMDIyOzVDNL09QkJaCugqLUtMwKsIn
 RsbW1APMn66NhAAAA
X-Change-ID: 20260311-edk2_arm_serial-e40226e695eb
To: qemu-devel@nongnu.org
Cc: Peter Maydell <peter.maydell@linaro.org>,
 Pierrick Bouvier <pierrick.bouvier@linaro.org>,
 Oliver Steffen <osteffen@redhat.com>, qemu-arm@nongnu.org,
 Gerd Hoffmann <kraxel@redhat.com>, Luigi Leonardi <leonardi@redhat.com>
X-Mailer: b4 0.14.2
Received-SPF: pass client-ip=170.10.129.124; envelope-from=leonardi@redhat.com;
 helo=us-smtp-delivery-124.mimecast.com
X-Spam_score_int: -3
X-Spam_score: -0.4
X-Spam_bar: /
X-Spam_report: (-0.4 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001,
 DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,
 RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001,
 RCVD_IN_VALIDITY_RPBL_BLOCKED=0.819, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.903,
 SPF_HELO_PASS=-0.001, SPF_PASS=-0.001,
 WEIRD_QUOTING=0.001 autolearn=no autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: qemu development <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org
Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org

Add a machine property to pass a debug level to EDK2 firmware via the
device tree. The value is set as an "edk2,debug-level" property on all
pl011 UART nodes.

This is to create a runtime parameter to set the verbosity of the debug
log on the serial ports in edk2. Currently, the only way to set the
verbosity is a compile-time option.

DT is used because the fw_cfg interface is not yet initialized in early
boot phases.

Corresponding edk2 PR: tianocore/edk2#12277

Suggested-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
---
 docs/system/arm/virt.rst |  6 ++++++
 hw/arm/virt.c            | 38 ++++++++++++++++++++++++++++++++++++++
 include/hw/arm/virt.h    |  2 ++
 3 files changed, 46 insertions(+)

diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
index fbe3ca9..adba8ff 100644
--- a/docs/system/arm/virt.rst
+++ b/docs/system/arm/virt.rst
@@ -239,6 +239,12 @@ x-oem-table-id
   Set string (up to 8 bytes) to override the default value of field OEM Table ID
   in ACPI table header.

+serial-debug-level
+  Set the EDK2 firmware debug level for serial port output. Valid values are
+  the debug level bitmasks defined in the EDK2
+  `DebugLib.h <https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/DebugLib.h>`_
+  header (e.g. ``0x00400000`` for ``DEBUG_INFO``).
+
 SMMU configuration
 """"""""""""""""""

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 7456614..bbea1bb 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -986,6 +986,11 @@ static void create_uart(const VirtMachineState *vms, int uart,

     nodename = g_strdup_printf("/pl011@%" PRIx64, base);
     qemu_fdt_add_subnode(ms->fdt, nodename);
+    if (vms->serial_debug_level_set) {
+        qemu_fdt_setprop_cell(ms->fdt, nodename, "edk2,debug-level",
+                              vms->serial_debug_level);
+    }
+
     /* Note that we can't use setprop_string because of the embedded NUL */
     qemu_fdt_setprop(ms->fdt, nodename, "compatible",
                          compat, sizeof(compat));
@@ -2869,6 +2874,31 @@ static void virt_set_dtb_randomness(Object *obj, bool value, Error **errp)
     vms->dtb_randomness = value;
 }

+static char *virt_get_serial_debug_level(Object *obj, Error **errp)
+{
+    VirtMachineState *vms = VIRT_MACHINE(obj);
+    return vms->serial_debug_level_set
+        ? g_strdup_printf("0x%" PRIx32, vms->serial_debug_level)
+        : g_strdup("");
+}
+
+static void
+virt_set_serial_debug_level(Object *obj, const char *value, Error **errp)
+{
+    VirtMachineState *vms = VIRT_MACHINE(obj);
+    uint64_t val;
+    int ret;
+
+    ret = qemu_strtou64(value, NULL, 0, &val);
+    if (ret < 0 || val > UINT32_MAX) {
+        error_setg(errp, "invalid serial-debug-level value '%s', "
+                   "must be a uint32 value", value);
+        return;
+    }
+    vms->serial_debug_level = (uint32_t)val;
+    vms->serial_debug_level_set = true;
+}
+
 static char *virt_get_oem_id(Object *obj, Error **errp)
 {
     VirtMachineState *vms = VIRT_MACHINE(obj);
@@ -3643,6 +3673,12 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
                                           "in ACPI table header."
                                           "The string may be up to 8 bytes in size");

+    object_class_property_add_str(oc, "serial-debug-level",
+                                  virt_get_serial_debug_level,
+                                  virt_set_serial_debug_level);
+    object_class_property_set_description(oc, "serial-debug-level",
+                                          "Set the EDK2 firmware debug level bitmask for "
+                                          "serial port output");
 }

 static void virt_instance_init(Object *obj)
@@ -3692,6 +3728,8 @@ static void virt_instance_init(Object *obj)

     vms->virtio_transports = NUM_VIRTIO_TRANSPORTS;

+    vms->serial_debug_level_set = false;
+
     virt_flash_create(vms);

     vms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index dba8ac7..1dddfa6 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -187,6 +187,8 @@ struct VirtMachineState {
     MemoryRegion *sysmem;
     MemoryRegion *secure_sysmem;
     bool pci_preserve_config;
+    uint32_t serial_debug_level;
+    bool serial_debug_level_set;
 };

 #define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)

---
base-commit: ae56950
change-id: 20260311-edk2_arm_serial-e40226e695eb

Best regards,
--
Luigi Leonardi <leonardi@redhat.com>

Signed-off-by: GitHub Actions Bot <bot@github.com>
Add `DebugLevel` and `DebugLevelSet` to the `FDT_SERIAL_PORTS` struct.

This will be used by ArmVirt, to get the debug log level for serial ports at
runtime using the device tree.

Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
Add support for a device-tree property "edk2,debug-level" on PL011 UART
nodes. When present, this 32-bit cell overrides the compiled-in
DebugPrintErrorLevel for serial port output, allowing the serial
verbosity to be tuned at boot time without rebuilding the firmware.

When this property is not present, the original behavior (serial output
follows DebugPrintErrorLevel) is preserved.

The memory debug log continues to use the compiled-in level.

Example DT snippet:

  pl011@9000000 {
      compatible = "arm,pl011";
      edk2,debug-level = <0x80000000>;
      ...
  };

Suggested-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
Comment on lines +23 to +24
BOOLEAN mRuntimeDebugLevelSet;
UINT32 mRuntimeDebugLevel;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
BOOLEAN mRuntimeDebugLevelSet;
UINT32 mRuntimeDebugLevel;
BOOLEAN mDebugLibFdtPL011UartRuntimeDebugLevelSet;
UINT32 mDebugLibFdtPL011UartRuntimeDebugLevel;

To avoid possible name conflict from other compilation objects.

@osteffenrh
Copy link
Contributor

Apart from the CI and my comment above: LGTM.

I tested with QEMU in tcg mode.
I dumped the original dtb and modified it manyally:

qemu-system-aarch64 -M virt -machine dumpdtb=file.dtb
dtc -I dtb -O dts -o file.dts file.dtb
# modify dts
dtc -I dts -O dtb -o file2.dtb file.dts

qemu-system-aarch64  \
  -machine virt,dtb=./file2.dtb \
  ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants