Skip to content

Commit 95f35b0

Browse files
authored
Merge pull request #14 from qwandor/transport
Factor out trait for transport, and add support for modern MMIO transport
2 parents 4ee80e5 + 6f5f190 commit 95f35b0

File tree

13 files changed

+723
-470
lines changed

13 files changed

+723
-470
lines changed

examples/riscv/Makefile

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,26 @@ header:
3636
clean:
3737
cargo clean
3838

39+
qemu-legacy: kernel $(img)
40+
qemu-system-$(arch) \
41+
-machine virt \
42+
-serial mon:stdio \
43+
-bios default \
44+
-kernel $(kernel) \
45+
-drive file=$(img),if=none,format=raw,id=x0 \
46+
-device virtio-blk-device,drive=x0 \
47+
-device virtio-gpu-device \
48+
-device virtio-mouse-device \
49+
# -netdev type=tap,id=net0,script=no,downscript=no \
50+
# -device virtio-net-device,netdev=net0
51+
3952
qemu: kernel $(img)
4053
qemu-system-$(arch) \
4154
-machine virt \
4255
-serial mon:stdio \
4356
-bios default \
4457
-kernel $(kernel) \
58+
-global virtio-mmio.force-legacy=false \
4559
-drive file=$(img),if=none,format=raw,id=x0 \
4660
-device virtio-blk-device,drive=x0 \
4761
-device virtio-gpu-device \
@@ -52,4 +66,4 @@ qemu: kernel $(img)
5266
$(img):
5367
dd if=/dev/zero of=$@ bs=512 count=32
5468

55-
run: build qemu
69+
run: build qemu-legacy qemu

examples/riscv/src/main.rs

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ extern crate alloc;
66
extern crate opensbi_rt;
77

88
use alloc::vec;
9+
use core::ptr::NonNull;
910
use device_tree::util::SliceRead;
1011
use device_tree::{DeviceTree, Node};
1112
use log::{info, warn, LevelFilter};
@@ -55,25 +56,35 @@ fn virtio_probe(node: &Node) {
5556
let size = reg.as_slice().read_be_u64(8).unwrap();
5657
let vaddr = paddr;
5758
info!("walk dt addr={:#x}, size={:#x}", paddr, size);
58-
let header = unsafe { &mut *(vaddr as *mut VirtIOHeader) };
59-
info!(
60-
"Detected virtio device with vendor id {:#X}, device type {:?}",
61-
header.vendor_id(),
62-
header.device_type(),
63-
);
6459
info!("Device tree node {:?}", node);
65-
match header.device_type() {
66-
DeviceType::Block => virtio_blk(header),
67-
DeviceType::GPU => virtio_gpu(header),
68-
DeviceType::Input => virtio_input(header),
69-
DeviceType::Network => virtio_net(header),
70-
t => warn!("Unrecognized virtio device: {:?}", t),
60+
let header = NonNull::new(vaddr as *mut VirtIOHeader).unwrap();
61+
match unsafe { MmioTransport::new(header) } {
62+
Err(e) => warn!("Error creating VirtIO MMIO transport: {}", e),
63+
Ok(transport) => {
64+
info!(
65+
"Detected virtio MMIO device with vendor id {:#X}, device type {:?}, version {:?}",
66+
transport.vendor_id(),
67+
transport.device_type(),
68+
transport.version(),
69+
);
70+
virtio_device(transport);
71+
}
7172
}
7273
}
7374
}
7475

