>From Windows 8.1 onwards ISA serial IRQs cannot be shared when ACPI Revision 5.0 is used in the FACP table. The reason for this is that if a 2-byte IRQ Descriptor is used then the interrupt is considered to be high true, edge sensitive, non-shareable. Since legacy serial ports COM1/3 and COM2/4 share an IRQ then if more than 2 serial ports are added, Windows indicates a conflict in Device Manager and these combinations cannot be used together.
Add a new 3-byte IRQ Descriptor to the _CRS resource indicating that the ISA serial IRQ is low true, edge sensitive and shareable, along with a corresponding _PRS resource so that the legacy serial ports also appear at a fixed address. This enables all 4 legacy serial ports to be used in Windows without conflict. Finally add a new x-acpi-shared-irq property to disable the ACPI IRQ descriptor changes for older PC machine types, and add it to the pc_compat_10_2[] array. Signed-off-by: Mark Cave-Ayland <[email protected]> --- hw/char/serial-isa.c | 23 ++++++++++++++++++++++- hw/i386/pc.c | 4 +++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index a4be0492c5..1662da86bd 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -28,6 +28,7 @@ #include "qemu/module.h" #include "system/system.h" #include "hw/acpi/acpi_aml_interface.h" +#include "hw/acpi/aml-build.h" #include "hw/char/serial.h" #include "hw/char/serial-isa.h" #include "hw/isa/isa.h" @@ -43,6 +44,7 @@ struct ISASerialState { uint32_t index; uint32_t iobase; uint32_t isairq; + bool acpi_shared_irq; SerialState state; }; @@ -92,7 +94,12 @@ static void serial_isa_build_aml(AcpiDevAmlIf *adev, Aml *scope) crs = aml_resource_template(); aml_append(crs, aml_io(AML_DECODE16, isa->iobase, isa->iobase, 0x00, 0x08)); - aml_append(crs, aml_irq_no_flags(isa->isairq)); + if (isa->acpi_shared_irq) { + aml_append(crs, aml_irq(isa->isairq, AML_EDGE, AML_ACTIVE_LOW, + AML_SHARED)); + } else { + aml_append(crs, aml_irq_no_flags(isa->isairq)); + } dev = aml_device("COM%d", isa->index + 1); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0501"))); @@ -100,6 +107,18 @@ static void serial_isa_build_aml(AcpiDevAmlIf *adev, Aml *scope) aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); aml_append(dev, aml_name_decl("_CRS", crs)); + if (isa->acpi_shared_irq) { + Aml *prs = aml_resource_template(); + + aml_append(prs, aml_start_dependent_function(0, 0)); + aml_append(prs, aml_io(AML_DECODE16, isa->iobase, isa->iobase, 0x00, + 0x08)); + aml_append(prs, aml_irq(isa->isairq, AML_EDGE, AML_ACTIVE_LOW, + AML_SHARED)); + aml_append(prs, aml_end_dependent_function()); + aml_append(dev, aml_name_decl("_PRS", prs)); + } + aml_append(scope, dev); } @@ -117,6 +136,8 @@ static const Property serial_isa_properties[] = { DEFINE_PROP_UINT32("index", ISASerialState, index, -1), DEFINE_PROP_UINT32("iobase", ISASerialState, iobase, -1), DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), + DEFINE_PROP_BOOL("x-acpi-shared-irq", ISASerialState, acpi_shared_irq, + true), }; static void serial_isa_class_initfn(ObjectClass *klass, const void *data) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 0dd3fd01d9..c0335b05ba 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -82,7 +82,9 @@ { "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\ { "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, }, -GlobalProperty pc_compat_10_2[] = {}; +GlobalProperty pc_compat_10_2[] = { + { "isa-serial", "x-acpi-shared-irq", "false" }, +}; const size_t pc_compat_10_2_len = G_N_ELEMENTS(pc_compat_10_2); GlobalProperty pc_compat_10_1[] = { -- 2.43.0
