From 011496bda030e40bf4ae37194e5028561afdf16a Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Fri, 23 Aug 2019 13:20:02 -0700 Subject: [PATCH] arch: acpi: Fix legacy interrupt for serial device The DSDT must declare the interrupt used by the serial device. This helps the guest kernel matching the right interrupt to the 8250 serial device. This is mandatory in case the IRQ routing is handled by ACPI, as we must let ACPI know what do do with pin based interrupts. One thing to notice, if we were using acpi=noirq from the kernel command line, this would mean ACPI is not in charge of the IRQ routing, and the device COM1 declaration would not be needed. One additional requirement is to provide the appropriate interrupt source override for the legacy ISA interrupts (0-15), which will give the right information to the guest kernel about how to allocate the associated IRQs. Because we want to keep the MADT as simple as possible, and given that our only device requiring pin based interrupt is the serial device, we choose to only define the pin 4. Signed-off-by: Sebastien Boeuf --- arch/src/x86_64/acpi.rs | 49 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/arch/src/x86_64/acpi.rs b/arch/src/x86_64/acpi.rs index a3036fb9f..85c010344 100644 --- a/arch/src/x86_64/acpi.rs +++ b/arch/src/x86_64/acpi.rs @@ -27,6 +27,17 @@ struct IOAPIC { pub gsi_base: u32, } +#[repr(packed)] +#[derive(Default)] +struct InterruptSourceOverride { + pub r#type: u8, + pub length: u8, + pub bus: u8, + pub source: u8, + pub gsi: u32, + pub flags: u16, +} + #[repr(packed)] #[derive(Default)] struct PCIRangeEntry { @@ -131,12 +142,31 @@ pub fn create_dsdt_table(serial_enabled: bool) -> SDT { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x79, 0x00, ]; + /* + Device (_SB.COM1) + { + Name (_HID, EisaId ("PNP0501") /* 16550A-compatible COM Serial Port */) // _HID: Hardware ID + Name (_UID, Zero) // _UID: Unique ID + Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings + { + Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, ) + { + 0x00000004, + } + IO (Decode16, + 0x03F8, // Range Minimum + 0x03F8, // Range Maximum + 0x00, // Alignment + 0x08, // Length + ) + }) + } + */ let com1_dsdt_data = [ - 0x10u8, 0x49, 0x04, 0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x50, 0x43, 0x49, 0x30, 0x5B, 0x82, 0x3C, - 0x49, 0x53, 0x41, 0x5F, 0x08, 0x5F, 0x41, 0x44, 0x52, 0x0C, 0x00, 0x00, 0x01, 0x00, 0x5B, - 0x82, 0x2B, 0x43, 0x4F, 0x4D, 0x31, 0x08, 0x5F, 0x48, 0x49, 0x44, 0x0C, 0x41, 0xD0, 0x05, - 0x01, 0x08, 0x5F, 0x55, 0x49, 0x44, 0x01, 0x08, 0x5F, 0x43, 0x52, 0x53, 0x11, 0x10, 0x0A, - 0x0D, 0x47, 0x01, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x08, 0x22, 0x10, 0x00, 0x79, 0x00, + 0x5Bu8, 0x82, 0x36, 0x2E, 0x5F, 0x53, 0x42, 0x5F, 0x43, 0x4F, 0x4D, 0x31, 0x08, 0x5F, 0x48, + 0x49, 0x44, 0x0C, 0x41, 0xD0, 0x05, 0x01, 0x08, 0x5F, 0x55, 0x49, 0x44, 0x00, 0x08, 0x5F, + 0x43, 0x52, 0x53, 0x11, 0x16, 0x0A, 0x13, 0x89, 0x06, 0x00, 0x03, 0x01, 0x04, 0x00, 0x00, + 0x00, 0x47, 0x01, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x08, 0x79, 0x00, ]; // DSDT @@ -211,6 +241,15 @@ pub fn create_acpi_tables( ..Default::default() }); + madt.append(InterruptSourceOverride { + r#type: 2, + length: 10, + bus: 0, + source: 4, + gsi: 4, + flags: 0, + }); + let madt_offset = facp_offset.checked_add(facp.len() as u64).unwrap(); guest_mem .write_slice(madt.as_slice(), madt_offset)