Skip to content

Commit 1d7ff1f

Browse files
committed
Implement looking up kernel-x86_64 file on FAT partition
1 parent a183966 commit 1d7ff1f

File tree

4 files changed

+175
-89
lines changed

4 files changed

+175
-89
lines changed

bios/second_stage/src/dap.rs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,18 @@ pub struct DiskAddressPacket {
1818
}
1919

2020
impl DiskAddressPacket {
21-
pub fn new(memory_buffer_start: u16, file_offset: u64, bytes: u32) -> Self {
22-
Self {
23-
packet_size: 0x10,
24-
zero: 0,
25-
number_of_sectors: (bytes / 512) as u16,
26-
offset: memory_buffer_start,
27-
segment: 0,
28-
start_lba: file_offset / 512,
29-
}
30-
}
31-
32-
pub fn from_lba(memory_buffer_start: u16, start_lba: u64, number_of_sectors: u16) -> Self {
21+
pub fn from_lba(
22+
start_lba: u64,
23+
number_of_sectors: u16,
24+
target_addr: u16,
25+
target_addr_segment: u16,
26+
) -> Self {
3327
Self {
3428
packet_size: 0x10,
3529
zero: 0,
3630
number_of_sectors,
37-
offset: memory_buffer_start,
38-
segment: 0,
31+
offset: target_addr,
32+
segment: target_addr_segment,
3933
start_lba,
4034
}
4135
}

bios/second_stage/src/disk.rs

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::{dap, screen, second_stage_end};
2-
use core::{fmt::Write as _, slice};
1+
use crate::{dap, screen};
2+
use core::fmt::Write as _;
33

44
#[derive(Clone)]
55
pub struct DiskAccess {
@@ -11,24 +11,36 @@ pub struct DiskAccess {
1111
impl Read for DiskAccess {
1212
fn read_exact(&mut self, buf: &mut [u8]) {
1313
writeln!(screen::Writer, "read {} bytes", buf.len()).unwrap();
14+
assert_eq!(buf.len() % 512, 0);
1415

1516
let end_addr = self.base_offset + self.current_offset + u64::try_from(buf.len()).unwrap();
16-
let start_lba = (self.base_offset + self.current_offset) / 512;
17+
let mut start_lba = (self.base_offset + self.current_offset) / 512;
1718
let end_lba = (end_addr - 1) / 512;
1819

19-
let target_addr = u16::try_from(second_stage_end() as usize).unwrap();
20-
let dap = dap::DiskAddressPacket::from_lba(
21-
target_addr,
22-
start_lba,
23-
u16::try_from(end_lba + 1 - start_lba).unwrap(),
24-
);
25-
writeln!(screen::Writer, "dap: {dap:?}").unwrap();
26-
unsafe {
27-
dap.perform_load(self.disk_number);
28-
}
20+
let mut number_of_sectors = end_lba + 1 - start_lba;
21+
let mut target_addr = buf.as_ptr_range().start as u32;
22+
23+
loop {
24+
let sectors = u64::min(number_of_sectors, 32) as u16;
25+
let dap = dap::DiskAddressPacket::from_lba(
26+
start_lba,
27+
sectors,
28+
(target_addr & 0b1111) as u16,
29+
(target_addr >> 4).try_into().unwrap(),
30+
);
31+
writeln!(screen::Writer, "dap: {dap:?}").unwrap();
32+
unsafe {
33+
dap.perform_load(self.disk_number);
34+
}
2935

30-
let data = unsafe { slice::from_raw_parts(target_addr as *const u8, buf.len()) };
31-
buf.copy_from_slice(data);
36+
start_lba += u64::from(sectors);
37+
number_of_sectors -= u64::from(sectors);
38+
target_addr = target_addr + u32::from(sectors) * 512;
39+
40+
if number_of_sectors == 0 {
41+
break;
42+
}
43+
}
3244

3345
self.current_offset = end_addr;
3446
}

bios/second_stage/src/fat.rs

Lines changed: 135 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ struct Bpb {
3838

3939
impl Bpb {
4040
fn parse<D: Read + Seek>(disk: &mut D) -> Self {
41-
let mut raw = [0u8; 512];
41+
let mut raw = {
42+
let buffer = unsafe { &mut BUFFER[..] };
43+
&mut buffer[..512]
44+
};
4245
disk.read_exact(&mut raw);
4346

4447
let bytes_per_sector = u16::from_le_bytes(raw[11..13].try_into().unwrap());
@@ -142,27 +145,50 @@ impl<D: Read + Seek> FileSystem<D> {
142145
}
143146
}
144147

145-
pub fn lookup_file(&mut self, path: &str) -> Option<File> {
146-
let root = self.read_root_dir();
147-
for entry in root {
148-
write!(screen::Writer, "entry: ").unwrap();
149-
match entry {
150-
Ok(RawDirectoryEntry::Normal(entry)) => {
151-
writeln!(screen::Writer, "{}", entry.short_filename_main).unwrap();
152-
}
153-
Ok(RawDirectoryEntry::LongName(entry)) => {
154-
for c in entry.name() {
155-
match c {
156-
Ok(c) => write!(screen::Writer, "{c}").unwrap(),
157-
Err(_) => write!(screen::Writer, "X").unwrap(),
158-
}
159-
}
160-
writeln!(screen::Writer).unwrap();
148+
pub fn find_file_in_root_dir(&mut self, name: &str) -> Option<File> {
149+
let mut root_entries = self.read_root_dir().filter_map(|e| e.ok());
150+
let raw_entry = root_entries.find(|e| e.eq_name(name))?;
151+
152+
let entry = match raw_entry {
153+
RawDirectoryEntry::Normal(entry) => DirectoryEntry {
154+
short_name: entry.short_filename_main,
155+
short_name_extension: entry.short_filename_extension,
156+
long_name_1: &[],
157+
long_name_2: &[],
158+
long_name_3: &[],
159+
file_size: entry.file_size,
160+
first_cluster: entry.first_cluster,
161+
attributes: entry.attributes,
162+
},
163+
RawDirectoryEntry::LongName(long_name) => match root_entries.next() {
164+
Some(RawDirectoryEntry::LongName(_)) => unimplemented!(),
165+
Some(RawDirectoryEntry::Normal(entry)) => DirectoryEntry {
166+
short_name: entry.short_filename_main,
167+
short_name_extension: entry.short_filename_extension,
168+
long_name_1: long_name.name_1,
169+
long_name_2: long_name.name_2,
170+
long_name_3: long_name.name_3,
171+
file_size: entry.file_size,
172+
first_cluster: entry.first_cluster,
173+
attributes: entry.attributes,
174+
},
175+
None => {
176+
panic!("next none");
177+
return None;
161178
}
162-
Err(()) => writeln!(screen::Writer, "<failed to read>").unwrap(),
163-
}
179+
},
180+
};
181+
182+
writeln!(screen::Writer, "entry: {entry:?}").unwrap();
183+
184+
if entry.is_directory() {
185+
None
186+
} else {
187+
Some(File {
188+
first_cluster: entry.first_cluster,
189+
file_size: entry.file_size,
190+
})
164191
}
165-
todo!();
166192
}
167193

168194
fn read_root_dir<'a>(&'a mut self) -> impl Iterator<Item = Result<RawDirectoryEntry, ()>> + 'a {
@@ -197,6 +223,76 @@ enum FatType {
197223
Fat32,
198224
}
199225

226+
#[derive(Clone)]
227+
pub struct DirectoryEntry<'a> {
228+
short_name: &'a str,
229+
short_name_extension: &'a str,
230+
long_name_1: &'a [u8],
231+
long_name_2: &'a [u8],
232+
long_name_3: &'a [u8],
233+
file_size: u32,
234+
first_cluster: u32,
235+
attributes: u8,
236+
}
237+
238+
impl<'a> DirectoryEntry<'a> {
239+
pub fn name(&self) -> impl Iterator<Item = Result<char, DecodeUtf16Error>> + 'a {
240+
let mut long_name = {
241+
let iter = self
242+
.long_name_1
243+
.chunks(2)
244+
.chain(self.long_name_2.chunks(2))
245+
.chain(self.long_name_3.chunks(2))
246+
.map(|c| u16::from_le_bytes(c.try_into().unwrap()))
247+
.take_while(|&c| c != 0);
248+
char::decode_utf16(iter).peekable()
249+
};
250+
let short_name = {
251+
let iter = self.short_name.chars();
252+
let extension_iter = {
253+
let raw = ".".chars().chain(self.short_name_extension.chars());
254+
raw.take(if self.short_name_extension.is_empty() {
255+
0
256+
} else {
257+
self.short_name_extension.len() + 1
258+
})
259+
};
260+
iter.chain(extension_iter).map(Ok)
261+
};
262+
263+
if long_name.peek().is_some() {
264+
long_name.chain(short_name.take(0))
265+
} else {
266+
long_name.chain(short_name.take(usize::MAX))
267+
}
268+
}
269+
270+
pub fn is_directory(&self) -> bool {
271+
self.attributes & directory_attributes::DIRECTORY != 0
272+
}
273+
}
274+
275+
impl core::fmt::Debug for DirectoryEntry<'_> {
276+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
277+
struct NamePrinter<'a>(&'a DirectoryEntry<'a>);
278+
impl core::fmt::Debug for NamePrinter<'_> {
279+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
280+
for char in self.0.name().filter_map(|e| e.ok()) {
281+
write!(f, "{char}")?;
282+
}
283+
Ok(())
284+
}
285+
}
286+
287+
f.debug_struct("DirectoryEntry")
288+
.field("name", &NamePrinter(self))
289+
.field("file_size", &self.file_size)
290+
.field("first_cluster", &self.first_cluster)
291+
.field("attributes", &self.attributes)
292+
.finish()
293+
}
294+
}
295+
200296
#[derive(Debug)]
201297
struct RawDirectoryEntryNormal<'a> {
202298
short_filename_main: &'a str,
@@ -257,10 +353,14 @@ impl<'a> RawDirectoryEntry<'a> {
257353
fn slice_to_string(slice: &[u8]) -> Result<&str, ()> {
258354
const SKIP_SPACE: u8 = 0x20;
259355
let mut iter = slice.into_iter().copied();
260-
let start_idx = iter.position(|c| c != SKIP_SPACE).ok_or(())?;
261-
let end_idx = start_idx + iter.position(|c| c == SKIP_SPACE).unwrap_or(slice.len());
262-
263-
core::str::from_utf8(&slice[start_idx..end_idx]).map_err(|_| ())
356+
match iter.position(|c| c != SKIP_SPACE) {
357+
Some(start_idx) => {
358+
let end_idx =
359+
start_idx + iter.position(|c| c == SKIP_SPACE).unwrap_or(slice.len());
360+
core::str::from_utf8(&slice[start_idx..end_idx]).map_err(|_| ())
361+
}
362+
None => Ok(""),
363+
}
264364
}
265365
let short_filename_main = slice_to_string(&raw[0..8])?;
266366
let short_filename_extension = slice_to_string(&raw[8..11])?;
@@ -277,6 +377,17 @@ impl<'a> RawDirectoryEntry<'a> {
277377
}))
278378
}
279379
}
380+
381+
pub fn eq_name(&self, name: &str) -> bool {
382+
match self {
383+
RawDirectoryEntry::Normal(entry) => entry
384+
.short_filename_main
385+
.chars()
386+
.chain(entry.short_filename_extension.chars())
387+
.eq(name.chars()),
388+
RawDirectoryEntry::LongName(entry) => entry.name().eq(name.chars().map(Ok)),
389+
}
390+
}
280391
}
281392

