mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-11-04 19:11:11 +00:00
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 <Henry.Wang@arm.com>
This commit is contained in:
parent
9c5528490e
commit
213da7d862
@ -22,6 +22,15 @@ impl GenericAddress {
|
||||
address: u64::from(address),
|
||||
}
|
||||
}
|
||||
pub fn mmio_address<T>(address: u64) -> Self {
|
||||
GenericAddress {
|
||||
address_space_id: 0,
|
||||
register_bit_width: 8 * std::mem::size_of::<T>() as u8,
|
||||
register_bit_offset: 0,
|
||||
access_size: std::mem::size_of::<T>() as u8,
|
||||
address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Sdt {
|
||||
|
@ -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::<u8>(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<Mutex<DeviceManager>>,
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user