disk.rs 3.43 KB
Newer Older
Jeremy Soller's avatar
Jeremy Soller committed
1 2
use std::ptr;

Jeremy Soller's avatar
Jeremy Soller committed
3
use dma::Dma;
4
use syscall::error::Result;
Jeremy Soller's avatar
Jeremy Soller committed
5 6 7 8 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

use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader};

pub struct Disk {
    id: usize,
    port: &'static mut HbaPort,
    size: u64,
    clb: Dma<[HbaCmdHeader; 32]>,
    ctbas: [Dma<HbaCmdTable>; 32],
    fb: Dma<[u8; 256]>,
    buf: Dma<[u8; 256 * 512]>
}

impl Disk {
    pub fn new(id: usize, port: &'static mut HbaPort) -> Result<Self> {
        let mut clb = Dma::zeroed()?;
        let mut ctbas = [
            Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
            Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
            Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
            Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
            Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
            Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
            Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
            Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
        ];
        let mut fb = Dma::zeroed()?;
        let buf = Dma::zeroed()?;

        port.init(&mut clb, &mut ctbas, &mut fb);

        let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) };

        Ok(Disk {
            id: id,
            port: port,
            size: size,
            clb: clb,
            ctbas: ctbas,
            fb: fb,
            buf: buf
        })
    }

    pub fn id(&self) -> usize {
        self.id
    }

    pub fn size(&self) -> u64 {
        self.size
    }

    pub fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
        let sectors = buffer.len()/512;

60 61 62 63
        let mut sector: usize = 0;
        while sectors - sector >= 255 {
            if let Err(err) = self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf) {
                return Err(err);
Jeremy Soller's avatar
Jeremy Soller committed
64 65
            }

66
            unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); }
Jeremy Soller's avatar
Jeremy Soller committed
67

68 69 70 71 72
            sector += 255;
        }
        if sector < sectors {
            if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf) {
                return Err(err);
Jeremy Soller's avatar
Jeremy Soller committed
73 74
            }

75 76 77
            unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); }

            sector += sectors - sector;
Jeremy Soller's avatar
Jeremy Soller committed
78
        }
79 80

        Ok(sector * 512)
Jeremy Soller's avatar
Jeremy Soller committed
81 82 83
    }

    pub fn write(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
84
        let sectors = buffer.len()/512;
Jeremy Soller's avatar
Jeremy Soller committed
85

86 87 88
        let mut sector: usize = 0;
        while sectors - sector >= 255 {
            unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), 255 * 512); }
Jeremy Soller's avatar
Jeremy Soller committed
89

90 91
            if let Err(err) = self.port.ata_dma(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) {
                return Err(err);
Jeremy Soller's avatar
Jeremy Soller committed
92 93
            }

94 95 96 97
            sector += 255;
        }
        if sector < sectors {
            unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), (sectors - sector) * 512); }
Jeremy Soller's avatar
Jeremy Soller committed
98

99 100
            if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) {
                return Err(err);
Jeremy Soller's avatar
Jeremy Soller committed
101 102
            }

103
            sector += sectors - sector;
Jeremy Soller's avatar
Jeremy Soller committed
104
        }
105 106

        Ok(sector * 512)
Jeremy Soller's avatar
Jeremy Soller committed
107 108
    }
}