From 213da7d8623690df7f346049e5190591c488aa28 Mon Sep 17 00:00:00 2001 From: Henry Wang Date: Sun, 31 Jan 2021 14:27:01 +0800 Subject: [PATCH] acpi: Implement SPCR on AArch64 This commit implements an AArch64-required ACPI table: Serial Port Console Redirection Table (SPCR). The table provides information about the configuration and use of the serial port or non-legacy UART interface. Signed-off-by: Henry Wang --- acpi_tables/src/sdt.rs | 9 +++++ vmm/src/acpi.rs | 78 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/acpi_tables/src/sdt.rs b/acpi_tables/src/sdt.rs index 894bd27cd..e6e465ce4 100644 --- a/acpi_tables/src/sdt.rs +++ b/acpi_tables/src/sdt.rs @@ -22,6 +22,15 @@ impl GenericAddress { address: u64::from(address), } } + pub fn mmio_address(address: u64) -> Self { + GenericAddress { + address_space_id: 0, + register_bit_width: 8 * std::mem::size_of::() as u8, + register_bit_offset: 0, + access_size: std::mem::size_of::() as u8, + address, + } + } } pub struct Sdt { diff --git a/vmm/src/acpi.rs b/vmm/src/acpi.rs index 47748322b..1de4010a0 100644 --- a/vmm/src/acpi.rs +++ b/vmm/src/acpi.rs @@ -6,9 +6,12 @@ use crate::cpu::CpuManager; use crate::device_manager::DeviceManager; use crate::memory_manager::MemoryManager; use crate::vm::NumaNodes; -#[cfg(target_arch = "x86_64")] use acpi_tables::sdt::GenericAddress; use acpi_tables::{aml::Aml, rsdp::Rsdp, sdt::Sdt}; +#[cfg(target_arch = "aarch64")] +use arch::aarch64::DeviceInfoForFdt; +#[cfg(target_arch = "aarch64")] +use arch::DeviceType; use bitflags::bitflags; use std::sync::{Arc, Mutex}; @@ -282,6 +285,34 @@ fn create_gtdt_table() -> Sdt { gtdt } +#[cfg(target_arch = "aarch64")] +fn create_spcr_table(base_address: u64, gsi: u32) -> Sdt { + // SPCR + let mut spcr = Sdt::new(*b"SPCR", 80, 2, *b"CLOUDH", *b"CHSPCR ", 1); + // Interface Type + spcr.write(36, 3u8); + // Base Address in format ACPI Generic Address Structure + spcr.write(40, GenericAddress::mmio_address::(base_address)); + // Interrupt Type: Bit[3] ARMH GIC interrupt + spcr.write(52, (1 << 3) as u8); + // Global System Interrupt used by the UART + spcr.write(54, (gsi as u32).to_le()); + // Baud Rate: 3 = 9600 + spcr.write(58, 3u8); + // Stop Bits: 1 Stop bit + spcr.write(60, 1u8); + // Flow Control: Bit[1] = RTS/CTS hardware flow control + spcr.write(61, (1 << 1) as u8); + // PCI Device ID: Not a PCI device + spcr.write(64, 0xffff_u16); + // PCI Vendor ID: Not a PCI device + spcr.write(66, 0xffff_u16); + + spcr.update_checksum(); + + spcr +} + pub fn create_acpi_tables( guest_mem: &GuestMemoryMmap, device_manager: &Arc>, @@ -339,15 +370,49 @@ pub fn create_acpi_tables( .write_slice(mcfg.as_slice(), mcfg_offset) .expect("Error writing MCFG table"); tables.push(mcfg_offset.0); + prev_tbl_len = mcfg.len() as u64; + prev_tbl_off = mcfg_offset; + + // SPCR + #[cfg(target_arch = "aarch64")] + { + let is_serial_on = device_manager + .lock() + .unwrap() + .get_device_info() + .clone() + .get(&(DeviceType::Serial, DeviceType::Serial.to_string())) + .is_some(); + let serial_device_addr = arch::layout::LEGACY_SERIAL_MAPPED_IO_START; + let serial_device_irq = if is_serial_on { + device_manager + .lock() + .unwrap() + .get_device_info() + .clone() + .get(&(DeviceType::Serial, DeviceType::Serial.to_string())) + .unwrap() + .irq() + } else { + // If serial is turned off, add a fake device with invalid irq. + 31 + }; + let spcr = create_spcr_table(serial_device_addr, serial_device_irq); + let spcr_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap(); + guest_mem + .write_slice(spcr.as_slice(), spcr_offset) + .expect("Error writing SPCR table"); + tables.push(spcr_offset.0); + prev_tbl_len = spcr.len() as u64; + prev_tbl_off = spcr_offset; + } // SRAT and SLIT // Only created if the NUMA nodes list is not empty. - let (prev_tbl_len, prev_tbl_off) = if numa_nodes.is_empty() { - (mcfg.len(), mcfg_offset) - } else { + if !numa_nodes.is_empty() { // SRAT let srat = create_srat_table(numa_nodes); - let srat_offset = mcfg_offset.checked_add(mcfg.len() as u64).unwrap(); + let srat_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap(); guest_mem .write_slice(srat.as_slice(), srat_offset) .expect("Error writing SRAT table"); @@ -361,7 +426,8 @@ pub fn create_acpi_tables( .expect("Error writing SRAT table"); tables.push(slit_offset.0); - (slit.len(), slit_offset) + prev_tbl_len = slit.len() as u64; + prev_tbl_off = slit_offset; }; // XSDT