Skip to content

Instantly share code, notes, and snippets.

@andyvand
Last active December 12, 2025 17:24
Show Gist options
  • Select an option

  • Save andyvand/26ca76b8e37953f5be894074ce62532d to your computer and use it in GitHub Desktop.

Select an option

Save andyvand/26ca76b8e37953f5be894074ce62532d to your computer and use it in GitHub Desktop.
QEMU Windows RT ARM (8.1/10) patch
diff -Nur qemu-10.1.3/hw/arm/virt-acpi-build.c qemu-10.1.3-winrt/hw/arm/virt-acpi-build.c
--- qemu-10.1.3/hw/arm/virt-acpi-build.c 2025-12-06 16:26:44
+++ qemu-10.1.3-winrt/hw/arm/virt-acpi-build.c 2025-12-12 18:19:56
@@ -139,6 +139,58 @@
aml_append(table, scope);
}
+static void acpi_dsdt_add_ehci(Aml *scope, const MemMapEntry *ehci_memmap,
+ uint32_t ehci_irq)
+{
+ Aml *dev = aml_device("USB0");
+ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0D20")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+
+ Aml *crs = aml_resource_template();
+ aml_append(crs,
+ aml_memory32_fixed(ehci_memmap->base,
+ ehci_memmap->size, AML_READ_WRITE));
+ aml_append(crs,
+ aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
+ AML_EXCLUSIVE, &ehci_irq, 1));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+}
+
+static void acpi_dsdt_add_mmci(Aml *scope, const MemMapEntry *sdhci_memmap,
+ uint32_t sdhci_irq)
+{
+ Aml *dev = aml_device("SDC1");
+ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0D40")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+
+ Aml *crs = aml_resource_template();
+ aml_append(crs,
+ aml_memory32_fixed(sdhci_memmap->base,
+ sdhci_memmap->size, AML_READ_WRITE));
+ aml_append(crs,
+ aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
+ AML_EXCLUSIVE, &sdhci_irq, 1));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+
+ /* Add a child device that represents the SD card,
+ which is marked as non-removable */
+ Aml *carddev = aml_device("SDMM");
+
+ Aml *adr = aml_method("_ADR", 0, AML_NOTSERIALIZED);
+ aml_append(adr, aml_return(aml_int(0)));
+
+ Aml *rmv = aml_method("_RMV", 0, AML_NOTSERIALIZED);
+ aml_append(rmv, aml_return(aml_int(0)));
+
+ aml_append(carddev, adr);
+ aml_append(carddev, rmv);
+ aml_append(dev, carddev);
+
+ aml_append(scope, dev);
+}
+
+#ifdef USE_ARM_PCI
static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
uint32_t irq, VirtMachineState *vms)
{
@@ -176,6 +228,7 @@
build_acpi0017(scope);
}
}
+#endif
static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
uint32_t gpio_irq)
@@ -932,7 +985,14 @@
virtio_acpi_dsdt_add(scope, memmap[VIRT_MMIO].base, memmap[VIRT_MMIO].size,
(irqmap[VIRT_MMIO] + ARM_SPI_BASE),
0, NUM_VIRTIO_TRANSPORTS);
+
+#ifdef USE_ARM_PCI
acpi_dsdt_add_pci(scope, memmap, irqmap[VIRT_PCIE] + ARM_SPI_BASE, vms);
+#endif
+
+ acpi_dsdt_add_ehci(scope, &memmap[VIRT_EHCI], irqmap[VIRT_EHCI] + ARM_SPI_BASE);
+ acpi_dsdt_add_mmci(scope, &memmap[VIRT_SDHCI], irqmap[VIRT_SDHCI] + ARM_SPI_BASE);
+
if (vms->acpi_dev) {
build_ged_aml(scope, "\\_SB."GED_DEVICE,
HOTPLUG_HANDLER(vms->acpi_dev),
@@ -955,6 +1015,7 @@
}
acpi_dsdt_add_power_button(scope);
+
#ifdef CONFIG_TPM
acpi_dsdt_add_tpm(scope, vms);
#endif
diff -Nur qemu-10.1.3/hw/arm/virt.c qemu-10.1.3-winrt/hw/arm/virt.c
--- qemu-10.1.3/hw/arm/virt.c 2025-12-06 16:26:44
+++ qemu-10.1.3-winrt/hw/arm/virt.c 2025-12-12 18:19:19
@@ -91,6 +91,8 @@
#include "hw/cxl/cxl.h"
#include "hw/cxl/cxl_host.h"
#include "qemu/guest-random.h"
+#include "hw/sd/sdhci.h"
+#include "hw/usb/hcd-ehci.h"
static GlobalProperty arm_virt_compat[] = {
{ TYPE_VIRTIO_IOMMU_PCI, "aw-bits", "48" },
@@ -187,7 +189,11 @@
[VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN},
[VIRT_PVTIME] = { 0x090a0000, 0x00010000 },
[VIRT_SECURE_GPIO] = { 0x090b0000, 0x00001000 },
+#ifdef USE_ARM_PCI
[VIRT_ACPI_PCIHP] = { 0x090c0000, ACPI_PCIHP_SIZE },
+#endif
+ [VIRT_EHCI] = { 0x090c0000, 0x00001000 },
+ [VIRT_SDHCI] = { 0x090d0000, 0x00000100 },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
@@ -239,6 +245,8 @@
[VIRT_GPIO] = 7,
[VIRT_UART1] = 8,
[VIRT_ACPI_GED] = 9,
+ [VIRT_EHCI] = 11,
+ [VIRT_SDHCI] = 12,
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
[VIRT_SMMU] = 74, /* ...to 74 + NUM_SMMU_IRQS - 1 */
@@ -691,7 +699,9 @@
SysBusDevice *sbdev;
int irq = vms->irqmap[VIRT_ACPI_GED];
uint32_t event = ACPI_GED_PWR_DOWN_EVT;
+#ifdef USE_ARM_PCI
bool acpi_pcihp;
+#endif
if (ms->ram_slots) {
event |= ACPI_GED_MEM_HOTPLUG_EVT;
@@ -711,6 +721,7 @@
sysbus_mmio_map_name(sbdev, ACPI_MEMHP_REGION_NAME,
vms->memmap[VIRT_PCDIMM_ACPI].base);
+#ifdef USE_ARM_PCI
acpi_pcihp = object_property_get_bool(OBJECT(dev),
ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, NULL);
@@ -721,6 +732,7 @@
vms->memmap[VIRT_ACPI_PCIHP].base);
assert(pcihp_region_index >= 0);
}
+#endif
sysbus_connect_irq(sbdev, 0, qdev_get_gpio_in(vms->gic, irq));
@@ -1443,6 +1455,45 @@
0x7 /* PCI irq */);
}
+static void create_ehci(const VirtMachineState *vms, int ehci)
+{
+ sysbus_create_simple(TYPE_PLATFORM_EHCI, vms->memmap[ehci].base,
+ qdev_get_gpio_in(vms->gic, vms->irqmap[ehci]));
+}
+
+static void create_sdhci(const VirtMachineState *vms)
+{
+
+ hwaddr base = vms->memmap[VIRT_SDHCI].base;
+ int irq = vms->irqmap[VIRT_SDHCI];
+ DeviceState *dev;
+ SysBusDevice *busdev;
+ DriveInfo *di;
+ BlockBackend *blk;
+ DeviceState *carddev;
+ BusState *bus;
+
+ dev = qdev_new(TYPE_SYSBUS_SDHCI);
+ qdev_prop_set_uint8(dev, "sd-spec-version", 2);
+ qdev_prop_set_uint64(dev, "capareg", VIRT_SDHCI_CAPABILITIES);
+
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(busdev, &error_fatal);
+ sysbus_mmio_map(busdev, 0, base);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(vms->gic, irq));
+
+ di = drive_get(IF_SD, 0, 0);
+ blk = di ? blk_by_legacy_dinfo(di) : NULL;
+ bus = qdev_get_child_bus(dev, "sd-bus");
+ if (bus == NULL) {
+ error_report("No SD bus found");
+ exit(1);
+ }
+ carddev = qdev_new(TYPE_SD_CARD);
+ qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
+ qdev_realize_and_unref(carddev, bus, &error_fatal);
+}
+
static void create_smmu(const VirtMachineState *vms,
PCIBus *bus)
{
@@ -2310,9 +2361,9 @@
aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL);
- if (!vms->secure) {
- object_property_set_bool(cpuobj, "has_el3", false, NULL);
- }
+ /* Enable EL3 even when secure=false, for Windows on ARM 32-Bit
+ Note: proper TrustZone with ATF+EDK2 does not work as of now */
+ object_property_set_bool(cpuobj, "has_el3", true, NULL);
if (!vms->virt && object_property_find(cpuobj, "has_el2")) {
object_property_set_bool(cpuobj, "has_el2", false, NULL);
@@ -2465,6 +2516,7 @@
create_rtc(vms);
create_pcie(vms);
+
create_cxl_host_reg_region(vms);
if (has_ged && aarch64 && firmware_loaded && virt_is_acpi_enabled(vms)) {
@@ -2486,6 +2538,12 @@
* no backend is created the transport will just sit harmlessly idle.
*/
create_virtio_devices(vms);
+
+ /* Create platform EHCI controller device */
+ create_ehci(vms, VIRT_EHCI);
+
+ /* Create platform SD host controller device */
+ create_sdhci(vms);
vms->fw_cfg = create_fw_cfg(vms, &address_space_memory);
rom_set_fw(vms->fw_cfg);
diff -Nur qemu-10.1.3/hw/intc/arm_gicv2m.c qemu-10.1.3-winrt/hw/intc/arm_gicv2m.c
--- qemu-10.1.3/hw/intc/arm_gicv2m.c 2025-12-06 16:26:44
+++ qemu-10.1.3-winrt/hw/intc/arm_gicv2m.c 2025-12-12 15:57:16
@@ -155,7 +155,13 @@
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->spi[i]);
}
+#ifdef USE_ARM_GPIO
msi_nonbroken = true;
+#else
+ fprintf(stderr, "%s: Disable MSI-X for Windows 10 ARM64 on KVM\n", __func__);
+ msi_nonbroken = false;
+#endif
+
kvm_gsi_direct_mapping = true;
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
}
diff -Nur qemu-10.1.3/include/hw/acpi/acpi-defs.h qemu-10.1.3-winrt/include/hw/acpi/acpi-defs.h
--- qemu-10.1.3/include/hw/acpi/acpi-defs.h 2025-12-06 16:26:45
+++ qemu-10.1.3-winrt/include/hw/acpi/acpi-defs.h 2025-12-12 16:04:44
@@ -98,6 +98,45 @@
uint64_t addr; /* Address */
} AcpiGas;
+#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
+ uint32_t signature; /* ACPI signature (4 ASCII characters) */ \
+ uint32_t length; /* Length of table, in bytes, including header */ \
+ uint8_t revision; /* ACPI Specification minor version # */ \
+ uint8_t checksum; /* To make sum of entire table == 0 */ \
+ uint8_t oem_id[6] \
+ QEMU_NONSTRING; /* OEM identification */ \
+ uint8_t oem_table_id[8] \
+ QEMU_NONSTRING; /* OEM table identification */ \
+ uint32_t oem_revision; /* OEM revision number */ \
+ uint8_t asl_compiler_id[4] \
+ QEMU_NONSTRING; /* ASL compiler vendor ID */ \
+ uint32_t asl_compiler_revision; /* ASL compiler revision number */
+
+struct AcpiDebugPort2 {
+ ACPI_TABLE_HEADER_DEF
+ uint32_t debug_devices_offset;
+ uint32_t number_debug_devices;
+ struct {
+ uint8_t revision;
+ uint16_t length;
+ uint8_t number_generic_address_registers;
+ uint16_t namespace_string_length;
+ uint16_t namespace_string_offset;
+ uint16_t oem_data_length;
+ uint16_t oem_data_offset;
+ uint16_t port_type;
+ uint16_t port_subtype;
+ uint8_t reserved1[2];
+ uint16_t base_address_register_offset;
+ uint16_t address_size_offset;
+ struct AcpiGenericAddress base_address[1];
+ uint32_t address_size[1];
+ uint8_t namespace_string[2];
+ } QEMU_PACKED debug_devices[1];
+} QEMU_PACKED;
+typedef struct AcpiDebugPort2
+ AcpiDebugPort2;
+
/* SPCR (Serial Port Console Redirection table) */
typedef struct AcpiSpcrData {
uint8_t interface_type;
diff -Nur qemu-10.1.3/include/hw/arm/virt.h qemu-10.1.3-winrt/include/hw/arm/virt.h
--- qemu-10.1.3/include/hw/arm/virt.h 2025-12-06 16:26:45
+++ qemu-10.1.3-winrt/include/hw/arm/virt.h 2025-12-12 17:30:11
@@ -64,6 +64,8 @@
VIRT_GIC_REDIST,
VIRT_SMMU,
VIRT_UART0,
+ VIRT_EHCI,
+ VIRT_SDHCI,
VIRT_MMIO,
VIRT_RTC,
VIRT_FW_CFG,
@@ -182,6 +184,8 @@
};
#define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)
+
+#define VIRT_SDHCI_CAPABILITIES 0x057834b4
#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
OBJECT_DECLARE_TYPE(VirtMachineState, VirtMachineClass, VIRT_MACHINE)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment