moros/sys/
ata.rs

1use crate::sys;
2use crate::api::fs::{FileIO, IO};
3
4use alloc::string::String;
5use alloc::vec::Vec;
6use bit_field::BitField;
7use core::convert::TryInto;
8use core::fmt;
9use core::hint::spin_loop;
10use lazy_static::lazy_static;
11use spin::Mutex;
12use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly};
13
14// Information Technology
15// AT Attachment with Packet Interface Extension (ATA/ATAPI-4)
16// (1998)
17
18pub const BLOCK_SIZE: usize = 512;
19
20// Keep track of the last selected bus and drive pair to speed up operations
21pub static LAST_SELECTED: Mutex<Option<(u8, u8)>> = Mutex::new(None);
22
23#[repr(u16)]
24#[derive(Debug, Clone, Copy)]
25enum Command {
26    Read     = 0x20,
27    Write    = 0x30,
28    Identify = 0xEC,
29}
30
31enum IdentifyResponse {
32    Ata([u16; 256]),
33    Atapi,
34    Sata,
35    None,
36}
37
38#[allow(dead_code)]
39#[repr(usize)]
40#[derive(Debug, Clone, Copy)]
41enum Status {
42    ERR  = 0, // Error
43    IDX  = 1, // (obsolete)
44    CORR = 2, // (obsolete)
45    DRQ  = 3, // Data Request
46    DSC  = 4, // (command dependant)
47    DF   = 5, // (command dependant)
48    DRDY = 6, // Device Ready
49    BSY  = 7, // Busy
50}
51
52#[allow(dead_code)]
53#[derive(Debug, Clone)]
54pub struct Bus {
55    id: u8,
56    irq: u8,
57
58    data_register: Port<u16>,
59    error_register: PortReadOnly<u8>,
60    features_register: PortWriteOnly<u8>,
61    sector_count_register: Port<u8>,
62    lba0_register: Port<u8>,
63    lba1_register: Port<u8>,
64    lba2_register: Port<u8>,
65    drive_register: Port<u8>,
66    status_register: PortReadOnly<u8>,
67    command_register: PortWriteOnly<u8>,
68
69    alternate_status_register: PortReadOnly<u8>,
70    control_register: PortWriteOnly<u8>,
71    drive_blockess_register: PortReadOnly<u8>,
72}
73
74impl Bus {
75    pub fn new(id: u8, io_base: u16, ctrl_base: u16, irq: u8) -> Self {
76        Self {
77            id,
78            irq,
79            data_register: Port::new(io_base + 0),
80            error_register: PortReadOnly::new(io_base + 1),
81            features_register: PortWriteOnly::new(io_base + 1),
82            sector_count_register: Port::new(io_base + 2),
83            lba0_register: Port::new(io_base + 3),
84            lba1_register: Port::new(io_base + 4),
85            lba2_register: Port::new(io_base + 5),
86            drive_register: Port::new(io_base + 6),
87            status_register: PortReadOnly::new(io_base + 7),
88            command_register: PortWriteOnly::new(io_base + 7),
89            alternate_status_register: PortReadOnly::new(ctrl_base + 0),
90            control_register: PortWriteOnly::new(ctrl_base + 0),
91            drive_blockess_register: PortReadOnly::new(ctrl_base + 1),
92        }
93    }
94
95    fn check_floating_bus(&mut self) -> Result<(), ()> {
96        match self.status() {
97            0xFF | 0x7F => Err(()),
98            _ => Ok(()),
99        }
100    }
101
102    fn wait(&mut self, ns: u64) {
103        sys::clk::wait(ns);
104    }
105
106    fn clear_interrupt(&mut self) -> u8 {
107        unsafe { self.status_register.read() }
108    }
109
110    fn status(&mut self) -> u8 {
111        unsafe { self.alternate_status_register.read() }
112    }
113
114    fn lba1(&mut self) -> u8 {
115        unsafe { self.lba1_register.read() }
116    }
117
118    fn lba2(&mut self) -> u8 {
119        unsafe { self.lba2_register.read() }
120    }
121
122    fn read_data(&mut self) -> u16 {
123        unsafe { self.data_register.read() }
124    }
125
126    fn write_data(&mut self, data: u16) {
127        unsafe { self.data_register.write(data) }
128    }
129
130    fn is_error(&mut self) -> bool {
131        self.status().get_bit(Status::ERR as usize)
132    }
133
134    fn poll(&mut self, bit: Status, val: bool) -> Result<(), ()> {
135        let start = sys::clk::boot_time();
136        while self.status().get_bit(bit as usize) != val {
137            if sys::clk::boot_time() - start > 1.0 {
138                debug!(
139                    "ATA hanged while polling {:?} bit in status register",
140                    bit
141                );
142                self.debug();
143                return Err(());
144            }
145            spin_loop();
146        }
147        Ok(())
148    }
149
150    fn select_drive(&mut self, drive: u8) -> Result<(), ()> {
151        self.poll(Status::BSY, false)?;
152        self.poll(Status::DRQ, false)?;
153
154        // Skip the rest if this drive was already selected
155        if *LAST_SELECTED.lock() == Some((self.id, drive)) {
156            return Ok(());
157        } else {
158            *LAST_SELECTED.lock() = Some((self.id, drive));
159        }
160
161        unsafe {
162            // Bit 4 => DEV
163            // Bit 5 => 1
164            // Bit 7 => 1
165            self.drive_register.write(0xA0 | (drive << 4))
166        }
167        sys::clk::wait(400); // Wait at least 400 ns
168        self.poll(Status::BSY, false)?;
169        self.poll(Status::DRQ, false)?;
170        Ok(())
171    }
172
173    fn write_command_params(
174        &mut self,
175        drive: u8,
176        block: u32
177    ) -> Result<(), ()> {
178        let lba = true;
179        let mut bytes = block.to_le_bytes();
180        bytes[3].set_bit(4, drive > 0);
181        bytes[3].set_bit(5, true);
182        bytes[3].set_bit(6, lba);
183        bytes[3].set_bit(7, true);
184        unsafe {
185            self.sector_count_register.write(1);
186            self.lba0_register.write(bytes[0]);
187            self.lba1_register.write(bytes[1]);
188            self.lba2_register.write(bytes[2]);
189            self.drive_register.write(bytes[3]);
190        }
191        Ok(())
192    }
193
194    fn write_command(&mut self, cmd: Command) -> Result<(), ()> {
195        unsafe { self.command_register.write(cmd as u8) }
196        self.wait(400); // Wait at least 400 ns
197        self.status(); // Ignore results of first read
198        self.clear_interrupt();
199        if self.status() == 0 { // Drive does not exist
200            return Err(());
201        }
202        if self.is_error() {
203            //debug!("ATA {:?} command errored", cmd);
204            //self.debug();
205            return Err(());
206        }
207        self.poll(Status::BSY, false)?;
208        self.poll(Status::DRQ, true)?;
209        Ok(())
210    }
211
212    fn setup_pio(&mut self, drive: u8, block: u32) -> Result<(), ()> {
213        self.select_drive(drive)?;
214        self.write_command_params(drive, block)?;
215        Ok(())
216    }
217
218    fn read(
219        &mut self,
220        drive: u8,
221        block: u32,
222        buf: &mut [u8]
223    ) -> Result<(), ()> {
224        debug_assert!(buf.len() == BLOCK_SIZE);
225        self.setup_pio(drive, block)?;
226        self.write_command(Command::Read)?;
227        for chunk in buf.chunks_mut(2) {
228            let data = self.read_data().to_le_bytes();
229            chunk.clone_from_slice(&data);
230        }
231        if self.is_error() {
232            debug!("ATA read: data error");
233            self.debug();
234            Err(())
235        } else {
236            Ok(())
237        }
238    }
239
240    fn write(&mut self, drive: u8, block: u32, buf: &[u8]) -> Result<(), ()> {
241        debug_assert!(buf.len() == BLOCK_SIZE);
242        self.setup_pio(drive, block)?;
243        self.write_command(Command::Write)?;
244        for chunk in buf.chunks(2) {
245            let data = u16::from_le_bytes(chunk.try_into().unwrap());
246            self.write_data(data);
247        }
248        if self.is_error() {
249            debug!("ATA write: data error");
250            self.debug();
251            Err(())
252        } else {
253            Ok(())
254        }
255    }
256
257    fn identify_drive(&mut self, drive: u8) -> Result<IdentifyResponse, ()> {
258        if self.check_floating_bus().is_err() {
259            return Ok(IdentifyResponse::None);
260        }
261        self.select_drive(drive)?;
262        self.write_command_params(drive, 0)?;
263        if self.write_command(Command::Identify).is_err() {
264            if self.status() == 0 {
265                return Ok(IdentifyResponse::None);
266            } else {
267                return Err(());
268            }
269        }
270        match (self.lba1(), self.lba2()) {
271            (0x00, 0x00) => {
272                Ok(IdentifyResponse::Ata([(); 256].map(|_| self.read_data())))
273            }
274            (0x14, 0xEB) => Ok(IdentifyResponse::Atapi),
275            (0x3C, 0xC3) => Ok(IdentifyResponse::Sata),
276            (_, _) => Err(()),
277        }
278    }
279
280    #[allow(dead_code)]
281    fn reset(&mut self) {
282        unsafe {
283            self.control_register.write(4); // Set SRST bit
284            self.wait(5); // Wait at least 5 ns
285            self.control_register.write(0); // Then clear it
286            self.wait(2000); // Wait at least 2 ms
287        }
288    }
289
290    #[allow(dead_code)]
291    fn debug(&mut self) {
292        unsafe {
293            debug!(
294                "ATA status register: 0b{:08b} <BSY|DRDY|#|#|DRQ|#|#|ERR>",
295                self.alternate_status_register.read()
296            );
297            debug!(
298                "ATA error register:  0b{:08b} <#|#|#|#|#|ABRT|#|#>",
299                self.error_register.read()
300            );
301        }
302    }
303}
304
305lazy_static! {
306    pub static ref BUSES: Mutex<Vec<Bus>> = Mutex::new(Vec::new());
307}
308
309pub fn init() {
310    {
311        let mut buses = BUSES.lock();
312        buses.push(Bus::new(0, 0x1F0, 0x3F6, 14));
313        buses.push(Bus::new(1, 0x170, 0x376, 15));
314    }
315
316    for drive in list() {
317        log!("ATA {}:{} {}", drive.bus, drive.dsk, drive);
318    }
319}
320
321#[derive(Clone, Debug)]
322pub struct Drive {
323    pub bus: u8,
324    pub dsk: u8,
325    model: String,
326    serial: String,
327    block_count: u32,
328    block_index: u32,
329}
330
331impl Drive {
332    pub fn size() -> usize {
333        BLOCK_SIZE
334    }
335
336    pub fn open(bus: u8, dsk: u8) -> Option<Self> {
337        let mut buses = BUSES.lock();
338        let res = buses[bus as usize].identify_drive(dsk);
339        if let Ok(IdentifyResponse::Ata(res)) = res {
340            let buf = res.map(u16::to_be_bytes).concat();
341            let model = String::from_utf8_lossy(&buf[54..94]).trim().into();
342            let serial = String::from_utf8_lossy(&buf[20..40]).trim().into();
343            let block_count = u32::from_be_bytes(
344                buf[120..124].try_into().unwrap()
345            ).rotate_left(16);
346            let block_index = 0;
347
348            Some(Self {
349                bus,
350                dsk,
351                model,
352                serial,
353                block_count,
354                block_index,
355            })
356        } else {
357            None
358        }
359    }
360
361    pub const fn block_size(&self) -> u32 {
362        BLOCK_SIZE as u32
363    }
364
365    pub fn block_count(&self) -> u32 {
366        self.block_count
367    }
368
369    fn humanized_size(&self) -> (usize, String) {
370        let size = self.block_size() as usize;
371        let count = self.block_count() as usize;
372        let bytes = size * count;
373        if bytes >> 20 < 1000 {
374            (bytes >> 20, String::from("MB"))
375        } else {
376            (bytes >> 30, String::from("GB"))
377        }
378    }
379}
380
381impl FileIO for Drive {
382    fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> {
383        if self.block_index == self.block_count {
384            return Ok(0);
385        }
386
387        let mut buses = BUSES.lock();
388        let bus = &mut buses[self.bus as usize];
389        bus.read(self.dsk, self.block_index, buf)?;
390        self.block_index += 1;
391        Ok(buf.len())
392    }
393
394    fn write(&mut self, buf: &[u8]) -> Result<usize, ()> {
395        let mut buses = BUSES.lock();
396        let bus = &mut buses[self.bus as usize];
397
398        let mut count = 0;
399        for chunk in buf.chunks(BLOCK_SIZE) {
400            if self.block_index == self.block_count {
401                return Err(());
402            }
403            let n = chunk.len();
404            if n == BLOCK_SIZE {
405                bus.write(self.dsk, self.block_index, chunk)?;
406            } else {
407                let mut block = [0; BLOCK_SIZE];
408                block[0..n].clone_from_slice(chunk);
409                bus.write(self.dsk, self.block_index, &block)?;
410            }
411            self.block_index += 1;
412            count += chunk.len();
413        }
414        Ok(count)
415    }
416
417    fn close(&mut self) {
418    }
419
420    fn poll(&mut self, event: IO) -> bool {
421        match event {
422            IO::Read => true,
423            IO::Write => true,
424        }
425    }
426}
427
428impl fmt::Display for Drive {
429    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
430        let (size, unit) = self.humanized_size();
431        write!(f, "{} {} ({} {})", self.model, self.serial, size, unit)
432    }
433}
434
435pub fn list() -> Vec<Drive> {
436    let mut res = Vec::new();
437    for bus in 0..2 {
438        for dsk in 0..2 {
439            if let Some(drive) = Drive::open(bus, dsk) {
440                res.push(drive)
441            }
442        }
443    }
444    res
445}
446
447pub fn read(bus: u8, drive: u8, block: u32, buf: &mut [u8]) -> Result<(), ()> {
448    let mut buses = BUSES.lock();
449    buses[bus as usize].read(drive, block, buf)
450}
451
452pub fn write(bus: u8, drive: u8, block: u32, buf: &[u8]) -> Result<(), ()> {
453    let mut buses = BUSES.lock();
454    buses[bus as usize].write(drive, block, buf)
455}