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,29 +1,20 @@
|
||||
#![no_std]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use hw_virtio::mmio::MmioAccess;
|
||||
use hw_virtio::queue::{QueueAddrs, VirtioQueue};
|
||||
use hw_virtio::block::{self, DmaAddrs};
|
||||
use hw_virtio::mmio::{MmioAccess, Registers};
|
||||
use hw_virtio::queue::VirtioQueue;
|
||||
use port_block_device::{BlockDevice, SectorId};
|
||||
use types::address::{PhysicalAddress, VirtualAddress};
|
||||
use types::bounded::PageCount;
|
||||
|
||||
const MMIO_BASE: usize = 0x20000;
|
||||
const VQUEUE_VA: usize = 0x21000;
|
||||
const REQ_HDR_VA: usize = 0x23000;
|
||||
const MMIO_VA: VirtualAddress = VirtualAddress::from_raw(0x20000);
|
||||
const VQUEUE_VA: VirtualAddress = VirtualAddress::from_raw(0x21000);
|
||||
const REQ_HDR_VA: VirtualAddress = VirtualAddress::from_raw(0x23000);
|
||||
const SECTOR_SIZE: usize = 512;
|
||||
|
||||
struct UserMmio;
|
||||
|
||||
impl MmioAccess for UserMmio {
|
||||
fn read(&self, offset: usize) -> u32 {
|
||||
unsafe { core::ptr::read_volatile((MMIO_BASE + offset) as *const u32) }
|
||||
}
|
||||
fn write(&self, offset: usize, val: u32) {
|
||||
unsafe { core::ptr::write_volatile((MMIO_BASE + offset) as *mut u32, val) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VirtioBlockDevice {
|
||||
mmio: UserMmio,
|
||||
mmio: Registers,
|
||||
queue: VirtioQueue,
|
||||
dma: DmaAddrs,
|
||||
sectors: usize,
|
||||
@@ -33,31 +24,31 @@ impl VirtioBlockDevice {
|
||||
/// Takes over the virtio block device behind `mmio`. `None` if it is
|
||||
/// not one or any step fails.
|
||||
pub fn new(mmio: types::bounded::CapSlot) -> Option<Self> {
|
||||
libkos::device::map_mmio(mmio, MMIO_BASE).ok()?;
|
||||
let regs = UserMmio;
|
||||
let regs = Registers::new(libkos::device::map_mmio(mmio, MMIO_VA).ok()?);
|
||||
if regs.read(hw_virtio::mmio::REG_MAGIC) != hw_virtio::mmio::MAGIC
|
||||
|| regs.read(hw_virtio::mmio::REG_DEVICE_ID) != hw_virtio::mmio::DEVICE_ID_BLOCK
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let vq_pa = libkos::device::dma(2, VQUEUE_VA).ok()?;
|
||||
let hdr_pa = libkos::device::dma(1, REQ_HDR_VA).ok()?;
|
||||
hw_virtio::mmio::init_legacy_device(®s, vq_pa, hw_virtio::queue::QUEUE_SIZE as u32);
|
||||
let rings = libkos::device::dma(PageCount::new(2)?, VQUEUE_VA).ok()?;
|
||||
let req = libkos::device::dma(PageCount::new(1)?, REQ_HDR_VA).ok()?;
|
||||
hw_virtio::mmio::init_legacy_device(®s, rings.physical, hw_virtio::queue::QUEUE_SIZE as u32);
|
||||
|
||||
// Header, status byte and one sector share the request page.
|
||||
let at = |offset: usize| PhysicalAddress::from_raw(req.physical.raw() + offset);
|
||||
let dma = DmaAddrs {
|
||||
header_pa: PhysicalAddress::from_raw(hdr_pa),
|
||||
header_va: VirtualAddress::from_raw(REQ_HDR_VA),
|
||||
status_pa: PhysicalAddress::from_raw(hdr_pa + 16),
|
||||
status_va: VirtualAddress::from_raw(REQ_HDR_VA + 16),
|
||||
data_pa: PhysicalAddress::from_raw(hdr_pa + 32),
|
||||
data_va: VirtualAddress::from_raw(REQ_HDR_VA + 32),
|
||||
header_pa: at(0),
|
||||
header: req.window.sub(0, 16),
|
||||
status_pa: at(16),
|
||||
status: req.window.sub(16, 1),
|
||||
data_pa: at(32),
|
||||
data: req.window.sub(32, SECTOR_SIZE),
|
||||
};
|
||||
let capacity = regs.read(block::CONFIG_CAPACITY) as u64
|
||||
| (regs.read(block::CONFIG_CAPACITY + 4) as u64) << 32;
|
||||
Some(Self {
|
||||
mmio: UserMmio,
|
||||
queue: VirtioQueue::new(QueueAddrs::from_base(VQUEUE_VA)),
|
||||
mmio: regs,
|
||||
queue: VirtioQueue::new(rings.window),
|
||||
dma,
|
||||
sectors: usize::try_from(capacity).ok()?,
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#![no_std]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use port_framebuffer::Framebuffer;
|
||||
use types::display::{Color, Dimension, ScreenCoord};
|
||||
|
||||
@@ -1,36 +1,30 @@
|
||||
#![no_std]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use hw_virtio::mmio::MmioAccess;
|
||||
use hw_virtio::queue::{QueueAddrs, VirtioQueue};
|
||||
use hw_virtio::gpu::{self, GpuDmaAddrs};
|
||||
use hw_virtio::mmio::{MmioAccess, Registers};
|
||||
use hw_virtio::queue::VirtioQueue;
|
||||
use libkos::Window;
|
||||
use port_framebuffer::Framebuffer;
|
||||
use types::address::{PhysicalAddress, VirtualAddress};
|
||||
use types::bounded::PageCount;
|
||||
use types::display::{Color, Dimension, ScreenCoord};
|
||||
|
||||
const GPU_MMIO_VA: usize = 0x20000;
|
||||
const VQUEUE_VA: usize = 0x21000;
|
||||
const CMDBUF_VA: usize = 0x23000;
|
||||
const FB_VA: usize = 0x100000;
|
||||
const GPU_MMIO_VA: VirtualAddress = VirtualAddress::from_raw(0x20000);
|
||||
const VQUEUE_VA: VirtualAddress = VirtualAddress::from_raw(0x21000);
|
||||
const CMDBUF_VA: VirtualAddress = VirtualAddress::from_raw(0x23000);
|
||||
const FB_VA: VirtualAddress = VirtualAddress::from_raw(0x100000);
|
||||
const FB_BPP: usize = 4;
|
||||
const RESOURCE_ID: u32 = 1;
|
||||
/// When the device will not say.
|
||||
const DEFAULT_SIZE: (u16, u16) = (640, 480);
|
||||
|
||||
struct GpuMmio;
|
||||
|
||||
impl MmioAccess for GpuMmio {
|
||||
fn read(&self, offset: usize) -> u32 {
|
||||
unsafe { core::ptr::read_volatile((GPU_MMIO_VA + offset) as *const u32) }
|
||||
}
|
||||
fn write(&self, offset: usize, val: u32) {
|
||||
unsafe { core::ptr::write_volatile((GPU_MMIO_VA + offset) as *mut u32, val) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VirtioFramebuffer {
|
||||
mmio: GpuMmio,
|
||||
mmio: Registers,
|
||||
queue: VirtioQueue,
|
||||
dma: GpuDmaAddrs,
|
||||
/// The pixels the device scans out, `stride` bytes a row.
|
||||
pixels: Window,
|
||||
width: Dimension,
|
||||
height: Dimension,
|
||||
stride: usize,
|
||||
@@ -40,24 +34,23 @@ impl VirtioFramebuffer {
|
||||
/// Takes over the virtio GPU behind `mmio` and makes a framebuffer its
|
||||
/// scanout. `None` if it is not a GPU or any step fails.
|
||||
pub fn try_new(mmio: types::bounded::CapSlot) -> Option<Self> {
|
||||
libkos::device::map_mmio(mmio, GPU_MMIO_VA).ok()?;
|
||||
let regs = GpuMmio;
|
||||
let regs = Registers::new(libkos::device::map_mmio(mmio, GPU_MMIO_VA).ok()?);
|
||||
if regs.read(hw_virtio::mmio::REG_MAGIC) != hw_virtio::mmio::MAGIC
|
||||
|| regs.read(hw_virtio::mmio::REG_DEVICE_ID) != hw_virtio::mmio::DEVICE_ID_GPU
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let vq_pa = libkos::device::dma(2, VQUEUE_VA).ok()?;
|
||||
let cmd_pa = libkos::device::dma(1, CMDBUF_VA).ok()?;
|
||||
hw_virtio::mmio::init_legacy_device(®s, vq_pa, hw_virtio::queue::QUEUE_SIZE as u32);
|
||||
let rings = libkos::device::dma(PageCount::new(2)?, VQUEUE_VA).ok()?;
|
||||
let cmd = libkos::device::dma(PageCount::new(1)?, CMDBUF_VA).ok()?;
|
||||
hw_virtio::mmio::init_legacy_device(®s, rings.physical, hw_virtio::queue::QUEUE_SIZE as u32);
|
||||
|
||||
let queue = VirtioQueue::new(QueueAddrs::from_base(VQUEUE_VA));
|
||||
let queue = VirtioQueue::new(rings.window);
|
||||
// Commands go out from the start of the page, responses come back
|
||||
// in its second half.
|
||||
let dma = GpuDmaAddrs {
|
||||
cmd_pa: PhysicalAddress::from_raw(cmd_pa),
|
||||
cmd_va: VirtualAddress::from_raw(CMDBUF_VA),
|
||||
resp_pa: PhysicalAddress::from_raw(cmd_pa + 512),
|
||||
cmd_pa: cmd.physical,
|
||||
cmd: cmd.window,
|
||||
resp_pa: PhysicalAddress::from_raw(cmd.physical.raw() + gpu::RESPONSE),
|
||||
};
|
||||
let (w, h) = gpu::get_display_info(®s, &queue, &dma)
|
||||
.and_then(|(w, h)| Some((u16::try_from(w).ok()?, u16::try_from(h).ok()?)))
|
||||
@@ -65,19 +58,20 @@ impl VirtioFramebuffer {
|
||||
.unwrap_or(DEFAULT_SIZE);
|
||||
let (width, height) = (Dimension::new(w), Dimension::new(h));
|
||||
let fb_bytes = w as usize * h as usize * FB_BPP;
|
||||
let fb_pages = u16::try_from(fb_bytes.div_ceil(4096)).ok()?;
|
||||
let fb_pa = PhysicalAddress::from_raw(libkos::device::dma(fb_pages, FB_VA).ok()?);
|
||||
let fb_pages = PageCount::new(u16::try_from(fb_bytes.div_ceil(4096)).ok()?)?;
|
||||
let fb = libkos::device::dma(fb_pages, FB_VA).ok()?;
|
||||
|
||||
let ready = gpu::create_2d(®s, &queue, &dma, RESOURCE_ID, width, height)
|
||||
&& gpu::attach_backing(®s, &queue, &dma, RESOURCE_ID, fb_pa, fb_bytes as u32)
|
||||
&& gpu::attach_backing(®s, &queue, &dma, RESOURCE_ID, fb.physical, fb_bytes as u32)
|
||||
&& gpu::set_scanout(®s, &queue, &dma, 0, RESOURCE_ID, width, height);
|
||||
if !ready {
|
||||
return None;
|
||||
}
|
||||
Some(Self {
|
||||
mmio: GpuMmio,
|
||||
mmio: regs,
|
||||
queue,
|
||||
dma,
|
||||
pixels: fb.window,
|
||||
width,
|
||||
height,
|
||||
stride: w as usize * FB_BPP,
|
||||
@@ -86,13 +80,20 @@ impl VirtioFramebuffer {
|
||||
}
|
||||
|
||||
impl Framebuffer for VirtioFramebuffer {
|
||||
fn width(&self) -> Dimension { self.width }
|
||||
fn height(&self) -> Dimension { self.height }
|
||||
fn width(&self) -> Dimension {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn height(&self) -> Dimension {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn write_pixel(&mut self, x: ScreenCoord, y: ScreenCoord, color: Color) {
|
||||
if x.raw() >= self.width.raw() || y.raw() >= self.height.raw() { return; }
|
||||
if x.raw() >= self.width.raw() || y.raw() >= self.height.raw() {
|
||||
return;
|
||||
}
|
||||
let offset = (y.raw() as usize) * self.stride + (x.raw() as usize) * FB_BPP;
|
||||
unsafe { core::ptr::write_volatile((FB_VA + offset) as *mut u32, color.raw()); }
|
||||
self.pixels.write(offset, color.raw());
|
||||
}
|
||||
|
||||
fn fill_rect(&mut self, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color) {
|
||||
@@ -105,9 +106,7 @@ impl Framebuffer for VirtioFramebuffer {
|
||||
|
||||
fn clear(&mut self, color: Color) {
|
||||
let total = self.width.raw() as usize * self.height.raw() as usize;
|
||||
for i in 0..total {
|
||||
unsafe { core::ptr::write_volatile((FB_VA as *mut u32).add(i), color.raw()); }
|
||||
}
|
||||
self.pixels.fill_u32(0, total, color.raw());
|
||||
}
|
||||
|
||||
fn flush(&mut self) {
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
#![no_std]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use libkos::Window;
|
||||
use port_input_device::{InputDevice, InputEvent, Key};
|
||||
use types::address::VirtualAddress;
|
||||
|
||||
const UART_VA: usize = 0x20000;
|
||||
const UART_VA: VirtualAddress = VirtualAddress::from_raw(0x20000);
|
||||
const UART_IER_OFFSET: usize = 1;
|
||||
const UART_LSR_OFFSET: usize = 5;
|
||||
/// IER bit: interrupt when a received byte is waiting (cleared by reading
|
||||
/// it, so `acknowledge` has nothing to do).
|
||||
const IER_RX_READY: u8 = 1;
|
||||
|
||||
pub struct UartInputDevice;
|
||||
/// The UART's registers, one byte each.
|
||||
pub struct UartInputDevice {
|
||||
regs: Window,
|
||||
}
|
||||
|
||||
impl UartInputDevice {
|
||||
/// Maps the 16550 UART whose region `mmio` names and enables its
|
||||
/// receive interrupt.
|
||||
pub fn new(mmio: types::bounded::CapSlot) -> Option<Self> {
|
||||
libkos::device::map_mmio(mmio, UART_VA).ok()?;
|
||||
// SAFETY: UART_VA now maps the UART's registers.
|
||||
unsafe { core::ptr::write_volatile((UART_VA + UART_IER_OFFSET) as *mut u8, IER_RX_READY) };
|
||||
Some(Self)
|
||||
let regs = libkos::device::map_mmio(mmio, UART_VA).ok()?;
|
||||
regs.write(UART_IER_OFFSET, IER_RX_READY);
|
||||
Some(Self { regs })
|
||||
}
|
||||
|
||||
fn read_byte(&self) -> Option<u8> {
|
||||
let lsr = unsafe { core::ptr::read_volatile((UART_VA + UART_LSR_OFFSET) as *const u8) };
|
||||
if lsr & 1 != 0 {
|
||||
Some(unsafe { core::ptr::read_volatile(UART_VA as *const u8) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
self.has_event().then(|| self.regs.read(0))
|
||||
}
|
||||
|
||||
fn byte_to_key(byte: u8) -> Key {
|
||||
@@ -50,7 +50,6 @@ impl InputDevice for UartInputDevice {
|
||||
}
|
||||
|
||||
fn has_event(&self) -> bool {
|
||||
let lsr = unsafe { core::ptr::read_volatile((UART_VA + UART_LSR_OFFSET) as *const u8) };
|
||||
lsr & 1 != 0
|
||||
self.regs.read::<u8>(UART_LSR_OFFSET) & 1 != 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,37 @@
|
||||
#![no_std]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
mod keymap;
|
||||
|
||||
use hw_virtio::mmio::MmioAccess;
|
||||
use core::sync::atomic::{Ordering, fence};
|
||||
use hw_virtio::mmio::{MmioAccess, Registers};
|
||||
use libkos::Window;
|
||||
use port_input_device::{InputDevice, InputEvent};
|
||||
use types::address::{PhysicalAddress, VirtualAddress};
|
||||
use types::bounded::PageCount;
|
||||
|
||||
const INPUT_MMIO_VA: usize = 0x25000;
|
||||
const VQUEUE_VA: usize = 0x26000;
|
||||
const EVBUF_VA: usize = 0x28000;
|
||||
const INPUT_MMIO_VA: VirtualAddress = VirtualAddress::from_raw(0x25000);
|
||||
const VQUEUE_VA: VirtualAddress = VirtualAddress::from_raw(0x26000);
|
||||
const EVBUF_VA: VirtualAddress = VirtualAddress::from_raw(0x28000);
|
||||
|
||||
const QUEUE_SIZE: usize = 32;
|
||||
const EVENT_SIZE: usize = 8;
|
||||
const DESC_SIZE: usize = 16;
|
||||
/// Where the legacy layout puts the available and used rings.
|
||||
const AVAIL: usize = QUEUE_SIZE * DESC_SIZE;
|
||||
const USED: usize = 4096;
|
||||
|
||||
const EV_KEY: u16 = 1;
|
||||
const KEY_PRESS: u32 = 1;
|
||||
|
||||
struct MmioInput;
|
||||
|
||||
impl hw_virtio::mmio::MmioAccess for MmioInput {
|
||||
fn read(&self, offset: usize) -> u32 {
|
||||
unsafe { core::ptr::read_volatile((INPUT_MMIO_VA + offset) as *const u32) }
|
||||
}
|
||||
fn write(&self, offset: usize, val: u32) {
|
||||
unsafe { core::ptr::write_volatile((INPUT_MMIO_VA + offset) as *mut u32, val) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VirtioInputDevice {
|
||||
regs: Registers,
|
||||
/// The queue's rings, and the buffers the device writes events into.
|
||||
rings: Window,
|
||||
events: Window,
|
||||
events_pa: PhysicalAddress,
|
||||
last_used: u16,
|
||||
next_avail: u16,
|
||||
evbuf_pa: usize,
|
||||
shift: bool,
|
||||
ctrl: bool,
|
||||
}
|
||||
@@ -38,87 +40,68 @@ impl VirtioInputDevice {
|
||||
/// Takes over the virtio input device behind `mmio`. `None` if it is
|
||||
/// not one or any step fails.
|
||||
pub fn try_new(mmio: types::bounded::CapSlot) -> Option<Self> {
|
||||
libkos::device::map_mmio(mmio, INPUT_MMIO_VA).ok()?;
|
||||
let regs = MmioInput;
|
||||
let regs = Registers::new(libkos::device::map_mmio(mmio, INPUT_MMIO_VA).ok()?);
|
||||
if regs.read(hw_virtio::mmio::REG_MAGIC) != hw_virtio::mmio::MAGIC
|
||||
|| regs.read(hw_virtio::mmio::REG_DEVICE_ID) != hw_virtio::mmio::DEVICE_ID_INPUT
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let vq_pa = libkos::device::dma(2, VQUEUE_VA).ok()?;
|
||||
let evbuf_pa = libkos::device::dma(1, EVBUF_VA).ok()?;
|
||||
hw_virtio::mmio::init_legacy_device(®s, vq_pa, QUEUE_SIZE as u32);
|
||||
let rings = libkos::device::dma(PageCount::new(2)?, VQUEUE_VA).ok()?;
|
||||
let events = libkos::device::dma(PageCount::new(1)?, EVBUF_VA).ok()?;
|
||||
hw_virtio::mmio::init_legacy_device(®s, rings.physical, QUEUE_SIZE as u32);
|
||||
|
||||
let mut dev = Self { last_used: 0, next_avail: 0, evbuf_pa, shift: false, ctrl: false };
|
||||
let mut dev = Self {
|
||||
regs,
|
||||
rings: rings.window,
|
||||
events: events.window,
|
||||
events_pa: events.physical,
|
||||
last_used: 0,
|
||||
next_avail: 0,
|
||||
shift: false,
|
||||
ctrl: false,
|
||||
};
|
||||
dev.fill_queue();
|
||||
Some(dev)
|
||||
}
|
||||
|
||||
/// Every buffer goes to the device, one event each.
|
||||
fn fill_queue(&mut self) {
|
||||
let evbuf_phys = self.evbuf_pa;
|
||||
let desc_base = VQUEUE_VA;
|
||||
let avail_base = VQUEUE_VA + QUEUE_SIZE * 16;
|
||||
|
||||
for i in 0..QUEUE_SIZE {
|
||||
let desc = desc_base + i * 16;
|
||||
let buf_pa = evbuf_phys + i * EVENT_SIZE;
|
||||
unsafe {
|
||||
core::ptr::write_volatile(desc as *mut u64, buf_pa as u64);
|
||||
core::ptr::write_volatile((desc + 8) as *mut u32, EVENT_SIZE as u32);
|
||||
core::ptr::write_volatile((desc + 12) as *mut u16, 2); // WRITE flag
|
||||
core::ptr::write_volatile((desc + 14) as *mut u16, 0); // no next
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let ring_entry = avail_base + 4 + (i % QUEUE_SIZE) * 2;
|
||||
core::ptr::write_volatile(ring_entry as *mut u16, i as u16);
|
||||
}
|
||||
let desc = i * DESC_SIZE;
|
||||
self.rings.write(desc, (self.events_pa.raw() + i * EVENT_SIZE) as u64);
|
||||
self.rings.write(desc + 8, EVENT_SIZE as u32);
|
||||
self.rings.write(desc + 12, 2u16); // WRITE flag
|
||||
self.rings.write(desc + 14, 0u16); // no next
|
||||
self.rings.write(AVAIL + 4 + i * 2, i as u16);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
|
||||
core::ptr::write_volatile((avail_base + 2) as *mut u16, QUEUE_SIZE as u16);
|
||||
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
|
||||
}
|
||||
|
||||
let mmio = MmioInput;
|
||||
mmio.write(hw_virtio::mmio::REG_QUEUE_NOTIFY, 0);
|
||||
fence(Ordering::SeqCst);
|
||||
self.rings.write(AVAIL + 2, QUEUE_SIZE as u16);
|
||||
fence(Ordering::SeqCst);
|
||||
self.regs.write(hw_virtio::mmio::REG_QUEUE_NOTIFY, 0);
|
||||
self.next_avail = QUEUE_SIZE as u16;
|
||||
}
|
||||
|
||||
fn resubmit(&mut self, desc_idx: u16) {
|
||||
let avail_base = VQUEUE_VA + QUEUE_SIZE * 16;
|
||||
let slot = self.next_avail as usize % QUEUE_SIZE;
|
||||
unsafe {
|
||||
core::ptr::write_volatile((avail_base + 4 + slot * 2) as *mut u16, desc_idx);
|
||||
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
|
||||
self.next_avail = self.next_avail.wrapping_add(1);
|
||||
core::ptr::write_volatile((avail_base + 2) as *mut u16, self.next_avail);
|
||||
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
|
||||
}
|
||||
let mmio = MmioInput;
|
||||
mmio.write(hw_virtio::mmio::REG_QUEUE_NOTIFY, 0);
|
||||
self.rings.write(AVAIL + 4 + slot * 2, desc_idx);
|
||||
fence(Ordering::SeqCst);
|
||||
self.next_avail = self.next_avail.wrapping_add(1);
|
||||
self.rings.write(AVAIL + 2, self.next_avail);
|
||||
fence(Ordering::SeqCst);
|
||||
self.regs.write(hw_virtio::mmio::REG_QUEUE_NOTIFY, 0);
|
||||
}
|
||||
|
||||
fn read_event(&self, desc_idx: u16) -> (u16, u16, u32) {
|
||||
let buf_va = EVBUF_VA + (desc_idx as usize) * EVENT_SIZE;
|
||||
unsafe {
|
||||
let ev_type = core::ptr::read_volatile(buf_va as *const u16);
|
||||
let ev_code = core::ptr::read_volatile((buf_va + 2) as *const u16);
|
||||
let ev_value = core::ptr::read_volatile((buf_va + 4) as *const u32);
|
||||
(ev_type, ev_code, ev_value)
|
||||
}
|
||||
let at = desc_idx as usize % QUEUE_SIZE * EVENT_SIZE;
|
||||
(self.events.read(at), self.events.read(at + 2), self.events.read(at + 4))
|
||||
}
|
||||
|
||||
fn used_idx(&self) -> u16 {
|
||||
let used_base = VQUEUE_VA + 4096;
|
||||
unsafe { core::ptr::read_volatile((used_base + 2) as *const u16) }
|
||||
self.rings.read(USED + 2)
|
||||
}
|
||||
|
||||
fn used_entry_id(&self, idx: u16) -> u16 {
|
||||
let used_base = VQUEUE_VA + 4096;
|
||||
let entry = used_base + 4 + (idx as usize % QUEUE_SIZE) * 8;
|
||||
unsafe { core::ptr::read_volatile(entry as *const u32) as u16 }
|
||||
self.rings.read::<u32>(USED + 4 + (idx as usize % QUEUE_SIZE) * 8) as u16
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,8 +146,7 @@ impl InputDevice for VirtioInputDevice {
|
||||
}
|
||||
|
||||
fn acknowledge(&mut self) {
|
||||
let regs = MmioInput;
|
||||
let status = regs.read(hw_virtio::mmio::REG_INTERRUPT_STATUS);
|
||||
regs.write(hw_virtio::mmio::REG_INTERRUPT_ACK, status);
|
||||
let status = self.regs.read(hw_virtio::mmio::REG_INTERRUPT_STATUS);
|
||||
self.regs.write(hw_virtio::mmio::REG_INTERRUPT_ACK, status);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user