75-
fn virtio_blk(header: &'static mut VirtIOHeader) {
76-
let mut blk = VirtIOBlk::<HalImpl>::new(header).expect("failed to create blk driver");
76+
fn virtio_device(transport: impl Transport) {
77+
match transport.device_type() {
78+
DeviceType::Block => virtio_blk(transport),
79+
DeviceType::GPU => virtio_gpu(transport),
80+
DeviceType::Input => virtio_input(transport),
81+
DeviceType::Network => virtio_net(transport),
82+
t => warn!("Unrecognized virtio device: {:?}", t),
83+
}
84+
}
85+
86+
fn virtio_blk<T: Transport>(transport: T) {
87+
let mut blk = VirtIOBlk::<HalImpl, T>::new(transport).expect("failed to create blk driver");
7788
let mut input = vec![0xffu8; 512];
7889
let mut output = vec![0; 512];
7990
for i in 0..32 {
@@ -87,8 +98,8 @@ fn virtio_blk(header: &'static mut VirtIOHeader) {
8798
info!("virtio-blk test finished");
8899
}
89100

90-
fn virtio_gpu(header: &'static mut VirtIOHeader) {
91-
let mut gpu = VirtIOGpu::<HalImpl>::new(header).expect("failed to create gpu driver");
101+
fn virtio_gpu<T: Transport>(transport: T) {
102+
let mut gpu = VirtIOGpu::<HalImpl, T>::new(transport).expect("failed to create gpu driver");
92103
let fb = gpu.setup_framebuffer().expect("failed to get fb");
93104
for y in 0..768 {
94105
for x in 0..1024 {
@@ -102,18 +113,19 @@ fn virtio_gpu(header: &'static mut VirtIOHeader) {
102113
info!("virtio-gpu test finished");
103114
}
104115

105-
fn virtio_input(header: &'static mut VirtIOHeader) {
116+
fn virtio_input<T: Transport>(transport: T) {
106117
//let mut event_buf = [0u64; 32];
107-
let mut _input = VirtIOInput::<HalImpl>::new(header).expect("failed to create input driver");
118+
let mut _input =
119+
VirtIOInput::<HalImpl, T>::new(transport).expect("failed to create input driver");
108120
// loop {
109121
// input.ack_interrupt().expect("failed to ack");
110122
// info!("mouse: {:?}", input.mouse_xy());
111123
// }
112124
// TODO: handle external interrupt
113125
}
114126

115-
fn virtio_net(header: &'static mut VirtIOHeader) {
116-
let mut net = VirtIONet::<HalImpl>::new(header).expect("failed to create net driver");
127+
fn virtio_net<T: Transport>(transport: T) {
128+
let mut net = VirtIONet::<HalImpl, T>::new(transport).expect("failed to create net driver");
117129
let mut buf = [0u8; 0x100];
118130
let len = net.recv(&mut buf).expect("failed to recv");
119131
info!("recv: {:?}", &buf[..len]);

src/blk.rs

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::*;
2-
use crate::header::VirtIOHeader;
32
use crate::queue::VirtQueue;
3+
use crate::transport::Transport;
44
use bitflags::*;
55
use core::hint::spin_loop;
66
use log::*;
@@ -10,16 +10,16 @@ use volatile::Volatile;
1010
///
1111
/// Read and write requests (and other exotic requests) are placed in the queue,
1212
/// and serviced (probably out of order) by the device except where noted.
13-
pub struct VirtIOBlk<'a, H: Hal> {
14-
header: &'static mut VirtIOHeader,
13+
pub struct VirtIOBlk<'a, H: Hal, T: Transport> {
14+
transport: T,
1515
queue: VirtQueue<'a, H>,
1616
capacity: usize,
1717
}
1818

19-
impl<H: Hal> VirtIOBlk<'_, H> {
19+
impl<H: Hal, T: Transport> VirtIOBlk<'_, H, T> {
2020
/// Create a new VirtIO-Blk driver.
21-
pub fn new(header: &'static mut VirtIOHeader) -> Result<Self> {
22-
header.begin_init(|features| {
21+
pub fn new(mut transport: T) -> Result<Self> {
22+
transport.begin_init(|features| {
2323
let features = BlkFeature::from_bits_truncate(features);
2424
info!("device features: {:?}", features);
2525
// negotiate these flags only
@@ -28,26 +28,27 @@ impl<H: Hal> VirtIOBlk<'_, H> {
2828
});
2929

3030
// read configuration space
31-
let config = unsafe { &mut *(header.config_space() as *mut BlkConfig) };
31+
let config_space = transport.config_space().cast::<BlkConfig>();
32+
let config = unsafe { config_space.as_ref() };
3233
info!("config: {:?}", config);
3334
info!(
3435
"found a block device of size {}KB",
3536
config.capacity.read() / 2
3637
);
3738

38-
let queue = VirtQueue::new(header, 0, 16)?;
39-
header.finish_init();
39+
let queue = VirtQueue::new(&mut transport, 0, 16)?;
40+
transport.finish_init();
4041

4142
Ok(VirtIOBlk {
42-
header,
43+
transport,
4344
queue,
4445
capacity: config.capacity.read() as usize,
4546
})
4647
}
4748

4849
/// Acknowledge interrupt.
4950
pub fn ack_interrupt(&mut self) -> bool {
50-
self.header.ack_interrupt()
51+
self.transport.ack_interrupt()
5152
}
5253

5354
/// Read a block.
@@ -60,7 +61,7 @@ impl<H: Hal> VirtIOBlk<'_, H> {
6061
};
6162
let mut resp = BlkResp::default();
6263
self.queue.add(&[req.as_buf()], &[buf, resp.as_buf_mut()])?;
63-
self.header.notify(0);
64+
self.transport.notify(0);
6465
while !self.queue.can_pop() {
6566
spin_loop();
6667
}
@@ -112,7 +113,7 @@ impl<H: Hal> VirtIOBlk<'_, H> {
112113
sector: block_id as u64,
113114
};
114115
let token = self.queue.add(&[req.as_buf()], &[buf, resp.as_buf_mut()])?;
115-
self.header.notify(0);
116+
self.transport.notify(0);
116117
Ok(token)
117118
}
118119

@@ -126,7 +127,7 @@ impl<H: Hal> VirtIOBlk<'_, H> {
126127
};
127128
let mut resp = BlkResp::default();
128129
self.queue.add(&[req.as_buf(), buf], &[resp.as_buf_mut()])?;
129-
self.header.notify(0);
130+
self.transport.notify(0);
130131
while !self.queue.can_pop() {
131132
spin_loop();
132133
}
@@ -167,7 +168,7 @@ impl<H: Hal> VirtIOBlk<'_, H> {
167168
sector: block_id as u64,
168169
};
169170
let token = self.queue.add(&[req.as_buf(), buf], &[resp.as_buf_mut()])?;
170-
self.header.notify(0);
171+
self.transport.notify(0);
171172
Ok(token)
172173
}
173174

src/console.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
use super::*;
22
use crate::queue::VirtQueue;
3+
use crate::transport::Transport;
34
use bitflags::*;
45
use core::{fmt, hint::spin_loop};
56
use log::*;
67
use volatile::{ReadOnly, WriteOnly};
78

89
const QUEUE_RECEIVEQ_PORT_0: usize = 0;
910
const QUEUE_TRANSMITQ_PORT_0: usize = 1;
11+
const QUEUE_SIZE: u16 = 2;
1012

1113
/// Virtio console. Only one single port is allowed since ``alloc'' is disabled.
1214
/// Emergency and cols/rows unimplemented.
13-
pub struct VirtIOConsole<'a, H: Hal> {
14-
header: &'static mut VirtIOHeader,
15+
pub struct VirtIOConsole<'a, H: Hal, T: Transport> {
16+
transport: T,
1517
receiveq: VirtQueue<'a, H>,
1618
transmitq: VirtQueue<'a, H>,
1719
queue_buf_dma: DMA<H>,
@@ -20,24 +22,25 @@ pub struct VirtIOConsole<'a, H: Hal> {
2022
pending_len: usize,
2123
}
2224

23-
impl<H: Hal> VirtIOConsole<'_, H> {
25+
impl<H: Hal, T: Transport> VirtIOConsole<'_, H, T> {
2426
/// Create a new VirtIO-Console driver.
25-
pub fn new(header: &'static mut VirtIOHeader) -> Result<Self> {
26-
header.begin_init(|features| {
27+
pub fn new(mut transport: T) -> Result<Self> {
28+
transport.begin_init(|features| {
2729
let features = Features::from_bits_truncate(features);
2830
info!("Device features {:?}", features);
2931
let supported_features = Features::empty();
3032
(features & supported_features).bits()
3133
});
32-
let config = unsafe { &mut *(header.config_space() as *mut Config) };
34+
let config_space = transport.config_space().cast::<Config>();
35+
let config = unsafe { config_space.as_ref() };
3336
info!("Config: {:?}", config);
34-
let receiveq = VirtQueue::new(header, QUEUE_RECEIVEQ_PORT_0, 2)?;
35-
let transmitq = VirtQueue::new(header, QUEUE_TRANSMITQ_PORT_0, 2)?;
37+
let receiveq = VirtQueue::new(&mut transport, QUEUE_RECEIVEQ_PORT_0, QUEUE_SIZE)?;
38+
let transmitq = VirtQueue::new(&mut transport, QUEUE_TRANSMITQ_PORT_0, QUEUE_SIZE)?;
3639
let queue_buf_dma = DMA::new(1)?;
3740
let queue_buf_rx = unsafe { &mut queue_buf_dma.as_buf()[0..] };
38-
header.finish_init();
41+
transport.finish_init();
3942
let mut console = VirtIOConsole {
40-
header,
43+
transport,
4144
receiveq,
4245
transmitq,
4346
queue_buf_dma,
@@ -48,13 +51,15 @@ impl<H: Hal> VirtIOConsole<'_, H> {
4851
console.poll_retrieve()?;
4952
Ok(console)
5053
}
54+
5155
fn poll_retrieve(&mut self) -> Result<()> {
5256
self.receiveq.add(&[], &[self.queue_buf_rx])?;
5357
Ok(())
5458
}
59+
5560
/// Acknowledge interrupt.
5661
pub fn ack_interrupt(&mut self) -> Result<bool> {
57-
let ack = self.header.ack_interrupt();
62+
let ack = self.transport.ack_interrupt();
5863
if !ack {
5964
return Ok(false);
6065
}
@@ -83,11 +88,12 @@ impl<H: Hal> VirtIOConsole<'_, H> {
8388
}
8489
Ok(Some(ch))
8590
}
91+
8692
/// Put a char onto the device.
8793
pub fn send(&mut self, chr: u8) -> Result<()> {
8894
let buf: [u8; 1] = [chr];
8995
self.transmitq.add(&[&buf], &[])?;
90-
self.header.notify(QUEUE_TRANSMITQ_PORT_0 as u32);
96+
self.transport.notify(QUEUE_TRANSMITQ_PORT_0 as u32);
9197
while !self.transmitq.can_pop() {
9298
spin_loop();
9399
}

src/gpu.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::*;
22
use crate::queue::VirtQueue;
3+
use crate::transport::Transport;
34
use bitflags::*;
45
use core::{fmt, hint::spin_loop};
56
use log::*;
@@ -12,8 +13,8 @@ use volatile::{ReadOnly, Volatile, WriteOnly};
1213
/// a gpu with 3D support on the host machine.
1314
/// In 2D mode the virtio-gpu device provides support for ARGB Hardware cursors
1415
/// and multiple scanouts (aka heads).
15-
pub struct VirtIOGpu<'a, H: Hal> {
16-
header: &'static mut VirtIOHeader,
16+
pub struct VirtIOGpu<'a, H: Hal, T: Transport> {
17+
transport: T,
1718
rect: Rect,
1819
/// DMA area of frame buffer.
1920
frame_buffer_dma: Option<DMA<H>>,
@@ -31,31 +32,32 @@ pub struct VirtIOGpu<'a, H: Hal> {
3132
queue_buf_recv: &'a mut [u8],
3233
}
3334

34-
impl<H: Hal> VirtIOGpu<'_, H> {
35+
impl<H: Hal, T: Transport> VirtIOGpu<'_, H, T> {
3536
/// Create a new VirtIO-Gpu driver.
36-
pub fn new(header: &'static mut VirtIOHeader) -> Result<Self> {
37-
header.begin_init(|features| {
37+
pub fn new(mut transport: T) -> Result<Self> {
38+
transport.begin_init(|features| {
3839
let features = Features::from_bits_truncate(features);
3940
info!("Device features {:?}", features);
4041
let supported_features = Features::empty();
4142
(features & supported_features).bits()
4243
});
4344

4445
// read configuration space
45-
let config = unsafe { &mut *(header.config_space() as *mut Config) };
46+
let config_space = transport.config_space().cast::<Config>();
47+
let config = unsafe { config_space.as_ref() };
4648
info!("Config: {:?}", config);
4749

48-
let control_queue = VirtQueue::new(header, QUEUE_TRANSMIT, 2)?;
49-
let cursor_queue = VirtQueue::new(header, QUEUE_CURSOR, 2)?;
50+
let control_queue = VirtQueue::new(&mut transport, QUEUE_TRANSMIT, 2)?;
51+
let cursor_queue = VirtQueue::new(&mut transport, QUEUE_CURSOR, 2)?;
5052

5153
let queue_buf_dma = DMA::new(2)?;
5254
let queue_buf_send = unsafe { &mut queue_buf_dma.as_buf()[..PAGE_SIZE] };
5355
let queue_buf_recv = unsafe { &mut queue_buf_dma.as_buf()[PAGE_SIZE..] };
5456

55-
header.finish_init();
57+
transport.finish_init();
5658

5759
Ok(VirtIOGpu {
58-
header,
60+
transport,
5961
frame_buffer_dma: None,
6062
cursor_buffer_dma: None,
6163
rect: Rect::default(),
@@ -69,7 +71,7 @@ impl<H: Hal> VirtIOGpu<'_, H> {
6971

7072
/// Acknowledge interrupt.
7173
pub fn ack_interrupt(&mut self) -> bool {
72-
self.header.ack_interrupt()
74+
self.transport.ack_interrupt()
7375
}
7476

7577
/// Get the resolution (width, height).
@@ -161,7 +163,7 @@ impl<H: Hal> VirtIOGpu<'_, H> {
161163
}
162164
self.control_queue
163165
.add(&[self.queue_buf_send], &[self.queue_buf_recv])?;
164-
self.header.notify(QUEUE_TRANSMIT as u32);
166+
self.transport.notify(QUEUE_TRANSMIT as u32);
165167
while !self.control_queue.can_pop() {
166168
spin_loop();
167169
}
@@ -175,7 +177,7 @@ impl<H: Hal> VirtIOGpu<'_, H> {
175177
(self.queue_buf_send.as_mut_ptr() as *mut Req).write(req);
176178
}
177179
self.cursor_queue.add(&[self.queue_buf_send], &[])?;
178-
self.header.notify(QUEUE_CURSOR as u32);
180+
self.transport.notify(QUEUE_CURSOR as u32);
179181
while !self.cursor_queue.can_pop() {
180182
spin_loop();
181183
}

0 commit comments

Comments
 (0)