xref: /DragonOS/kernel/src/filesystem/mbr.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1 use core::{default::Default, mem::size_of};
2 
3 use alloc::{
4     sync::{Arc, Weak},
5     vec::Vec,
6 };
7 use log::debug;
8 use system_error::SystemError;
9 
10 use crate::{
11     driver::base::block::{block_device::BlockDevice, disk_info::Partition, SeekFrom},
12     libs::vec_cursor::VecCursor,
13 };
14 
15 /// @brief MBR硬盘分区表项的结构
16 #[repr(packed)]
17 #[derive(Debug, Clone, Copy, Default)]
18 pub struct MbrDiskPartitionTableEntry {
19     pub flags: u8,                     // 引导标志符,标记此分区为活动分区
20     pub starting_head: u8,             // 起始磁头号
21     pub starting_sector_cylinder: u16, // sector : 低6, cylinder : 高10;   起始扇区号 + 起始柱面号
22     pub part_type: u8,                 // 分区类型ID
23     pub ending_head: u8,               // 结束磁头号
24     pub ending_sector_cylinder: u16, // ending_sector : 低6, ending_cylinder : 高10;  结束扇区号 + 结束柱面号
25     pub starting_lba: u32,           // 起始逻辑扇区
26     pub total_sectors: u32,          // 分区占用的磁盘扇区数
27 }
28 
29 impl MbrDiskPartitionTableEntry {
30     pub fn starting_sector(&self) -> u32 {
31         return (self.starting_sector_cylinder & ((1 << 6) - 1)).into();
32     }
33     pub fn starting_cylinder(&self) -> u16 {
34         return (self.starting_sector_cylinder >> 6) & ((1 << 10) - 1) as u16;
35     }
36     pub fn ending_sector(&self) -> u32 {
37         self.starting_sector() + self.total_sectors - 1
38     }
39 
40     pub fn ending_cylinder(&self) -> u16 {
41         return (self.ending_sector_cylinder >> 6) & ((1 << 10) - 1) as u16;
42     }
43 
44     pub fn is_valid(&self) -> bool {
45         // 其他更多的可能判断条件
46         self.starting_sector() <= self.ending_sector()
47             && self.starting_cylinder() <= self.ending_cylinder()
48             && self.starting_lba != 0
49             && self.total_sectors != 0
50             && self.part_type != 0
51     }
52 }
53 
54 /// @brief MBR磁盘分区表结构体
55 #[repr(packed)]
56 #[derive(Debug, Clone, Copy)]
57 pub struct MbrDiskPartionTable {
58     pub _reserved: [u8; 446],
59     pub dpte: [MbrDiskPartitionTableEntry; 4], // 磁盘分区表项
60     pub bs_trailsig: u16,
61 }
62 
63 impl Default for MbrDiskPartionTable {
64     fn default() -> Self {
65         MbrDiskPartionTable {
66             _reserved: [0; 446],
67             dpte: [Default::default(); 4],
68             bs_trailsig: Default::default(),
69         }
70     }
71 }
72 
73 impl MbrDiskPartionTable {
74     /// # 从磁盘读取MBR分区表 - 从磁盘设备中读取并解析MBR分区表
75     ///
76     /// 这个函数从提供的磁盘设备中读取MBR分区表,并将其解析为一个`MbrDiskPartionTable`实例。
77     ///
78     /// ## 参数
79     ///
80     /// - `disk`: Arc<dyn BlockDevice> - 一个磁盘设备的共享引用,用于从磁盘读取数据。
81     ///
82     /// ## 返回值
83     ///
84     /// - `Ok(MbrDiskPartionTable)`: 成功解析的分区表实例。
85     /// - `Err(SystemError)`: 读取磁盘失败或其他系统错误。
86     pub fn from_disk(disk: Arc<dyn BlockDevice>) -> Result<MbrDiskPartionTable, SystemError> {
87         let mut table: MbrDiskPartionTable = Default::default();
88 
89         // 数据缓冲区
90         let mut buf: Vec<u8> = vec![0; size_of::<MbrDiskPartionTable>()];
91         buf.resize(size_of::<MbrDiskPartionTable>(), 0);
92 
93         disk.read_at_sync(0, 1, &mut buf)?;
94 
95         // 创建 Cursor 用于按字节读取
96         let mut cursor = VecCursor::new(buf);
97         cursor.seek(SeekFrom::SeekCurrent(446))?;
98 
99         for i in 0..4 {
100             table.dpte[i].flags = cursor.read_u8()?;
101             table.dpte[i].starting_head = cursor.read_u8()?;
102             table.dpte[i].starting_sector_cylinder = cursor.read_u16()?;
103             table.dpte[i].part_type = cursor.read_u8()?;
104             table.dpte[i].ending_head = cursor.read_u8()?;
105             table.dpte[i].ending_sector_cylinder = cursor.read_u16()?;
106             table.dpte[i].starting_lba = cursor.read_u32()?;
107             table.dpte[i].total_sectors = cursor.read_u32()?;
108 
109             debug!("dpte[{i}] = {:?}", table.dpte[i]);
110         }
111         table.bs_trailsig = cursor.read_u16()?;
112         // debug!("bs_trailsig = {}", unsafe {
113         //     read_unaligned(addr_of!(table.bs_trailsig))
114         // });
115 
116         if !table.is_valid() {
117             return Err(SystemError::EINVAL);
118         }
119 
120         return Ok(table);
121     }
122 
123     /// # partitions - 获取磁盘的分区信息
124     ///
125     /// 该函数用于获取指定磁盘的分区信息,并将这些分区信息以分区对象的向量形式返回。分区对象包含了分区的类型、起始扇区和总扇区数等信息。
126     ///
127     /// ## 参数
128     ///
129     /// - `disk`: Weak<dyn BlockDevice>: 一个对磁盘设备的弱引用。这个磁盘设备必须实现`BlockDevice` trait。
130     ///
131     /// ## 返回值
132     ///
133     /// 返回一个包含分区信息的`Vec`。每个分区都是一个`Arc<Partition>`,它表示分区的一个强引用。
134     ///
135     pub fn partitions(&self, disk: Weak<dyn BlockDevice>) -> Vec<Arc<Partition>> {
136         let mut partitions: Vec<Arc<Partition>> = Vec::new();
137         for i in 0..4 {
138             if self.dpte[i].is_valid() {
139                 partitions.push(Partition::new(
140                     self.dpte[i].starting_sector() as u64,
141                     self.dpte[i].starting_lba as u64,
142                     self.dpte[i].total_sectors as u64,
143                     disk.clone(),
144                     i as u16,
145                 ));
146             }
147         }
148         return partitions;
149     }
150 
151     /// # partitions_raw - 获取磁盘的分区信息,不包含磁盘设备信息
152     pub fn partitions_raw(&self) -> MbrPartitionIter {
153         MbrPartitionIter::new(self)
154     }
155 
156     pub fn is_valid(&self) -> bool {
157         self.bs_trailsig == 0xAA55
158     }
159 }
160 
161 pub struct MbrPartitionIter<'a> {
162     table: &'a MbrDiskPartionTable,
163     index: usize,
164 }
165 
166 impl<'a> MbrPartitionIter<'a> {
167     fn new(table: &'a MbrDiskPartionTable) -> Self {
168         MbrPartitionIter { table, index: 0 }
169     }
170 }
171 
172 impl<'a> Iterator for MbrPartitionIter<'a> {
173     type Item = Partition;
174 
175     fn next(&mut self) -> Option<Self::Item> {
176         while self.index < 4 {
177             let entry = &self.table.dpte[self.index];
178             let index = self.index;
179             self.index += 1;
180             if entry.is_valid() {
181                 let p = Partition::new_raw(
182                     self.table.dpte[index].starting_sector() as u64,
183                     self.table.dpte[index].starting_lba as u64,
184                     self.table.dpte[index].total_sectors as u64,
185                     index as u16,
186                 );
187                 return Some(p);
188             }
189         }
190         return None;
191     }
192 }
193