mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-18 10:35:23 +00:00
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:
parent
06487131f9
commit
9ab4bb1ae2
@ -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]);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
)));
|
)));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user