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 { x86_64::instructions::port::Port::new(self.io_base + offset as u16).read() }
58 }
59
60 fn write8(&self, offset: usize, value: u8) {
62 unsafe { x86_64::instructions::port::Port::new(self.io_base + offset as u16).write(value) }
63 }
64
65 fn read16(&self) -> u16 {
67 unsafe { x86_64::instructions::port::Port::new(self.io_base).read() }
68 }
69
70 fn write16(&self, value: u16) {
72 unsafe { x86_64::instructions::port::Port::new(self.io_base).write(value) }
73 }
74
75 fn wait_ready(&self) -> Result<(), &'static str> {
77 for _ in 0..100000 {
78 let status = self.read8(ATA_REG_STATUS);
79 if (status & ATA_SR_BSY) == 0 {
80 return Ok(());
81 }
82 core::hint::spin_loop();
83 }
84 Err("ATA timeout")
85 }
86
87 fn wait_drq(&self) -> Result<(), &'static str> {
89 for _ in 0..100000 {
90 let status = self.read8(ATA_REG_STATUS);
91 if (status & ATA_SR_DRQ) != 0 {
92 return Ok(());
93 }
94 if (status & ATA_SR_ERR) != 0 {
95 return Err("ATA error");
96 }
97 core::hint::spin_loop();
98 }
99 Err("ATA timeout")
100 }
101
102 fn select_device(&self, _device: u8, lba: u64) {
104 let device_reg = ATA_DEVICE_MASTER | ATA_DEVICE_LBA | ((lba >> 24) & 0x0F) as u8;
105 self.write8(ATA_REG_DEVICE, device_reg);
106 self.read8(ATA_REG_STATUS);
107 for _ in 0..4 {
108 core::hint::spin_loop();
109 }
110 }
111
112 fn identify(&self, device: u8) -> Option<AtaDriveInfo> {
114 self.select_device(device, 0);
115 self.write8(ATA_REG_SECCOUNT, 0);
116 self.write8(ATA_REG_LBA_LOW, 0);
117 self.write8(ATA_REG_LBA_MID, 0);
118 self.write8(ATA_REG_LBA_HIGH, 0);
119 self.write8(ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
120
121 let status = self.read8(ATA_REG_STATUS);
122 if status == 0 {
123 return None;
124 }
125
126 if let Err(_) = self.wait_ready() {
127 return None;
128 }
129
130 if let Err(_) = self.wait_drq() {
131 return None;
132 }
133
134 let mut buffer = [0u16; 256];
135 for i in 0..256 {
136 buffer[i] = self.read16();
137 }
138
139 let serial = Self::decode_identify_string(&buffer, 10, 20);
140 let model = Self::decode_identify_string(&buffer, 27, 54);
141 let capacity = (buffer[60] as u64) | ((buffer[61] as u64) << 16);
142
143 Some(AtaDriveInfo {
144 model,
145 serial,
146 capacity,
147 })
148 }
149
150 fn decode_identify_string(buffer: &[u16], start: usize, end: usize) -> String {
152 use alloc::string::String;
153 let mut s = String::new();
154 for i in start..end {
155 if i < buffer.len() {
156 let c = buffer[i];
157 let hi = (c >> 8) as u8;
158 let lo = (c & 0xFF) as u8;
159 if hi != 0 {
160 s.push(hi as char);
161 }
162 if lo != 0 {
163 s.push(lo as char);
164 }
165 }
166 }
167 s
168 }
169
170 fn read_sector_pio(&self, device: u8, lba: u64, buffer: &mut [u8]) -> Result<(), &'static str> {
172 if buffer.len() < SECTOR_SIZE {
173 return Err("Buffer too small");
174 }
175
176 self.wait_ready()?;
177 self.select_device(device, lba);
178
179 self.write8(ATA_REG_SECCOUNT, 1);
180 self.write8(ATA_REG_LBA_LOW, (lba & 0xFF) as u8);
181 self.write8(ATA_REG_LBA_MID, ((lba >> 8) & 0xFF) as u8);
182 self.write8(ATA_REG_LBA_HIGH, ((lba >> 16) & 0xFF) as u8);
183
184 self.write8(ATA_REG_COMMAND, 0x24);
185 self.wait_drq()?;
186
187 let buf_ptr = buffer.as_mut_ptr() as *mut u16;
188 for i in 0..256 {
189 unsafe {
190 core::ptr::write_volatile(buf_ptr.add(i), self.read16());
191 }
192 }
193
194 self.wait_ready()?;
195 Ok(())
196 }
197
198 fn write_sector_pio(&self, device: u8, lba: u64, buffer: &[u8]) -> Result<(), &'static str> {
200 if buffer.len() < SECTOR_SIZE {
201 return Err("Buffer too small");
202 }
203
204 self.wait_ready()?;
205 self.select_device(device, lba);
206
207 self.write8(ATA_REG_SECCOUNT, 1);
208 self.write8(ATA_REG_LBA_LOW, (lba & 0xFF) as u8);
209 self.write8(ATA_REG_LBA_MID, ((lba >> 8) & 0xFF) as u8);
210 self.write8(ATA_REG_LBA_HIGH, ((lba >> 16) & 0xFF) as u8);
211
212 self.write8(ATA_REG_COMMAND, 0x34);
213 self.wait_drq()?;
214
215 let buf_ptr = buffer.as_ptr() as *const u16;
216 for i in 0..256 {
217 unsafe {
218 self.write16(core::ptr::read_volatile(buf_ptr.add(i)));
219 }
220 }
221
222 self.wait_ready()?;
223 Ok(())
224 }
225}
226
227#[derive(Clone)]
228pub struct AtaDriveInfo {
229 pub model: String,
230 pub serial: String,
231 pub capacity: u64,
232}
233
234pub struct AtaDrive {
235 channel: AtaChannel,
236 device: u8,
237 info: AtaDriveInfo,
238 #[allow(dead_code)]
239 name: String,
240}
241
242unsafe impl Send for AtaDrive {}
243unsafe impl Sync for AtaDrive {}
244
245impl AtaDrive {
246 pub fn new(channel: AtaChannel, device: u8) -> Option<Self> {
248 let info = channel.identify(device)?;
249 let name = format!(
250 "ata{}_{}",
251 channel.bus,
252 if device == ATA_DEVICE_MASTER {
253 "master"
254 } else {
255 "slave"
256 }
257 );
258 Some(Self {
259 channel,
260 device,
261 info,
262 name,
263 })
264 }
265
266 pub fn info(&self) -> &AtaDriveInfo {
268 &self.info
269 }
270}
271
272impl BlockDevice for AtaDrive {
273 fn read_sector(&self, sector: u64, buf: &mut [u8]) -> Result<(), BlockError> {
275 self.channel
276 .read_sector_pio(self.device, sector, buf)
277 .map_err(|_| BlockError::IoError)
278 }
279
280 fn write_sector(&self, sector: u64, buf: &[u8]) -> Result<(), BlockError> {
282 self.channel
283 .write_sector_pio(self.device, sector, buf)
284 .map_err(|_| BlockError::IoError)
285 }
286
287 fn sector_count(&self) -> u64 {
289 self.info.capacity
290 }
291}
292
293static ATA_DRIVES: Mutex<Vec<Arc<AtaDrive>>> = Mutex::new(Vec::new());
294static ATA_INITIALIZED: AtomicBool = AtomicBool::new(false);
295
296pub fn init() {
298 log::info!("[ATA] Scanning for legacy ATA/IDE devices...");
299
300 let channels = [
301 AtaChannel::new(ATA_PRIMARY_IO, 0),
302 AtaChannel::new(ATA_SECONDARY_IO, 1),
303 ];
304
305 for channel in &channels {
306 for device in [ATA_DEVICE_MASTER, ATA_DEVICE_SLAVE] {
307 if let Some(drive) = AtaDrive::new(channel.clone(), device) {
308 log::info!(
309 "ATA: Found drive on bus{} device{}: {} ({} sectors)",
310 channel.bus,
311 if device == ATA_DEVICE_MASTER {
312 "master"
313 } else {
314 "slave"
315 },
316 drive.info().model,
317 drive.info().capacity
318 );
319 ATA_DRIVES.lock().push(Arc::new(drive));
320 }
321 }
322 }
323
324 ATA_INITIALIZED.store(true, Ordering::SeqCst);
325 log::info!("[ATA] Found {} drive(s)", ATA_DRIVES.lock().len());
326}
327
328pub fn get_drive(index: usize) -> Option<Arc<AtaDrive>> {
330 ATA_DRIVES.lock().get(index).cloned()
331}
332
333pub fn get_first_drive() -> Option<Arc<AtaDrive>> {
335 ATA_DRIVES.lock().first().cloned()
336}
337
338pub fn is_available() -> bool {
340 ATA_INITIALIZED.load(Ordering::Relaxed)
341}