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
/// guest, use `queue_input_bytes`.
pub struct Serial {
id: String,
interrupt_enable: u8,
interrupt_identification: u8,
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
@ -88,10 +89,12 @@ pub struct SerialState {
impl Serial {
pub fn new(
id: String,
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
out: Option<Box<dyn io::Write + Send>>,
) -> Serial {
Serial {
id,
interrupt_enable: 0,
interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION,
interrupt,
@ -108,15 +111,16 @@ impl Serial {
/// Constructs a Serial port ready for output.
pub fn new_out(
id: String,
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
out: Box<dyn io::Write + Send>,
) -> Serial {
Self::new(interrupt, Some(out))
Self::new(id, interrupt, Some(out))
}
/// Constructs a Serial port with no connected output.
pub fn new_sink(interrupt: Arc<Box<dyn InterruptSourceGroup>>) -> Serial {
Self::new(interrupt, None)
pub fn new_sink(id: String, interrupt: Arc<Box<dyn InterruptSourceGroup>>) -> Serial {
Self::new(id, interrupt, None)
}
/// 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 {
fn id(&self) -> String {
SERIAL_SNAPSHOT_ID.to_string()
self.id.clone()
}
fn snapshot(&self) -> std::result::Result<Snapshot, MigratableError> {
let snapshot =
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 {
id: format!("{}-section", SERIAL_SNAPSHOT_ID),
id: format!("{}-section", self.id),
snapshot,
});
@ -300,10 +303,7 @@ impl Snapshottable for Serial {
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(serial_section) = snapshot
.snapshot_data
.get(&format!("{}-section", SERIAL_SNAPSHOT_ID))
{
if let Some(serial_section) = snapshot.snapshot_data.get(&format!("{}-section", self.id)) {
let serial_state = match serde_json::from_slice(&serial_section.snapshot) {
Ok(state) => state,
Err(error) => {
@ -337,6 +337,8 @@ mod tests {
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
use vmm_sys_util::eventfd::EventFd;
const SERIAL_NAME: &str = "serial";
struct TestInterrupt {
event_fd: EventFd,
}
@ -387,6 +389,7 @@ mod tests {
let intr_evt = EventFd::new(0).unwrap();
let serial_out = SharedBuffer::new();
let mut serial = Serial::new_out(
String::from(SERIAL_NAME),
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
Box::new(serial_out.clone()),
);
@ -406,6 +409,7 @@ mod tests {
let intr_evt = EventFd::new(0).unwrap();
let serial_out = SharedBuffer::new();
let mut serial = Serial::new_out(
String::from(SERIAL_NAME),
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
Box::new(serial_out.clone()),
);
@ -443,9 +447,10 @@ mod tests {
#[test]
fn serial_thr() {
let intr_evt = EventFd::new(0).unwrap();
let mut serial = Serial::new_sink(Arc::new(Box::new(TestInterrupt::new(
intr_evt.try_clone().unwrap(),
))));
let mut serial = Serial::new_sink(
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
// counter doesn't change (for 0 it blocks)
@ -464,9 +469,10 @@ mod tests {
#[test]
fn serial_dlab() {
let intr_evt = EventFd::new(0).unwrap();
let mut serial = Serial::new_sink(Arc::new(Box::new(TestInterrupt::new(
intr_evt.try_clone().unwrap(),
))));
let mut serial = Serial::new_sink(
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, DLAB_LOW as u64, &[0x12 as u8]);
@ -484,9 +490,10 @@ mod tests {
#[test]
fn serial_modem() {
let intr_evt = EventFd::new(0).unwrap();
let mut serial = Serial::new_sink(Arc::new(Box::new(TestInterrupt::new(
intr_evt.try_clone().unwrap(),
))));
let mut serial = Serial::new_sink(
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, DATA as u64, &['a' as u8]);
@ -509,9 +516,10 @@ mod tests {
#[test]
fn serial_scratch() {
let intr_evt = EventFd::new(0).unwrap();
let mut serial = Serial::new_sink(Arc::new(Box::new(TestInterrupt::new(
intr_evt.try_clone().unwrap(),
))));
let mut serial = Serial::new_sink(
String::from(SERIAL_NAME),
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
);
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 IOAPIC_DEVICE_NAME: &str = "ioapic";
const SERIAL_DEVICE_NAME_PREFIX: &str = "serial";
const CONSOLE_DEVICE_NAME: &str = "console";
const DISK_DEVICE_NAME_PREFIX: &str = "disk";
@ -1060,6 +1061,8 @@ impl DeviceManager {
// Serial is tied to IRQ #4
let serial_irq = 4;
let id = String::from(SERIAL_DEVICE_NAME_PREFIX);
let interrupt_group = interrupt_manager
.create_group(LegacyIrqGroupConfig {
irq: serial_irq as InterruptIndex,
@ -1067,6 +1070,7 @@ impl DeviceManager {
.map_err(DeviceManagerError::CreateInterruptGroup)?;
let serial = Arc::new(Mutex::new(devices::legacy::Serial::new(
id,
interrupt_group,
serial_writer,
)));