refactor: unsafe only in adapter + libkos; forbid(unsafe_code) everywhere else; libkos Window (volatile, bounds-checked MMIO/DMA/shared mem), entry!, thread::spawn; MapRegion returns pages; kernel const-built (with_cores/install_platform); newtype addrs
This commit is contained in:
@@ -1,24 +1,13 @@
|
||||
use crate::mmio::{MmioAccess, REG_QUEUE_NOTIFY};
|
||||
use core::sync::atomic::{Ordering, fence};
|
||||
use libkos::Window;
|
||||
|
||||
pub const QUEUE_SIZE: usize = 8;
|
||||
const DESC_SIZE: usize = 16;
|
||||
const TIMEOUT: u32 = 10_000_000;
|
||||
|
||||
pub struct QueueAddrs {
|
||||
pub desc: usize,
|
||||
pub avail: usize,
|
||||
pub used: usize,
|
||||
}
|
||||
|
||||
impl QueueAddrs {
|
||||
pub fn from_base(base: usize) -> Self {
|
||||
Self {
|
||||
desc: base,
|
||||
avail: base + QUEUE_SIZE * DESC_SIZE,
|
||||
used: base + 4096,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Where the legacy layout puts the available and used rings.
|
||||
const AVAIL: usize = QUEUE_SIZE * DESC_SIZE;
|
||||
const USED: usize = 4096;
|
||||
|
||||
pub struct Descriptor {
|
||||
pub addr: u64,
|
||||
@@ -26,55 +15,49 @@ pub struct Descriptor {
|
||||
pub writable: bool,
|
||||
}
|
||||
|
||||
/// One virtqueue in the legacy layout, over the two pages its rings sit in.
|
||||
pub struct VirtioQueue {
|
||||
addrs: QueueAddrs,
|
||||
rings: Window,
|
||||
}
|
||||
|
||||
impl VirtioQueue {
|
||||
pub fn new(addrs: QueueAddrs) -> Self {
|
||||
Self { addrs }
|
||||
pub fn new(rings: Window) -> Self {
|
||||
Self { rings }
|
||||
}
|
||||
|
||||
/// Hands the device a chain of `descs` and waits until it is used.
|
||||
pub fn submit(&self, mmio: &impl MmioAccess, descs: &[Descriptor]) -> bool {
|
||||
if descs.is_empty() || descs.len() > QUEUE_SIZE {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let desc_base = self.addrs.desc as *mut u8;
|
||||
for (i, d) in descs.iter().enumerate() {
|
||||
let p = desc_base.add(i * DESC_SIZE);
|
||||
core::ptr::write_volatile(p as *mut u64, d.addr);
|
||||
core::ptr::write_volatile(p.add(8) as *mut u32, d.len);
|
||||
let last = i == descs.len() - 1;
|
||||
let flags: u16 = if d.writable { 2 } else { 0 }
|
||||
| if !last { 1 } else { 0 };
|
||||
core::ptr::write_volatile(p.add(12) as *mut u16, flags);
|
||||
core::ptr::write_volatile(p.add(14) as *mut u16, if last { 0 } else { (i + 1) as u16 });
|
||||
}
|
||||
|
||||
let avail = self.addrs.avail;
|
||||
let avail_idx = core::ptr::read_volatile((avail + 2) as *const u16);
|
||||
core::ptr::write_volatile(
|
||||
(avail + 4 + (avail_idx as usize % QUEUE_SIZE) * 2) as *mut u16,
|
||||
0,
|
||||
);
|
||||
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
|
||||
core::ptr::write_volatile((avail + 2) as *mut u16, avail_idx.wrapping_add(1));
|
||||
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
mmio.write(REG_QUEUE_NOTIFY, 0);
|
||||
|
||||
let expected = avail_idx.wrapping_add(1);
|
||||
let used = self.addrs.used;
|
||||
let mut timeout = TIMEOUT;
|
||||
while core::ptr::read_volatile((used + 2) as *const u16) != expected {
|
||||
core::hint::spin_loop();
|
||||
timeout -= 1;
|
||||
if timeout == 0 { return false; }
|
||||
}
|
||||
let r = &self.rings;
|
||||
for (i, d) in descs.iter().enumerate() {
|
||||
let at = i * DESC_SIZE;
|
||||
let last = i == descs.len() - 1;
|
||||
let flags: u16 = if d.writable { 2 } else { 0 } | if !last { 1 } else { 0 };
|
||||
r.write(at, d.addr);
|
||||
r.write(at + 8, d.len);
|
||||
r.write(at + 12, flags);
|
||||
r.write(at + 14, if last { 0 } else { (i + 1) as u16 });
|
||||
}
|
||||
|
||||
let avail_idx: u16 = r.read(AVAIL + 2);
|
||||
r.write(AVAIL + 4 + (avail_idx as usize % QUEUE_SIZE) * 2, 0u16);
|
||||
fence(Ordering::SeqCst);
|
||||
r.write(AVAIL + 2, avail_idx.wrapping_add(1));
|
||||
fence(Ordering::SeqCst);
|
||||
|
||||
mmio.write(REG_QUEUE_NOTIFY, 0);
|
||||
|
||||
let expected = avail_idx.wrapping_add(1);
|
||||
let mut timeout = TIMEOUT;
|
||||
while r.read::<u16>(USED + 2) != expected {
|
||||
core::hint::spin_loop();
|
||||
timeout -= 1;
|
||||
if timeout == 0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user