282393
mod directory_attributes {

bios/second_stage/src/main.rs

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
use byteorder::{ByteOrder, LittleEndian};
55
use core::{fmt::Write as _, slice};
6-
use disk::Read;
76
use mbr_nostd::{PartitionTableEntry, PartitionType};
87

98
mod dap;
@@ -68,45 +67,15 @@ pub extern "C" fn _start(disk_number: u16, partition_table_start: *const u8) {
6867
base_offset: u64::from(fat_partition.logical_block_address) * 512,
6968
current_offset: 0,
7069
};
71-
72-
let mut fs = fat::FileSystem::parse(disk.clone());
73-
let kernel = fs
74-
.lookup_file("kernel-x86_64")
75-
.expect("no `kernel-x86_64` file found");
7670
screen::print_char(b'2');
7771

78-
let mut buffer = [0u8; 512];
79-
disk.read_exact(&mut buffer);
72+
let mut fs = fat::FileSystem::parse(disk.clone());
8073
screen::print_char(b'3');
8174

82-
let kernel_first_cluster = todo!();
83-
loop {}
84-
85-
// try to parse FAT file system
86-
// let fat_slice = unsafe {
87-
// slice::from_raw_parts(
88-
// partition_buf as *const u8,
89-
// usize::try_from(second_stage_partition.sector_count).unwrap_or_else(|_| fail(b'a'))
90-
// * 512,
91-
// )
92-
// };
93-
94-
// print_char(b'4');
95-
// let boot_sector = fat::BootSector::deserialize(fat_slice);
96-
// let root_dir = boot_sector.bpb.root_dir_first_cluster;
97-
// boot_sector.bpb.check_root_dir();
98-
99-
// print_char(b'5');
100-
101-
// TODO: get root dir
102-
103-
// TODO: get offset of `second_stage` file
104-
105-
// TODO: get offset of `kernel-x86_64` file
106-
107-
// TODO: load `second_stage` file into memory
108-
109-
// TODO: jump to `second_stage`, pass offset of `kernel-x86_64` and disk number as arguments
75+
let kernel = fs
76+
.find_file_in_root_dir("kernel-x86_64")
77+
.expect("no `kernel-x86_64` file found");
78+
screen::print_char(b'4');
11079

11180
loop {}
11281
}

0 commit comments

Comments
 (0)