xref: /DragonOS/kernel/src/driver/disk/ahci/ahcidisk.rs (revision 1496ba7b24a5e6954291ca9643b9f3cec567479a)
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::{Device, DeviceType, KObject};
6 use crate::driver::disk::ahci::HBA_PxIS_TFES;
7 use crate::filesystem::mbr::MbrDiskPartionTable;
8 use crate::include::bindings::bindings::verify_area;
9 
10 use crate::kdebug;
11 use crate::libs::{spinlock::SpinLock, vec_cursor::VecCursor};
12 use crate::mm::phys_2_virt;
13 use crate::syscall::SystemError;
14 use crate::{
15     driver::disk::ahci::hba::{
16         FisRegH2D, FisType, HbaCmdHeader, ATA_CMD_READ_DMA_EXT, ATA_CMD_WRITE_DMA_EXT,
17         ATA_DEV_BUSY, ATA_DEV_DRQ,
18     },
19     kerror,
20 };
21 
22 use alloc::sync::Weak;
23 use alloc::{string::String, sync::Arc, vec::Vec};
24 
25 use core::fmt::Debug;
26 use core::sync::atomic::compiler_fence;
27 use core::{mem::size_of, ptr::write_bytes};
28 
29 /// @brief: 只支持MBR分区格式的磁盘结构体
30 pub struct AhciDisk {
31     pub name: String,
32     pub flags: u16,                      // 磁盘的状态flags
33     pub partitions: Vec<Arc<Partition>>, // 磁盘分区数组
34     // port: &'static mut HbaPort,      // 控制硬盘的端口
35     pub ctrl_num: u8,
36     pub port_num: u8,
37     /// 指向LockAhciDisk的弱引用
38     self_ref: Weak<LockedAhciDisk>,
39 }
40 
41 /// @brief: 带锁的AhciDisk
42 #[derive(Debug)]
43 pub struct LockedAhciDisk(pub SpinLock<AhciDisk>);
44 /// 函数实现
45 impl Debug for AhciDisk {
46     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
47         write!(
48             f,
49             "{{ name: {}, flags: {}, part_s: {:?} }}",
50             self.name, self.flags, self.partitions
51         )?;
52         return Ok(());
53     }
54 }
55 
56 impl AhciDisk {
57     fn read_at(
58         &self,
59         lba_id_start: BlockId, // 起始lba编号
60         count: usize,          // 读取lba的数量
61         buf: &mut [u8],
62     ) -> Result<usize, SystemError> {
63         compiler_fence(core::sync::atomic::Ordering::SeqCst);
64         let check_length = ((count - 1) >> 4) + 1; // prdt length
65         if count * 512 > buf.len() || check_length > u16::MAX as usize {
66             kerror!("ahci read: e2big");
67             // 不可能的操作
68             return Err(SystemError::E2BIG);
69         } else if count == 0 {
70             return Ok(0);
71         }
72 
73         let port = _port(self.ctrl_num, self.port_num);
74         volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits
75 
76         let slot = port.find_cmdslot().unwrap_or(u32::MAX);
77 
78         if slot == u32::MAX {
79             return Err(SystemError::EIO);
80         }
81 
82         #[allow(unused_unsafe)]
83         let cmdheader: &mut HbaCmdHeader = unsafe {
84             (phys_2_virt(
85                 volatile_read!(port.clb) as usize
86                     + slot as usize * size_of::<HbaCmdHeader>() as usize,
87             ) as *mut HbaCmdHeader)
88                 .as_mut()
89                 .unwrap()
90         };
91 
92         volatile_write_bit!(
93             cmdheader.cfl,
94             (1 << 5) - 1 as u8,
95             (size_of::<FisRegH2D>() / size_of::<u32>()) as u8
96         ); // Command FIS size
97 
98         volatile_set_bit!(cmdheader.cfl, 1 << 6, false); //  Read/Write bit : Read from device
99         volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
100 
101         // 设置数据存放地址
102         let mut buf_ptr = buf as *mut [u8] as *mut usize as usize;
103 
104         // 由于目前的内存管理机制无法把用户空间的内存地址转换为物理地址,所以只能先把数据拷贝到内核空间
105         // TODO:在内存管理重构后,可以直接使用用户空间的内存地址
106         let user_buf = if unsafe { verify_area(buf_ptr as u64, buf.len() as u64) } {
107             true
108         } else {
109             false
110         };
111         let mut kbuf = if user_buf {
112             let mut x: Vec<u8> = Vec::with_capacity(buf.len());
113             unsafe {
114                 x.set_len(buf.len());
115             }
116             Some(x)
117         } else {
118             None
119         };
120 
121         if kbuf.is_some() {
122             buf_ptr = kbuf.as_mut().unwrap().as_mut_ptr() as usize;
123         }
124 
125         #[allow(unused_unsafe)]
126         let cmdtbl = unsafe {
127             (phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable)
128                 .as_mut()
129                 .unwrap() // 必须使用 as_mut ,得到的才是原来的变量
130         };
131         let mut tmp_count = count;
132 
133         unsafe {
134             // 清空整个table的旧数据
135             write_bytes(cmdtbl, 0, 1);
136         }
137 
138         // 8K bytes (16 sectors) per PRDT
139         for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) {
140             volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64);
141             volatile_write_bit!(cmdtbl.prdt_entry[i].dbc, (1 << 22) - 1, 8 * 1024 - 1); // 数据长度 prdt_entry.dbc
142             volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断 prdt_entry.i
143             buf_ptr += 8 * 1024;
144             tmp_count -= 16;
145         }
146 
147         // Last entry
148         let las = (volatile_read!(cmdheader.prdtl) - 1) as usize;
149         volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64);
150         volatile_write_bit!(
151             cmdtbl.prdt_entry[las].dbc,
152             (1 << 22) - 1,
153             ((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         compiler_fence(core::sync::atomic::Ordering::SeqCst);
223         let check_length = ((count - 1) >> 4) + 1; // prdt length
224         if count * 512 > buf.len() || check_length > u16::MAX as usize {
225             // 不可能的操作
226             return Err(SystemError::E2BIG);
227         } else if count == 0 {
228             return Ok(0);
229         }
230 
231         let port = _port(self.ctrl_num, self.port_num);
232 
233         volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits
234 
235         let slot = port.find_cmdslot().unwrap_or(u32::MAX);
236 
237         if slot == u32::MAX {
238             return Err(SystemError::EIO);
239         }
240 
241         compiler_fence(core::sync::atomic::Ordering::SeqCst);
242         #[allow(unused_unsafe)]
243         let cmdheader: &mut HbaCmdHeader = unsafe {
244             (phys_2_virt(
245                 volatile_read!(port.clb) as usize
246                     + slot as usize * size_of::<HbaCmdHeader>() as usize,
247             ) as *mut HbaCmdHeader)
248                 .as_mut()
249                 .unwrap()
250         };
251         compiler_fence(core::sync::atomic::Ordering::SeqCst);
252 
253         volatile_write_bit!(
254             cmdheader.cfl,
255             (1 << 5) - 1 as u8,
256             (size_of::<FisRegH2D>() / size_of::<u32>()) as u8
257         ); // Command FIS size
258 
259         volatile_set_bit!(cmdheader.cfl, 7 << 5, true); // (p,c,w)都设置为1, Read/Write bit :  Write from device
260         volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
261 
262         // 设置数据存放地址
263         compiler_fence(core::sync::atomic::Ordering::SeqCst);
264         let mut buf_ptr = buf as *const [u8] as *mut usize as usize;
265 
266         // 由于目前的内存管理机制无法把用户空间的内存地址转换为物理地址,所以只能先把数据拷贝到内核空间
267         // TODO:在内存管理重构后,可以直接使用用户空间的内存地址
268         let user_buf = if unsafe { verify_area(buf_ptr as u64, buf.len() as u64) } {
269             true
270         } else {
271             false
272         };
273         let mut kbuf = if user_buf {
274             let mut x: Vec<u8> = Vec::with_capacity(buf.len());
275             x.resize(buf.len(), 0);
276             x.copy_from_slice(buf);
277             Some(x)
278         } else {
279             None
280         };
281 
282         if kbuf.is_some() {
283             buf_ptr = kbuf.as_mut().unwrap().as_mut_ptr() as usize;
284         }
285 
286         #[allow(unused_unsafe)]
287         let cmdtbl = unsafe {
288             (phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable)
289                 .as_mut()
290                 .unwrap()
291         };
292         let mut tmp_count = count;
293         compiler_fence(core::sync::atomic::Ordering::SeqCst);
294 
295         unsafe {
296             // 清空整个table的旧数据
297             write_bytes(cmdtbl, 0, 1);
298         }
299 
300         // 8K bytes (16 sectors) per PRDT
301         for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) {
302             volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64);
303             volatile_write_bit!(cmdtbl.prdt_entry[i].dbc, (1 << 22) - 1, 8 * 1024 - 1); // 数据长度
304             volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断
305             buf_ptr += 8 * 1024;
306             tmp_count -= 16;
307         }
308 
309         // Last entry
310         let las = (volatile_read!(cmdheader.prdtl) - 1) as usize;
311         volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64);
312         volatile_set_bit!(cmdtbl.prdt_entry[las].dbc, 1 << 31, true); // 允许中断
313         volatile_write_bit!(
314             cmdtbl.prdt_entry[las].dbc,
315             (1 << 22) - 1,
316             ((tmp_count << 9) - 1) as u32
317         ); // 数据长度
318 
319         // 设置命令
320         let cmdfis = unsafe {
321             ((&mut cmdtbl.cfis) as *mut [u8] as *mut usize as *mut FisRegH2D)
322                 .as_mut()
323                 .unwrap()
324         };
325         volatile_write!(cmdfis.fis_type, FisType::RegH2D as u8);
326         volatile_set_bit!(cmdfis.pm, 1 << 7, true); // command_bit set
327         volatile_write!(cmdfis.command, ATA_CMD_WRITE_DMA_EXT);
328 
329         volatile_write!(cmdfis.lba0, (lba_id_start & 0xFF) as u8);
330         volatile_write!(cmdfis.lba1, ((lba_id_start >> 8) & 0xFF) as u8);
331         volatile_write!(cmdfis.lba2, ((lba_id_start >> 16) & 0xFF) as u8);
332         volatile_write!(cmdfis.lba3, ((lba_id_start >> 24) & 0xFF) as u8);
333         volatile_write!(cmdfis.lba4, ((lba_id_start >> 32) & 0xFF) as u8);
334         volatile_write!(cmdfis.lba5, ((lba_id_start >> 40) & 0xFF) as u8);
335 
336         volatile_write!(cmdfis.countl, (count & 0xFF) as u8);
337         volatile_write!(cmdfis.counth, ((count >> 8) & 0xFF) as u8);
338 
339         volatile_write!(cmdfis.device, 1 << 6); // LBA Mode
340 
341         volatile_set_bit!(port.ci, 1 << slot, true); // Issue command
342 
343         // 等待操作完成
344         loop {
345             if (volatile_read!(port.ci) & (1 << slot)) == 0 {
346                 break;
347             }
348             if (volatile_read!(port.is) & HBA_PxIS_TFES) > 0 {
349                 kerror!("Write disk error");
350                 return Err(SystemError::EIO);
351             }
352         }
353 
354         compiler_fence(core::sync::atomic::Ordering::SeqCst);
355         // successfully read
356         return Ok(count * 512);
357     }
358 
359     fn sync(&self) -> Result<(), SystemError> {
360         // 由于目前没有block cache, 因此sync返回成功即可
361         return Ok(());
362     }
363 }
364 
365 impl LockedAhciDisk {
366     pub fn new(
367         name: String,
368         flags: u16,
369         ctrl_num: u8,
370         port_num: u8,
371     ) -> Result<Arc<LockedAhciDisk>, SystemError> {
372         let mut part_s: Vec<Arc<Partition>> = Vec::new();
373 
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         let weak_this: Weak<LockedAhciDisk> = Arc::downgrade(&result); // 获取this的弱指针
386 
387         // 求出有多少可用分区
388         for i in 0..4 {
389             if table.dpte[i].part_type != 0 {
390                 part_s.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                     weak_this.clone(),
395                     i as u16,
396                 ));
397             }
398         }
399         result.0.lock().partitions = part_s;
400         result.0.lock().self_ref = weak_this;
401         return Ok(result);
402     }
403 
404     /// @brief: 从磁盘中读取 MBR 分区表结构体 TODO: Cursor
405     pub fn read_mbr_table(&self) -> Result<MbrDiskPartionTable, SystemError> {
406         let mut table: MbrDiskPartionTable = Default::default();
407 
408         // 数据缓冲区
409         let mut buf: Vec<u8> = Vec::new();
410         buf.resize(size_of::<MbrDiskPartionTable>(), 0);
411 
412         BlockDevice::read_at(self, 0, 1, &mut buf)?;
413         // 创建 Cursor 用于按字节读取
414         let mut cursor = VecCursor::new(buf);
415         cursor.seek(SeekFrom::SeekCurrent(446))?;
416 
417         for i in 0..4 {
418             kdebug!("infomation of partition {}:\n", i);
419 
420             table.dpte[i].flags = cursor.read_u8()?;
421             table.dpte[i].starting_head = cursor.read_u8()?;
422             table.dpte[i].starting_sector_cylinder = cursor.read_u16()?;
423             table.dpte[i].part_type = cursor.read_u8()?;
424             table.dpte[i].ending_head = cursor.read_u8()?;
425             table.dpte[i].ending_sector_cylingder = cursor.read_u16()?;
426             table.dpte[i].starting_lba = cursor.read_u32()?;
427             table.dpte[i].total_sectors = cursor.read_u32()?;
428 
429             kdebug!("dpte[i] = {:?}", table.dpte[i]);
430         }
431         table.bs_trailsig = cursor.read_u16()?;
432         // kdebug!("bs_trailsig = {}", unsafe {
433         //     read_unaligned(addr_of!(table.bs_trailsig))
434         // });
435 
436         return Ok(table);
437     }
438 }
439 
440 impl KObject for LockedAhciDisk {}
441 
442 impl Device for LockedAhciDisk {
443     fn dev_type(&self) -> DeviceType {
444         return DeviceType::Block;
445     }
446 
447     fn as_any_ref(&self) -> &dyn core::any::Any {
448         return self;
449     }
450 
451     fn id_table(&self) -> crate::driver::base::device::IdTable {
452         todo!()
453     }
454 
455     fn set_sys_info(&self, _sys_info: Option<Arc<dyn crate::filesystem::vfs::IndexNode>>) {
456         todo!()
457     }
458 
459     fn sys_info(&self) -> Option<Arc<dyn crate::filesystem::vfs::IndexNode>> {
460         todo!()
461     }
462 }
463 
464 impl BlockDevice for LockedAhciDisk {
465     #[inline]
466     fn as_any_ref(&self) -> &dyn core::any::Any {
467         self
468     }
469 
470     #[inline]
471     fn blk_size_log2(&self) -> u8 {
472         9
473     }
474 
475     fn sync(&self) -> Result<(), SystemError> {
476         return self.0.lock().sync();
477     }
478 
479     #[inline]
480     fn device(&self) -> Arc<dyn Device> {
481         return self.0.lock().self_ref.upgrade().unwrap();
482     }
483 
484     fn block_size(&self) -> usize {
485         todo!()
486     }
487 
488     fn partitions(&self) -> Vec<Arc<Partition>> {
489         return self.0.lock().partitions.clone();
490     }
491 
492     #[inline]
493     fn read_at(
494         &self,
495         lba_id_start: BlockId, // 起始lba编号
496         count: usize,          // 读取lba的数量
497         buf: &mut [u8],
498     ) -> Result<usize, SystemError> {
499         self.0.lock().read_at(lba_id_start, count, buf)
500     }
501 
502     #[inline]
503     fn write_at(
504         &self,
505         lba_id_start: BlockId,
506         count: usize,
507         buf: &[u8],
508     ) -> Result<usize, SystemError> {
509         self.0.lock().write_at(lba_id_start, count, buf)
510     }
511 }
512