#[allow(unused_imports)]
use super::super::*;
use std::os::unix::io::AsRawFd;
use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE};
use virtio_bindings::virtio_mmio::VIRTIO_MMIO_INT_CONFIG;
use virtio_queue::desc::{RawDescriptor, split::Descriptor as SplitDescriptor};
use virtio_queue::mock::MockSplitQueue;
use vm_memory::{Address, GuestAddress};
fn read_reg(dev: &VirtioConsole, offset: u32) -> u32 {
let mut buf = [0u8; 4];
dev.mmio_read(offset as u64, &mut buf);
u32::from_le_bytes(buf)
}
fn write_reg(dev: &mut VirtioConsole, offset: u32, val: u32) {
dev.mmio_write(offset as u64, &val.to_le_bytes());
}
fn init_device(dev: &mut VirtioConsole) {
write_reg(dev, VIRTIO_MMIO_STATUS, S_ACK);
write_reg(dev, VIRTIO_MMIO_STATUS, S_DRV);
write_reg(dev, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 0);
write_reg(
dev,
VIRTIO_MMIO_DRIVER_FEATURES,
1 << VIRTIO_CONSOLE_F_MULTIPORT,
);
write_reg(dev, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 1);
write_reg(
dev,
VIRTIO_MMIO_DRIVER_FEATURES,
1 << (VIRTIO_F_VERSION_1 - 32),
);
write_reg(dev, VIRTIO_MMIO_STATUS, S_FEAT);
write_reg(dev, VIRTIO_MMIO_STATUS, S_OK);
}
fn make_chain_test_mem() -> GuestMemoryMmap {
GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 2 << 20)])
.expect("create chain test guest mem")
}
fn wire_console_queue_to_mock(
dev: &mut VirtioConsole,
mock: &MockSplitQueue<GuestMemoryMmap>,
queue_idx: u32,
) {
write_reg(dev, VIRTIO_MMIO_STATUS, S_ACK);
write_reg(dev, VIRTIO_MMIO_STATUS, S_DRV);
write_reg(dev, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 0);
write_reg(
dev,
VIRTIO_MMIO_DRIVER_FEATURES,
1 << VIRTIO_CONSOLE_F_MULTIPORT,
);
write_reg(dev, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 1);
write_reg(
dev,
VIRTIO_MMIO_DRIVER_FEATURES,
1 << (VIRTIO_F_VERSION_1 - 32),
);
write_reg(dev, VIRTIO_MMIO_STATUS, S_FEAT);
write_reg(dev, VIRTIO_MMIO_QUEUE_SEL, queue_idx);
write_reg(dev, VIRTIO_MMIO_QUEUE_NUM, 16);
let desc = mock.desc_table_addr().0;
let avail = mock.avail_addr().0;
let used = mock.used_addr().0;
write_reg(dev, VIRTIO_MMIO_QUEUE_DESC_LOW, desc as u32);
write_reg(dev, VIRTIO_MMIO_QUEUE_DESC_HIGH, (desc >> 32) as u32);
write_reg(dev, VIRTIO_MMIO_QUEUE_AVAIL_LOW, avail as u32);
write_reg(dev, VIRTIO_MMIO_QUEUE_AVAIL_HIGH, (avail >> 32) as u32);
write_reg(dev, VIRTIO_MMIO_QUEUE_USED_LOW, used as u32);
write_reg(dev, VIRTIO_MMIO_QUEUE_USED_HIGH, (used >> 32) as u32);
write_reg(dev, VIRTIO_MMIO_QUEUE_READY, 1);
write_reg(dev, VIRTIO_MMIO_STATUS, S_OK);
assert_eq!(
dev.device_status, S_OK,
"wire_console_queue_to_mock: FSM did not reach DRIVER_OK \
(got {:#x}) — feature negotiation likely regressed",
dev.device_status,
);
assert!(
dev.queues[queue_idx as usize].ready(),
"wire_console_queue_to_mock: queue {queue_idx} did not \
become ready after QUEUE_READY=1",
);
}
fn wire_port1_rxq_to_mock(dev: &mut VirtioConsole, mock: &MockSplitQueue<GuestMemoryMmap>) {
wire_console_queue_to_mock(dev, mock, PORT1_RXQ as u32);
}
fn open_port1(dev: &mut VirtioConsole) {
dev.handle_control_event(VirtioConsoleControl {
id: 1,
event: VIRTIO_CONSOLE_PORT_OPEN,
value: 1,
});
assert!(
dev.ports[1].opened,
"open_port1 helper precondition: PORT_OPEN(value=1) must \
set port_opened[1]"
);
}
fn open_port2(dev: &mut VirtioConsole) {
dev.handle_control_event(VirtioConsoleControl {
id: 2,
event: VIRTIO_CONSOLE_PORT_OPEN,
value: 1,
});
assert!(
dev.ports[2].opened,
"open_port2 helper precondition: PORT_OPEN(value=1) must \
set port_opened[2]"
);
}
fn wire_port2_rxq_to_mock(dev: &mut VirtioConsole, mock: &MockSplitQueue<GuestMemoryMmap>) {
wire_console_queue_to_mock(dev, mock, PORT2_RXQ as u32);
}
mod control_events;
mod mmio_config;
mod mmio_read;
mod port2;
mod port_tx;
mod rx_drain;
mod status_fsm;