devices: serial: Expect an identifier upon device creation

This identifier is chosen from the DeviceManager so that it will manage
all identifiers across the VM, which will ensure uniqueness.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2020-04-28 19:11:56 +02:00 committed by Rob Bradford
parent 06487131f9
commit 9ab4bb1ae2
2 changed files with 35 additions and 23 deletions

View File

@ -60,6 +60,7 @@ const DEFAULT_BAUD_DIVISOR: u16 = 12; // 9600 bps
/// This can optionally write the guest's output to a Write trait object. To send input to the /// This can optionally write the guest's output to a Write trait object. To send input to the
/// guest, use `queue_input_bytes`. /// guest, use `queue_input_bytes`.
pub struct Serial { pub struct Serial {
id: String,
interrupt_enable: u8, interrupt_enable: u8,
interrupt_identification: u8, interrupt_identification: u8,
interrupt: Arc<Box<dyn InterruptSourceGroup>>, interrupt: Arc<Box<dyn InterruptSourceGroup>>,
@ -88,10 +89,12 @@ pub struct SerialState {
impl Serial { impl Serial {
pub fn new( pub fn new(
id: String,
interrupt: Arc<Box<dyn InterruptSourceGroup>>, interrupt: Arc<Box<dyn InterruptSourceGroup>>,
out: Option<Box<dyn io::Write + Send>>, out: Option<Box<dyn io::Write + Send>>,
) -> Serial { ) -> Serial {
Serial { Serial {
id,
interrupt_enable: 0, interrupt_enable: 0,
interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION, interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION,
interrupt, interrupt,
@ -108,15 +111,16 @@ impl Serial {
/// Constructs a Serial port ready for output. /// Constructs a Serial port ready for output.
pub fn new_out( pub fn new_out(
id: String,
interrupt: Arc<Box<dyn InterruptSourceGroup>>, interrupt: Arc<Box<dyn InterruptSourceGroup>>,
out: Box<dyn io::Write + Send>, out: Box<dyn io::Write + Send>,
) -> Serial { ) -> Serial {
Self::new(interrupt, Some(out)) Self::new(id, interrupt, Some(out))
} }
/// Constructs a Serial port with no connected output. /// Constructs a Serial port with no connected output.
pub fn new_sink(interrupt: Arc<Box<dyn InterruptSourceGroup>>) -> Serial { pub fn new_sink(id: String, interrupt: Arc<Box<dyn InterruptSourceGroup>>) -> Serial {
Self::new(interrupt, None) Self::new(id, interrupt, None)
} }
/// Queues raw bytes for the guest to read and signals the interrupt if the line status would /// Queues raw bytes for the guest to read and signals the interrupt if the line status would
@ -280,19 +284,18 @@ impl BusDevice for Serial {
} }
} }
const SERIAL_SNAPSHOT_ID: &str = "serial";
impl Snapshottable for Serial { impl Snapshottable for Serial {
fn id(&self) -> String { fn id(&self) -> String {
SERIAL_SNAPSHOT_ID.to_string() self.id.clone()
} }
fn snapshot(&self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot = let snapshot =
serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?; serde_json::to_vec(&self.state()).map_err(|e| MigratableError::Snapshot(e.into()))?;
let mut serial_snapshot = Snapshot::new(SERIAL_SNAPSHOT_ID); let mut serial_snapshot = Snapshot::new(self.id.as_str());
serial_snapshot.add_data_section(SnapshotDataSection { serial_snapshot.add_data_section(SnapshotDataSection {
id: format!("{}-section", SERIAL_SNAPSHOT_ID), id: format!("{}-section", self.id),
snapshot, snapshot,
}); });
@ -300,10 +303,7 @@ impl Snapshottable for Serial {
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(serial_section) = snapshot if let Some(serial_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) {
.snapshot_data
.get(&format!("{}-section", SERIAL_SNAPSHOT_ID))
{
let serial_state = match serde_json::from_slice(&serial_section.snapshot) { let serial_state = match serde_json::from_slice(&serial_section.snapshot) {
Ok(state) => state, Ok(state) => state,
Err(error) => { Err(error) => {
@ -337,6 +337,8 @@ mod tests {
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig}; use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
const SERIAL_NAME: &str = "serial";
struct TestInterrupt { struct TestInterrupt {
event_fd: EventFd, event_fd: EventFd,
} }
@ -387,6 +389,7 @@ mod tests {
let intr_evt = EventFd::new(0).unwrap(); let intr_evt = EventFd::new(0).unwrap();
let serial_out = SharedBuffer::new(); let serial_out = SharedBuffer::new();
let mut serial = Serial::new_out( let mut serial = Serial::new_out(
String::from(SERIAL_NAME),
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))), Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
Box::new(serial_out.clone()), Box::new(serial_out.clone()),
); );
@ -406,6 +409,7 @@ mod tests {
let intr_evt = EventFd::new(0).unwrap(); let intr_evt = EventFd::new(0).unwrap();
let serial_out = SharedBuffer::new(); let serial_out = SharedBuffer::new();
let mut serial = Serial::new_out( let mut serial = Serial::new_out(
String::from(SERIAL_NAME),
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))), Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
Box::new(serial_out.clone()), Box::new(serial_out.clone()),
); );
@ -443,9 +447,10 @@ mod tests {
#[test] #[test]
fn serial_thr() { fn serial_thr() {
let intr_evt = EventFd::new(0).unwrap(); let intr_evt = EventFd::new(0).unwrap();
let mut serial = Serial::new_sink(Arc::new(Box::new(TestInterrupt::new( let mut serial = Serial::new_sink(
intr_evt.try_clone().unwrap(), String::from(SERIAL_NAME),
)))); Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
);
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd // write 1 to the interrupt event fd, so that read doesn't block in case the event fd
// counter doesn't change (for 0 it blocks) // counter doesn't change (for 0 it blocks)
@ -464,9 +469,10 @@ mod tests {
#[test] #[test]
fn serial_dlab() { fn serial_dlab() {
let intr_evt = EventFd::new(0).unwrap(); let intr_evt = EventFd::new(0).unwrap();
let mut serial = Serial::new_sink(Arc::new(Box::new(TestInterrupt::new( let mut serial = Serial::new_sink(
intr_evt.try_clone().unwrap(), String::from(SERIAL_NAME),
)))); Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
);
serial.write(0, LCR as u64, &[LCR_DLAB_BIT as u8]); serial.write(0, LCR as u64, &[LCR_DLAB_BIT as u8]);
serial.write(0, DLAB_LOW as u64, &[0x12 as u8]); serial.write(0, DLAB_LOW as u64, &[0x12 as u8]);
@ -484,9 +490,10 @@ mod tests {
#[test] #[test]
fn serial_modem() { fn serial_modem() {
let intr_evt = EventFd::new(0).unwrap(); let intr_evt = EventFd::new(0).unwrap();
let mut serial = Serial::new_sink(Arc::new(Box::new(TestInterrupt::new( let mut serial = Serial::new_sink(
intr_evt.try_clone().unwrap(), String::from(SERIAL_NAME),
)))); Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
);
serial.write(0, MCR as u64, &[MCR_LOOP_BIT as u8]); serial.write(0, MCR as u64, &[MCR_LOOP_BIT as u8]);
serial.write(0, DATA as u64, &['a' as u8]); serial.write(0, DATA as u64, &['a' as u8]);
@ -509,9 +516,10 @@ mod tests {
#[test] #[test]
fn serial_scratch() { fn serial_scratch() {
let intr_evt = EventFd::new(0).unwrap(); let intr_evt = EventFd::new(0).unwrap();
let mut serial = Serial::new_sink(Arc::new(Box::new(TestInterrupt::new( let mut serial = Serial::new_sink(
intr_evt.try_clone().unwrap(), String::from(SERIAL_NAME),
)))); Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
);
serial.write(0, SCR as u64, &[0x12 as u8]); serial.write(0, SCR as u64, &[0x12 as u8]);

View File

@ -73,6 +73,7 @@ const MMIO_LEN: u64 = 0x1000;
const VFIO_DEVICE_NAME_PREFIX: &str = "vfio"; const VFIO_DEVICE_NAME_PREFIX: &str = "vfio";
const IOAPIC_DEVICE_NAME: &str = "ioapic"; const IOAPIC_DEVICE_NAME: &str = "ioapic";
const SERIAL_DEVICE_NAME_PREFIX: &str = "serial";
const CONSOLE_DEVICE_NAME: &str = "console"; const CONSOLE_DEVICE_NAME: &str = "console";
const DISK_DEVICE_NAME_PREFIX: &str = "disk"; const DISK_DEVICE_NAME_PREFIX: &str = "disk";
@ -1060,6 +1061,8 @@ impl DeviceManager {
// Serial is tied to IRQ #4 // Serial is tied to IRQ #4
let serial_irq = 4; let serial_irq = 4;
let id = String::from(SERIAL_DEVICE_NAME_PREFIX);
let interrupt_group = interrupt_manager let interrupt_group = interrupt_manager
.create_group(LegacyIrqGroupConfig { .create_group(LegacyIrqGroupConfig {
irq: serial_irq as InterruptIndex, irq: serial_irq as InterruptIndex,
@ -1067,6 +1070,7 @@ impl DeviceManager {
.map_err(DeviceManagerError::CreateInterruptGroup)?; .map_err(DeviceManagerError::CreateInterruptGroup)?;
let serial = Arc::new(Mutex::new(devices::legacy::Serial::new( let serial = Arc::new(Mutex::new(devices::legacy::Serial::new(
id,
interrupt_group, interrupt_group,
serial_writer, serial_writer,
))); )));