hal.rs 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. #[cfg(test)]
  2. pub mod fake;
  3. use super::*;
  4. use core::marker::PhantomData;
  5. /// A virtual memory address in the address space of the program.
  6. pub type VirtAddr = usize;
  7. /// A physical address as used for virtio.
  8. pub type PhysAddr = usize;
  9. /// A region of contiguous physical memory used for DMA.
  10. #[derive(Debug)]
  11. pub struct DMA<H: Hal> {
  12. paddr: usize,
  13. pages: usize,
  14. _phantom: PhantomData<H>,
  15. }
  16. impl<H: Hal> DMA<H> {
  17. pub fn new(pages: usize) -> Result<Self> {
  18. let paddr = H::dma_alloc(pages);
  19. if paddr == 0 {
  20. return Err(Error::DmaError);
  21. }
  22. Ok(DMA {
  23. paddr,
  24. pages,
  25. _phantom: PhantomData::default(),
  26. })
  27. }
  28. pub fn paddr(&self) -> usize {
  29. self.paddr
  30. }
  31. pub fn vaddr(&self) -> usize {
  32. H::phys_to_virt(self.paddr)
  33. }
  34. /// Convert to a buffer
  35. pub unsafe fn as_buf(&self) -> &'static mut [u8] {
  36. core::slice::from_raw_parts_mut(self.vaddr() as _, PAGE_SIZE * self.pages as usize)
  37. }
  38. }
  39. impl<H: Hal> Drop for DMA<H> {
  40. fn drop(&mut self) {
  41. let err = H::dma_dealloc(self.paddr as usize, self.pages as usize);
  42. assert_eq!(err, 0, "failed to deallocate DMA");
  43. }
  44. }
  45. /// The interface which a particular hardware implementation must implement.
  46. pub trait Hal {
  47. /// Allocates the given number of contiguous physical pages of DMA memory for virtio use.
  48. fn dma_alloc(pages: usize) -> PhysAddr;
  49. /// Deallocates the given contiguous physical DMA memory pages.
  50. fn dma_dealloc(paddr: PhysAddr, pages: usize) -> i32;
  51. /// Converts a physical address used for virtio to a virtual address which the program can
  52. /// access.
  53. fn phys_to_virt(paddr: PhysAddr) -> VirtAddr;
  54. /// Converts a virtual address which the program can access to the corresponding physical
  55. /// address to use for virtio.
  56. fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr;
  57. }