lib.rs 1.72 KB
Newer Older
Jeremy Soller's avatar
Jeremy Soller committed
1 2 3 4
#![feature(question_mark)]

extern crate syscall;

5 6 7
use std::{mem, ptr};
use std::ops::{Deref, DerefMut};

Jeremy Soller's avatar
Jeremy Soller committed
8
use syscall::Result;
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

struct PhysBox {
    address: usize,
    size: usize
}

impl PhysBox {
    fn new(size: usize) -> Result<PhysBox> {
        let address = unsafe { syscall::physalloc(size)? };
        Ok(PhysBox {
            address: address,
            size: size
        })
    }
}

impl Drop for PhysBox {
    fn drop(&mut self) {
        let _ = unsafe { syscall::physfree(self.address, self.size) };
    }
}

pub struct Dma<T> {
    phys: PhysBox,
    virt: *mut T
}

impl<T> Dma<T> {
    pub fn new(value: T) -> Result<Dma<T>> {
        let phys = PhysBox::new(mem::size_of::<T>())?;
        let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T;
        unsafe { ptr::write(virt, value); }
        Ok(Dma {
            phys: phys,
            virt: virt
        })
    }

    pub fn zeroed() -> Result<Dma<T>> {
        let phys = PhysBox::new(mem::size_of::<T>())?;
        let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T;
        unsafe { ptr::write_bytes(virt as *mut u8, 0, phys.size); }
        Ok(Dma {
            phys: phys,
            virt: virt
        })
    }

    pub fn physical(&self) -> usize {
        self.phys.address
    }
}

impl<T> Deref for Dma<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.virt }
    }
}

impl<T> DerefMut for Dma<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.virt }
    }
}

impl<T> Drop for Dma<T> {
    fn drop(&mut self) {
        unsafe { drop(ptr::read(self.virt)); }
        let _ = unsafe { syscall::physunmap(self.virt as usize) };
    }
}