xref: /DragonOS/kernel/src/driver/disk/ahci/ahcidisk.rs (revision c75089286e9d49cef8d039446bf570c1bd4d2550)
1 use super::{_port, hba::HbaCmdTable, virt_2_phys};
2 use crate::driver::base::block::block_device::{BlockDevice, BlockId};
3 use crate::driver::base::block::disk_info::Partition;
4 use crate::driver::base::block::SeekFrom;
5 use crate::driver::base::device::bus::Bus;
6 
7 use crate::driver::base::device::driver::Driver;
8 use crate::driver::base::device::{Device, DeviceType, IdTable};
9 use crate::driver::base::kobject::{KObjType, KObject, KObjectState};
10 use crate::driver::base::kset::KSet;
11 use crate::driver::disk::ahci::HBA_PxIS_TFES;
12 
13 use crate::filesystem::kernfs::KernFSInode;
14 use crate::filesystem::mbr::MbrDiskPartionTable;
15 use crate::include::bindings::bindings::verify_area;
16 
17 use crate::kdebug;
18 use crate::libs::rwlock::{RwLockReadGuard, RwLockWriteGuard};
19 use crate::libs::{spinlock::SpinLock, vec_cursor::VecCursor};
20 use crate::mm::phys_2_virt;
21 use crate::syscall::SystemError;
22 use crate::{
23     driver::disk::ahci::hba::{
24         FisRegH2D, FisType, HbaCmdHeader, ATA_CMD_READ_DMA_EXT, ATA_CMD_WRITE_DMA_EXT,
25         ATA_DEV_BUSY, ATA_DEV_DRQ,
26     },
27     kerror,
28 };
29 
30 use alloc::sync::Weak;
31 use alloc::{string::String, sync::Arc, vec::Vec};
32 
33 use core::fmt::Debug;
34 use core::sync::atomic::{compiler_fence, Ordering};
35 use core::{mem::size_of, ptr::write_bytes};
36 
37 /// @brief: 只支持MBR分区格式的磁盘结构体
38 pub struct AhciDisk {
39     pub name: String,
40     pub flags: u16,                      // 磁盘的状态flags
41     pub partitions: Vec<Arc<Partition>>, // 磁盘分区数组
42     // port: &'static mut HbaPort,      // 控制硬盘的端口
43     pub ctrl_num: u8,
44     pub port_num: u8,
45     /// 指向LockAhciDisk的弱引用
46     self_ref: Weak<LockedAhciDisk>,
47 }
48 
49 /// @brief: 带锁的AhciDisk
50 #[derive(Debug)]
51 pub struct LockedAhciDisk(pub SpinLock<AhciDisk>);
52 /// 函数实现
53 impl Debug for AhciDisk {
54     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55         write!(
56             f,
57             "{{ name: {}, flags: {}, part_s: {:?} }}",
58             self.name, self.flags, self.partitions
59         )?;
60         return Ok(());
61     }
62 }
63 
64 impl AhciDisk {
65     fn read_at(
66         &self,
67         lba_id_start: BlockId, // 起始lba编号
68         count: usize,          // 读取lba的数量
69         buf: &mut [u8],
70     ) -> Result<usize, SystemError> {
71         assert!((buf.len() & 511) == 0);
72         compiler_fence(core::sync::atomic::Ordering::SeqCst);
73         let check_length = ((count - 1) >> 4) + 1; // prdt length
74         if count * 512 > buf.len() || check_length > 8 as usize {
75             kerror!("ahci read: e2big");
76             // 不可能的操作
77             return Err(SystemError::E2BIG);
78         } else if count == 0 {
79             return Ok(0);
80         }
81 
82         let port = _port(self.ctrl_num, self.port_num);
83         volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits
84 
85         let slot = port.find_cmdslot().unwrap_or(u32::MAX);
86 
87         if slot == u32::MAX {
88             return Err(SystemError::EIO);
89         }
90 
91         #[allow(unused_unsafe)]
92         let cmdheader: &mut HbaCmdHeader = unsafe {
93             (phys_2_virt(
94                 volatile_read!(port.clb) as usize
95                     + slot as usize * size_of::<HbaCmdHeader>() as usize,
96             ) as *mut HbaCmdHeader)
97                 .as_mut()
98                 .unwrap()
99         };
100 
101         cmdheader.cfl = (size_of::<FisRegH2D>() / size_of::<u32>()) as u8;
102 
103         volatile_set_bit!(cmdheader.cfl, 1 << 6, false); //  Read/Write bit : Read from device
104         volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
105 
106         // 设置数据存放地址
107         let mut buf_ptr = buf as *mut [u8] as *mut usize as usize;
108 
109         // 由于目前的内存管理机制无法把用户空间的内存地址转换为物理地址,所以只能先把数据拷贝到内核空间
110         // TODO:在内存管理重构后,可以直接使用用户空间的内存地址
111         let user_buf = if unsafe { verify_area(buf_ptr as u64, buf.len() as u64) } {
112             true
113         } else {
114             false
115         };
116         let mut kbuf = if user_buf {
117             let mut x: Vec<u8> = Vec::new();
118             x.resize(buf.len(), 0);
119             Some(x)
120         } else {
121             None
122         };
123 
124         if kbuf.is_some() {
125             buf_ptr = kbuf.as_mut().unwrap().as_mut_ptr() as usize;
126         }
127 
128         #[allow(unused_unsafe)]
129         let cmdtbl = unsafe {
130             (phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable)
131                 .as_mut()
132                 .unwrap() // 必须使用 as_mut ,得到的才是原来的变量
133         };
134         let mut tmp_count = count;
135 
136         unsafe {
137             // 清空整个table的旧数据
138             write_bytes(cmdtbl, 0, 1);
139         }
140         // kdebug!("cmdheader.prdtl={}", volatile_read!(cmdheader.prdtl));
141 
142         // 8K bytes (16 sectors) per PRDT
143         for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) {
144             volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64);
145             cmdtbl.prdt_entry[i].dbc = 8 * 1024 - 1;
146             volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断 prdt_entry.i
147             buf_ptr += 8 * 1024;
148             tmp_count -= 16;
149         }
150 
151         // Last entry
152         let las = (volatile_read!(cmdheader.prdtl) - 1) as usize;
153         volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64);
154         cmdtbl.prdt_entry[las].dbc = ((tmp_count << 9) - 1) as u32; // 数据长度
155 
156         volatile_set_bit!(cmdtbl.prdt_entry[las].dbc, 1 << 31, true); // 允许中断
157 
158         // 设置命令
159         let cmdfis = unsafe {
160             ((&mut cmdtbl.cfis) as *mut [u8] as *mut usize as *mut FisRegH2D)
161                 .as_mut()
162                 .unwrap()
163         };
164         volatile_write!(cmdfis.fis_type, FisType::RegH2D as u8);
165         volatile_set_bit!(cmdfis.pm, 1 << 7, true); // command_bit set
166         volatile_write!(cmdfis.command, ATA_CMD_READ_DMA_EXT);
167 
168         volatile_write!(cmdfis.lba0, (lba_id_start & 0xFF) as u8);
169         volatile_write!(cmdfis.lba1, ((lba_id_start >> 8) & 0xFF) as u8);
170         volatile_write!(cmdfis.lba2, ((lba_id_start >> 16) & 0xFF) as u8);
171         volatile_write!(cmdfis.lba3, ((lba_id_start >> 24) & 0xFF) as u8);
172         volatile_write!(cmdfis.lba4, ((lba_id_start >> 32) & 0xFF) as u8);
173         volatile_write!(cmdfis.lba5, ((lba_id_start >> 40) & 0xFF) as u8);
174 
175         volatile_write!(cmdfis.countl, (count & 0xFF) as u8);
176         volatile_write!(cmdfis.counth, ((count >> 8) & 0xFF) as u8);
177 
178         volatile_write!(cmdfis.device, 1 << 6); // LBA Mode
179 
180         // 等待之前的操作完成
181         let mut spin_count = 0;
182         const SPIN_LIMIT: u32 = 10000;
183 
184         while (volatile_read!(port.tfd) as u8 & (ATA_DEV_BUSY | ATA_DEV_DRQ)) > 0
185             && spin_count < SPIN_LIMIT
186         {
187             spin_count += 1;
188         }
189 
190         if spin_count == SPIN_LIMIT {
191             kerror!("Port is hung");
192             return Err(SystemError::EIO);
193         }
194 
195         volatile_set_bit!(port.ci, 1 << slot, true); // Issue command
196                                                      // kdebug!("To wait ahci read complete.");
197                                                      // 等待操作完成
198         loop {
199             if (volatile_read!(port.ci) & (1 << slot)) == 0 {
200                 break;
201             }
202             if (volatile_read!(port.is) & HBA_PxIS_TFES) > 0 {
203                 kerror!("Read disk error");
204                 return Err(SystemError::EIO);
205             }
206         }
207 
208         if kbuf.is_some() {
209             buf.copy_from_slice(kbuf.as_ref().unwrap());
210         }
211 
212         compiler_fence(core::sync::atomic::Ordering::SeqCst);
213         // successfully read
214         return Ok(count * 512);
215     }
216 
217     fn write_at(
218         &self,
219         lba_id_start: BlockId,
220         count: usize,
221         buf: &[u8],
222     ) -> Result<usize, SystemError> {
223         assert!((buf.len() & 511) == 0);
224         compiler_fence(core::sync::atomic::Ordering::SeqCst);
225         let check_length = ((count - 1) >> 4) + 1; // prdt length
226         if count * 512 > buf.len() || check_length > 8 as usize {
227             // 不可能的操作
228             return Err(SystemError::E2BIG);
229         } else if count == 0 {
230             return Ok(0);
231         }
232 
233         let port = _port(self.ctrl_num, self.port_num);
234 
235         volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits
236 
237         let slot = port.find_cmdslot().unwrap_or(u32::MAX);
238 
239         if slot == u32::MAX {
240             return Err(SystemError::EIO);
241         }
242 
243         compiler_fence(core::sync::atomic::Ordering::SeqCst);
244         #[allow(unused_unsafe)]
245         let cmdheader: &mut HbaCmdHeader = unsafe {
246             (phys_2_virt(
247                 volatile_read!(port.clb) as usize
248                     + slot as usize * size_of::<HbaCmdHeader>() as usize,
249             ) as *mut HbaCmdHeader)
250                 .as_mut()
251                 .unwrap()
252         };
253         compiler_fence(core::sync::atomic::Ordering::SeqCst);
254 
255         volatile_write_bit!(
256             cmdheader.cfl,
257             (1 << 5) - 1 as u8,
258             (size_of::<FisRegH2D>() / size_of::<u32>()) as u8
259         ); // Command FIS size
260 
261         volatile_set_bit!(cmdheader.cfl, 7 << 5, true); // (p,c,w)都设置为1, Read/Write bit :  Write from device
262         volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
263 
264         // 设置数据存放地址
265         compiler_fence(core::sync::atomic::Ordering::SeqCst);
266         let mut buf_ptr = buf as *const [u8] as *mut usize as usize;
267 
268         // 由于目前的内存管理机制无法把用户空间的内存地址转换为物理地址,所以只能先把数据拷贝到内核空间
269         // TODO:在内存管理重构后,可以直接使用用户空间的内存地址
270         let user_buf = if unsafe { verify_area(buf_ptr as u64, buf.len() as u64) } {
271             true
272         } else {
273             false
274         };
275         let mut kbuf = if user_buf {
276             let mut x: Vec<u8> = Vec::with_capacity(buf.len());
277             x.resize(buf.len(), 0);
278             x.copy_from_slice(buf);
279             Some(x)
280         } else {
281             None
282         };
283 
284         if kbuf.is_some() {
285             buf_ptr = kbuf.as_mut().unwrap().as_mut_ptr() as usize;
286         }
287 
288         #[allow(unused_unsafe)]
289         let cmdtbl = unsafe {
290             (phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable)
291                 .as_mut()
292                 .unwrap()
293         };
294         let mut tmp_count = count;
295         compiler_fence(core::sync::atomic::Ordering::SeqCst);
296 
297         unsafe {
298             // 清空整个table的旧数据
299             write_bytes(cmdtbl, 0, 1);
300         }
301 
302         // 8K bytes (16 sectors) per PRDT
303         for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) {
304             volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64);
305             volatile_write_bit!(cmdtbl.prdt_entry[i].dbc, (1 << 22) - 1, 8 * 1024 - 1); // 数据长度
306             volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断
307             buf_ptr += 8 * 1024;
308             tmp_count -= 16;
309         }
310 
311         // Last entry
312         let las = (volatile_read!(cmdheader.prdtl) - 1) as usize;
313         volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64);
314         volatile_set_bit!(cmdtbl.prdt_entry[las].dbc, 1 << 31, true); // 允许中断
315         volatile_write_bit!(
316             cmdtbl.prdt_entry[las].dbc,
317             (1 << 22) - 1,
318             ((tmp_count << 9) - 1) as u32
319         ); // 数据长度
320 
321         // 设置命令
322         let cmdfis = unsafe {
323             ((&mut cmdtbl.cfis) as *mut [u8] as *mut usize as *mut FisRegH2D)
324                 .as_mut()
325                 .unwrap()
326         };
327         volatile_write!(cmdfis.fis_type, FisType::RegH2D as u8);
328         volatile_set_bit!(cmdfis.pm, 1 << 7, true); // command_bit set
329         volatile_write!(cmdfis.command, ATA_CMD_WRITE_DMA_EXT);
330 
331         volatile_write!(cmdfis.lba0, (lba_id_start & 0xFF) as u8);
332         volatile_write!(cmdfis.lba1, ((lba_id_start >> 8) & 0xFF) as u8);
333         volatile_write!(cmdfis.lba2, ((lba_id_start >> 16) & 0xFF) as u8);
334         volatile_write!(cmdfis.lba3, ((lba_id_start >> 24) & 0xFF) as u8);
335         volatile_write!(cmdfis.lba4, ((lba_id_start >> 32) & 0xFF) as u8);
336         volatile_write!(cmdfis.lba5, ((lba_id_start >> 40) & 0xFF) as u8);
337 
338         volatile_write!(cmdfis.countl, (count & 0xFF) as u8);
339         volatile_write!(cmdfis.counth, ((count >> 8) & 0xFF) as u8);
340 
341         volatile_write!(cmdfis.device, 1 << 6); // LBA Mode
342 
343         volatile_set_bit!(port.ci, 1 << slot, true); // Issue command
344 
345         // 等待操作完成
346         loop {
347             if (volatile_read!(port.ci) & (1 << slot)) == 0 {
348                 break;
349             }
350             if (volatile_read!(port.is) & HBA_PxIS_TFES) > 0 {
351                 kerror!("Write disk error");
352                 return Err(SystemError::EIO);
353             }
354         }
355 
356         compiler_fence(core::sync::atomic::Ordering::SeqCst);
357         // successfully read
358         return Ok(count * 512);
359     }
360 
361     fn sync(&self) -> Result<(), SystemError> {
362         // 由于目前没有block cache, 因此sync返回成功即可
363         return Ok(());
364     }
365 }
366 
367 impl LockedAhciDisk {
368     pub fn new(
369         name: String,
370         flags: u16,
371         ctrl_num: u8,
372         port_num: u8,
373     ) -> Result<Arc<LockedAhciDisk>, SystemError> {
374         // 构建磁盘结构体
375         let result: Arc<LockedAhciDisk> = Arc::new(LockedAhciDisk(SpinLock::new(AhciDisk {
376             name,
377             flags,
378             partitions: Default::default(),
379             ctrl_num,
380             port_num,
381             self_ref: Weak::default(),
382         })));
383 
384         let table: MbrDiskPartionTable = result.read_mbr_table()?;
385 
386         // 求出有多少可用分区
387         for i in 0..4 {
388             compiler_fence(Ordering::SeqCst);
389             if table.dpte[i].part_type != 0 {
390                 let w = Arc::downgrade(&result);
391                 result.0.lock().partitions.push(Partition::new(
392                     table.dpte[i].starting_sector() as u64,
393                     table.dpte[i].starting_lba as u64,
394                     table.dpte[i].total_sectors as u64,
395                     w,
396                     i as u16,
397                 ));
398             }
399         }
400 
401         result.0.lock().self_ref = Arc::downgrade(&result);
402 
403         return Ok(result);
404     }
405 
406     /// @brief: 从磁盘中读取 MBR 分区表结构体 TODO: Cursor
407     pub fn read_mbr_table(&self) -> Result<MbrDiskPartionTable, SystemError> {
408         let mut table: MbrDiskPartionTable = Default::default();
409 
410         // 数据缓冲区
411         let mut buf: Vec<u8> = Vec::new();
412         buf.resize(size_of::<MbrDiskPartionTable>(), 0);
413 
414         self.read_at(0, 1, &mut buf)?;
415         // 创建 Cursor 用于按字节读取
416         let mut cursor = VecCursor::new(buf);
417         cursor.seek(SeekFrom::SeekCurrent(446))?;
418 
419         for i in 0..4 {
420             kdebug!("infomation of partition {}:\n", i);
421 
422             table.dpte[i].flags = cursor.read_u8()?;
423             table.dpte[i].starting_head = cursor.read_u8()?;
424             table.dpte[i].starting_sector_cylinder = cursor.read_u16()?;
425             table.dpte[i].part_type = cursor.read_u8()?;
426             table.dpte[i].ending_head = cursor.read_u8()?;
427             table.dpte[i].ending_sector_cylingder = cursor.read_u16()?;
428             table.dpte[i].starting_lba = cursor.read_u32()?;
429             table.dpte[i].total_sectors = cursor.read_u32()?;
430 
431             kdebug!("dpte[i] = {:?}", table.dpte[i]);
432         }
433         table.bs_trailsig = cursor.read_u16()?;
434         // kdebug!("bs_trailsig = {}", unsafe {
435         //     read_unaligned(addr_of!(table.bs_trailsig))
436         // });
437 
438         return Ok(table);
439     }
440 }
441 
442 impl KObject for LockedAhciDisk {
443     fn as_any_ref(&self) -> &dyn core::any::Any {
444         self
445     }
446 
447     fn inode(&self) -> Option<Arc<KernFSInode>> {
448         todo!()
449     }
450 
451     fn kobj_type(&self) -> Option<&'static dyn KObjType> {
452         todo!()
453     }
454 
455     fn kset(&self) -> Option<Arc<KSet>> {
456         todo!()
457     }
458 
459     fn parent(&self) -> Option<Weak<dyn KObject>> {
460         todo!()
461     }
462 
463     fn set_inode(&self, _inode: Option<Arc<KernFSInode>>) {
464         todo!()
465     }
466 
467     fn kobj_state(&self) -> RwLockReadGuard<KObjectState> {
468         todo!()
469     }
470 
471     fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
472         todo!()
473     }
474 
475     fn set_kobj_state(&self, _state: KObjectState) {
476         todo!()
477     }
478 
479     fn name(&self) -> alloc::string::String {
480         todo!()
481     }
482 
483     fn set_name(&self, _name: alloc::string::String) {
484         todo!()
485     }
486 
487     fn set_kset(&self, _kset: Option<Arc<KSet>>) {
488         todo!()
489     }
490 
491     fn set_parent(&self, _parent: Option<Weak<dyn KObject>>) {
492         todo!()
493     }
494 
495     fn set_kobj_type(&self, _ktype: Option<&'static dyn KObjType>) {
496         todo!()
497     }
498 }
499 
500 impl Device for LockedAhciDisk {
501     fn dev_type(&self) -> DeviceType {
502         return DeviceType::Block;
503     }
504 
505     fn id_table(&self) -> IdTable {
506         todo!()
507     }
508 
509     fn bus(&self) -> Option<Arc<dyn Bus>> {
510         todo!("LockedAhciDisk::bus()")
511     }
512 
513     fn set_bus(&self, _bus: Option<Arc<dyn Bus>>) {
514         todo!("LockedAhciDisk::set_bus()")
515     }
516 
517     fn driver(&self) -> Option<Arc<dyn Driver>> {
518         todo!("LockedAhciDisk::driver()")
519     }
520 
521     fn is_dead(&self) -> bool {
522         false
523     }
524 
525     fn set_driver(&self, _driver: Option<Weak<dyn Driver>>) {
526         todo!("LockedAhciDisk::set_driver()")
527     }
528 
529     fn can_match(&self) -> bool {
530         todo!()
531     }
532 
533     fn set_can_match(&self, _can_match: bool) {
534         todo!()
535     }
536 
537     fn state_synced(&self) -> bool {
538         todo!()
539     }
540 }
541 
542 impl BlockDevice for LockedAhciDisk {
543     #[inline]
544     fn as_any_ref(&self) -> &dyn core::any::Any {
545         self
546     }
547 
548     #[inline]
549     fn blk_size_log2(&self) -> u8 {
550         9
551     }
552 
553     fn sync(&self) -> Result<(), SystemError> {
554         return self.0.lock().sync();
555     }
556 
557     #[inline]
558     fn device(&self) -> Arc<dyn Device> {
559         return self.0.lock().self_ref.upgrade().unwrap();
560     }
561 
562     fn block_size(&self) -> usize {
563         todo!()
564     }
565 
566     fn partitions(&self) -> Vec<Arc<Partition>> {
567         return self.0.lock().partitions.clone();
568     }
569 
570     #[inline]
571     fn read_at(
572         &self,
573         lba_id_start: BlockId, // 起始lba编号
574         count: usize,          // 读取lba的数量
575         buf: &mut [u8],
576     ) -> Result<usize, SystemError> {
577         self.0.lock().read_at(lba_id_start, count, buf)
578     }
579 
580     #[inline]
581     fn write_at(
582         &self,
583         lba_id_start: BlockId,
584         count: usize,
585         buf: &[u8],
586     ) -> Result<usize, SystemError> {
587         self.0.lock().write_at(lba_id_start, count, buf)
588     }
589 }
590