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: https://github.com/tianocore/edk2/pull/12277

Suggested-by: Gerd Hoffmann <[email protected]>
Signed-off-by: Luigi Leonardi <[email protected]>
---
 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 
fbe3ca9e129db514aeb7b0bddd6432a818d0a09d..adba8fff2157b62957f6c8770de44faa8449b34d
 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 
7456614d0585af52662c4eb5bb9c4eb76e729a7b..bbea1bb84a4f7613195f5d3fac5fba31a0fb6e89
 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 
dba8ac7f2f49fc07a857f8af55786cb0ef960bd2..1dddfa6a11c1309f82c241cb1756a3e8f28a4ad0
 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: ae56950eac7b61b1abf42003329ee0f3ce111711
change-id: 20260311-edk2_arm_serial-e40226e695eb

Best regards,
-- 
Luigi Leonardi <[email protected]>


Reply via email to