Explorar o código

Allow transport to use 64-bit addresses for queue rather than PFN.

This will allow support for the modern MMIO interface.
Andrew Walbran %!s(int64=2) %!d(string=hai) anos
pai
achega
2905932e70
Modificáronse 4 ficheiros con 44 adicións e 20 borrados
  1. 0 5
      src/hal.rs
  2. 8 2
      src/queue.rs
  3. 24 3
      src/transport/mmio.rs
  4. 12 10
      src/transport/mod.rs

+ 0 - 5
src/hal.rs

@@ -39,11 +39,6 @@ impl<H: Hal> DMA<H> {
         H::phys_to_virt(self.paddr)
     }
 
-    /// Returns the physical page frame number.
-    pub fn pfn(&self) -> u32 {
-        (self.paddr >> 12) as u32
-    }
-
     /// Convert to a buffer
     pub unsafe fn as_buf(&self) -> &'static mut [u8] {
         core::slice::from_raw_parts_mut(self.vaddr() as _, PAGE_SIZE * self.pages as usize)

+ 8 - 2
src/queue.rs

@@ -50,7 +50,13 @@ impl<H: Hal> VirtQueue<'_, H> {
         // Allocate contiguous pages.
         let dma = DMA::new(layout.size / PAGE_SIZE)?;
 
-        transport.queue_set(idx as u32, size as u32, PAGE_SIZE as u32, dma.pfn());
+        transport.queue_set(
+            idx as u32,
+            size as u32,
+            dma.paddr(),
+            dma.paddr() + layout.avail_offset,
+            dma.paddr() + layout.used_offset,
+        );
 
         let desc =
             unsafe { slice::from_raw_parts_mut(dma.vaddr() as *mut Descriptor, size as usize) };
@@ -209,7 +215,7 @@ impl VirtQueueLayout {
 
 #[repr(C, align(16))]
 #[derive(Debug)]
-struct Descriptor {
+pub(crate) struct Descriptor {
     addr: Volatile<u64>,
     len: Volatile<u32>,
     flags: Volatile<DescFlags>,

+ 24 - 3
src/transport/mmio.rs

@@ -1,4 +1,6 @@
 use super::{DeviceStatus, DeviceType, Transport};
+use crate::{align_up, queue::Descriptor, PhysAddr, PAGE_SIZE};
+use core::mem::size_of;
 use volatile::{ReadOnly, Volatile, WriteOnly};
 
 const MAGIC_VALUE: u32 = 0x7472_6976;
@@ -246,16 +248,35 @@ impl Transport for VirtIOHeader {
         self.guest_page_size.write(guest_page_size);
     }
 
-    fn queue_set(&mut self, queue: u32, size: u32, align: u32, pfn: u32) {
+    fn queue_set(
+        &mut self,
+        queue: u32,
+        size: u32,
+        descriptors: PhysAddr,
+        driver_area: PhysAddr,
+        device_area: PhysAddr,
+    ) {
+        assert_eq!(
+            driver_area - descriptors,
+            size_of::<Descriptor>() * size as usize
+        );
+        assert_eq!(
+            device_area - descriptors,
+            align_up(
+                size_of::<Descriptor>() * size as usize + size_of::<u16>() * (size as usize + 3)
+            )
+        );
+        let align = PAGE_SIZE as u32;
+        let pfn = (descriptors / PAGE_SIZE) as u32;
         self.queue_sel.write(queue);
         self.queue_num.write(size);
         self.queue_align.write(align);
         self.queue_pfn.write(pfn);
     }
 
-    fn queue_physical_page_number(&mut self, queue: u32) -> u32 {
+    fn queue_used(&mut self, queue: u32) -> bool {
         self.queue_sel.write(queue);
-        self.queue_pfn.read()
+        self.queue_pfn.read() != 0
     }
 
     fn ack_interrupt(&mut self) -> bool {

+ 12 - 10
src/transport/mod.rs

@@ -1,6 +1,6 @@
 pub mod mmio;
 
-use crate::PAGE_SIZE;
+use crate::{PhysAddr, PAGE_SIZE};
 use bitflags::bitflags;
 
 /// A VirtIO transport layer.
@@ -24,10 +24,17 @@ pub trait Transport {
     fn set_guest_page_size(&mut self, guest_page_size: u32);
 
     /// Sets up the given queue.
-    fn queue_set(&mut self, queue: u32, size: u32, align: u32, pfn: u32);
-
-    /// Gets the guest physical page number of the given virtual queue.
-    fn queue_physical_page_number(&mut self, queue: u32) -> u32;
+    fn queue_set(
+        &mut self,
+        queue: u32,
+        size: u32,
+        descriptors: PhysAddr,
+        driver_area: PhysAddr,
+        device_area: PhysAddr,
+    );
+
+    /// Returns whether the queue is in use, i.e. has a nonzero PFN or is marked as ready.
+    fn queue_used(&mut self, queue: u32) -> bool;
 
     /// Acknowledges an interrupt.
     ///
@@ -53,11 +60,6 @@ pub trait Transport {
         self.set_status(DeviceStatus::DRIVER_OK);
     }
 
-    /// Returns whether the queue is in use, i.e. has a nonzero PFN.
-    fn queue_used(&mut self, queue: u32) -> bool {
-        self.queue_physical_page_number(queue) != 0
-    }
-
     /// Gets the pointer to the config space.
     fn config_space(&self) -> *mut u64;
 }