strat9_kernel/hardware/storage/
ata_legacy.rs1use alloc::{format, string::String, sync::Arc, vec::Vec};
5use core::sync::atomic::{AtomicBool, Ordering};
6use spin::Mutex;
7
8use super::virtio_block::{BlockDevice, BlockError, SECTOR_SIZE};
9
10const ATA_PRIMARY_IO: u16 = 0x1F0;
11const ATA_SECONDARY_IO: u16 = 0x170;
12
13#[allow(dead_code)]
14const ATA_REG_DATA: usize = 0;
15#[allow(dead_code)]
16const ATA_REG_ERROR: usize = 1;
17const ATA_REG_SECCOUNT: usize = 2;
18const ATA_REG_LBA_LOW: usize = 3;
19const ATA_REG_LBA_MID: usize = 4;
20const ATA_REG_LBA_HIGH: usize = 5;
21const ATA_REG_DEVICE: usize = 6;
22const ATA_REG_STATUS: usize = 7;
23const ATA_REG_COMMAND: usize = 7;
24
25const ATA_SR_BSY: u8 = 0x80;
26#[allow(dead_code)]
27const ATA_SR_DRDY: u8 = 0x40;
28const ATA_SR_DRQ: u8 = 0x08;
29const ATA_SR_ERR: u8 = 0x01;
30
31const ATA_CMD_IDENTIFY: u8 = 0xEC;
32
33const ATA_DEVICE_MASTER: u8 = 0xA0;
34const ATA_DEVICE_SLAVE: u8 = 0xB0;
35const ATA_DEVICE_LBA: u8 = 0x40;
36
37#[derive(Clone, Copy)]
38pub struct AtaChannel {
39 io_base: u16,
40 #[allow(dead_code)]
41 control_base: u16,
42 bus: u8,
43}
44
45impl AtaChannel {
46 fn new(io_base: u16, bus: u8) -> Self {
48 Self {
49 io_base,
50 control_base: io_base + 0x206,
51 bus,
52 }
53 }
54
55 fn read8(&self, offset: usize) -> u8 {
57 unsafe {
58 crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset as u16)
59 .read()
60 }
61 }
62
63 fn write8(&self, offset: usize, value: u8) {
65 unsafe {
66 crate::x86_crate_shim::instructions::port::Port::new(self.io_base + offset as u16)
67 .write(value)
68 }
69 }
70
71 fn read16(&self) -> u16 {
73 unsafe { crate::x86_crate_shim::instructions::port::Port::new(self.io_base).read() }
74 }
75
76 fn write16(&self, value: u16) {
78 unsafe { crate::x86_crate_shim::instructions::port::Port::new(self.io_base).write(value) }
79 }
80
81 fn wait_ready(&self) -> Result<(), &'static str> {
83 for _ in 0..100000 {
84 let status = self.read8(ATA_REG_STATUS);
85 if (status & ATA_SR_BSY) == 0 {
86 return Ok(());
87 }
88 core::hint::spin_loop();
89 }
90 Err("ATA timeout")
91 }
92
93 fn wait_drq(&self) -> Result<(), &'static str> {
95 for _ in 0..100000 {
96 let status = self.read8(ATA_REG_STATUS);
97 if (status & ATA_SR_DRQ) != 0 {
98 return Ok(());
99 }
100 if (status & ATA_SR_ERR) != 0 {
101 return Err("ATA error");
102 }
103 core::hint::spin_loop();
104 }
105 Err("ATA timeout")
106 }
107
108 fn select_device(&self, _device: u8, lba: u64) {
110 let device_reg = ATA_DEVICE_MASTER | ATA_DEVICE_LBA | ((lba >> 24) & 0x0F) as u8;
111 self.write8(ATA_REG_DEVICE, device_reg);
112 self.read8(ATA_REG_STATUS);
113 for _ in 0..4 {
114 core::hint::spin_loop();
115 }
116 }
117
118 fn identify(&self, device: u8) -> Option<AtaDriveInfo> {
120 self.select_device(device, 0);
121 self.write8(ATA_REG_SECCOUNT, 0);
122 self.write8(ATA_REG_LBA_LOW, 0);
123 self.write8(ATA_REG_LBA_MID, 0);
124 self.write8(ATA_REG_LBA_HIGH, 0);
125 self.write8(ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
126
127 let status = self.read8(ATA_REG_STATUS);
128 if status == 0 {
129 return None;
130 }
131
132 if let Err(_) = self.wait_ready() {
133 return None;
134 }
135
136 if let Err(_) = self.wait_drq() {
137 return None;
138 }
139
140 let mut buffer = [0u16; 256];
141 for i in 0..256 {
142 buffer[i] = self.read16();
143 }
144
145 let serial = Self::decode_identify_string(&buffer, 10, 20);
146 let model = Self::decode_identify_string(&buffer, 27, 54);
147 let capacity = (buffer[60] as u64) | ((buffer[61] as u64) << 16);
148
149 Some(AtaDriveInfo {
150 model,
151 serial,
152 capacity,
153 })
154 }
155
156 fn decode_identify_string(buffer: &[u16], start: usize, end: usize) -> String {
158 use alloc::string::String;
159 let mut s = String::new();
160 for i in start..end {
161 if i < buffer.len() {
162 let c = buffer[i];
163 let hi = (c >> 8) as u8;
164 let lo = (c & 0xFF) as u8;
165 if hi != 0 {
166 s.push(hi as char);
167 }
168 if lo != 0 {
169 s.push(lo as char);
170 }
171 }
172 }
173 s
174 }
175
176 fn read_sector_pio(&self, device: u8, lba: u64, buffer: &mut [u8]) -> Result<(), &'static str> {
178 if buffer.len() < SECTOR_SIZE {
179 return Err("Buffer too small");
180 }
181
182 self.wait_ready()?;
183 self.select_device(device, lba);
184
185 self.write8(ATA_REG_SECCOUNT, 1);
186 self.write8(ATA_REG_LBA_LOW, (lba & 0xFF) as u8);
187 self.write8(ATA_REG_LBA_MID, ((lba >> 8) & 0xFF) as u8);
188 self.write8(ATA_REG_LBA_HIGH, ((lba >> 16) & 0xFF) as u8);
189
190 self.write8(ATA_REG_COMMAND, 0x24);
191 self.wait_drq()?;
192
193 let buf_ptr = buffer.as_mut_ptr() as *mut u16;
194 for i in 0..256 {
195 unsafe {
196 core::ptr::write_volatile(buf_ptr.add(i), self.read16());
197 }
198 }
199
200 self.wait_ready()?;
201 Ok(())
202 }
203
204 fn write_sector_pio(&self, device: u8, lba: u64, buffer: &[u8]) -> Result<(), &'static str> {
206 if buffer.len() < SECTOR_SIZE {
207 return Err("Buffer too small");
208 }
209
210 self.wait_ready()?;
211 self.select_device(device, lba);
212
213 self.write8(ATA_REG_SECCOUNT, 1);
214 self.write8(ATA_REG_LBA_LOW, (lba & 0xFF) as u8);
215 self.write8(ATA_REG_LBA_MID, ((lba >> 8) & 0xFF) as u8);
216 self.write8(ATA_REG_LBA_HIGH, ((lba >> 16) & 0xFF) as u8);
217
218 self.write8(ATA_REG_COMMAND, 0x34);
219 self.wait_drq()?;
220
221 let buf_ptr = buffer.as_ptr() as *const u16;
222 for i in 0..256 {
223 unsafe {
224 self.write16(core::ptr::read_volatile(buf_ptr.add(i)));
225 }
226 }
227
228 self.wait_ready()?;
229 Ok(())
230 }
231}
232
233#[derive(Clone)]
234pub struct AtaDriveInfo {
235 pub model: String,
236 pub serial: String,
237 pub capacity: u64,
238}
239
240pub struct AtaDrive {
241 channel: AtaChannel,
242 device: u8,
243 info: AtaDriveInfo,
244 #[allow(dead_code)]
245 name: String,
246}
247
248unsafe impl Send for AtaDrive {}
249unsafe impl Sync for AtaDrive {}
250
251impl AtaDrive {
252 pub fn new(channel: AtaChannel, device: u8) -> Option<Self> {
254 let info = channel.identify(device)?;
255 let name = format!(
256 "ata{}_{}",
257 channel.bus,
258 if device == ATA_DEVICE_MASTER {
259 "master"
260 } else {
261 "slave"
262 }
263 );
264 Some(Self {
265 channel,
266 device,
267 info,
268 name,
269 })
270 }
271
272 pub fn info(&self) -> &AtaDriveInfo {
274 &self.info
275 }
276}
277
278impl BlockDevice for AtaDrive {
279 fn read_sector(&self, sector: u64, buf: &mut [u8]) -> Result<(), BlockError> {
281 self.channel
282 .read_sector_pio(self.device, sector, buf)
283 .map_err(|_| BlockError::IoError)
284 }
285
286 fn write_sector(&self, sector: u64, buf: &[u8]) -> Result<(), BlockError> {
288 self.channel
289 .write_sector_pio(self.device, sector, buf)
290 .map_err(|_| BlockError::IoError)
291 }
292
293 fn sector_count(&self) -> u64 {
295 self.info.capacity
296 }
297}
298
299static ATA_DRIVES: Mutex<Vec<Arc<AtaDrive>>> = Mutex::new(Vec::new());
300static ATA_INITIALIZED: AtomicBool = AtomicBool::new(false);
301
302pub fn init() {
304 log::info!("[ATA] Scanning for legacy ATA/IDE devices...");
305
306 let channels = [
307 AtaChannel::new(ATA_PRIMARY_IO, 0),
308 AtaChannel::new(ATA_SECONDARY_IO, 1),
309 ];
310
311 for channel in &channels {
312 for device in [ATA_DEVICE_MASTER, ATA_DEVICE_SLAVE] {
313 if let Some(drive) = AtaDrive::new(channel.clone(), device) {
314 log::info!(
315 "ATA: Found drive on bus{} device{}: {} ({} sectors)",
316 channel.bus,
317 if device == ATA_DEVICE_MASTER {
318 "master"
319 } else {
320 "slave"
321 },
322 drive.info().model,
323 drive.info().capacity
324 );
325 ATA_DRIVES.lock().push(Arc::new(drive));
326 }
327 }
328 }
329
330 ATA_INITIALIZED.store(true, Ordering::SeqCst);
331 log::info!("[ATA] Found {} drive(s)", ATA_DRIVES.lock().len());
332}
333
334pub fn get_drive(index: usize) -> Option<Arc<AtaDrive>> {
336 ATA_DRIVES.lock().get(index).cloned()
337}
338
339pub fn get_first_drive() -> Option<Arc<AtaDrive>> {
341 ATA_DRIVES.lock().first().cloned()
342}
343
344pub fn is_available() -> bool {
346 ATA_INITIALIZED.load(Ordering::Relaxed)
347}