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