xref: /DragonOS/kernel/src/driver/disk/ahci/ahcidisk.rs (revision 45b8371173b070028457f7ee64be33f68b4f9ada)
1 use super::{_port, hba::HbaCmdTable, virt_2_phys};
2 use crate::driver::disk::ahci::HBA_PxIS_TFES;
3 use crate::filesystem::mbr::MbrDiskPartionTable;
4 use crate::include::bindings::bindings::{E2BIG, EIO};
5 use crate::io::{device::BlockDevice, disk_info::Partition, SeekFrom};
6 
7 use crate::libs::{spinlock::SpinLock, vec_cursor::VecCursor};
8 use crate::mm::phys_2_virt;
9 use crate::{
10     driver::disk::ahci::hba::{
11         FisRegH2D, FisType, HbaCmdHeader, ATA_CMD_READ_DMA_EXT, ATA_CMD_WRITE_DMA_EXT,
12         ATA_DEV_BUSY, ATA_DEV_DRQ,
13     },
14     kerror,
15 };
16 
17 use alloc::sync::Weak;
18 use alloc::{string::String, sync::Arc, vec::Vec};
19 
20 use core::fmt::Debug;
21 use core::sync::atomic::compiler_fence;
22 use core::{mem::size_of, ptr::write_bytes};
23 
24 /// @brief: 只支持MBR分区格式的磁盘结构体
25 pub struct AhciDisk {
26     pub name: String,
27     pub flags: u16,                      // 磁盘的状态flags
28     pub partitions: Vec<Arc<Partition>>, // 磁盘分区数组
29     // port: &'static mut HbaPort,      // 控制硬盘的端口
30     pub ctrl_num: u8,
31     pub port_num: u8,
32     /// 指向LockAhciDisk的弱引用
33     self_ref: Weak<LockedAhciDisk>,
34 }
35 
36 /// @brief: 带锁的AhciDisk
37 #[derive(Debug)]
38 pub struct LockedAhciDisk(pub SpinLock<AhciDisk>);
39 /// 函数实现
40 impl Debug for AhciDisk {
41     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42         write!(
43             f,
44             "{{ name: {}, flags: {}, part_s: {:?} }}",
45             self.name, self.flags, self.partitions
46         )?;
47         return Ok(());
48     }
49 }
50 
51 impl AhciDisk {
52     fn read_at(
53         &self,
54         lba_id_start: crate::io::device::BlockId, // 起始lba编号
55         count: usize,                             // 读取lba的数量
56         buf: &mut [u8],
57     ) -> Result<usize, i32> {
58         compiler_fence(core::sync::atomic::Ordering::SeqCst);
59         let check_length = ((count - 1) >> 4) + 1; // prdt length
60         if count * 512 > buf.len() || check_length > u16::MAX as usize {
61             kerror!("ahci read: e2big");
62             // 不可能的操作
63             return Err(-(E2BIG as i32));
64         } else if count == 0 {
65             return Ok(0);
66         }
67 
68         let port = _port(self.ctrl_num, self.port_num);
69         volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits
70 
71         let slot = port.find_cmdslot().unwrap_or(u32::MAX);
72 
73         if slot == u32::MAX {
74             return Err(-(EIO as i32));
75         }
76 
77         #[allow(unused_unsafe)]
78         let cmdheader: &mut HbaCmdHeader = unsafe {
79             (phys_2_virt(
80                 volatile_read!(port.clb) as usize
81                     + slot as usize * size_of::<HbaCmdHeader>() as usize,
82             ) as *mut HbaCmdHeader)
83                 .as_mut()
84                 .unwrap()
85         };
86 
87         volatile_write_bit!(
88             cmdheader.cfl,
89             (1 << 5) - 1 as u8,
90             (size_of::<FisRegH2D>() / size_of::<u32>()) as u8
91         ); // Command FIS size
92 
93         volatile_set_bit!(cmdheader.cfl, 1 << 6, false); //  Read/Write bit : Read from device
94         volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
95 
96         // 设置数据存放地址
97         let mut buf_ptr = buf as *mut [u8] as *mut usize as usize;
98         #[allow(unused_unsafe)]
99         let cmdtbl = unsafe {
100             (phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable)
101                 .as_mut()
102                 .unwrap() // 必须使用 as_mut ,得到的才是原来的变量
103         };
104         let mut tmp_count = count;
105 
106         unsafe {
107             // 清空整个table的旧数据
108             write_bytes(cmdtbl, 0, 1);
109         }
110 
111         // 8K bytes (16 sectors) per PRDT
112         for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) {
113             volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64);
114             volatile_write_bit!(cmdtbl.prdt_entry[i].dbc, (1 << 22) - 1, 8 * 1024 - 1); // 数据长度 prdt_entry.dbc
115             volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断 prdt_entry.i
116             buf_ptr += 8 * 1024;
117             tmp_count -= 16;
118         }
119 
120         // Last entry
121         let las = (volatile_read!(cmdheader.prdtl) - 1) as usize;
122         volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64);
123         volatile_write_bit!(
124             cmdtbl.prdt_entry[las].dbc,
125             (1 << 22) - 1,
126             ((tmp_count << 9) - 1) as u32
127         ); // 数据长度
128         volatile_set_bit!(cmdtbl.prdt_entry[las].dbc, 1 << 31, true); // 允许中断
129 
130         // 设置命令
131         let cmdfis = unsafe {
132             ((&mut cmdtbl.cfis) as *mut [u8] as *mut usize as *mut FisRegH2D)
133                 .as_mut()
134                 .unwrap()
135         };
136         volatile_write!(cmdfis.fis_type, FisType::RegH2D as u8);
137         volatile_set_bit!(cmdfis.pm, 1 << 7, true); // command_bit set
138         volatile_write!(cmdfis.command, ATA_CMD_READ_DMA_EXT);
139 
140         volatile_write!(cmdfis.lba0, (lba_id_start & 0xFF) as u8);
141         volatile_write!(cmdfis.lba1, ((lba_id_start >> 8) & 0xFF) as u8);
142         volatile_write!(cmdfis.lba2, ((lba_id_start >> 16) & 0xFF) as u8);
143         volatile_write!(cmdfis.lba3, ((lba_id_start >> 24) & 0xFF) as u8);
144         volatile_write!(cmdfis.lba4, ((lba_id_start >> 32) & 0xFF) as u8);
145         volatile_write!(cmdfis.lba5, ((lba_id_start >> 40) & 0xFF) as u8);
146 
147         volatile_write!(cmdfis.countl, (count & 0xFF) as u8);
148         volatile_write!(cmdfis.counth, ((count >> 8) & 0xFF) as u8);
149 
150         volatile_write!(cmdfis.device, 1 << 6); // LBA Mode
151 
152         // 等待之前的操作完成
153         let mut spin_count = 0;
154         const SPIN_LIMIT: u32 = 10000;
155 
156         while (volatile_read!(port.tfd) as u8 & (ATA_DEV_BUSY | ATA_DEV_DRQ)) > 0
157             && spin_count < SPIN_LIMIT
158         {
159             spin_count += 1;
160         }
161 
162         if spin_count == SPIN_LIMIT {
163             kerror!("Port is hung");
164             return Err(-(EIO as i32));
165         }
166 
167         volatile_set_bit!(port.ci, 1 << slot, true); // Issue command
168                                                      // kdebug!("To wait ahci read complete.");
169                                                      // 等待操作完成
170         loop {
171             if (volatile_read!(port.ci) & (1 << slot)) == 0 {
172                 break;
173             }
174             if (volatile_read!(port.is) & HBA_PxIS_TFES) > 0 {
175                 kerror!("Read disk error");
176                 return Err(-(EIO as i32));
177             }
178         }
179 
180         compiler_fence(core::sync::atomic::Ordering::SeqCst);
181         // successfully read
182         return Ok(count * 512);
183     }
184 
185     fn write_at(
186         &self,
187         lba_id_start: crate::io::device::BlockId,
188         count: usize,
189         buf: &[u8],
190     ) -> Result<usize, i32> {
191         compiler_fence(core::sync::atomic::Ordering::SeqCst);
192         let check_length = ((count - 1) >> 4) + 1; // prdt length
193         if count * 512 > buf.len() || check_length > u16::MAX as usize {
194             // 不可能的操作
195             return Err(-(E2BIG as i32));
196         } else if count == 0 {
197             return Ok(0);
198         }
199 
200         let port = _port(self.ctrl_num, self.port_num);
201 
202         volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits
203 
204         let slot = port.find_cmdslot().unwrap_or(u32::MAX);
205 
206         if slot == u32::MAX {
207             return Err(-(EIO as i32));
208         }
209 
210         compiler_fence(core::sync::atomic::Ordering::SeqCst);
211         #[allow(unused_unsafe)]
212         let cmdheader: &mut HbaCmdHeader = unsafe {
213             (phys_2_virt(
214                 volatile_read!(port.clb) as usize
215                     + slot as usize * size_of::<HbaCmdHeader>() as usize,
216             ) as *mut HbaCmdHeader)
217                 .as_mut()
218                 .unwrap()
219         };
220         compiler_fence(core::sync::atomic::Ordering::SeqCst);
221 
222         volatile_write_bit!(
223             cmdheader.cfl,
224             (1 << 5) - 1 as u8,
225             (size_of::<FisRegH2D>() / size_of::<u32>()) as u8
226         ); // Command FIS size
227 
228         volatile_set_bit!(cmdheader.cfl, 7 << 5, true); // (p,c,w)都设置为1, Read/Write bit :  Write from device
229         volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
230 
231         // 设置数据存放地址
232         compiler_fence(core::sync::atomic::Ordering::SeqCst);
233         let mut buf_ptr = buf as *const [u8] as *mut usize as usize;
234         #[allow(unused_unsafe)]
235         let cmdtbl = unsafe {
236             (phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable)
237                 .as_mut()
238                 .unwrap()
239         };
240         let mut tmp_count = count;
241         compiler_fence(core::sync::atomic::Ordering::SeqCst);
242 
243         unsafe {
244             // 清空整个table的旧数据
245             write_bytes(cmdtbl, 0, 1);
246         }
247 
248         // 8K bytes (16 sectors) per PRDT
249         for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) {
250             volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64);
251             volatile_write_bit!(cmdtbl.prdt_entry[i].dbc, (1 << 22) - 1, 8 * 1024 - 1); // 数据长度
252             volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断
253             buf_ptr += 8 * 1024;
254             tmp_count -= 16;
255         }
256 
257         // Last entry
258         let las = (volatile_read!(cmdheader.prdtl) - 1) as usize;
259         volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64);
260         volatile_set_bit!(cmdtbl.prdt_entry[las].dbc, 1 << 31, true); // 允许中断
261         volatile_write_bit!(
262             cmdtbl.prdt_entry[las].dbc,
263             (1 << 22) - 1,
264             ((tmp_count << 9) - 1) as u32
265         ); // 数据长度
266 
267         // 设置命令
268         let cmdfis = unsafe {
269             ((&mut cmdtbl.cfis) as *mut [u8] as *mut usize as *mut FisRegH2D)
270                 .as_mut()
271                 .unwrap()
272         };
273         volatile_write!(cmdfis.fis_type, FisType::RegH2D as u8);
274         volatile_set_bit!(cmdfis.pm, 1 << 7, true); // command_bit set
275         volatile_write!(cmdfis.command, ATA_CMD_WRITE_DMA_EXT);
276 
277         volatile_write!(cmdfis.lba0, (lba_id_start & 0xFF) as u8);
278         volatile_write!(cmdfis.lba1, ((lba_id_start >> 8) & 0xFF) as u8);
279         volatile_write!(cmdfis.lba2, ((lba_id_start >> 16) & 0xFF) as u8);
280         volatile_write!(cmdfis.lba3, ((lba_id_start >> 24) & 0xFF) as u8);
281         volatile_write!(cmdfis.lba4, ((lba_id_start >> 32) & 0xFF) as u8);
282         volatile_write!(cmdfis.lba5, ((lba_id_start >> 40) & 0xFF) as u8);
283 
284         volatile_write!(cmdfis.countl, (count & 0xFF) as u8);
285         volatile_write!(cmdfis.counth, ((count >> 8) & 0xFF) as u8);
286 
287         volatile_write!(cmdfis.device, 1 << 6); // LBA Mode
288 
289         volatile_set_bit!(port.ci, 1 << slot, true); // Issue command
290 
291         // 等待操作完成
292         loop {
293             if (volatile_read!(port.ci) & (1 << slot)) == 0 {
294                 break;
295             }
296             if (volatile_read!(port.is) & HBA_PxIS_TFES) > 0 {
297                 kerror!("Write disk error");
298                 return Err(-(EIO as i32));
299             }
300         }
301 
302         compiler_fence(core::sync::atomic::Ordering::SeqCst);
303         // successfully read
304         return Ok(count * 512);
305     }
306 
307     fn sync(&self) -> Result<(), i32> {
308         // 由于目前没有block cache, 因此sync返回成功即可
309         return Ok(());
310     }
311 }
312 
313 impl LockedAhciDisk {
314     pub fn new(
315         name: String,
316         flags: u16,
317         ctrl_num: u8,
318         port_num: u8,
319     ) -> Result<Arc<LockedAhciDisk>, i32> {
320         let mut part_s: Vec<Arc<Partition>> = Vec::new();
321 
322         // 构建磁盘结构体
323         let result: Arc<LockedAhciDisk> = Arc::new(LockedAhciDisk(SpinLock::new(AhciDisk {
324             name,
325             flags,
326             partitions: Default::default(),
327             ctrl_num,
328             port_num,
329             self_ref: Weak::default(),
330         })));
331 
332         let table: MbrDiskPartionTable = result.read_mbr_table()?;
333         let weak_this: Weak<LockedAhciDisk> = Arc::downgrade(&result); // 获取this的弱指针
334 
335         // 求出有多少可用分区
336         for i in 0..4 {
337             if table.dpte[i].part_type != 0 {
338                 part_s.push(Partition::new(
339                     table.dpte[i].starting_sector() as u64,
340                     table.dpte[i].starting_lba as u64,
341                     table.dpte[i].total_sectors as u64,
342                     weak_this.clone(),
343                     i as u16,
344                 ));
345             }
346         }
347 
348         result.0.lock().partitions = part_s;
349         result.0.lock().self_ref = weak_this;
350         return Ok(result);
351     }
352 
353     /// @brief: 从磁盘中读取 MBR 分区表结构体 TODO: Cursor
354     pub fn read_mbr_table(&self) -> Result<MbrDiskPartionTable, i32> {
355         let mut table: MbrDiskPartionTable = Default::default();
356 
357         // 数据缓冲区
358         let mut buf: Vec<u8> = Vec::new();
359         buf.resize(size_of::<MbrDiskPartionTable>(), 0);
360 
361         self.read_at(0, 1, &mut buf)?;
362 
363         // 创建 Cursor 用于按字节读取
364         let mut cursor = VecCursor::new(buf);
365         cursor.seek(SeekFrom::SeekCurrent(446))?;
366 
367         for i in 0..4 {
368             // kdebug!("infomation of partition {}:\n", i);
369 
370             table.dpte[i].flags = cursor.read_u8()?;
371             table.dpte[i].starting_head = cursor.read_u8()?;
372             table.dpte[i].starting_sector_cylinder = cursor.read_u16()?;
373             table.dpte[i].part_type = cursor.read_u8()?;
374             table.dpte[i].ending_head = cursor.read_u8()?;
375             table.dpte[i].ending_sector_cylingder = cursor.read_u16()?;
376             table.dpte[i].starting_lba = cursor.read_u32()?;
377             table.dpte[i].total_sectors = cursor.read_u32()?;
378 
379             // kdebug!("dpte[i] = {:?}", table.dpte[i]);
380         }
381         table.bs_trailsig = cursor.read_u16()?;
382         // kdebug!("bs_trailsig = {}", unsafe {
383         //     read_unaligned(addr_of!(table.bs_trailsig))
384         // });
385 
386         return Ok(table);
387     }
388 }
389 
390 impl BlockDevice for LockedAhciDisk {
391     #[inline]
392     fn as_any_ref(&self) -> &dyn core::any::Any {
393         self
394     }
395 
396     #[inline]
397     fn blk_size_log2(&self) -> u8 {
398         9
399     }
400 
401     #[inline]
402     fn read_at(
403         &self,
404         lba_id_start: crate::io::device::BlockId,
405         count: usize,
406         buf: &mut [u8],
407     ) -> Result<usize, i32> {
408         // kdebug!(
409         //     "ahci read at {lba_id_start}, count={count}, lock={:?}",
410         //     self.0
411         // );
412         return self.0.lock().read_at(lba_id_start, count, buf);
413     }
414 
415     #[inline]
416     fn write_at(
417         &self,
418         lba_id_start: crate::io::device::BlockId,
419         count: usize,
420         buf: &[u8],
421     ) -> Result<usize, i32> {
422         self.0.lock().write_at(lba_id_start, count, buf)
423     }
424 
425     fn sync(&self) -> Result<(), i32> {
426         return self.0.lock().sync();
427     }
428 
429     #[inline]
430     fn device(&self) -> Arc<dyn crate::io::device::Device> {
431         return self.0.lock().self_ref.upgrade().unwrap();
432     }
433 
434     fn block_size(&self) -> usize {
435         todo!()
436     }
437 
438     fn partitions(&self) -> Vec<Arc<Partition>> {
439         return self.0.lock().partitions.clone();
440     }
441 }
442