Skip to content

Commit 1581eae

Browse files
authored
Use a safer approach to the HAL interface (#11)
* Expose address types rather than redefining them. * Define a trait for HAL and pass it as a type parameter. This avoids the need to use extern functions and removes some unsafe blocks. * Keep address and page count as usize. Converting to u32 and back could lose bits.
1 parent 93f821c commit 1581eae

File tree

10 files changed

+88
-84
lines changed

10 files changed

+88
-84
lines changed

examples/riscv/src/main.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use device_tree::util::SliceRead;
1010
use device_tree::{DeviceTree, Node};
1111
use log::{info, warn, LevelFilter};
1212
use virtio_drivers::*;
13+
use virtio_impl::HalImpl;
1314

1415
mod virtio_impl;
1516

@@ -72,7 +73,7 @@ fn virtio_probe(node: &Node) {
7273
}
7374

7475
fn virtio_blk(header: &'static mut VirtIOHeader) {
75-
let mut blk = VirtIOBlk::new(header).expect("failed to create blk driver");
76+
let mut blk = VirtIOBlk::<HalImpl>::new(header).expect("failed to create blk driver");
7677
let mut input = vec![0xffu8; 512];
7778
let mut output = vec![0; 512];
7879
for i in 0..32 {
@@ -87,7 +88,7 @@ fn virtio_blk(header: &'static mut VirtIOHeader) {
8788
}
8889

8990
fn virtio_gpu(header: &'static mut VirtIOHeader) {
90-
let mut gpu = VirtIOGpu::new(header).expect("failed to create gpu driver");
91+
let mut gpu = VirtIOGpu::<HalImpl>::new(header).expect("failed to create gpu driver");
9192
let fb = gpu.setup_framebuffer().expect("failed to get fb");
9293
for y in 0..768 {
9394
for x in 0..1024 {
@@ -103,7 +104,7 @@ fn virtio_gpu(header: &'static mut VirtIOHeader) {
103104

104105
fn virtio_input(header: &'static mut VirtIOHeader) {
105106
//let mut event_buf = [0u64; 32];
106-
let mut _input = VirtIOInput::new(header).expect("failed to create input driver");
107+
let mut _input = VirtIOInput::<HalImpl>::new(header).expect("failed to create input driver");
107108
// loop {
108109
// input.ack_interrupt().expect("failed to ack");
109110
// info!("mouse: {:?}", input.mouse_xy());
@@ -112,7 +113,7 @@ fn virtio_input(header: &'static mut VirtIOHeader) {
112113
}
113114

114115
fn virtio_net(header: &'static mut VirtIOHeader) {
115-
let mut net = VirtIONet::new(header).expect("failed to create net driver");
116+
let mut net = VirtIONet::<HalImpl>::new(header).expect("failed to create net driver");
116117
let mut buf = [0u8; 0x100];
117118
let len = net.recv(&mut buf).expect("failed to recv");
118119
info!("recv: {:?}", &buf[..len]);

examples/riscv/src/virtio_impl.rs

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use core::sync::atomic::*;
22
use lazy_static::lazy_static;
33
use log::trace;
4+
use virtio_drivers::{Hal, PhysAddr, VirtAddr};
45

56
extern "C" {
67
fn end();
@@ -10,28 +11,25 @@ lazy_static! {
1011
static ref DMA_PADDR: AtomicUsize = AtomicUsize::new(end as usize);
1112
}
1213

13-
#[no_mangle]
14-
extern "C" fn virtio_dma_alloc(pages: usize) -> PhysAddr {
15-
let paddr = DMA_PADDR.fetch_add(0x1000 * pages, Ordering::SeqCst);
16-
trace!("alloc DMA: paddr={:#x}, pages={}", paddr, pages);
17-
paddr
18-
}
14+
pub struct HalImpl;
1915

20-
#[no_mangle]
21-
extern "C" fn virtio_dma_dealloc(paddr: PhysAddr, pages: usize) -> i32 {
22-
trace!("dealloc DMA: paddr={:#x}, pages={}", paddr, pages);
23-
0
24-
}
16+
impl Hal for HalImpl {
17+
fn dma_alloc(pages: usize) -> PhysAddr {
18+
let paddr = DMA_PADDR.fetch_add(0x1000 * pages, Ordering::SeqCst);
19+
trace!("alloc DMA: paddr={:#x}, pages={}", paddr, pages);
20+
paddr
21+
}
2522

26-
#[no_mangle]
27-
extern "C" fn virtio_phys_to_virt(paddr: PhysAddr) -> VirtAddr {
28-
paddr
29-
}
23+
fn dma_dealloc(paddr: PhysAddr, pages: usize) -> i32 {
24+
trace!("dealloc DMA: paddr={:#x}, pages={}", paddr, pages);
25+
0
26+
}
3027

31-
#[no_mangle]
32-
extern "C" fn virtio_virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
33-
vaddr
34-
}
28+
fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
29+
paddr
30+
}
3531

36-
type VirtAddr = usize;
37-
type PhysAddr = usize;
32+
fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
33+
vaddr
34+
}
35+
}

src/blk.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ 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> {
13+
pub struct VirtIOBlk<'a, H: Hal> {
1414
header: &'static mut VirtIOHeader,
15-
queue: VirtQueue<'a>,
15+
queue: VirtQueue<'a, H>,
1616
capacity: usize,
1717
}
1818

19-
impl VirtIOBlk<'_> {
19+
impl<H: Hal> VirtIOBlk<'_, H> {
2020
/// Create a new VirtIO-Blk driver.
2121
pub fn new(header: &'static mut VirtIOHeader) -> Result<Self> {
2222
header.begin_init(|features| {

src/console.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@ const QUEUE_TRANSMITQ_PORT_0: usize = 1;
1010

1111
/// Virtio console. Only one single port is allowed since ``alloc'' is disabled.
1212
/// Emergency and cols/rows unimplemented.
13-
pub struct VirtIOConsole<'a> {
13+
pub struct VirtIOConsole<'a, H: Hal> {
1414
header: &'static mut VirtIOHeader,
15-
receiveq: VirtQueue<'a>,
16-
transmitq: VirtQueue<'a>,
17-
queue_buf_dma: DMA,
15+
receiveq: VirtQueue<'a, H>,
16+
transmitq: VirtQueue<'a, H>,
17+
queue_buf_dma: DMA<H>,
1818
queue_buf_rx: &'a mut [u8],
1919
cursor: usize,
2020
pending_len: usize,
2121
}
2222

23-
impl<'a> VirtIOConsole<'a> {
23+
impl<H: Hal> VirtIOConsole<'_, H> {
2424
/// Create a new VirtIO-Console driver.
2525
pub fn new(header: &'static mut VirtIOHeader) -> Result<Self> {
2626
header.begin_init(|features| {

src/gpu.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,26 @@ use volatile::{ReadOnly, Volatile, WriteOnly};
1212
/// a gpu with 3D support on the host machine.
1313
/// In 2D mode the virtio-gpu device provides support for ARGB Hardware cursors
1414
/// and multiple scanouts (aka heads).
15-
pub struct VirtIOGpu<'a> {
15+
pub struct VirtIOGpu<'a, H: Hal> {
1616
header: &'static mut VirtIOHeader,
1717
rect: Rect,
1818
/// DMA area of frame buffer.
19-
frame_buffer_dma: Option<DMA>,
19+
frame_buffer_dma: Option<DMA<H>>,
2020
/// DMA area of cursor image buffer.
21-
cursor_buffer_dma: Option<DMA>,
21+
cursor_buffer_dma: Option<DMA<H>>,
2222
/// Queue for sending control commands.
23-
control_queue: VirtQueue<'a>,
23+
control_queue: VirtQueue<'a, H>,
2424
/// Queue for sending cursor commands.
25-
cursor_queue: VirtQueue<'a>,
25+
cursor_queue: VirtQueue<'a, H>,
2626
/// Queue buffer DMA
27-
queue_buf_dma: DMA,
27+
queue_buf_dma: DMA<H>,
2828
/// Send buffer for queue.
2929
queue_buf_send: &'a mut [u8],
3030
/// Recv buffer for queue.
3131
queue_buf_recv: &'a mut [u8],
3232
}
3333

34-
impl VirtIOGpu<'_> {
34+
impl<H: Hal> VirtIOGpu<'_, H> {
3535
/// Create a new VirtIO-Gpu driver.
3636
pub fn new(header: &'static mut VirtIOHeader) -> Result<Self> {
3737
header.begin_init(|features| {
@@ -153,9 +153,7 @@ impl VirtIOGpu<'_> {
153153
self.update_cursor(RESOURCE_ID_CURSOR, SCANOUT_ID, pos_x, pos_y, 0, 0, true)?;
154154
Ok(())
155155
}
156-
}
157156

158-
impl VirtIOGpu<'_> {
159157
/// Send a request to the device and block for a response.
160158
fn request<Req, Rsp>(&mut self, req: Req) -> Result<Rsp> {
161159
unsafe {

src/hal.rs

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,43 @@
11
use super::*;
2+
use core::marker::PhantomData;
23

3-
type VirtAddr = usize;
4-
type PhysAddr = usize;
4+
/// A virtual memory address in the address space of the program.
5+
pub type VirtAddr = usize;
6+
7+
/// A physical address as used for virtio.
8+
pub type PhysAddr = usize;
59

610
/// A region of contiguous physical memory used for DMA.
7-
pub struct DMA {
8-
paddr: u32,
9-
pages: u32,
11+
pub struct DMA<H: Hal> {
12+
paddr: usize,
13+
pages: usize,
14+
_phantom: PhantomData<H>,
1015
}
1116

12-
impl DMA {
17+
impl<H: Hal> DMA<H> {
1318
pub fn new(pages: usize) -> Result<Self> {
14-
let paddr = unsafe { virtio_dma_alloc(pages) };
19+
let paddr = H::dma_alloc(pages);
1520
if paddr == 0 {
1621
return Err(Error::DmaError);
1722
}
1823
Ok(DMA {
19-
paddr: paddr as u32,
20-
pages: pages as u32,
24+
paddr,
25+
pages,
26+
_phantom: PhantomData::default(),
2127
})
2228
}
2329

2430
pub fn paddr(&self) -> usize {
25-
self.paddr as usize
31+
self.paddr
2632
}
2733

2834
pub fn vaddr(&self) -> usize {
29-
phys_to_virt(self.paddr as usize)
35+
H::phys_to_virt(self.paddr)
3036
}
3137

3238
/// Returns the physical page frame number.
3339
pub fn pfn(&self) -> u32 {
34-
self.paddr >> 12
40+
(self.paddr >> 12) as u32
3541
}
3642

3743
/// Convert to a buffer
@@ -40,24 +46,23 @@ impl DMA {
4046
}
4147
}
4248

43-
impl Drop for DMA {
49+
impl<H: Hal> Drop for DMA<H> {
4450
fn drop(&mut self) {
45-
let err = unsafe { virtio_dma_dealloc(self.paddr as usize, self.pages as usize) };
51+
let err = H::dma_dealloc(self.paddr as usize, self.pages as usize);
4652
assert_eq!(err, 0, "failed to deallocate DMA");
4753
}
4854
}
4955

50-
pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
51-
unsafe { virtio_phys_to_virt(paddr) }
52-
}
53-
54-
pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
55-
unsafe { virtio_virt_to_phys(vaddr) }
56-
}
57-
58-
extern "C" {
59-
fn virtio_dma_alloc(pages: usize) -> PhysAddr;
60-
fn virtio_dma_dealloc(paddr: PhysAddr, pages: usize) -> i32;
61-
fn virtio_phys_to_virt(paddr: PhysAddr) -> VirtAddr;
62-
fn virtio_virt_to_phys(vaddr: VirtAddr) -> PhysAddr;
56+
/// The interface which a particular hardware implementation must implement.
57+
pub trait Hal {
58+
/// Allocates the given number of contiguous physical pages of DMA memory for virtio use.
59+
fn dma_alloc(pages: usize) -> PhysAddr;
60+
/// Deallocates the given contiguous physical DMA memory pages.
61+
fn dma_dealloc(paddr: PhysAddr, pages: usize) -> i32;
62+
/// Converts a physical address used for virtio to a virtual address which the program can
63+
/// access.
64+
fn phys_to_virt(paddr: PhysAddr) -> VirtAddr;
65+
/// Converts a virtual address which the program can access to the corresponding physical
66+
/// address to use for virtio.
67+
fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr;
6368
}

src/input.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ use volatile::{ReadOnly, WriteOnly};
99
/// An instance of the virtio device represents one such input device.
1010
/// Device behavior mirrors that of the evdev layer in Linux,
1111
/// making pass-through implementations on top of evdev easy.
12-
pub struct VirtIOInput<'a> {
12+
pub struct VirtIOInput<'a, H: Hal> {
1313
header: &'static mut VirtIOHeader,
14-
event_queue: VirtQueue<'a>,
15-
status_queue: VirtQueue<'a>,
14+
event_queue: VirtQueue<'a, H>,
15+
status_queue: VirtQueue<'a, H>,
1616
event_buf: Box<[InputEvent; 32]>,
1717
}
1818

19-
impl<'a> VirtIOInput<'a> {
19+
impl<'a, H: Hal> VirtIOInput<'a, H> {
2020
/// Create a new VirtIO-Input driver.
2121
pub fn new(header: &'static mut VirtIOHeader) -> Result<Self> {
2222
let mut event_buf = Box::new([InputEvent::default(); QUEUE_SIZE]);

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ mod queue;
1919
pub use self::blk::{BlkResp, RespStatus, VirtIOBlk};
2020
pub use self::console::VirtIOConsole;
2121
pub use self::gpu::VirtIOGpu;
22+
pub use self::hal::{Hal, PhysAddr, VirtAddr};
2223
pub use self::header::*;
2324
pub use self::input::{InputConfigSelect, InputEvent, VirtIOInput};
2425
pub use self::net::VirtIONet;

src/net.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ use volatile::{ReadOnly, Volatile};
1313
/// Empty buffers are placed in one virtqueue for receiving packets, and
1414
/// outgoing packets are enqueued into another for transmission in that order.
1515
/// A third command queue is used to control advanced filtering features.
16-
pub struct VirtIONet<'a> {
16+
pub struct VirtIONet<'a, H: Hal> {
1717
header: &'static mut VirtIOHeader,
1818
mac: EthernetAddress,
19-
recv_queue: VirtQueue<'a>,
20-
send_queue: VirtQueue<'a>,
19+
recv_queue: VirtQueue<'a, H>,
20+
send_queue: VirtQueue<'a, H>,
2121
}
2222

23-
impl VirtIONet<'_> {
23+
impl<H: Hal> VirtIONet<'_, H> {
2424
/// Create a new VirtIO-Net driver.
2525
pub fn new(header: &'static mut VirtIOHeader) -> Result<Self> {
2626
header.begin_init(|features| {

src/queue.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ use volatile::Volatile;
1212
///
1313
/// Each device can have zero or more virtqueues.
1414
#[repr(C)]
15-
pub struct VirtQueue<'a> {
15+
pub struct VirtQueue<'a, H: Hal> {
1616
/// DMA guard
17-
dma: DMA,
17+
dma: DMA<H>,
1818
/// Descriptor table
1919
desc: &'a mut [Descriptor],
2020
/// Available ring
@@ -34,7 +34,7 @@ pub struct VirtQueue<'a> {
3434
last_used_idx: u16,
3535
}
3636

37-
impl VirtQueue<'_> {
37+
impl<H: Hal> VirtQueue<'_, H> {
3838
/// Create a new VirtQueue.
3939
pub fn new(header: &mut VirtIOHeader, idx: usize, size: u16) -> Result<Self> {
4040
if header.queue_used(idx as u32) {
@@ -89,14 +89,14 @@ impl VirtQueue<'_> {
8989
let mut last = self.free_head;
9090
for input in inputs.iter() {
9191
let desc = &mut self.desc[self.free_head as usize];
92-
desc.set_buf(input);
92+
desc.set_buf::<H>(input);
9393
desc.flags.write(DescFlags::NEXT);
9494
last = self.free_head;
9595
self.free_head = desc.next.read();
9696
}
9797
for output in outputs.iter() {
9898
let desc = &mut self.desc[self.free_head as usize];
99-
desc.set_buf(output);
99+
desc.set_buf::<H>(output);
100100
desc.flags.write(DescFlags::NEXT | DescFlags::WRITE);
101101
last = self.free_head;
102102
self.free_head = desc.next.read();
@@ -214,8 +214,9 @@ struct Descriptor {
214214
}
215215

216216
impl Descriptor {
217-
fn set_buf(&mut self, buf: &[u8]) {
218-
self.addr.write(virt_to_phys(buf.as_ptr() as usize) as u64);
217+
fn set_buf<H: Hal>(&mut self, buf: &[u8]) {
218+
self.addr
219+
.write(H::virt_to_phys(buf.as_ptr() as usize) as u64);
219220
self.len.write(buf.len() as u32);
220221
}
221222
}

0 commit comments

Comments
 (0)