Skip to content

Commit 06d3b95

Browse files
committed
Read FAT clusters of kernel file
1 parent b12a3cf commit 06d3b95

File tree

3 files changed

+192
-11
lines changed

3 files changed

+192
-11
lines changed

bios/second_stage/src/disk.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,15 @@ pub struct DiskAccess {
99
}
1010

1111
impl Read for DiskAccess {
12-
fn read_exact(&mut self, buf: &mut [u8]) {
13-
writeln!(screen::Writer, "read {} bytes", buf.len()).unwrap();
12+
fn read_exact(&mut self, input_buf: &mut [u8]) {
13+
writeln!(screen::Writer, "read {} bytes", input_buf.len()).unwrap();
14+
static mut TMP_BUF: [u8; 512] = [0; 512];
15+
let tmp_buf = unsafe { &mut TMP_BUF[..] };
16+
let (buf, copy_needed) = if input_buf.len() >= tmp_buf.len() {
17+
(&mut input_buf[..], false)
18+
} else {
19+
(&mut tmp_buf[..], true)
20+
};
1421
assert_eq!(buf.len() % 512, 0);
1522

1623
let end_addr = self.base_offset + self.current_offset + u64::try_from(buf.len()).unwrap();
@@ -43,6 +50,15 @@ impl Read for DiskAccess {
4350
}
4451

4552
self.current_offset = end_addr;
53+
54+
if copy_needed {
55+
let len = input_buf.len();
56+
for i in 0..len {
57+
input_buf[i] = tmp_buf[i];
58+
}
59+
}
60+
61+
writeln!(screen::Writer, "read {} bytes done", input_buf.len()).unwrap();
4662
}
4763
}
4864

bios/second_stage/src/fat.rs

Lines changed: 166 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// based on https://crates.io/crates/mini_fat
1+
// based on https://crates.io/crates/mini_fat by https://github.com/gridbugs
22

33
use crate::{
44
disk::{Read, Seek, SeekFrom},
@@ -10,8 +10,6 @@ const DIRECTORY_ENTRY_BYTES: usize = 32;
1010
const UNUSED_ENTRY_PREFIX: u8 = 0xE5;
1111
const END_OF_DIRECTORY_PREFIX: u8 = 0;
1212

13-
static mut BUFFER: [u8; 0x4000] = [0; 0x4000];
14-
1513
pub struct File {
1614
first_cluster: u32,
1715
file_size: u32,
@@ -38,8 +36,9 @@ struct Bpb {
3836

3937
impl Bpb {
4038
fn parse<D: Read + Seek>(disk: &mut D) -> Self {
39+
static mut BPB_BUFFER: [u8; 512] = [0; 512];
4140
let mut raw = {
42-
let buffer = unsafe { &mut BUFFER[..] };
41+
let buffer = unsafe { &mut BPB_BUFFER[..] };
4342
&mut buffer[..512]
4443
};
4544
disk.read_exact(&mut raw);
@@ -130,6 +129,25 @@ impl Bpb {
130129
(self.reserved_sector_count as u64 + (self.num_fats as u64 * self.fat_size_16 as u64))
131130
* self.bytes_per_sector as u64
132131
}
132+
133+
fn maximum_valid_cluster(&self) -> u32 {
134+
self.count_of_clusters() + 1
135+
}
136+
137+
fn fat_offset(&self) -> u64 {
138+
self.reserved_sector_count as u64 * self.bytes_per_sector as u64
139+
}
140+
141+
fn data_offset(&self) -> u64 {
142+
self.root_directory_size() as u64
143+
+ ((self.reserved_sector_count as u64
144+
+ self.fat_size_in_sectors() as u64 * self.num_fats as u64)
145+
* self.bytes_per_sector as u64)
146+
}
147+
148+
pub fn bytes_per_cluster(&self) -> u32 {
149+
self.bytes_per_sector as u32 * self.sectors_per_cluster as u32
150+
}
133151
}
134152

135153
pub struct FileSystem<D> {
@@ -199,7 +217,8 @@ impl<D: Read + Seek> FileSystem<D> {
199217
}
200218
FatType::Fat12 | FatType::Fat16 => {
201219
let root_directory_size = self.bpb.root_directory_size();
202-
let buffer = unsafe { &mut BUFFER[..] };
220+
static mut ROOT_DIR_BUFFER: [u8; 0x4000] = [0; 0x4000];
221+
let buffer = unsafe { &mut ROOT_DIR_BUFFER[..] };
203222
assert!(root_directory_size <= buffer.len());
204223
let raw = &mut buffer[..root_directory_size];
205224

@@ -214,6 +233,68 @@ impl<D: Read + Seek> FileSystem<D> {
214233
}
215234
}
216235
}
236+
237+
pub fn file_clusters<'a>(
238+
&'a mut self,
239+
file: &File,
240+
) -> impl Iterator<Item = Result<u32, ()>> + 'a {
241+
Traverser {
242+
current_entry: file.first_cluster,
243+
bpb: &self.bpb,
244+
disk: &mut self.disk,
245+
}
246+
}
247+
}
248+
249+
struct Traverser<'a, D> {
250+
disk: &'a mut D,
251+
current_entry: u32,
252+
bpb: &'a Bpb,
253+
}
254+
255+
impl<D> Traverser<'_, D>
256+
where
257+
D: Read + Seek,
258+
{
259+
fn next_cluster(&mut self) -> Result<Option<u32>, ()> {
260+
let entry = classify_fat_entry(
261+
self.bpb.fat_type(),
262+
self.current_entry,
263+
self.bpb.maximum_valid_cluster(),
264+
)
265+
.map_err(|_| ())?;
266+
let entry = match entry {
267+
FileFatEntry::AllocatedCluster(cluster) => cluster,
268+
FileFatEntry::EndOfFile => return Ok(None),
269+
};
270+
let cluster_start =
271+
self.bpb.data_offset() + (u64::from(entry) - 2) * self.bpb.bytes_per_cluster() as u64;
272+
// handle_read(
273+
// self.traverser.handle,
274+
// cluster_start,
275+
// self.traverser.bpb.bytes_per_cluster() as usize,
276+
// &mut self.traverser.buf,
277+
// )?;
278+
// if let Some(t) = f(&self.traverser.buf) {
279+
// break Ok(Some(t));
280+
// }
281+
let next_entry =
282+
fat_entry_of_nth_cluster(self.disk, self.bpb.fat_type(), self.bpb.fat_offset(), entry);
283+
self.current_entry = next_entry;
284+
285+
Ok(Some(entry))
286+
}
287+
}
288+
289+
impl<D> Iterator for Traverser<'_, D>
290+
where
291+
D: Read + Seek,
292+
{
293+
type Item = Result<u32, ()>;
294+
295+
fn next(&mut self) -> Option<Self::Item> {
296+
self.next_cluster().transpose()
297+
}
217298
}
218299

219300
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -223,6 +304,16 @@ enum FatType {
223304
Fat32,
224305
}
225306

307+
impl FatType {
308+
fn fat_entry_defective(self) -> u32 {
309+
match self {
310+
Self::Fat12 => 0xFF7,
311+
Self::Fat16 => 0xFFF7,
312+
Self::Fat32 => 0x0FFFFFF7,
313+
}
314+
}
315+
}
316+
226317
#[derive(Clone)]
227318
pub struct DirectoryEntry<'a> {
228319
short_name: &'a str,
@@ -399,3 +490,73 @@ mod directory_attributes {
399490

400491
pub const LONG_NAME: u8 = READ_ONLY | HIDDEN | SYSTEM | VOLUME_ID;
401492
}
493+
494+
fn classify_fat_entry(
495+
fat_type: FatType,
496+
entry: u32,
497+
maximum_valid_cluster: u32,
498+
) -> Result<FileFatEntry, FatLookupError> {
499+
match entry {
500+
0 => Err(FatLookupError::FreeCluster),
501+
1 => Err(FatLookupError::UnspecifiedEntryOne),
502+
entry => {
503+
if entry <= maximum_valid_cluster {
504+
Ok(FileFatEntry::AllocatedCluster(entry))
505+
} else if entry < fat_type.fat_entry_defective() {
506+
Err(FatLookupError::ReservedEntry)
507+
} else if entry == fat_type.fat_entry_defective() {
508+
Err(FatLookupError::DefectiveCluster)
509+
} else {
510+
Ok(FileFatEntry::EndOfFile)
511+
}
512+
}
513+
}
514+
}
515+
516+
#[derive(Debug)]
517+
pub enum FatLookupError {
518+
FreeCluster,
519+
DefectiveCluster,
520+
UnspecifiedEntryOne,
521+
ReservedEntry,
522+
}
523+
524+
enum FileFatEntry {
525+
AllocatedCluster(u32),
526+
EndOfFile,
527+
}
528+
529+
fn fat_entry_of_nth_cluster<D>(disk: &mut D, fat_type: FatType, fat_start: u64, n: u32) -> u32
530+
where
531+
D: Seek + Read,
532+
{
533+
debug_assert!(n >= 2);
534+
match fat_type {
535+
FatType::Fat32 => {
536+
let base = n as u64 * 4;
537+
disk.seek(SeekFrom::Start(fat_start + base));
538+
let mut buf = [0; 4];
539+
disk.read_exact(&mut buf);
540+
u32::from_le_bytes(buf) & 0x0FFFFFFF
541+
}
542+
FatType::Fat16 => {
543+
let base = n as u64 * 2;
544+
disk.seek(SeekFrom::Start(fat_start + base));
545+
let mut buf = [0; 2];
546+
disk.read_exact(&mut buf);
547+
u16::from_le_bytes(buf) as u32
548+
}
549+
FatType::Fat12 => {
550+
let base = n as u64 + (n as u64 / 2);
551+
disk.seek(SeekFrom::Start(fat_start + base));
552+
let mut buf = [0; 2];
553+
disk.read_exact(&mut buf);
554+
let entry16 = u16::from_le_bytes(buf);
555+
if n & 1 == 0 {
556+
(entry16 & 0xFFF) as u32
557+
} else {
558+
(entry16 >> 4) as u32
559+
}
560+
}
561+
}
562+
}

bios/second_stage/src/main.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,27 @@ pub extern "C" fn _start(disk_number: u16, partition_table_start: *const u8) {
5959
fat_partition.partition_type,
6060
PartitionType::Fat12(_) | PartitionType::Fat16(_) | PartitionType::Fat32(_)
6161
));
62-
screen::print_char(b'1');
62+
writeln!(screen::Writer, "1").unwrap();
6363

6464
// load fat partition
6565
let mut disk = disk::DiskAccess {
6666
disk_number,
6767
base_offset: u64::from(fat_partition.logical_block_address) * 512,
6868
current_offset: 0,
6969
};
70-
screen::print_char(b'2');
70+
writeln!(screen::Writer, "2").unwrap();
7171

7272
let mut fs = fat::FileSystem::parse(disk.clone());
73-
screen::print_char(b'3');
73+
writeln!(screen::Writer, "3").unwrap();
7474

7575
let kernel = fs
7676
.find_file_in_root_dir("kernel-x86_64")
7777
.expect("no `kernel-x86_64` file found");
78-
screen::print_char(b'4');
78+
writeln!(screen::Writer, "4").unwrap();
79+
80+
for cluster in fs.file_clusters(&kernel) {
81+
writeln!(screen::Writer, "kernel cluster: {cluster:?}").unwrap();
82+
}
7983

8084
// TODO: Retrieve memory map
8185

0 commit comments

Comments
 (0)