From fbd7a573085da3d8ca53cce335475af126fe675d Mon Sep 17 00:00:00 2001 From: alloncm Date: Mon, 4 Sep 2023 16:18:38 +0300 Subject: [PATCH 01/39] WIP add file write to the fat32 fs * Add root_dir cache and fat cache --- Cargo.lock | 7 ++ rpi/Cargo.toml | 1 + rpi/src/drivers/disk.rs | 28 +++++-- rpi/src/drivers/fat32.rs | 163 +++++++++++++++++++++++++++++++++--- rpi/src/peripherals/emmc.rs | 20 +++-- 5 files changed, 190 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75704014..78be1b1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "atty" version = "0.2.14" @@ -801,6 +807,7 @@ dependencies = [ name = "magenboy_rpi" version = "4.0.0" dependencies = [ + "arrayvec", "bitfield-struct", "cfg-if", "crossbeam-channel", diff --git a/rpi/Cargo.toml b/rpi/Cargo.toml index 520f8b12..f60054da 100644 --- a/rpi/Cargo.toml +++ b/rpi/Cargo.toml @@ -12,6 +12,7 @@ magenboy_common = {path = "../common"} log = "0.4" cfg-if = "1" bitfield-struct = "0.5" +arrayvec = "0.7" libc = {version = "0.2", optional = true} nix = {version = "0.24", optional = true} crossbeam-channel = {version = "0.5", optional = true} diff --git a/rpi/src/drivers/disk.rs b/rpi/src/drivers/disk.rs index 7e4496d9..92972d10 100644 --- a/rpi/src/drivers/disk.rs +++ b/rpi/src/drivers/disk.rs @@ -57,16 +57,20 @@ impl Disk{ /// Returns the number of blocks the read operation fetched /// The user knows how much of the buffer is filled pub fn read(&mut self, block_index:u32, buffer:&mut [u8]) -> u32 { - let block_size = self.emmc.get_block_size(); - let buffer_size = buffer.len(); - if buffer_size % block_size as usize != 0{ - core::panic!("buffer size must be a division of block size: {}", block_size); - } - self.emmc.seek((block_index * block_size) as u64); + self.prepare_for_disk_operation(block_index, buffer); if !self.emmc.read(buffer){ - core::panic!("Error while reading object of size: {}", buffer_size); + core::panic!("Error while reading object of size: {}", buffer.len()); + } + return buffer.len() as u32 / self.get_block_size(); + } + + /// Returns the number of blocks the write operation modified + pub fn write(&mut self, block_index:u32, buffer:&mut [u8])->u32{ + self.prepare_for_disk_operation(block_index, buffer); + if !self.emmc.write(buffer){ + core::panic!("Error while writing object of size: {}", buffer.len()); } - return buffer_size as u32 / block_size; + return buffer.len() as u32 / self.get_block_size(); } pub fn get_partition_first_sector_index(&self, partition_index:u8)->u32{ @@ -74,4 +78,12 @@ impl Disk{ } pub fn get_block_size(&self)->u32{self.emmc.get_block_size()} + + fn prepare_for_disk_operation(&mut self, block_index:u32, buffer:&[u8]){ + let block_size = self.get_block_size(); + if buffer.len() % block_size as usize != 0{ + core::panic!("buffer size must be a division of block size: {}", block_size); + } + self.emmc.seek((block_index * block_size) as u64); + } } \ No newline at end of file diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index 97055b97..6508ef20 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -1,5 +1,7 @@ use core::mem::size_of; +use arrayvec::ArrayVec; + use crate::peripherals::compile_time_size_assert; use super::{as_mut_buffer, disk::*}; @@ -75,6 +77,12 @@ struct FatShortDirEntry{ file_size:u32, } +impl FatShortDirEntry{ + pub fn get_first_cluster_index(&self)->u32{ + self.first_cluster_index_low as u32 | ((self.first_cluster_index_high as u32) << 16) + } +} + // This struct is for support to the long filenames that I will add later // unused for now #[derive(Clone, Copy)] @@ -125,10 +133,34 @@ impl FileEntry{ } } +struct FatIndex{ + sector_number:u32, + sector_offset:usize, +} + +impl FatIndex{ + fn get_fat_entry(&mut self, buffer:&[u8;SECTOR_SIZE as usize])->u32{ + let result = u32::from_ne_bytes(buffer[self.sector_offset .. self.sector_offset + FAT_ENTRY_SIZE].try_into().unwrap()) & FAT_ENTRY_MASK; + self.sector_offset += FAT_ENTRY_SIZE; + return result; + } +} + +// Currently the driver support only 0x100 files in the root directory +const MAX_FILES: usize = 0x100; +// Assuming each files is 0x100 clusters in average +const MAX_CLUSTERS_COUNT: usize = MAX_FILES * 0x100; + pub struct Fat32{ disk: Disk, boot_sector:Fat32BootSector, partition_start_sector_index:u32, + + clusters_count:u32, + fat_table_cache: ArrayVec, + root_dir_cache: ArrayVec, + occupied_clusters:[u32; MAX_CLUSTERS_COUNT], + occupied_cluster_count:usize, } impl Fat32{ @@ -155,11 +187,52 @@ impl Fat32{ let fat_count = boot_sector.fat32_bpb.fats_count; log::debug!("FAT count: {}", fat_count); - return Self { disk, boot_sector, partition_start_sector_index:bpb_sector_index }; + let fat32_data_sectors = boot_sector.fat32_bpb.total_sectors_count_32 - (boot_sector.fat32_bpb.reserved_sectors_count as u32 + (boot_sector.fat32_bpb.sectors_per_fat_32 as u32 * boot_sector.fat32_bpb.fats_count as u32)); + let clusters_count = fat32_data_sectors / boot_sector.fat32_bpb.sectors_per_cluster as u32; + + let mut fat32 = Self { disk, boot_sector, partition_start_sector_index:bpb_sector_index, occupied_clusters:[0;MAX_CLUSTERS_COUNT], occupied_cluster_count:0, clusters_count, + fat_table_cache: ArrayVec::::new(), + root_dir_cache: ArrayVec::::new() + }; + fat32.init_root_directory_cache(); + fat32.init_fat_table_cache(); + + return fat32; + } + + fn init_root_directory_cache(&mut self){ + let root_start_sector_index = self.get_cluster_start_sector_index(self.boot_sector.fat32_bpb.root_dir_first_cluster); + let mut sector_offset = 0; + 'search: loop{ + let mut root_dir = [FatShortDirEntry::default();FAT_DIR_ENTRIES_PER_SECTOR]; + let buffer = unsafe{as_mut_buffer(&mut root_dir)}; + sector_offset += self.disk.read(root_start_sector_index + sector_offset, buffer); + for dir in root_dir{ + if dir.file_name[0] == DIR_EOF_PREFIX { + break 'search; + } + self.root_dir_cache.push(dir); + } + } + } + + fn init_fat_table_cache(&mut self){ + let mut fat_index = FatIndex{sector_number: self.get_fat_start_sector(), sector_offset: 0}; + let mut fat_buffer = [0; SECTOR_SIZE as usize]; + let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer); + + // The fat has entry per cluster in the volume, were adding 2 for the first 2 reserved entries (0,1) + // This way the array is larger by 2 (fat entry at position clusters_count + 1 is the last valid entry) + let fat_entries_count = self.clusters_count + 1; + for _ in 0..=fat_entries_count{ + let fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); + self.fat_table_cache.push(fat_entry); + } } pub fn root_dir_list(&mut self, offset:usize)->[Option;RESULT_MAX_LEN]{ let root_start_sector_index = self.get_cluster_start_sector_index(self.boot_sector.fat32_bpb.root_dir_first_cluster); + self.set_occupied_cluser(self.boot_sector.fat32_bpb.root_dir_first_cluster); let mut root_dir_files_count = 0; let mut output_dir = [None;RESULT_MAX_LEN]; @@ -189,7 +262,7 @@ impl Fat32{ let mut filename:[u8;11] = [0;11]; filename[..8].copy_from_slice(&dir.file_name); filename[8..11].copy_from_slice(&dir.file_extension); - let first_cluster_index = dir.first_cluster_index_low as u32 | ((dir.first_cluster_index_high as u32) << 16); + let first_cluster_index = dir.get_first_cluster_index(); output_dir[root_dir_files_count] = Some(FileEntry{ name: filename, first_cluster_index, size: dir.file_size }); root_dir_files_count += 1; @@ -205,36 +278,92 @@ impl Fat32{ /// Reads a file from the first FAT pub fn read_file(&mut self, file_entry:&FileEntry, output:&mut [u8]){ log::debug!("Reading file {}, size {}, cluster: {}", file_entry.get_name(), file_entry.size, file_entry.first_cluster_index); - let fat_offset = file_entry.first_cluster_index * FAT_ENTRY_SIZE as u32; - let mut fat_sector_number = self.partition_start_sector_index + self.boot_sector.fat32_bpb.reserved_sectors_count as u32 + (fat_offset / SECTOR_SIZE); - let mut fat_entry_offset = (fat_offset % SECTOR_SIZE) as usize; + let mut fat_index: FatIndex = self.get_fat_index(file_entry.first_cluster_index); let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster; let mut current_cluster = file_entry.first_cluster_index; let mut cluster_counter = 0; let mut fat_buffer = [0; SECTOR_SIZE as usize]; - let _ = self.disk.read(fat_sector_number, &mut fat_buffer); + let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer); loop{ let start_sector = self.get_cluster_start_sector_index(current_cluster); + self.set_occupied_cluser(current_cluster); let start_index = sectors_per_cluster as usize * cluster_counter * SECTOR_SIZE as usize; let end_index = start_index + (sectors_per_cluster as usize * SECTOR_SIZE as usize); let _ = self.disk.read(start_sector, &mut output[start_index..end_index]); - let fat_entry = u32::from_ne_bytes(fat_buffer[fat_entry_offset .. fat_entry_offset + FAT_ENTRY_SIZE].try_into().unwrap()) & FAT_ENTRY_MASK; + let fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); if fat_entry == FAT_ENTRY_EOF_INDEX{ return; } current_cluster = fat_entry; cluster_counter += 1; - fat_entry_offset += FAT_ENTRY_SIZE; - if fat_entry_offset >= SECTOR_SIZE as usize{ - fat_entry_offset = 0; - fat_sector_number += 1; - let _ = self.disk.read(fat_sector_number, &mut fat_buffer); - } } + } + /// Write a file to the root dir + pub fn write_file(&mut self, filename:&str, content:&mut [u8]){ + let free_fat_entry = self.get_free_fat_entry(1000).expect("Filesystem is too large, cant find free entry"); + + } + + fn get_fat_entry(&mut self, fat_index:&mut FatIndex, fat_buffer:&mut [u8; SECTOR_SIZE as usize])->u32{ + let fat_entry = fat_index.get_fat_entry(&fat_buffer); + if fat_index.sector_offset >= SECTOR_SIZE as usize{ + fat_index.sector_offset = 0; + fat_index.sector_number += 1; + let _ = self.disk.read(fat_index.sector_number, fat_buffer); + } + return fat_entry; + } + + fn get_fat_index(&self, first_cluster_index:u32)->FatIndex{ + let fat_offset = first_cluster_index * FAT_ENTRY_SIZE as u32; + return FatIndex { + sector_number:self.get_fat_start_sector() + (fat_offset / SECTOR_SIZE), + sector_offset: (fat_offset % SECTOR_SIZE) as usize + }; + } + + fn get_fat_start_sector(&self) -> u32 { + self.partition_start_sector_index + self.boot_sector.fat32_bpb.reserved_sectors_count as u32 + } + + fn get_free_fat_entry(&mut self, max_iterations:u32) -> Option { + let root_start_sector_index = self.get_cluster_start_sector_index(self.boot_sector.fat32_bpb.root_dir_first_cluster); + let mut sector_offset = 0; + let mut iteration_counter = 0; + let mut result = None; + 'search_loop: loop{ + let mut root_dir = [FatShortDirEntry::default();FAT_DIR_ENTRIES_PER_SECTOR]; + let buffer = unsafe{as_mut_buffer(&mut root_dir)}; + sector_offset += self.disk.read(root_start_sector_index + sector_offset, buffer); + for dir in root_dir{ + let dir_prefix = dir.file_name[0]; + if dir_prefix == DELETED_DIR_ENTRY_PREFIX { + result = result.or(Some(iteration_counter)); + } + else if dir_prefix == DIR_EOF_PREFIX { + return result.or(Some(iteration_counter)); + } + else{ + let mut fat_index = self.get_fat_index(dir.get_first_cluster_index()); + let mut fat_buffer = [0;SECTOR_SIZE as usize]; + let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer); + let mut fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); + while fat_entry != FAT_ENTRY_EOF_INDEX{ + self.set_occupied_cluser(fat_entry); + fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); + } + } + iteration_counter += 1; + if iteration_counter == max_iterations{ + break 'search_loop; + } + } + } + return result; } fn get_cluster_start_sector_index(&self, cluster:u32)->u32{ @@ -244,4 +373,12 @@ impl Fat32{ ((cluster - FIRST_DATA_CLUSTER) * self.boot_sector.fat32_bpb.sectors_per_cluster as u32) + (self.boot_sector.fat32_bpb.sectors_per_fat_32 * self.boot_sector.fat32_bpb.fats_count as u32) } + + fn set_occupied_cluser(&mut self, cluster_number:u32){ + if self.occupied_clusters.contains(&cluster_number){ + return; + } + self.occupied_clusters[self.occupied_cluster_count] = cluster_number; + self.occupied_cluster_count += 1; + } } \ No newline at end of file diff --git a/rpi/src/peripherals/emmc.rs b/rpi/src/peripherals/emmc.rs index fdee624f..5f01769e 100644 --- a/rpi/src/peripherals/emmc.rs +++ b/rpi/src/peripherals/emmc.rs @@ -280,21 +280,26 @@ impl Emmc{ } pub fn read(&mut self, buffer:&mut [u8])->bool{ - if self.offset % BLOCK_SIZE as u64 != 0{ - return false; - } - - let block = self.offset / BLOCK_SIZE as u64; + memory_barrier(); + let result = self.execute_data_transfer_command(false, buffer).is_ok(); + memory_barrier(); + return result; + } + pub fn write(&mut self, buffer: &mut [u8])->bool{ memory_barrier(); - let result = self.execute_data_transfer_command(false, buffer, block as u32).is_ok(); + let result = self.execute_data_transfer_command(true, buffer).is_ok(); memory_barrier(); return result; } pub fn get_block_size(&self)->u32{self.block_size} - fn execute_data_transfer_command(&mut self, write: bool, buffer: &mut [u8], mut block_index:u32)->Result<(), SdError>{ + fn execute_data_transfer_command(&mut self, write: bool, buffer: &mut [u8])->Result<(), SdError>{ + if self.offset % BLOCK_SIZE as u64 != 0{ + return Err(SdError::Error); + } + let mut block_index = (self.offset / BLOCK_SIZE as u64) as u32; if !self.sdhc_support{ block_index *= BLOCK_SIZE; } @@ -565,7 +570,6 @@ impl Emmc{ self::delay::wait_ms(3); } - fn setup_peripheral_clock(&mut self, mbox:&mut Mailbox){ self.registers.control2.write(0); // clear according to Circle and LLD let clock_rate = self.get_base_clock(mbox); From 60246e99e1ca7a64824c1dc0620199756672ab58 Mon Sep 17 00:00:00 2001 From: alloncm Date: Mon, 4 Sep 2023 17:50:35 +0300 Subject: [PATCH 02/39] Succesfully initing the fat32 driver caches Also increase the stack size to 2MB --- rpi/Cargo.toml | 2 +- rpi/src/bin/baremetal/link.ld | 2 +- rpi/src/bin/baremetal/main.rs | 8 ++- rpi/src/drivers/fat32.rs | 107 +++++++++++++++------------------- 4 files changed, 55 insertions(+), 64 deletions(-) diff --git a/rpi/Cargo.toml b/rpi/Cargo.toml index f60054da..0072bcbd 100644 --- a/rpi/Cargo.toml +++ b/rpi/Cargo.toml @@ -12,7 +12,7 @@ magenboy_common = {path = "../common"} log = "0.4" cfg-if = "1" bitfield-struct = "0.5" -arrayvec = "0.7" +arrayvec = {version = "0.7", default-features = false} libc = {version = "0.2", optional = true} nix = {version = "0.24", optional = true} crossbeam-channel = {version = "0.5", optional = true} diff --git a/rpi/src/bin/baremetal/link.ld b/rpi/src/bin/baremetal/link.ld index 64aeea77..5208ab85 100644 --- a/rpi/src/bin/baremetal/link.ld +++ b/rpi/src/bin/baremetal/link.ld @@ -1,7 +1,7 @@ /* Place _start procedure at the entry address for RPI */ __rpi_32_phys_binary_load_addr = 0x8000; __isr_table_addr = 0; -__stack_size = 0x100000; /* 1MB stack */ +__stack_size = 0x200000; /* 2MB stack */ ENTRY(__rpi_32_phys_binary_load_addr) /* enry point */ SECTIONS diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index b5a1aaa4..27a19140 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -80,10 +80,9 @@ fn read_menu_options(fs: &mut Fat32, menu_options: &mut [MenuOption(root_dir_offset); - for entry in dir_entries{ - let Some(entry) = entry else {break 'search_dir_loop}; + for entry in &dir_entries{ let extension = entry.get_extension(); if extension.eq_ignore_ascii_case("gb") || extension.eq_ignore_ascii_case("gbc"){ menu_options[menu_options_size] = MenuOption{ value: entry.clone(), prompt: StackString::from(entry.get_name()) }; @@ -91,6 +90,9 @@ fn read_menu_options(fs: &mut Fat32, menu_options: &mut [MenuOptionu32{ + fn get_fat_entry(&mut self, buffer:&[u8;FAT_BUFFER_SIZE])->u32{ let result = u32::from_ne_bytes(buffer[self.sector_offset .. self.sector_offset + FAT_ENTRY_SIZE].try_into().unwrap()) & FAT_ENTRY_MASK; self.sector_offset += FAT_ENTRY_SIZE; return result; } } +#[derive(Clone)] +struct FatSegment{ + value:u32, + len:u32, +} + // Currently the driver support only 0x100 files in the root directory const MAX_FILES: usize = 0x100; // Assuming each files is 0x100 clusters in average -const MAX_CLUSTERS_COUNT: usize = MAX_FILES * 0x100; +const MAX_FAT_SEGMENTS_COUNT: usize = MAX_FILES * 0x100; + +const FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; pub struct Fat32{ disk: Disk, @@ -157,10 +165,8 @@ pub struct Fat32{ partition_start_sector_index:u32, clusters_count:u32, - fat_table_cache: ArrayVec, + fat_table_cache: ArrayVec, root_dir_cache: ArrayVec, - occupied_clusters:[u32; MAX_CLUSTERS_COUNT], - occupied_cluster_count:usize, } impl Fat32{ @@ -190,8 +196,8 @@ impl Fat32{ let fat32_data_sectors = boot_sector.fat32_bpb.total_sectors_count_32 - (boot_sector.fat32_bpb.reserved_sectors_count as u32 + (boot_sector.fat32_bpb.sectors_per_fat_32 as u32 * boot_sector.fat32_bpb.fats_count as u32)); let clusters_count = fat32_data_sectors / boot_sector.fat32_bpb.sectors_per_cluster as u32; - let mut fat32 = Self { disk, boot_sector, partition_start_sector_index:bpb_sector_index, occupied_clusters:[0;MAX_CLUSTERS_COUNT], occupied_cluster_count:0, clusters_count, - fat_table_cache: ArrayVec::::new(), + let mut fat32 = Self { disk, boot_sector, partition_start_sector_index:bpb_sector_index, clusters_count, + fat_table_cache: ArrayVec::::new(), root_dir_cache: ArrayVec::::new() }; fat32.init_root_directory_cache(); @@ -218,57 +224,49 @@ impl Fat32{ fn init_fat_table_cache(&mut self){ let mut fat_index = FatIndex{sector_number: self.get_fat_start_sector(), sector_offset: 0}; - let mut fat_buffer = [0; SECTOR_SIZE as usize]; + let mut fat_buffer = [0; FAT_BUFFER_SIZE]; let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer); // The fat has entry per cluster in the volume, were adding 2 for the first 2 reserved entries (0,1) // This way the array is larger by 2 (fat entry at position clusters_count + 1 is the last valid entry) let fat_entries_count = self.clusters_count + 1; + log::debug!("fat entries count {}", fat_entries_count); + let mut current_segment = FatSegment{value: self.get_fat_entry(&mut fat_index, &mut fat_buffer), len: 1}; for _ in 0..=fat_entries_count{ let fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); - self.fat_table_cache.push(fat_entry); + if fat_entry == current_segment.value{ + current_segment.len += 1; + continue; + } + self.fat_table_cache.push(current_segment.clone()); + current_segment = FatSegment{value: fat_entry, len: 1}; } + self.fat_table_cache.push(current_segment); + log::debug!("Fat segments count {}", self.fat_table_cache.len()); } - pub fn root_dir_list(&mut self, offset:usize)->[Option;RESULT_MAX_LEN]{ - let root_start_sector_index = self.get_cluster_start_sector_index(self.boot_sector.fat32_bpb.root_dir_first_cluster); - self.set_occupied_cluser(self.boot_sector.fat32_bpb.root_dir_first_cluster); - - let mut root_dir_files_count = 0; - let mut output_dir = [None;RESULT_MAX_LEN]; - let mut sector_offset = 0; + pub fn root_dir_list(&mut self, offset:usize)->ArrayVec{ + let mut output_dir = ArrayVec::::new(); let mut discard = offset; - 'search: loop{ - let mut root_dir = [FatShortDirEntry::default();FAT_DIR_ENTRIES_PER_SECTOR]; - let buffer = unsafe{as_mut_buffer(&mut root_dir)}; - sector_offset += self.disk.read(root_start_sector_index + sector_offset, buffer); - for dir in root_dir{ - if dir.file_name[0] == DIR_EOF_PREFIX{ - break 'search; - } - if dir.file_name[0] == DELETED_DIR_ENTRY_PREFIX{ - continue; - } - if dir.attributes == ATTR_LONG_NAME{ - continue; - // handle long file names here - } - if discard > 0{ - discard -= 1; - continue; - } + for dir in &self.root_dir_cache{ + if dir.attributes == ATTR_LONG_NAME{ + continue; + // handle long file names here + } + if discard > 0{ + discard -= 1; + continue; + } - let mut filename:[u8;11] = [0;11]; - filename[..8].copy_from_slice(&dir.file_name); - filename[8..11].copy_from_slice(&dir.file_extension); - let first_cluster_index = dir.get_first_cluster_index(); - - output_dir[root_dir_files_count] = Some(FileEntry{ name: filename, first_cluster_index, size: dir.file_size }); - root_dir_files_count += 1; - if root_dir_files_count == RESULT_MAX_LEN{ - break 'search; - } + let mut filename:[u8;11] = [0;11]; + filename[..8].copy_from_slice(&dir.file_name); + filename[8..11].copy_from_slice(&dir.file_extension); + let first_cluster_index = dir.get_first_cluster_index(); + + output_dir.push(FileEntry{ name: filename, first_cluster_index, size: dir.file_size }); + if output_dir.remaining_capacity() == 0{ + break; } } @@ -283,12 +281,11 @@ impl Fat32{ let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster; let mut current_cluster = file_entry.first_cluster_index; let mut cluster_counter = 0; - let mut fat_buffer = [0; SECTOR_SIZE as usize]; + let mut fat_buffer = [0; FAT_BUFFER_SIZE]; let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer); loop{ let start_sector = self.get_cluster_start_sector_index(current_cluster); - self.set_occupied_cluser(current_cluster); let start_index = sectors_per_cluster as usize * cluster_counter * SECTOR_SIZE as usize; let end_index = start_index + (sectors_per_cluster as usize * SECTOR_SIZE as usize); let _ = self.disk.read(start_sector, &mut output[start_index..end_index]); @@ -308,9 +305,9 @@ impl Fat32{ } - fn get_fat_entry(&mut self, fat_index:&mut FatIndex, fat_buffer:&mut [u8; SECTOR_SIZE as usize])->u32{ + fn get_fat_entry(&mut self, fat_index:&mut FatIndex, fat_buffer:&mut [u8; FAT_BUFFER_SIZE])->u32{ let fat_entry = fat_index.get_fat_entry(&fat_buffer); - if fat_index.sector_offset >= SECTOR_SIZE as usize{ + if fat_index.sector_offset >= FAT_BUFFER_SIZE{ fat_index.sector_offset = 0; fat_index.sector_number += 1; let _ = self.disk.read(fat_index.sector_number, fat_buffer); @@ -349,11 +346,11 @@ impl Fat32{ } else{ let mut fat_index = self.get_fat_index(dir.get_first_cluster_index()); - let mut fat_buffer = [0;SECTOR_SIZE as usize]; + let mut fat_buffer = [0;FAT_BUFFER_SIZE]; let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer); let mut fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); while fat_entry != FAT_ENTRY_EOF_INDEX{ - self.set_occupied_cluser(fat_entry); + // self.set_occupied_cluser(fat_entry); fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); } } @@ -373,12 +370,4 @@ impl Fat32{ ((cluster - FIRST_DATA_CLUSTER) * self.boot_sector.fat32_bpb.sectors_per_cluster as u32) + (self.boot_sector.fat32_bpb.sectors_per_fat_32 * self.boot_sector.fat32_bpb.fats_count as u32) } - - fn set_occupied_cluser(&mut self, cluster_number:u32){ - if self.occupied_clusters.contains(&cluster_number){ - return; - } - self.occupied_clusters[self.occupied_cluster_count] = cluster_number; - self.occupied_cluster_count += 1; - } } \ No newline at end of file From e0d01d4e9b0579cc105017606bf6f88944cdfbc9 Mon Sep 17 00:00:00 2001 From: alloncm Date: Mon, 4 Sep 2023 21:28:27 +0300 Subject: [PATCH 03/39] Improve the fat32 file read performance. --- rpi/src/drivers/fat32.rs | 85 ++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 20 deletions(-) diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index 86500072..7913da6d 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -146,10 +146,38 @@ impl FatIndex{ } } +#[derive(Clone, Copy, PartialEq)] +enum FatSegmentState{ + Free, + Allocated, + Reserved, + Bad, + Eof, +} + +impl From for FatSegmentState{ + fn from(value: u32) -> Self { + match value{ + 0=>Self::Free, + 2..=0xFFF_FFF5 => Self::Allocated, + 0xFFF_FFFF=>Self::Eof, + 0xFFF_FFF7=>Self::Bad, + _=>Self::Reserved + } + } +} + #[derive(Clone)] struct FatSegment{ - value:u32, + state:FatSegmentState, len:u32, + start_index:u32, +} + +impl FatSegment{ + fn new(value:u32, start_index:u32)->Self{ + Self { state: value.into(), len: 1, start_index } + } } // Currently the driver support only 0x100 files in the root directory @@ -231,15 +259,16 @@ impl Fat32{ // This way the array is larger by 2 (fat entry at position clusters_count + 1 is the last valid entry) let fat_entries_count = self.clusters_count + 1; log::debug!("fat entries count {}", fat_entries_count); - let mut current_segment = FatSegment{value: self.get_fat_entry(&mut fat_index, &mut fat_buffer), len: 1}; - for _ in 0..=fat_entries_count{ + let fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); + let mut current_segment = FatSegment::new(fat_entry, 0); + for i in 0..fat_entries_count{ let fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); - if fat_entry == current_segment.value{ + if FatSegmentState::from(fat_entry) == current_segment.state{ current_segment.len += 1; continue; } self.fat_table_cache.push(current_segment.clone()); - current_segment = FatSegment{value: fat_entry, len: 1}; + current_segment = FatSegment::new(fat_entry, i + 1); } self.fat_table_cache.push(current_segment); log::debug!("Fat segments count {}", self.fat_table_cache.len()); @@ -273,30 +302,46 @@ impl Fat32{ return output_dir; } + // In this implemenation Im trying to read as much many clusters as possible at a time + // in order to improve performance /// Reads a file from the first FAT pub fn read_file(&mut self, file_entry:&FileEntry, output:&mut [u8]){ log::debug!("Reading file {}, size {}, cluster: {}", file_entry.get_name(), file_entry.size, file_entry.first_cluster_index); - let mut fat_index: FatIndex = self.get_fat_index(file_entry.first_cluster_index); - + let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster; - let mut current_cluster = file_entry.first_cluster_index; - let mut cluster_counter = 0; - let mut fat_buffer = [0; FAT_BUFFER_SIZE]; - let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer); + let mut cluster_counter:usize = 0; + let fat_first_entry = &self.fat_table_cache.as_slice().into_iter().find(|t|t.start_index == file_entry.first_cluster_index).unwrap(); + if fat_first_entry.state != FatSegmentState::Allocated{ + core::panic!("Error recevied not allocated segment"); + } + let mut fat_buffer = [0;FAT_BUFFER_SIZE]; + let mut fat_index = self.get_fat_index(file_entry.first_cluster_index); + let fat_sequence_size = fat_first_entry.len as usize * FAT_ENTRY_SIZE; + let fat_end_read = SECTOR_SIZE as usize + fat_sequence_size + (SECTOR_SIZE as usize - (fat_sequence_size % SECTOR_SIZE as usize)); + log::debug!("Fat end read: {:#X}", fat_end_read); + let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer[..fat_end_read]); - loop{ - let start_sector = self.get_cluster_start_sector_index(current_cluster); + let mut current_cluster = file_entry.first_cluster_index; + let mut next_read_cluster = current_cluster; + let mut clusters_sequence = 1; + while cluster_counter < fat_first_entry.len as usize{ + let fat_entry = fat_index.get_fat_entry(&mut fat_buffer); + if current_cluster + 1 == fat_entry{ + current_cluster = fat_entry; + clusters_sequence += 1; + continue; + } + let start_sector = self.get_cluster_start_sector_index(next_read_cluster); let start_index = sectors_per_cluster as usize * cluster_counter * SECTOR_SIZE as usize; - let end_index = start_index + (sectors_per_cluster as usize * SECTOR_SIZE as usize); + let end_index = start_index + (sectors_per_cluster as usize * SECTOR_SIZE as usize * clusters_sequence); let _ = self.disk.read(start_sector, &mut output[start_index..end_index]); - - let fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); - if fat_entry == FAT_ENTRY_EOF_INDEX{ - return; - } + + next_read_cluster = fat_entry; current_cluster = fat_entry; - cluster_counter += 1; + cluster_counter += clusters_sequence; + clusters_sequence = 1; } + // TODO: verify all the file has been read } /// Write a file to the root dir From c790a88d147d2f2e730437405a7efbf0ad28c623 Mon Sep 17 00:00:00 2001 From: alloncm Date: Tue, 5 Sep 2023 20:40:26 +0300 Subject: [PATCH 04/39] Trying to arrange all the fat handling --- rpi/src/drivers/fat32.rs | 224 ++++++++++++++++++++++++++++----------- 1 file changed, 162 insertions(+), 62 deletions(-) diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index 7913da6d..9956a606 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -74,13 +74,30 @@ struct FatShortDirEntry{ last_write_time:u16, last_write_date:u16, first_cluster_index_low:u16, - file_size:u32, + size:u32, } +compile_time_size_assert!(FatShortDirEntry, 32); impl FatShortDirEntry{ - pub fn get_first_cluster_index(&self)->u32{ + fn new(name:[u8;8], extension:[u8;3], size:u32)->Self{ + return Self { + file_name: name, file_extension: extension, attributes: 0, nt_reserve: 0, creation_time_tenth_secs: 0, creation_time: 0, + creation_date: 0, last_access_date: 0, first_cluster_index_high:0, last_write_time: 0, last_write_date: 0, first_cluster_index_low:0, size + }; + } + fn get_first_cluster_index(&self)->u32{ self.first_cluster_index_low as u32 | ((self.first_cluster_index_high as u32) << 16) } + fn set_first_cluster_index(&mut self, first_cluster_index:u32){ + self.first_cluster_index_low = (first_cluster_index & 0xFFFF) as u16; + self.first_cluster_index_high = (first_cluster_index << 16) as u16; + } + fn get_filename(&self)->[u8;11]{ + let mut filename:[u8;11] = [0;11]; + filename[..8].copy_from_slice(&self.file_name); + filename[8..11].copy_from_slice(&self.file_extension); + return filename; + } } // This struct is for support to the long filenames that I will add later @@ -99,7 +116,7 @@ struct FatLongDirEntry{ } const DISK_PARTITION_INDEX:u8 = 0; -const SECTOR_SIZE:u32 = 512; +const SECTOR_SIZE:usize = 512; const FAT_ENTRY_SIZE:usize = size_of::(); // each fat entry in fat32 is 4 the size of u32 const FAT_ENTRY_EOF_INDEX:u32 = 0x0FFF_FFFF; const FAT_ENTRY_MASK:u32 = 0x0FFF_FFFF; @@ -123,27 +140,30 @@ pub struct FileEntry{ impl FileEntry{ pub const FILENAME_SIZE:usize = 11; - pub fn get_name<'a>(&'a self)->&'a str{ core::str::from_utf8(&self.name).unwrap().trim() } - pub fn get_extension<'a>(&'a self)->&'a str{ core::str::from_utf8(&self.name[8..]).unwrap().trim() } } +#[derive(Clone)] struct FatIndex{ sector_number:u32, sector_offset:usize, } impl FatIndex{ - fn get_fat_entry(&mut self, buffer:&[u8;FAT_BUFFER_SIZE])->u32{ + fn get_fat_entry(&mut self, buffer:&[u8;SECTOR_SIZE as usize])->u32{ let result = u32::from_ne_bytes(buffer[self.sector_offset .. self.sector_offset + FAT_ENTRY_SIZE].try_into().unwrap()) & FAT_ENTRY_MASK; self.sector_offset += FAT_ENTRY_SIZE; return result; } + fn set_fat_entry(&mut self, entry:u32, buffer:&[u8;FAT_BUFFER_SIZE]){ + let entry = u32::to_ne_bytes(entry); + + } } #[derive(Clone, Copy, PartialEq)] @@ -176,14 +196,51 @@ struct FatSegment{ impl FatSegment{ fn new(value:u32, start_index:u32)->Self{ - Self { state: value.into(), len: 1, start_index } + Self { state: value.into(), len: 1, start_index} + } +} + +struct FatBuffer{ + buffer:[u8;FAT_BUFFER_SIZE], + buffer_len: usize, + fat_start_index:FatIndex, + entries_count:usize, + fat_internal_index:FatIndex, +} + +impl FatBuffer{ + fn new(fat_start_sector:usize, first_cluster_index:usize, entries_count: Option, disk: &mut Disk)->Self{ + let entries_count = entries_count.unwrap_or(FAT_BUFFER_SIZE/FAT_ENTRY_SIZE); + let mut buffer = [0; FAT_BUFFER_SIZE]; + let fat_offset = first_cluster_index * FAT_ENTRY_SIZE; + let fat_index = FatIndex{ sector_number: (fat_start_sector + fat_offset / SECTOR_SIZE) as u32, sector_offset: fat_offset % SECTOR_SIZE }; + + // Align the end read to SECTOR_SIZE + let fat_end_read = SECTOR_SIZE as usize + entries_count + (SECTOR_SIZE as usize - (entries_count % SECTOR_SIZE as usize)); + let _ = disk.read(fat_index.sector_number, &mut buffer[..fat_end_read]); + return Self { buffer, fat_start_index: fat_index.clone(), entries_count, fat_internal_index: fat_index, buffer_len: fat_end_read }; + } + + /// On sucess returns the FAT entry, on error returns the last valid fat index + fn read(&mut self, disk: &mut Disk)->Result{ + let interal_sector_offset = (self.fat_internal_index.sector_number - self.fat_start_index.sector_number) as usize; + if interal_sector_offset * SECTOR_SIZE >= self.buffer_len{ + return Err(self.fat_internal_index.clone()); + } + let start_index = interal_sector_offset * SECTOR_SIZE; + let end_index = start_index + SECTOR_SIZE; + let entry = self.fat_internal_index.get_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); + if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ + self.fat_internal_index.sector_number += 1; + self.fat_internal_index.sector_offset = 0; + } + return Ok(entry); } } // Currently the driver support only 0x100 files in the root directory const MAX_FILES: usize = 0x100; -// Assuming each files is 0x100 clusters in average -const MAX_FAT_SEGMENTS_COUNT: usize = MAX_FILES * 0x100; +const MAX_FAT_SEGMENTS_COUNT: usize = MAX_FILES * 10; const FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; @@ -215,7 +272,7 @@ impl Fat32{ core::panic!("Detected FAT16 and not FAT32 file system"); } let bytes_per_sector = boot_sector.fat32_bpb.bytes_per_sector as u32; - if bytes_per_sector != disk.get_block_size() || bytes_per_sector != SECTOR_SIZE{ + if bytes_per_sector != disk.get_block_size() || bytes_per_sector != SECTOR_SIZE as u32{ core::panic!("Currently dont support fat32 disks with sectors size other than {}", SECTOR_SIZE); } let fat_count = boot_sector.fat32_bpb.fats_count; @@ -251,6 +308,7 @@ impl Fat32{ } fn init_fat_table_cache(&mut self){ + // let fat_buffer = FatBuffer::new(self.get_fat_start_sector() as usize, 0, None, &mut self.disk); let mut fat_index = FatIndex{sector_number: self.get_fat_start_sector(), sector_offset: 0}; let mut fat_buffer = [0; FAT_BUFFER_SIZE]; let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer); @@ -287,13 +345,10 @@ impl Fat32{ discard -= 1; continue; } - - let mut filename:[u8;11] = [0;11]; - filename[..8].copy_from_slice(&dir.file_name); - filename[8..11].copy_from_slice(&dir.file_extension); + let filename = dir.get_filename(); let first_cluster_index = dir.get_first_cluster_index(); - output_dir.push(FileEntry{ name: filename, first_cluster_index, size: dir.file_size }); + output_dir.push(FileEntry{ name: filename, first_cluster_index, size: dir.size }); if output_dir.remaining_capacity() == 0{ break; } @@ -309,21 +364,17 @@ impl Fat32{ log::debug!("Reading file {}, size {}, cluster: {}", file_entry.get_name(), file_entry.size, file_entry.first_cluster_index); let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster; - let mut cluster_counter:usize = 0; - let fat_first_entry = &self.fat_table_cache.as_slice().into_iter().find(|t|t.start_index == file_entry.first_cluster_index).unwrap(); + let fat_first_entry = self.fat_table_cache.as_slice().into_iter().find(|t|t.start_index == file_entry.first_cluster_index).unwrap().clone(); if fat_first_entry.state != FatSegmentState::Allocated{ core::panic!("Error recevied not allocated segment"); } let mut fat_buffer = [0;FAT_BUFFER_SIZE]; - let mut fat_index = self.get_fat_index(file_entry.first_cluster_index); - let fat_sequence_size = fat_first_entry.len as usize * FAT_ENTRY_SIZE; - let fat_end_read = SECTOR_SIZE as usize + fat_sequence_size + (SECTOR_SIZE as usize - (fat_sequence_size % SECTOR_SIZE as usize)); - log::debug!("Fat end read: {:#X}", fat_end_read); - let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer[..fat_end_read]); + let mut fat_index = self.read_fat(file_entry.first_cluster_index, fat_first_entry.len, &mut fat_buffer); let mut current_cluster = file_entry.first_cluster_index; let mut next_read_cluster = current_cluster; let mut clusters_sequence = 1; + let mut cluster_counter:usize = 0; while cluster_counter < fat_first_entry.len as usize{ let fat_entry = fat_index.get_fat_entry(&mut fat_buffer); if current_cluster + 1 == fat_entry{ @@ -344,10 +395,95 @@ impl Fat32{ // TODO: verify all the file has been read } + fn read_fat(&mut self, first_cluster_index:u32, fat_segment_len: u32, fat_buffer: &mut [u8; FAT_BUFFER_SIZE]) -> FatIndex { + let fat_index = self.get_fat_index(first_cluster_index); + let fat_sequence_size = fat_segment_len as usize * FAT_ENTRY_SIZE; + // Align the end read to SECTOR_SIZE + let fat_end_read = SECTOR_SIZE as usize + fat_sequence_size + (SECTOR_SIZE as usize - (fat_sequence_size % SECTOR_SIZE as usize)); + let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer[..fat_end_read]); + return fat_index; + } + /// Write a file to the root dir pub fn write_file(&mut self, filename:&str, content:&mut [u8]){ - let free_fat_entry = self.get_free_fat_entry(1000).expect("Filesystem is too large, cant find free entry"); - + let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster as u32; + let cluster_size = sectors_per_cluster * SECTOR_SIZE as u32; + let (name, extension) = self.create_filename(filename).unwrap_or_else(|_|core::panic!("File name format is bad: {}", filename)); + // check if file exists, if exists try to overwrite it, if cant mark it as deleted + if let Some(existing_entry) = self.root_dir_cache.as_mut_slice().into_iter().find(|d|d.file_name == name && d.file_extension == extension){ + if (existing_entry.size as usize) < content.len(){ + existing_entry.file_name[0] = DELETED_DIR_ENTRY_PREFIX; + // TODO: mark the fat entries as free + } + else{ + let existing_entry = existing_entry.clone(); // Shadow the original in order to statisify the borrow checker + let segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == existing_entry.get_first_cluster_index()).unwrap().clone(); + let mut fat_buffer = [0; FAT_BUFFER_SIZE]; + let mut fat_index = self.read_fat(existing_entry.get_first_cluster_index(), segment.len, &mut fat_buffer); + let mut current_cluster = existing_entry.get_first_cluster_index(); + let mut cluster_count = 0; + while cluster_count < segment.len{ + let start_sector = self.get_cluster_start_sector_index(current_cluster); + let start_index = (sectors_per_cluster * cluster_count) as usize * SECTOR_SIZE; + let end_index = start_index + (sectors_per_cluster * SECTOR_SIZE as u32) as usize; + let _ = self.disk.write(start_sector, &mut content[start_index..end_index]); + + current_cluster = fat_index.get_fat_entry(&mut fat_buffer); + cluster_count += 1; + } + return; + } + } + + // create a new file by allocating place in the root dir and then picking some free fat segment and use it's clusters + let new_dir_entry = match self.root_dir_cache.as_mut_slice().into_iter().find(|d|d.file_name[0] == DELETED_DIR_ENTRY_PREFIX){ + Some(dir) => dir, + None => { + // Check the root dir allocation size to check it needs to be reallocated + let root_dir_entry = self.root_dir_cache.as_slice().into_iter().find(|d|d.attributes == ATTR_VOLUME_ID).unwrap(); + if root_dir_entry.size as usize >= self.root_dir_cache.len() * size_of::() { + core::panic!("driver do not support resizing of the root dir"); + } + // Allocate new entry in the root dir + self.root_dir_cache.push(FatShortDirEntry::new(name, extension, content.len() as u32)); + self.root_dir_cache.last_mut().unwrap() + }, + }; + let free_fat_seqment = self.fat_table_cache.as_slice().into_iter().find(|t|t.state == FatSegmentState::Free && t.len >= content.len() as u32 / cluster_size).unwrap(); + let first_cluster_index = free_fat_seqment.start_index; + new_dir_entry.set_first_cluster_index(first_cluster_index); + let mut fat_buffer = [0;FAT_BUFFER_SIZE]; + self.read_fat(first_cluster_index, free_fat_seqment.len, &mut fat_buffer); + let fat_index = self.get_fat_index(first_cluster_index); + + // write the data to the clusters, since the cluster index is the initial index in the fat I can know which one is free or allocated + + // sync the root dir modifications + self.write_root_dir_cache(); + } + + fn create_filename(&self, filename:&str)->Result<([u8;8],[u8;3]), ()>{ + const ILLEGAL_CHARS:[u8;16] = [b'"', b'*', b'+', b',', b'.', b'/', b':', b';', b'<', b'=', b'>', b'?', b'[',b'\\', b']', b'|' ]; + if filename.len() != 11 || !filename.is_ascii() || filename.as_bytes().into_iter().any(|b|ILLEGAL_CHARS.contains(b) && *b > 0x20){ + return Err(()); + } + let filename:[u8;11] = filename.to_uppercase().as_bytes().try_into().unwrap(); + let name:[u8;8] = filename[..8].try_into().unwrap(); + let extension:[u8;3] = filename[8..].try_into().unwrap(); + return Ok((name, extension)); + } + + fn write_root_dir_cache(&mut self){ + let chunks = self.root_dir_cache.chunks_exact(FAT_DIR_ENTRIES_PER_SECTOR); + let mut root_sector_index = self.get_cluster_start_sector_index(self.boot_sector.fat32_bpb.root_dir_first_cluster); + let reminder = chunks.remainder(); + let mut buffer = [FatShortDirEntry::default(); FAT_DIR_ENTRIES_PER_SECTOR]; + for chunk in chunks{ + buffer.copy_from_slice(chunk); + let mut buffer = unsafe{as_mut_buffer(&mut buffer)}; + root_sector_index += self.disk.write(root_sector_index, &mut buffer); + } + buffer[..reminder.len()].copy_from_slice(reminder); } fn get_fat_entry(&mut self, fat_index:&mut FatIndex, fat_buffer:&mut [u8; FAT_BUFFER_SIZE])->u32{ @@ -363,8 +499,8 @@ impl Fat32{ fn get_fat_index(&self, first_cluster_index:u32)->FatIndex{ let fat_offset = first_cluster_index * FAT_ENTRY_SIZE as u32; return FatIndex { - sector_number:self.get_fat_start_sector() + (fat_offset / SECTOR_SIZE), - sector_offset: (fat_offset % SECTOR_SIZE) as usize + sector_number: self.get_fat_start_sector() + (fat_offset / SECTOR_SIZE as u32), + sector_offset: fat_offset as usize % SECTOR_SIZE }; } @@ -372,42 +508,6 @@ impl Fat32{ self.partition_start_sector_index + self.boot_sector.fat32_bpb.reserved_sectors_count as u32 } - fn get_free_fat_entry(&mut self, max_iterations:u32) -> Option { - let root_start_sector_index = self.get_cluster_start_sector_index(self.boot_sector.fat32_bpb.root_dir_first_cluster); - let mut sector_offset = 0; - let mut iteration_counter = 0; - let mut result = None; - 'search_loop: loop{ - let mut root_dir = [FatShortDirEntry::default();FAT_DIR_ENTRIES_PER_SECTOR]; - let buffer = unsafe{as_mut_buffer(&mut root_dir)}; - sector_offset += self.disk.read(root_start_sector_index + sector_offset, buffer); - for dir in root_dir{ - let dir_prefix = dir.file_name[0]; - if dir_prefix == DELETED_DIR_ENTRY_PREFIX { - result = result.or(Some(iteration_counter)); - } - else if dir_prefix == DIR_EOF_PREFIX { - return result.or(Some(iteration_counter)); - } - else{ - let mut fat_index = self.get_fat_index(dir.get_first_cluster_index()); - let mut fat_buffer = [0;FAT_BUFFER_SIZE]; - let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer); - let mut fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); - while fat_entry != FAT_ENTRY_EOF_INDEX{ - // self.set_occupied_cluser(fat_entry); - fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); - } - } - iteration_counter += 1; - if iteration_counter == max_iterations{ - break 'search_loop; - } - } - } - return result; - } - fn get_cluster_start_sector_index(&self, cluster:u32)->u32{ const FIRST_DATA_CLUSTER:u32 = 2; From f812c76e6d19c543b59885da5902e834f2bf113b Mon Sep 17 00:00:00 2001 From: alloncm Date: Tue, 5 Sep 2023 22:54:39 +0300 Subject: [PATCH 05/39] Refactor all the fat handling * need to clear all the logs I used for debug * finish the write file impl --- rpi/src/drivers/fat32.rs | 108 ++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 64 deletions(-) diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index 9956a606..477964f7 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -155,12 +155,10 @@ struct FatIndex{ } impl FatIndex{ - fn get_fat_entry(&mut self, buffer:&[u8;SECTOR_SIZE as usize])->u32{ - let result = u32::from_ne_bytes(buffer[self.sector_offset .. self.sector_offset + FAT_ENTRY_SIZE].try_into().unwrap()) & FAT_ENTRY_MASK; - self.sector_offset += FAT_ENTRY_SIZE; - return result; + fn get_fat_entry(&mut self, buffer:&[u8;FAT_ENTRY_SIZE])->u32{ + u32::from_ne_bytes(*buffer) & FAT_ENTRY_MASK } - fn set_fat_entry(&mut self, entry:u32, buffer:&[u8;FAT_BUFFER_SIZE]){ + fn set_fat_entry(&mut self, entry:u32, buffer:&[u8;FAT_ENTRY_SIZE]){ let entry = u32::to_ne_bytes(entry); } @@ -204,32 +202,37 @@ struct FatBuffer{ buffer:[u8;FAT_BUFFER_SIZE], buffer_len: usize, fat_start_index:FatIndex, - entries_count:usize, fat_internal_index:FatIndex, } impl FatBuffer{ fn new(fat_start_sector:usize, first_cluster_index:usize, entries_count: Option, disk: &mut Disk)->Self{ - let entries_count = entries_count.unwrap_or(FAT_BUFFER_SIZE/FAT_ENTRY_SIZE); + log::info!("fat_start_sector: {}, first_cluster_index: {}, entries_count: {:?}",fat_start_sector,first_cluster_index, entries_count); + let entries_count = entries_count.unwrap_or((FAT_BUFFER_SIZE - SECTOR_SIZE) / FAT_ENTRY_SIZE); let mut buffer = [0; FAT_BUFFER_SIZE]; let fat_offset = first_cluster_index * FAT_ENTRY_SIZE; let fat_index = FatIndex{ sector_number: (fat_start_sector + fat_offset / SECTOR_SIZE) as u32, sector_offset: fat_offset % SECTOR_SIZE }; // Align the end read to SECTOR_SIZE - let fat_end_read = SECTOR_SIZE as usize + entries_count + (SECTOR_SIZE as usize - (entries_count % SECTOR_SIZE as usize)); + let fat_end_read = (entries_count * FAT_ENTRY_SIZE) + (SECTOR_SIZE - ((entries_count * FAT_ENTRY_SIZE) % SECTOR_SIZE)) + ((fat_index.sector_offset != 0) as usize * SECTOR_SIZE); + if fat_end_read > FAT_BUFFER_SIZE{ + core::panic!("Error fat entries count is too much: expected:{}, actual: {}", FAT_BUFFER_SIZE / FAT_ENTRY_SIZE, entries_count); + } + log::warn!("offset: {}, end read: {}", fat_index.sector_offset, fat_end_read); let _ = disk.read(fat_index.sector_number, &mut buffer[..fat_end_read]); - return Self { buffer, fat_start_index: fat_index.clone(), entries_count, fat_internal_index: fat_index, buffer_len: fat_end_read }; + return Self { buffer, fat_start_index: fat_index.clone(), fat_internal_index: fat_index, buffer_len: fat_end_read }; } /// On sucess returns the FAT entry, on error returns the last valid fat index - fn read(&mut self, disk: &mut Disk)->Result{ - let interal_sector_offset = (self.fat_internal_index.sector_number - self.fat_start_index.sector_number) as usize; - if interal_sector_offset * SECTOR_SIZE >= self.buffer_len{ + fn read(&mut self)->Result{ + let interal_sector_index = (self.fat_internal_index.sector_number - self.fat_start_index.sector_number) as usize; + if interal_sector_index * SECTOR_SIZE >= self.buffer_len{ return Err(self.fat_internal_index.clone()); } - let start_index = interal_sector_offset * SECTOR_SIZE; - let end_index = start_index + SECTOR_SIZE; + let start_index = (interal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; + let end_index = start_index + FAT_ENTRY_SIZE; let entry = self.fat_internal_index.get_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); + self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ self.fat_internal_index.sector_number += 1; self.fat_internal_index.sector_offset = 0; @@ -240,7 +243,7 @@ impl FatBuffer{ // Currently the driver support only 0x100 files in the root directory const MAX_FILES: usize = 0x100; -const MAX_FAT_SEGMENTS_COUNT: usize = MAX_FILES * 10; +const MAX_FAT_SEGMENTS_COUNT: usize = MAX_FILES * 100; const FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; @@ -308,25 +311,26 @@ impl Fat32{ } fn init_fat_table_cache(&mut self){ - // let fat_buffer = FatBuffer::new(self.get_fat_start_sector() as usize, 0, None, &mut self.disk); - let mut fat_index = FatIndex{sector_number: self.get_fat_start_sector(), sector_offset: 0}; - let mut fat_buffer = [0; FAT_BUFFER_SIZE]; - let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer); + let mut fat_buffer = FatBuffer::new(self.get_fat_start_sector() as usize, 0, None, &mut self.disk); // The fat has entry per cluster in the volume, were adding 2 for the first 2 reserved entries (0,1) // This way the array is larger by 2 (fat entry at position clusters_count + 1 is the last valid entry) let fat_entries_count = self.clusters_count + 1; log::debug!("fat entries count {}", fat_entries_count); - let fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); + let fat_entry = fat_buffer.read().ok().unwrap(); let mut current_segment = FatSegment::new(fat_entry, 0); - for i in 0..fat_entries_count{ - let fat_entry = self.get_fat_entry(&mut fat_index, &mut fat_buffer); + for i in 1..=fat_entries_count{ + let fat_entry = fat_buffer.read().unwrap_or_else(|_|{ + fat_buffer = FatBuffer::new(self.get_fat_start_sector(), i as usize, None, &mut self.disk); + fat_buffer.read().ok().unwrap() + }); if FatSegmentState::from(fat_entry) == current_segment.state{ current_segment.len += 1; continue; } self.fat_table_cache.push(current_segment.clone()); - current_segment = FatSegment::new(fat_entry, i + 1); + current_segment = FatSegment::new(fat_entry, i); + log::info!("found new segment, start index: {}", current_segment.start_index); } self.fat_table_cache.push(current_segment); log::debug!("Fat segments count {}", self.fat_table_cache.len()); @@ -368,15 +372,16 @@ impl Fat32{ if fat_first_entry.state != FatSegmentState::Allocated{ core::panic!("Error recevied not allocated segment"); } - let mut fat_buffer = [0;FAT_BUFFER_SIZE]; - let mut fat_index = self.read_fat(file_entry.first_cluster_index, fat_first_entry.len, &mut fat_buffer); + log::warn!("fat entries: {}", fat_first_entry.len); + let mut fat_buffer = FatBuffer::new(self.get_fat_start_sector() as usize, file_entry.first_cluster_index as usize, Some(fat_first_entry.len as usize), &mut self.disk); let mut current_cluster = file_entry.first_cluster_index; let mut next_read_cluster = current_cluster; let mut clusters_sequence = 1; let mut cluster_counter:usize = 0; while cluster_counter < fat_first_entry.len as usize{ - let fat_entry = fat_index.get_fat_entry(&mut fat_buffer); + log::warn!("Cluster index: {}, cluster sequence: {}", cluster_counter, clusters_sequence); + let fat_entry = fat_buffer.read().ok().unwrap(); if current_cluster + 1 == fat_entry{ current_cluster = fat_entry; clusters_sequence += 1; @@ -395,15 +400,6 @@ impl Fat32{ // TODO: verify all the file has been read } - fn read_fat(&mut self, first_cluster_index:u32, fat_segment_len: u32, fat_buffer: &mut [u8; FAT_BUFFER_SIZE]) -> FatIndex { - let fat_index = self.get_fat_index(first_cluster_index); - let fat_sequence_size = fat_segment_len as usize * FAT_ENTRY_SIZE; - // Align the end read to SECTOR_SIZE - let fat_end_read = SECTOR_SIZE as usize + fat_sequence_size + (SECTOR_SIZE as usize - (fat_sequence_size % SECTOR_SIZE as usize)); - let _ = self.disk.read(fat_index.sector_number, &mut fat_buffer[..fat_end_read]); - return fat_index; - } - /// Write a file to the root dir pub fn write_file(&mut self, filename:&str, content:&mut [u8]){ let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster as u32; @@ -418,8 +414,7 @@ impl Fat32{ else{ let existing_entry = existing_entry.clone(); // Shadow the original in order to statisify the borrow checker let segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == existing_entry.get_first_cluster_index()).unwrap().clone(); - let mut fat_buffer = [0; FAT_BUFFER_SIZE]; - let mut fat_index = self.read_fat(existing_entry.get_first_cluster_index(), segment.len, &mut fat_buffer); + let mut fat_buffer = FatBuffer::new(self.get_fat_start_sector() as usize, existing_entry.get_first_cluster_index() as usize, Some(segment.len as usize), &mut self.disk); let mut current_cluster = existing_entry.get_first_cluster_index(); let mut cluster_count = 0; while cluster_count < segment.len{ @@ -428,7 +423,7 @@ impl Fat32{ let end_index = start_index + (sectors_per_cluster * SECTOR_SIZE as u32) as usize; let _ = self.disk.write(start_sector, &mut content[start_index..end_index]); - current_cluster = fat_index.get_fat_entry(&mut fat_buffer); + current_cluster = fat_buffer.read().ok().unwrap(); cluster_count += 1; } return; @@ -449,12 +444,12 @@ impl Fat32{ self.root_dir_cache.last_mut().unwrap() }, }; - let free_fat_seqment = self.fat_table_cache.as_slice().into_iter().find(|t|t.state == FatSegmentState::Free && t.len >= content.len() as u32 / cluster_size).unwrap(); + let required_clusters_count = content.len() as u32 / cluster_size; + let free_fat_seqment = self.fat_table_cache.as_slice().into_iter().find(|t|t.state == FatSegmentState::Free && t.len >= required_clusters_count).unwrap(); let first_cluster_index = free_fat_seqment.start_index; new_dir_entry.set_first_cluster_index(first_cluster_index); - let mut fat_buffer = [0;FAT_BUFFER_SIZE]; - self.read_fat(first_cluster_index, free_fat_seqment.len, &mut fat_buffer); - let fat_index = self.get_fat_index(first_cluster_index); + let mut fat_buffer = FatBuffer::new(self.get_fat_start_sector(), first_cluster_index as usize, Some(required_clusters_count as usize), &mut self.disk); + // write the data to the clusters, since the cluster index is the initial index in the fat I can know which one is free or allocated @@ -464,10 +459,13 @@ impl Fat32{ fn create_filename(&self, filename:&str)->Result<([u8;8],[u8;3]), ()>{ const ILLEGAL_CHARS:[u8;16] = [b'"', b'*', b'+', b',', b'.', b'/', b':', b';', b'<', b'=', b'>', b'?', b'[',b'\\', b']', b'|' ]; - if filename.len() != 11 || !filename.is_ascii() || filename.as_bytes().into_iter().any(|b|ILLEGAL_CHARS.contains(b) && *b > 0x20){ + if filename.len() != 11 || + !filename.is_ascii() || + filename.as_bytes().into_iter().any(|b|ILLEGAL_CHARS.contains(b) && *b > 0x20) || + filename.as_bytes().into_iter().any(|c| *c >= b'a' && *c <= b'z'){ return Err(()); } - let filename:[u8;11] = filename.to_uppercase().as_bytes().try_into().unwrap(); + let filename:[u8;11] = filename.as_bytes().try_into().unwrap(); let name:[u8;8] = filename[..8].try_into().unwrap(); let extension:[u8;3] = filename[8..].try_into().unwrap(); return Ok((name, extension)); @@ -486,26 +484,8 @@ impl Fat32{ buffer[..reminder.len()].copy_from_slice(reminder); } - fn get_fat_entry(&mut self, fat_index:&mut FatIndex, fat_buffer:&mut [u8; FAT_BUFFER_SIZE])->u32{ - let fat_entry = fat_index.get_fat_entry(&fat_buffer); - if fat_index.sector_offset >= FAT_BUFFER_SIZE{ - fat_index.sector_offset = 0; - fat_index.sector_number += 1; - let _ = self.disk.read(fat_index.sector_number, fat_buffer); - } - return fat_entry; - } - - fn get_fat_index(&self, first_cluster_index:u32)->FatIndex{ - let fat_offset = first_cluster_index * FAT_ENTRY_SIZE as u32; - return FatIndex { - sector_number: self.get_fat_start_sector() + (fat_offset / SECTOR_SIZE as u32), - sector_offset: fat_offset as usize % SECTOR_SIZE - }; - } - - fn get_fat_start_sector(&self) -> u32 { - self.partition_start_sector_index + self.boot_sector.fat32_bpb.reserved_sectors_count as u32 + fn get_fat_start_sector(&self) -> usize { + (self.partition_start_sector_index + self.boot_sector.fat32_bpb.reserved_sectors_count as u32) as usize } fn get_cluster_start_sector_index(&self, cluster:u32)->u32{ From 5184118460eca89874ca91363f375b3a5a7d726b Mon Sep 17 00:00:00 2001 From: alloncm Date: Tue, 5 Sep 2023 23:40:30 +0300 Subject: [PATCH 06/39] Add optimization comment --- rpi/src/drivers/fat32.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index 477964f7..3a6770bf 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -310,6 +310,7 @@ impl Fat32{ } } + // Optimization : Perhaps I can read the files from the root dir, and once I have all the entries abort and mark the rest of the clusters as free?? fn init_fat_table_cache(&mut self){ let mut fat_buffer = FatBuffer::new(self.get_fat_start_sector() as usize, 0, None, &mut self.disk); From cc135f11114ad6ab98feb7d786d5b67806e9c34e Mon Sep 17 00:00:00 2001 From: alloncm Date: Sat, 16 Sep 2023 12:49:21 +0300 Subject: [PATCH 07/39] WIP --- rpi/src/drivers/fat32.rs | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index 3a6770bf..8560b3e6 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -164,21 +164,19 @@ impl FatIndex{ } } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Debug)] enum FatSegmentState{ Free, Allocated, Reserved, Bad, - Eof, } impl From for FatSegmentState{ fn from(value: u32) -> Self { match value{ 0=>Self::Free, - 2..=0xFFF_FFF5 => Self::Allocated, - 0xFFF_FFFF=>Self::Eof, + 2..=0xFFF_FFF5 | 0xFFF_FFFF=>Self::Allocated, 0xFFF_FFF7=>Self::Bad, _=>Self::Reserved } @@ -214,11 +212,11 @@ impl FatBuffer{ let fat_index = FatIndex{ sector_number: (fat_start_sector + fat_offset / SECTOR_SIZE) as u32, sector_offset: fat_offset % SECTOR_SIZE }; // Align the end read to SECTOR_SIZE - let fat_end_read = (entries_count * FAT_ENTRY_SIZE) + (SECTOR_SIZE - ((entries_count * FAT_ENTRY_SIZE) % SECTOR_SIZE)) + ((fat_index.sector_offset != 0) as usize * SECTOR_SIZE); + let fat_end_read = (entries_count * FAT_ENTRY_SIZE) + (SECTOR_SIZE - ((entries_count * FAT_ENTRY_SIZE) % SECTOR_SIZE)); if fat_end_read > FAT_BUFFER_SIZE{ core::panic!("Error fat entries count is too much: expected:{}, actual: {}", FAT_BUFFER_SIZE / FAT_ENTRY_SIZE, entries_count); } - log::warn!("offset: {}, end read: {}", fat_index.sector_offset, fat_end_read); + // log::warn!("offset: {}, end read: {}", fat_index.sector_offset, fat_end_read); let _ = disk.read(fat_index.sector_number, &mut buffer[..fat_end_read]); return Self { buffer, fat_start_index: fat_index.clone(), fat_internal_index: fat_index, buffer_len: fat_end_read }; } @@ -302,36 +300,49 @@ impl Fat32{ let buffer = unsafe{as_mut_buffer(&mut root_dir)}; sector_offset += self.disk.read(root_start_sector_index + sector_offset, buffer); for dir in root_dir{ + if dir.file_name[0] == DELETED_DIR_ENTRY_PREFIX { + continue; + } if dir.file_name[0] == DIR_EOF_PREFIX { break 'search; } + log::info!("dir: {} attrib: {:#X}", core::str::from_utf8(&dir.file_name).unwrap().trim(), dir.attributes); self.root_dir_cache.push(dir); } } } - // Optimization : Perhaps I can read the files from the root dir, and once I have all the entries abort and mark the rest of the clusters as free?? + // Optimization: Perhaps I can read the files from the root dir, and once I have all the entries abort and mark the rest of the clusters as free?? fn init_fat_table_cache(&mut self){ let mut fat_buffer = FatBuffer::new(self.get_fat_start_sector() as usize, 0, None, &mut self.disk); // The fat has entry per cluster in the volume, were adding 2 for the first 2 reserved entries (0,1) // This way the array is larger by 2 (fat entry at position clusters_count + 1 is the last valid entry) let fat_entries_count = self.clusters_count + 1; - log::debug!("fat entries count {}", fat_entries_count); + log::debug!("fat entries count {}, root_dir len: {}", fat_entries_count, self.root_dir_cache.len()); let fat_entry = fat_buffer.read().ok().unwrap(); let mut current_segment = FatSegment::new(fat_entry, 0); - for i in 1..=fat_entries_count{ + + // Since indices [0,1] are resereved ignore and skip them + // the loop starting from 2 is probably a bug / mistake + for i in 2..=fat_entries_count{ let fat_entry = fat_buffer.read().unwrap_or_else(|_|{ fat_buffer = FatBuffer::new(self.get_fat_start_sector(), i as usize, None, &mut self.disk); fat_buffer.read().ok().unwrap() }); - if FatSegmentState::from(fat_entry) == current_segment.state{ + if FatSegmentState::from(fat_entry) == current_segment.state { current_segment.len += 1; - continue; + if fat_entry != FAT_ENTRY_EOF_INDEX{ + continue; + } } self.fat_table_cache.push(current_segment.clone()); current_segment = FatSegment::new(fat_entry, i); - log::info!("found new segment, start index: {}", current_segment.start_index); + log::info!("found new segment: {:#?}, start index: {}", current_segment.state, current_segment.start_index); + if self.fat_table_cache.iter().filter(|f|f.state == FatSegmentState::Allocated).count() == self.root_dir_cache.len(){ + current_segment.len = fat_entries_count - i; + break; + } } self.fat_table_cache.push(current_segment); log::debug!("Fat segments count {}", self.fat_table_cache.len()); From 24530be88c97e7a9a7b174c33a551b6fa98c9688 Mon Sep 17 00:00:00 2001 From: alloncm Date: Sat, 16 Sep 2023 16:12:26 +0300 Subject: [PATCH 08/39] Finished the init of the fat table cacheI hope the little optimization I dd there is fast enough, cause I failed with the actual one --- rpi/src/drivers/fat32.rs | 48 +++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index 8560b3e6..c0061865 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -196,27 +196,25 @@ impl FatSegment{ } } -struct FatBuffer{ - buffer:[u8;FAT_BUFFER_SIZE], +struct FatBuffer{ + buffer:[u8;FBS], buffer_len: usize, fat_start_index:FatIndex, fat_internal_index:FatIndex, } -impl FatBuffer{ +impl FatBuffer{ fn new(fat_start_sector:usize, first_cluster_index:usize, entries_count: Option, disk: &mut Disk)->Self{ - log::info!("fat_start_sector: {}, first_cluster_index: {}, entries_count: {:?}",fat_start_sector,first_cluster_index, entries_count); - let entries_count = entries_count.unwrap_or((FAT_BUFFER_SIZE - SECTOR_SIZE) / FAT_ENTRY_SIZE); - let mut buffer = [0; FAT_BUFFER_SIZE]; + let entries_count = entries_count.unwrap_or((FBS - SECTOR_SIZE) / FAT_ENTRY_SIZE); + let mut buffer = [0; FBS]; let fat_offset = first_cluster_index * FAT_ENTRY_SIZE; let fat_index = FatIndex{ sector_number: (fat_start_sector + fat_offset / SECTOR_SIZE) as u32, sector_offset: fat_offset % SECTOR_SIZE }; // Align the end read to SECTOR_SIZE let fat_end_read = (entries_count * FAT_ENTRY_SIZE) + (SECTOR_SIZE - ((entries_count * FAT_ENTRY_SIZE) % SECTOR_SIZE)); - if fat_end_read > FAT_BUFFER_SIZE{ - core::panic!("Error fat entries count is too much: expected:{}, actual: {}", FAT_BUFFER_SIZE / FAT_ENTRY_SIZE, entries_count); + if fat_end_read > FBS{ + core::panic!("Error fat entries count is too much: expected:{}, actual: {}", FBS / FAT_ENTRY_SIZE, entries_count); } - // log::warn!("offset: {}, end read: {}", fat_index.sector_offset, fat_end_read); let _ = disk.read(fat_index.sector_number, &mut buffer[..fat_end_read]); return Self { buffer, fat_start_index: fat_index.clone(), fat_internal_index: fat_index, buffer_len: fat_end_read }; } @@ -306,26 +304,31 @@ impl Fat32{ if dir.file_name[0] == DIR_EOF_PREFIX { break 'search; } - log::info!("dir: {} attrib: {:#X}", core::str::from_utf8(&dir.file_name).unwrap().trim(), dir.attributes); self.root_dir_cache.push(dir); } } } - // Optimization: Perhaps I can read the files from the root dir, and once I have all the entries abort and mark the rest of the clusters as free?? + // Optimization: Perhaps I can read the files from the root dir, and once I have all the entries abort and mark the rest of the clusters as free + // Tried that, for some reason there were allcoated entries on the FAT that I couldnt understand what allocated them so Ill live it like that for now fn init_fat_table_cache(&mut self){ - let mut fat_buffer = FatBuffer::new(self.get_fat_start_sector() as usize, 0, None, &mut self.disk); + const INIT_FAT_BUFFER_SIZE:usize = FAT_BUFFER_SIZE * 10; + let mut fat_buffer:FatBuffer = FatBuffer::new(self.get_fat_start_sector() as usize, 0, None, &mut self.disk); // The fat has entry per cluster in the volume, were adding 2 for the first 2 reserved entries (0,1) // This way the array is larger by 2 (fat entry at position clusters_count + 1 is the last valid entry) let fat_entries_count = self.clusters_count + 1; - log::debug!("fat entries count {}, root_dir len: {}", fat_entries_count, self.root_dir_cache.len()); + log::debug!("fat entries count {}", fat_entries_count); + + // Since indices [0,1] are resereved ignore and discard them + let _ = fat_buffer.read().ok().unwrap(); + let _ = fat_buffer.read().ok().unwrap(); + + // Index 2 to bootstrap let fat_entry = fat_buffer.read().ok().unwrap(); - let mut current_segment = FatSegment::new(fat_entry, 0); + let mut current_segment = FatSegment::new(fat_entry, 2); - // Since indices [0,1] are resereved ignore and skip them - // the loop starting from 2 is probably a bug / mistake - for i in 2..=fat_entries_count{ + for i in 3..=fat_entries_count{ let fat_entry = fat_buffer.read().unwrap_or_else(|_|{ fat_buffer = FatBuffer::new(self.get_fat_start_sector(), i as usize, None, &mut self.disk); fat_buffer.read().ok().unwrap() @@ -338,11 +341,6 @@ impl Fat32{ } self.fat_table_cache.push(current_segment.clone()); current_segment = FatSegment::new(fat_entry, i); - log::info!("found new segment: {:#?}, start index: {}", current_segment.state, current_segment.start_index); - if self.fat_table_cache.iter().filter(|f|f.state == FatSegmentState::Allocated).count() == self.root_dir_cache.len(){ - current_segment.len = fat_entries_count - i; - break; - } } self.fat_table_cache.push(current_segment); log::debug!("Fat segments count {}", self.fat_table_cache.len()); @@ -385,7 +383,7 @@ impl Fat32{ core::panic!("Error recevied not allocated segment"); } log::warn!("fat entries: {}", fat_first_entry.len); - let mut fat_buffer = FatBuffer::new(self.get_fat_start_sector() as usize, file_entry.first_cluster_index as usize, Some(fat_first_entry.len as usize), &mut self.disk); + let mut fat_buffer:FatBuffer = FatBuffer::new(self.get_fat_start_sector() as usize, file_entry.first_cluster_index as usize, Some(fat_first_entry.len as usize), &mut self.disk); let mut current_cluster = file_entry.first_cluster_index; let mut next_read_cluster = current_cluster; @@ -426,7 +424,7 @@ impl Fat32{ else{ let existing_entry = existing_entry.clone(); // Shadow the original in order to statisify the borrow checker let segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == existing_entry.get_first_cluster_index()).unwrap().clone(); - let mut fat_buffer = FatBuffer::new(self.get_fat_start_sector() as usize, existing_entry.get_first_cluster_index() as usize, Some(segment.len as usize), &mut self.disk); + let mut fat_buffer:FatBuffer = FatBuffer::new(self.get_fat_start_sector() as usize, existing_entry.get_first_cluster_index() as usize, Some(segment.len as usize), &mut self.disk); let mut current_cluster = existing_entry.get_first_cluster_index(); let mut cluster_count = 0; while cluster_count < segment.len{ @@ -460,7 +458,7 @@ impl Fat32{ let free_fat_seqment = self.fat_table_cache.as_slice().into_iter().find(|t|t.state == FatSegmentState::Free && t.len >= required_clusters_count).unwrap(); let first_cluster_index = free_fat_seqment.start_index; new_dir_entry.set_first_cluster_index(first_cluster_index); - let mut fat_buffer = FatBuffer::new(self.get_fat_start_sector(), first_cluster_index as usize, Some(required_clusters_count as usize), &mut self.disk); + let mut fat_buffer:FatBuffer = FatBuffer::new(self.get_fat_start_sector(), first_cluster_index as usize, Some(required_clusters_count as usize), &mut self.disk); // write the data to the clusters, since the cluster index is the initial index in the fat I can know which one is free or allocated From 88db99b7e0a3bf2c9a8436d7c86395bbdad8acdf Mon Sep 17 00:00:00 2001 From: alloncm Date: Sun, 17 Sep 2023 16:12:37 +0300 Subject: [PATCH 09/39] Still trying to implement writing file --- rpi/src/bin/baremetal/main.rs | 5 +- rpi/src/drivers/disk.rs | 4 +- rpi/src/drivers/fat32.rs | 150 ++++++++++++++++++++++++---------- rpi/src/peripherals/emmc.rs | 4 + 4 files changed, 116 insertions(+), 47 deletions(-) diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index 27a19140..577ff1a6 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -29,6 +29,8 @@ pub extern "C" fn main()->!{ let mut power_manager = unsafe{PERIPHERALS.take_power()}; let mut fs = Fat32::new(); + let mut content = b"alon hagever".clone(); + fs.write_file("TEST TXT", &mut content); let mut gfx = Ili9341GfxDevice::new(RESET_PIN_BCM, LED_PIN_BCM, TURBO, FRAME_LIMITER); let mut pause_menu_gfx = gfx.clone(); let mut joypad_provider = GpioJoypadProvider::new(button_to_bcm_pin); @@ -100,8 +102,7 @@ fn read_menu_options(fs: &mut Fat32, menu_options: &mut [MenuOption!{ - log::error!("An error has occoured!"); - log::error!("{}", info); + log::error!("An error has occoured!: \n{}", info); unsafe{boot::hang_led()}; } \ No newline at end of file diff --git a/rpi/src/drivers/disk.rs b/rpi/src/drivers/disk.rs index 92972d10..729964b8 100644 --- a/rpi/src/drivers/disk.rs +++ b/rpi/src/drivers/disk.rs @@ -81,8 +81,8 @@ impl Disk{ fn prepare_for_disk_operation(&mut self, block_index:u32, buffer:&[u8]){ let block_size = self.get_block_size(); - if buffer.len() % block_size as usize != 0{ - core::panic!("buffer size must be a division of block size: {}", block_size); + if buffer.len() % block_size as usize != 0{ + core::panic!("buffer size must be a division of block size: {}, actual buffer_size: {}", block_size, buffer.len()); } self.emmc.seek((block_index * block_size) as u64); } diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index c0061865..e57b704c 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -148,7 +148,7 @@ impl FileEntry{ } } -#[derive(Clone)] +#[derive(Clone, Debug)] struct FatIndex{ sector_number:u32, sector_offset:usize, @@ -156,11 +156,10 @@ struct FatIndex{ impl FatIndex{ fn get_fat_entry(&mut self, buffer:&[u8;FAT_ENTRY_SIZE])->u32{ - u32::from_ne_bytes(*buffer) & FAT_ENTRY_MASK + u32::from_ne_bytes(*buffer) } - fn set_fat_entry(&mut self, entry:u32, buffer:&[u8;FAT_ENTRY_SIZE]){ - let entry = u32::to_ne_bytes(entry); - + fn get_raw_fat_entry(&mut self, entry:u32)->[u8;FAT_ENTRY_SIZE]{ + u32::to_ne_bytes(entry) } } @@ -168,6 +167,7 @@ impl FatIndex{ enum FatSegmentState{ Free, Allocated, + AllocatedEof, Reserved, Bad, } @@ -175,15 +175,16 @@ enum FatSegmentState{ impl From for FatSegmentState{ fn from(value: u32) -> Self { match value{ - 0=>Self::Free, - 2..=0xFFF_FFF5 | 0xFFF_FFFF=>Self::Allocated, - 0xFFF_FFF7=>Self::Bad, - _=>Self::Reserved + 0 => Self::Free, + 2..=0xFFF_FFF5 => Self::Allocated, + 0xFFF_FFFF => Self::AllocatedEof, + 0xFFF_FFF7 => Self::Bad, + _ => Self::Reserved } } } -#[derive(Clone)] +#[derive(Clone, Debug)] struct FatSegment{ state:FatSegmentState, len:u32, @@ -196,19 +197,27 @@ impl FatSegment{ } } +#[derive(Clone, Copy)] +struct FatInfo{ + first_fat_start_sector:usize, + fat_sectors_count:usize, + fats_count:usize +} + struct FatBuffer{ buffer:[u8;FBS], buffer_len: usize, fat_start_index:FatIndex, fat_internal_index:FatIndex, + fat_info:FatInfo, } impl FatBuffer{ - fn new(fat_start_sector:usize, first_cluster_index:usize, entries_count: Option, disk: &mut Disk)->Self{ + fn new(fat_info:FatInfo, first_cluster_index:usize, entries_count: Option, disk: &mut Disk)->Self{ let entries_count = entries_count.unwrap_or((FBS - SECTOR_SIZE) / FAT_ENTRY_SIZE); let mut buffer = [0; FBS]; let fat_offset = first_cluster_index * FAT_ENTRY_SIZE; - let fat_index = FatIndex{ sector_number: (fat_start_sector + fat_offset / SECTOR_SIZE) as u32, sector_offset: fat_offset % SECTOR_SIZE }; + let fat_index = FatIndex{ sector_number: (fat_info.first_fat_start_sector + fat_offset / SECTOR_SIZE) as u32, sector_offset: fat_offset % SECTOR_SIZE }; // Align the end read to SECTOR_SIZE let fat_end_read = (entries_count * FAT_ENTRY_SIZE) + (SECTOR_SIZE - ((entries_count * FAT_ENTRY_SIZE) % SECTOR_SIZE)); @@ -216,24 +225,56 @@ impl FatBuffer{ core::panic!("Error fat entries count is too much: expected:{}, actual: {}", FBS / FAT_ENTRY_SIZE, entries_count); } let _ = disk.read(fat_index.sector_number, &mut buffer[..fat_end_read]); - return Self { buffer, fat_start_index: fat_index.clone(), fat_internal_index: fat_index, buffer_len: fat_end_read }; + return Self { buffer, fat_start_index: fat_index.clone(), fat_internal_index: fat_index, buffer_len: fat_end_read, fat_info }; } /// On sucess returns the FAT entry, on error returns the last valid fat index fn read(&mut self)->Result{ - let interal_sector_index = (self.fat_internal_index.sector_number - self.fat_start_index.sector_number) as usize; - if interal_sector_index * SECTOR_SIZE >= self.buffer_len{ - return Err(self.fat_internal_index.clone()); + let interal_sector_index = self.get_interal_sector_index()?; + let start_index = (interal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; + let end_index = start_index + FAT_ENTRY_SIZE; + let entry = self.fat_internal_index.get_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); + self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; + if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ + self.fat_internal_index.sector_number += 1; + self.fat_internal_index.sector_offset = 0; } + // Mask the entry to hide the reserved bits + return Ok(entry & FAT_ENTRY_MASK); + } + + /// On error retusns the last valid fat index + fn write(&mut self, mut value:u32)->Result<(), FatIndex>{ + let interal_sector_index = self.get_interal_sector_index()?; let start_index = (interal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; let end_index = start_index + FAT_ENTRY_SIZE; let entry = self.fat_internal_index.get_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); + let reserved_bits = entry & (!FAT_ENTRY_MASK); + value = (value & FAT_ENTRY_MASK) | reserved_bits; + self.buffer[start_index .. end_index].copy_from_slice(&self.fat_internal_index.get_raw_fat_entry(value)); self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ self.fat_internal_index.sector_number += 1; self.fat_internal_index.sector_offset = 0; } - return Ok(entry); + return Ok(()); + } + + /// Sync the fat buffer to the disk + fn flush(&mut self, disk:&mut Disk){ + // Sync all the fat sectors to disk + for i in 0..self.fat_info.fats_count{ + let fat_start_sector = self.fat_info.first_fat_start_sector + (self.fat_info.fat_sectors_count * i) + self.get_interal_sector_index().ok().unwrap(); + let _ = disk.write(fat_start_sector as u32, &mut self.buffer[..self.buffer_len]); + } + } + + fn get_interal_sector_index(&self)->Result{ + let interal_sector_index = (self.fat_internal_index.sector_number - self.fat_start_index.sector_number) as usize; + if interal_sector_index * SECTOR_SIZE >= self.buffer_len{ + return Err(self.fat_internal_index.clone()); + } + return Ok(interal_sector_index); } } @@ -249,6 +290,7 @@ pub struct Fat32{ partition_start_sector_index:u32, clusters_count:u32, + fat_info:FatInfo, fat_table_cache: ArrayVec, root_dir_cache: ArrayVec, } @@ -279,8 +321,10 @@ impl Fat32{ let fat32_data_sectors = boot_sector.fat32_bpb.total_sectors_count_32 - (boot_sector.fat32_bpb.reserved_sectors_count as u32 + (boot_sector.fat32_bpb.sectors_per_fat_32 as u32 * boot_sector.fat32_bpb.fats_count as u32)); let clusters_count = fat32_data_sectors / boot_sector.fat32_bpb.sectors_per_cluster as u32; - - let mut fat32 = Self { disk, boot_sector, partition_start_sector_index:bpb_sector_index, clusters_count, + let fat_start_sector = (bpb_sector_index + boot_sector.fat32_bpb.reserved_sectors_count as u32) as usize; + let mut fat32 = Self { + fat_info:FatInfo { first_fat_start_sector: fat_start_sector, fat_sectors_count: boot_sector.fat32_bpb.sectors_per_fat_32 as usize, fats_count: boot_sector.fat32_bpb.fats_count as usize }, + disk, boot_sector, partition_start_sector_index:bpb_sector_index, clusters_count, fat_table_cache: ArrayVec::::new(), root_dir_cache: ArrayVec::::new() }; @@ -298,9 +342,6 @@ impl Fat32{ let buffer = unsafe{as_mut_buffer(&mut root_dir)}; sector_offset += self.disk.read(root_start_sector_index + sector_offset, buffer); for dir in root_dir{ - if dir.file_name[0] == DELETED_DIR_ENTRY_PREFIX { - continue; - } if dir.file_name[0] == DIR_EOF_PREFIX { break 'search; } @@ -313,7 +354,7 @@ impl Fat32{ // Tried that, for some reason there were allcoated entries on the FAT that I couldnt understand what allocated them so Ill live it like that for now fn init_fat_table_cache(&mut self){ const INIT_FAT_BUFFER_SIZE:usize = FAT_BUFFER_SIZE * 10; - let mut fat_buffer:FatBuffer = FatBuffer::new(self.get_fat_start_sector() as usize, 0, None, &mut self.disk); + let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, 0, None, &mut self.disk); // The fat has entry per cluster in the volume, were adding 2 for the first 2 reserved entries (0,1) // This way the array is larger by 2 (fat entry at position clusters_count + 1 is the last valid entry) @@ -330,14 +371,12 @@ impl Fat32{ for i in 3..=fat_entries_count{ let fat_entry = fat_buffer.read().unwrap_or_else(|_|{ - fat_buffer = FatBuffer::new(self.get_fat_start_sector(), i as usize, None, &mut self.disk); + fat_buffer = FatBuffer::new(self.fat_info, i as usize, None, &mut self.disk); fat_buffer.read().ok().unwrap() }); if FatSegmentState::from(fat_entry) == current_segment.state { current_segment.len += 1; - if fat_entry != FAT_ENTRY_EOF_INDEX{ - continue; - } + continue; } self.fat_table_cache.push(current_segment.clone()); current_segment = FatSegment::new(fat_entry, i); @@ -351,6 +390,9 @@ impl Fat32{ let mut discard = offset; for dir in &self.root_dir_cache{ + if dir.file_name[0] == DELETED_DIR_ENTRY_PREFIX{ + continue; + } if dir.attributes == ATTR_LONG_NAME{ continue; // handle long file names here @@ -378,19 +420,19 @@ impl Fat32{ log::debug!("Reading file {}, size {}, cluster: {}", file_entry.get_name(), file_entry.size, file_entry.first_cluster_index); let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster; - let fat_first_entry = self.fat_table_cache.as_slice().into_iter().find(|t|t.start_index == file_entry.first_cluster_index).unwrap().clone(); - if fat_first_entry.state != FatSegmentState::Allocated{ - core::panic!("Error recevied not allocated segment"); + let mut fat_first_entry = self.fat_table_cache.as_slice().into_iter().find(|t|t.start_index == file_entry.first_cluster_index).unwrap().clone(); + match fat_first_entry.state { + FatSegmentState::Allocated => fat_first_entry.len += 1, + FatSegmentState::AllocatedEof => {}, + _ => core::panic!("Error recevied not allocated segment"), } - log::warn!("fat entries: {}", fat_first_entry.len); - let mut fat_buffer:FatBuffer = FatBuffer::new(self.get_fat_start_sector() as usize, file_entry.first_cluster_index as usize, Some(fat_first_entry.len as usize), &mut self.disk); + let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, file_entry.first_cluster_index as usize, Some(fat_first_entry.len as usize), &mut self.disk); let mut current_cluster = file_entry.first_cluster_index; let mut next_read_cluster = current_cluster; let mut clusters_sequence = 1; let mut cluster_counter:usize = 0; while cluster_counter < fat_first_entry.len as usize{ - log::warn!("Cluster index: {}, cluster sequence: {}", cluster_counter, clusters_sequence); let fat_entry = fat_buffer.read().ok().unwrap(); if current_cluster + 1 == fat_entry{ current_cluster = fat_entry; @@ -424,7 +466,7 @@ impl Fat32{ else{ let existing_entry = existing_entry.clone(); // Shadow the original in order to statisify the borrow checker let segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == existing_entry.get_first_cluster_index()).unwrap().clone(); - let mut fat_buffer:FatBuffer = FatBuffer::new(self.get_fat_start_sector() as usize, existing_entry.get_first_cluster_index() as usize, Some(segment.len as usize), &mut self.disk); + let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, existing_entry.get_first_cluster_index() as usize, Some(segment.len as usize), &mut self.disk); let mut current_cluster = existing_entry.get_first_cluster_index(); let mut cluster_count = 0; while cluster_count < segment.len{ @@ -440,7 +482,7 @@ impl Fat32{ } } - // create a new file by allocating place in the root dir and then picking some free fat segment and use it's clusters + // create a new file by allocating place in the root dir and then picking some free fat segment to use it's clusters let new_dir_entry = match self.root_dir_cache.as_mut_slice().into_iter().find(|d|d.file_name[0] == DELETED_DIR_ENTRY_PREFIX){ Some(dir) => dir, None => { @@ -454,16 +496,42 @@ impl Fat32{ self.root_dir_cache.last_mut().unwrap() }, }; - let required_clusters_count = content.len() as u32 / cluster_size; + let required_clusters_count = (content.len() as u32 / cluster_size) + (content.len() as u32 % cluster_size != 0) as u32; let free_fat_seqment = self.fat_table_cache.as_slice().into_iter().find(|t|t.state == FatSegmentState::Free && t.len >= required_clusters_count).unwrap(); let first_cluster_index = free_fat_seqment.start_index; + + // Update the fat and the root directory new_dir_entry.set_first_cluster_index(first_cluster_index); - let mut fat_buffer:FatBuffer = FatBuffer::new(self.get_fat_start_sector(), first_cluster_index as usize, Some(required_clusters_count as usize), &mut self.disk); - + new_dir_entry.size = content.len() as u32; + + let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, first_cluster_index as usize, Some(required_clusters_count as usize), &mut self.disk); + for i in 0..required_clusters_count - 1{ + // Adding 1 in order to point to the next fat entry, since all the cluster are allocated in contiguous disk clusters + fat_buffer.write(first_cluster_index + i + 1).unwrap(); + } + fat_buffer.write(FAT_ENTRY_EOF_INDEX).unwrap(); // write the data to the clusters, since the cluster index is the initial index in the fat I can know which one is free or allocated + let mut chunks = content.chunks_exact_mut(cluster_size as usize); + let mut cluster_index = first_cluster_index; + while let Some(chunk) = chunks.next() { + let start_sector = self.get_cluster_start_sector_index(cluster_index); + let _ = self.disk.write(start_sector, chunk); + cluster_index += 1; + } + let mut reminder_chunks = chunks.into_remainder().chunks_exact_mut(SECTOR_SIZE); + let mut sector_index = self.get_cluster_start_sector_index(cluster_index); + while let Some(chunk) = reminder_chunks.next() { + self.disk.write(sector_index, chunk); + sector_index += 1; + } + let reminder_chunk = reminder_chunks.into_remainder(); + let mut buffer = [0;SECTOR_SIZE]; + buffer[..reminder_chunk.len()].copy_from_slice(reminder_chunk); + self.disk.write(sector_index, &mut buffer); - // sync the root dir modifications + // sync the modifications + fat_buffer.flush(&mut self.disk); self.write_root_dir_cache(); } @@ -494,10 +562,6 @@ impl Fat32{ buffer[..reminder.len()].copy_from_slice(reminder); } - fn get_fat_start_sector(&self) -> usize { - (self.partition_start_sector_index + self.boot_sector.fat32_bpb.reserved_sectors_count as u32) as usize - } - fn get_cluster_start_sector_index(&self, cluster:u32)->u32{ const FIRST_DATA_CLUSTER:u32 = 2; diff --git a/rpi/src/peripherals/emmc.rs b/rpi/src/peripherals/emmc.rs index 5f01769e..f7d56640 100644 --- a/rpi/src/peripherals/emmc.rs +++ b/rpi/src/peripherals/emmc.rs @@ -100,6 +100,7 @@ struct SdCommand{ impl SdCommand{ fn get_command(self)->u32{ + // Reverting the app_command bit in case it will distrrupt with the emmc device self.with_app_command(false).0 } } @@ -117,6 +118,9 @@ const fn resolve_command(command_type:SdCommandType)->SdCommand{ SdCommandType::ReadBlock => command.with_direction(true).with_response_type(CommandResponseType::B48).with_crc_enable(true).with_is_data(true), SdCommandType::ReadMultiple => command.with_block_count(true).with_auto_command(1).with_direction(true).with_multiblock(true) .with_response_type(CommandResponseType::B48).with_crc_enable(true).with_is_data(true), + SdCommandType::WriteBlock => command.with_direction(false).with_response_type(CommandResponseType::B48).with_crc_enable(true).with_is_data(true), + SdCommandType::WriteMultiple => command.with_block_count(true).with_auto_command(1).with_direction(false).with_multiblock(true) + .with_response_type(CommandResponseType::B48).with_crc_enable(true).with_is_data(true), SdCommandType::OcrCheck => command.with_response_type(CommandResponseType::B48).with_app_command(true), SdCommandType::SendScr => command.with_direction(true).with_response_type(CommandResponseType::B48).with_crc_enable(true).with_is_data(true).with_app_command(true), SdCommandType::App => command.with_response_type(CommandResponseType::B48).with_crc_enable(true), From 8d81449aa3a6ddda147d869e0321e1b77b2bcf9a Mon Sep 17 00:00:00 2001 From: alloncm Date: Sun, 17 Sep 2023 23:48:33 +0300 Subject: [PATCH 10/39] WIP writing files The file apears in root dir but is corrupted (at least in windows) --- rpi/src/bin/baremetal/main.rs | 2 +- rpi/src/drivers/fat32.rs | 89 +++++++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index 577ff1a6..d4560faf 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -102,7 +102,7 @@ fn read_menu_options(fs: &mut Fat32, menu_options: &mut [MenuOption!{ - log::error!("An error has occoured!: \n{}", info); + log::error!("An error has occoured!: \r\n{}", info); unsafe{boot::hang_led()}; } \ No newline at end of file diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index e57b704c..ecfebb2c 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -80,10 +80,10 @@ compile_time_size_assert!(FatShortDirEntry, 32); impl FatShortDirEntry{ fn new(name:[u8;8], extension:[u8;3], size:u32)->Self{ - return Self { + Self { file_name: name, file_extension: extension, attributes: 0, nt_reserve: 0, creation_time_tenth_secs: 0, creation_time: 0, creation_date: 0, last_access_date: 0, first_cluster_index_high:0, last_write_time: 0, last_write_date: 0, first_cluster_index_low:0, size - }; + } } fn get_first_cluster_index(&self)->u32{ self.first_cluster_index_low as u32 | ((self.first_cluster_index_high as u32) << 16) @@ -184,6 +184,18 @@ impl From for FatSegmentState{ } } +impl FatSegmentState{ + /// Checks whether a value should be part of this segment or not + fn should_continue_segment(&self, other: &Self)->bool{ + // AllocatedEof is should never continue segment + // otherwise fallback to check raw values of the enum + if *self as isize == Self::AllocatedEof as isize || *other as isize == Self::AllocatedEof as isize{ + return false; + } + return self == other; + } +} + #[derive(Clone, Debug)] struct FatSegment{ state:FatSegmentState, @@ -200,7 +212,7 @@ impl FatSegment{ #[derive(Clone, Copy)] struct FatInfo{ first_fat_start_sector:usize, - fat_sectors_count:usize, + sectors_per_fat:usize, fats_count:usize } @@ -257,16 +269,17 @@ impl FatBuffer{ self.fat_internal_index.sector_number += 1; self.fat_internal_index.sector_offset = 0; } + log::debug!("FAT buffer write, start_index: {:?}, buffer_start: {}, value: {}", self.fat_start_index, start_index, value); return Ok(()); } /// Sync the fat buffer to the disk fn flush(&mut self, disk:&mut Disk){ // Sync all the fat sectors to disk - for i in 0..self.fat_info.fats_count{ - let fat_start_sector = self.fat_info.first_fat_start_sector + (self.fat_info.fat_sectors_count * i) + self.get_interal_sector_index().ok().unwrap(); - let _ = disk.write(fat_start_sector as u32, &mut self.buffer[..self.buffer_len]); - } + // for i in 0..self.fat_info.fats_count{ + // let fat_start_sector = self.fat_info.first_fat_start_sector + self.get_interal_sector_index().ok().unwrap() /*+ (self.fat_info.sectors_per_fat * i)*/; + let _ = disk.write(self.fat_start_index.sector_number, &mut self.buffer[..self.buffer_len]); + // } } fn get_interal_sector_index(&self)->Result{ @@ -323,7 +336,7 @@ impl Fat32{ let clusters_count = fat32_data_sectors / boot_sector.fat32_bpb.sectors_per_cluster as u32; let fat_start_sector = (bpb_sector_index + boot_sector.fat32_bpb.reserved_sectors_count as u32) as usize; let mut fat32 = Self { - fat_info:FatInfo { first_fat_start_sector: fat_start_sector, fat_sectors_count: boot_sector.fat32_bpb.sectors_per_fat_32 as usize, fats_count: boot_sector.fat32_bpb.fats_count as usize }, + fat_info:FatInfo { first_fat_start_sector: fat_start_sector, sectors_per_fat: boot_sector.fat32_bpb.sectors_per_fat_32 as usize, fats_count: boot_sector.fat32_bpb.fats_count as usize }, disk, boot_sector, partition_start_sector_index:bpb_sector_index, clusters_count, fat_table_cache: ArrayVec::::new(), root_dir_cache: ArrayVec::::new() @@ -342,10 +355,11 @@ impl Fat32{ let buffer = unsafe{as_mut_buffer(&mut root_dir)}; sector_offset += self.disk.read(root_start_sector_index + sector_offset, buffer); for dir in root_dir{ + // Pusing also the DIR_EOF in order to support syncing the whole dir easily + self.root_dir_cache.push(dir); if dir.file_name[0] == DIR_EOF_PREFIX { break 'search; } - self.root_dir_cache.push(dir); } } } @@ -374,7 +388,7 @@ impl Fat32{ fat_buffer = FatBuffer::new(self.fat_info, i as usize, None, &mut self.disk); fat_buffer.read().ok().unwrap() }); - if FatSegmentState::from(fat_entry) == current_segment.state { + if current_segment.state.should_continue_segment(&FatSegmentState::from(fat_entry)) { current_segment.len += 1; continue; } @@ -389,7 +403,10 @@ impl Fat32{ let mut output_dir = ArrayVec::::new(); let mut discard = offset; - for dir in &self.root_dir_cache{ + for dir in &self.root_dir_cache { + if dir.file_name[0] == DIR_EOF_PREFIX{ + break; + } if dir.file_name[0] == DELETED_DIR_ENTRY_PREFIX{ continue; } @@ -454,6 +471,10 @@ impl Fat32{ /// Write a file to the root dir pub fn write_file(&mut self, filename:&str, content:&mut [u8]){ + log::debug!("Writing file: {}, size: {}", filename, content.len()); + for fat in &self.fat_table_cache{ + log::warn!("fat cache entry: {:?}", fat); + } let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster as u32; let cluster_size = sectors_per_cluster * SECTOR_SIZE as u32; let (name, extension) = self.create_filename(filename).unwrap_or_else(|_|core::panic!("File name format is bad: {}", filename)); @@ -465,7 +486,13 @@ impl Fat32{ } else{ let existing_entry = existing_entry.clone(); // Shadow the original in order to statisify the borrow checker - let segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == existing_entry.get_first_cluster_index()).unwrap().clone(); + log::warn!("Looking for cluster index: {}", existing_entry.get_first_cluster_index()); + let mut segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == existing_entry.get_first_cluster_index()).unwrap().clone(); + match segment.state { + FatSegmentState::Allocated => segment.len += 1, + FatSegmentState::AllocatedEof => {}, + _ => core::panic!("Error recevied not allocated segment"), + } let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, existing_entry.get_first_cluster_index() as usize, Some(segment.len as usize), &mut self.disk); let mut current_cluster = existing_entry.get_first_cluster_index(); let mut cluster_count = 0; @@ -484,7 +511,11 @@ impl Fat32{ // create a new file by allocating place in the root dir and then picking some free fat segment to use it's clusters let new_dir_entry = match self.root_dir_cache.as_mut_slice().into_iter().find(|d|d.file_name[0] == DELETED_DIR_ENTRY_PREFIX){ - Some(dir) => dir, + Some(dir) => { + dir.file_name = name; + dir.file_extension = extension; + dir + } None => { // Check the root dir allocation size to check it needs to be reallocated let root_dir_entry = self.root_dir_cache.as_slice().into_iter().find(|d|d.attributes == ATTR_VOLUME_ID).unwrap(); @@ -492,19 +523,20 @@ impl Fat32{ core::panic!("driver do not support resizing of the root dir"); } // Allocate new entry in the root dir - self.root_dir_cache.push(FatShortDirEntry::new(name, extension, content.len() as u32)); + self.root_dir_cache.insert(self.root_dir_cache.len() - 1, FatShortDirEntry::new(name, extension, content.len() as u32)); // write to the last place pusing the last item to index len(), in order to keep the DIR_EOF last self.root_dir_cache.last_mut().unwrap() }, }; let required_clusters_count = (content.len() as u32 / cluster_size) + (content.len() as u32 % cluster_size != 0) as u32; - let free_fat_seqment = self.fat_table_cache.as_slice().into_iter().find(|t|t.state == FatSegmentState::Free && t.len >= required_clusters_count).unwrap(); + let free_fat_seqment = self.fat_table_cache.as_slice().into_iter().find(|t|t.state == FatSegmentState::Free && t.len >= required_clusters_count).unwrap(); let first_cluster_index = free_fat_seqment.start_index; // Update the fat and the root directory + log::debug!("File first cluster index: {}", first_cluster_index); new_dir_entry.set_first_cluster_index(first_cluster_index); new_dir_entry.size = content.len() as u32; - let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, first_cluster_index as usize, Some(required_clusters_count as usize), &mut self.disk); + let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, first_cluster_index as usize, Some(required_clusters_count as usize), &mut self.disk); for i in 0..required_clusters_count - 1{ // Adding 1 in order to point to the next fat entry, since all the cluster are allocated in contiguous disk clusters fat_buffer.write(first_cluster_index + i + 1).unwrap(); @@ -512,6 +544,14 @@ impl Fat32{ fat_buffer.write(FAT_ENTRY_EOF_INDEX).unwrap(); // write the data to the clusters, since the cluster index is the initial index in the fat I can know which one is free or allocated + self.write_to_data_section(content, cluster_size, first_cluster_index); + + // sync the modifications + fat_buffer.flush(&mut self.disk); + self.write_root_dir_cache(); + } + + fn write_to_data_section(&mut self, content: &mut [u8], cluster_size: u32, first_cluster_index: u32) { let mut chunks = content.chunks_exact_mut(cluster_size as usize); let mut cluster_index = first_cluster_index; while let Some(chunk) = chunks.next() { @@ -522,17 +562,12 @@ impl Fat32{ let mut reminder_chunks = chunks.into_remainder().chunks_exact_mut(SECTOR_SIZE); let mut sector_index = self.get_cluster_start_sector_index(cluster_index); while let Some(chunk) = reminder_chunks.next() { - self.disk.write(sector_index, chunk); - sector_index += 1; + sector_index += self.disk.write(sector_index, chunk); } let reminder_chunk = reminder_chunks.into_remainder(); let mut buffer = [0;SECTOR_SIZE]; buffer[..reminder_chunk.len()].copy_from_slice(reminder_chunk); - self.disk.write(sector_index, &mut buffer); - - // sync the modifications - fat_buffer.flush(&mut self.disk); - self.write_root_dir_cache(); + let _ = self.disk.write(sector_index, &mut buffer); } fn create_filename(&self, filename:&str)->Result<([u8;8],[u8;3]), ()>{ @@ -550,16 +585,18 @@ impl Fat32{ } fn write_root_dir_cache(&mut self){ - let chunks = self.root_dir_cache.chunks_exact(FAT_DIR_ENTRIES_PER_SECTOR); let mut root_sector_index = self.get_cluster_start_sector_index(self.boot_sector.fat32_bpb.root_dir_first_cluster); - let reminder = chunks.remainder(); + let mut chunks = self.root_dir_cache.chunks_exact_mut(FAT_DIR_ENTRIES_PER_SECTOR); let mut buffer = [FatShortDirEntry::default(); FAT_DIR_ENTRIES_PER_SECTOR]; - for chunk in chunks{ + while let Some(chunk) = chunks.next(){ buffer.copy_from_slice(chunk); let mut buffer = unsafe{as_mut_buffer(&mut buffer)}; root_sector_index += self.disk.write(root_sector_index, &mut buffer); } + let reminder = chunks.into_remainder(); buffer[..reminder.len()].copy_from_slice(reminder); + let buffer = unsafe{as_mut_buffer(&mut buffer)}; + self.disk.write(root_sector_index, buffer); } fn get_cluster_start_sector_index(&self, cluster:u32)->u32{ From eef0b3fc159690e2b64a399ca379f80646e69607 Mon Sep 17 00:00:00 2001 From: alloncm Date: Sun, 24 Sep 2023 12:52:52 +0300 Subject: [PATCH 11/39] WIP - Still debugging --- rpi/src/bin/baremetal/main.rs | 6 ++++++ rpi/src/drivers/fat32.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index d4560faf..8b21cc50 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -31,6 +31,12 @@ pub extern "C" fn main()->!{ let mut fs = Fat32::new(); let mut content = b"alon hagever".clone(); fs.write_file("TEST TXT", &mut content); + // let file_entry = fs.root_dir_list::<20>(0).into_iter().find(|f|f.get_name() == "TEST TXT").unwrap(); + // let mut buffer = [0;512]; + // fs.read_file(&file_entry, &mut buffer); + // for i in buffer{ + // log::warn!("{:#X}", i); + // } let mut gfx = Ili9341GfxDevice::new(RESET_PIN_BCM, LED_PIN_BCM, TURBO, FRAME_LIMITER); let mut pause_menu_gfx = gfx.clone(); let mut joypad_provider = GpioJoypadProvider::new(button_to_bcm_pin); diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index ecfebb2c..83f9603e 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -90,7 +90,7 @@ impl FatShortDirEntry{ } fn set_first_cluster_index(&mut self, first_cluster_index:u32){ self.first_cluster_index_low = (first_cluster_index & 0xFFFF) as u16; - self.first_cluster_index_high = (first_cluster_index << 16) as u16; + self.first_cluster_index_high = (first_cluster_index >> 16) as u16; } fn get_filename(&self)->[u8;11]{ let mut filename:[u8;11] = [0;11]; From 2ec9255a28fdfd7deaaded8185801f4daa9818e0 Mon Sep 17 00:00:00 2001 From: alloncm Date: Sun, 24 Sep 2023 14:10:20 +0300 Subject: [PATCH 12/39] Writing and reading a file now working still need to update the backup FAT table --- rpi/src/bin/baremetal/main.rs | 2 +- rpi/src/drivers/fat32.rs | 31 +++++++++++++++++-------------- rpi/src/peripherals/emmc.rs | 3 +-- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index 8b21cc50..c34cf82f 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -35,7 +35,7 @@ pub extern "C" fn main()->!{ // let mut buffer = [0;512]; // fs.read_file(&file_entry, &mut buffer); // for i in buffer{ - // log::warn!("{:#X}", i); + // log::warn!("{}", i as char); // } let mut gfx = Ili9341GfxDevice::new(RESET_PIN_BCM, LED_PIN_BCM, TURBO, FRAME_LIMITER); let mut pause_menu_gfx = gfx.clone(); diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index 83f9603e..f2b0a291 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -306,6 +306,7 @@ pub struct Fat32{ fat_info:FatInfo, fat_table_cache: ArrayVec, root_dir_cache: ArrayVec, + root_dir_allocated_clusters_count: u32, } impl Fat32{ @@ -339,7 +340,8 @@ impl Fat32{ fat_info:FatInfo { first_fat_start_sector: fat_start_sector, sectors_per_fat: boot_sector.fat32_bpb.sectors_per_fat_32 as usize, fats_count: boot_sector.fat32_bpb.fats_count as usize }, disk, boot_sector, partition_start_sector_index:bpb_sector_index, clusters_count, fat_table_cache: ArrayVec::::new(), - root_dir_cache: ArrayVec::::new() + root_dir_cache: ArrayVec::::new(), + root_dir_allocated_clusters_count: 0 }; fat32.init_root_directory_cache(); fat32.init_fat_table_cache(); @@ -362,6 +364,9 @@ impl Fat32{ } } } + let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster as u32; + self.root_dir_allocated_clusters_count = sector_offset / sectors_per_cluster + ((sector_offset % sectors_per_cluster) != 0) as u32; + log::debug!("Root dir allocated clusters count: {}", self.root_dir_allocated_clusters_count); } // Optimization: Perhaps I can read the files from the root dir, and once I have all the entries abort and mark the rest of the clusters as free @@ -458,7 +463,7 @@ impl Fat32{ } let start_sector = self.get_cluster_start_sector_index(next_read_cluster); let start_index = sectors_per_cluster as usize * cluster_counter * SECTOR_SIZE as usize; - let end_index = start_index + (sectors_per_cluster as usize * SECTOR_SIZE as usize * clusters_sequence); + let end_index = core::cmp::min(output.len(), start_index + (sectors_per_cluster as usize * SECTOR_SIZE as usize * clusters_sequence)); let _ = self.disk.read(start_sector, &mut output[start_index..end_index]); next_read_cluster = fat_entry; @@ -472,9 +477,6 @@ impl Fat32{ /// Write a file to the root dir pub fn write_file(&mut self, filename:&str, content:&mut [u8]){ log::debug!("Writing file: {}, size: {}", filename, content.len()); - for fat in &self.fat_table_cache{ - log::warn!("fat cache entry: {:?}", fat); - } let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster as u32; let cluster_size = sectors_per_cluster * SECTOR_SIZE as u32; let (name, extension) = self.create_filename(filename).unwrap_or_else(|_|core::panic!("File name format is bad: {}", filename)); @@ -486,7 +488,6 @@ impl Fat32{ } else{ let existing_entry = existing_entry.clone(); // Shadow the original in order to statisify the borrow checker - log::warn!("Looking for cluster index: {}", existing_entry.get_first_cluster_index()); let mut segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == existing_entry.get_first_cluster_index()).unwrap().clone(); match segment.state { FatSegmentState::Allocated => segment.len += 1, @@ -497,10 +498,7 @@ impl Fat32{ let mut current_cluster = existing_entry.get_first_cluster_index(); let mut cluster_count = 0; while cluster_count < segment.len{ - let start_sector = self.get_cluster_start_sector_index(current_cluster); - let start_index = (sectors_per_cluster * cluster_count) as usize * SECTOR_SIZE; - let end_index = start_index + (sectors_per_cluster * SECTOR_SIZE as u32) as usize; - let _ = self.disk.write(start_sector, &mut content[start_index..end_index]); + self.write_to_data_section(content, cluster_size, current_cluster); current_cluster = fat_buffer.read().ok().unwrap(); cluster_count += 1; @@ -518,13 +516,18 @@ impl Fat32{ } None => { // Check the root dir allocation size to check it needs to be reallocated - let root_dir_entry = self.root_dir_cache.as_slice().into_iter().find(|d|d.attributes == ATTR_VOLUME_ID).unwrap(); - if root_dir_entry.size as usize >= self.root_dir_cache.len() * size_of::() { - core::panic!("driver do not support resizing of the root dir"); + let root_dir_allocation_size = (self.root_dir_allocated_clusters_count * self.boot_sector.fat32_bpb.sectors_per_cluster as u32) as usize * SECTOR_SIZE; + let expected_root_dir_size_after_allocation = (self.root_dir_cache.len() + 1) * size_of::(); + if root_dir_allocation_size <= expected_root_dir_size_after_allocation { + core::panic!("root dir is too small: {:#X} and driver do not support resizing of the root dir", root_dir_allocation_size); } // Allocate new entry in the root dir self.root_dir_cache.insert(self.root_dir_cache.len() - 1, FatShortDirEntry::new(name, extension, content.len() as u32)); // write to the last place pusing the last item to index len(), in order to keep the DIR_EOF last - self.root_dir_cache.last_mut().unwrap() + let root_dir_cache_updated_len = self.root_dir_cache.len(); + + // Root dir cache len must be atleast 2 (entry for the root dir itself and a EOF) and not the one I inserted (so actually 3) + // This retuns the last non EOF entry + &mut self.root_dir_cache[root_dir_cache_updated_len - 2] }, }; let required_clusters_count = (content.len() as u32 / cluster_size) + (content.len() as u32 % cluster_size != 0) as u32; diff --git a/rpi/src/peripherals/emmc.rs b/rpi/src/peripherals/emmc.rs index f7d56640..8c48fc68 100644 --- a/rpi/src/peripherals/emmc.rs +++ b/rpi/src/peripherals/emmc.rs @@ -123,8 +123,7 @@ const fn resolve_command(command_type:SdCommandType)->SdCommand{ .with_response_type(CommandResponseType::B48).with_crc_enable(true).with_is_data(true), SdCommandType::OcrCheck => command.with_response_type(CommandResponseType::B48).with_app_command(true), SdCommandType::SendScr => command.with_direction(true).with_response_type(CommandResponseType::B48).with_crc_enable(true).with_is_data(true).with_app_command(true), - SdCommandType::App => command.with_response_type(CommandResponseType::B48).with_crc_enable(true), - _=> unreachable!() + SdCommandType::App => command.with_response_type(CommandResponseType::B48).with_crc_enable(true) }; } From 3a42a10f1d584171b7045b3f422015a514563fad Mon Sep 17 00:00:00 2001 From: alloncm Date: Sun, 24 Sep 2023 14:21:10 +0300 Subject: [PATCH 13/39] Finish syncing all the other fats --- rpi/src/drivers/fat32.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index f2b0a291..0119742b 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -276,10 +276,11 @@ impl FatBuffer{ /// Sync the fat buffer to the disk fn flush(&mut self, disk:&mut Disk){ // Sync all the fat sectors to disk - // for i in 0..self.fat_info.fats_count{ + for i in 0..self.fat_info.fats_count{ // let fat_start_sector = self.fat_info.first_fat_start_sector + self.get_interal_sector_index().ok().unwrap() /*+ (self.fat_info.sectors_per_fat * i)*/; - let _ = disk.write(self.fat_start_index.sector_number, &mut self.buffer[..self.buffer_len]); - // } + let start_sector = self.fat_start_index.sector_number + (self.fat_info.sectors_per_fat * i) as u32; + let _ = disk.write(start_sector, &mut self.buffer[..self.buffer_len]); + } } fn get_interal_sector_index(&self)->Result{ From 809dc977b51a32c1a594a39073563cc4a8f97ef4 Mon Sep 17 00:00:00 2001 From: alloncm Date: Sun, 24 Sep 2023 15:10:11 +0300 Subject: [PATCH 14/39] Trying to implement savefiles for rpibm --- core/src/mmu/carts/mod.rs | 6 ++--- rpi/src/bin/baremetal/main.rs | 51 +++++++++++++++++++++++++---------- rpi/src/peripherals/emmc.rs | 2 +- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/core/src/mmu/carts/mod.rs b/core/src/mmu/carts/mod.rs index 3e3ea5e9..88898752 100644 --- a/core/src/mmu/carts/mod.rs +++ b/core/src/mmu/carts/mod.rs @@ -17,11 +17,11 @@ pub const MBC_RAM_SIZE_LOCATION:usize = 0x149; pub fn get_ram_size(ram_size_register:u8)->usize{ match ram_size_register{ 0x0=>0, - 0x1=>0x800, + 0x1=>0x800, // Unofficial - Undefined according to official docs 0x2=>0x4000, 0x3=>0x8000, - 0x4=>0x20000, - 0x5=>0x10000, + 0x4=>0x2_0000, + 0x5=>0x1_0000, _=>core::panic!("invalid ram size register {:#X}", ram_size_register) } } diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index c34cf82f..78f841c0 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -10,11 +10,20 @@ use magenboy_common::{joypad_menu::{joypad_gfx_menu::{self, GfxDeviceMenuRendere use magenboy_core::{machine::{gameboy::GameBoy, mbc_initializer::initialize_mbc}, mmu::external_memory_bus::Bootrom, utils::stack_string::StackString}; use magenboy_rpi::{drivers::*, peripherals::{PERIPHERALS, GpioPull}, configuration::{display::*, joypad::button_to_bcm_pin, emulation::*}, MENU_PIN_BCM, delay}; +#[panic_handler] +fn panic(info:&PanicInfo)->!{ + log::error!("An error has occoured!: \r\n{}", info); + + unsafe{boot::hang_led()}; +} + const MAX_ROM_SIZE:usize = 0x80_0000; // 8 MiB, Max size of MBC5 rom +const MAX_RAM_SIZE:usize = 0x2_0000; // 128 KiB // Allocating as static buffer (on the .bss) because it is a very large buffer and // I dont want to cause problems in stack making it overflow and shit (I can increase it when needed but I afraid Id forget) static mut ROM_BUFFER:[u8; MAX_ROM_SIZE] = [0;MAX_ROM_SIZE]; +static mut RAM_BUFFER:[u8; MAX_RAM_SIZE] = [0;MAX_RAM_SIZE]; // This function is no regular main. // It will not return and will be jumped to from the _start proc in the boot code @@ -29,14 +38,6 @@ pub extern "C" fn main()->!{ let mut power_manager = unsafe{PERIPHERALS.take_power()}; let mut fs = Fat32::new(); - let mut content = b"alon hagever".clone(); - fs.write_file("TEST TXT", &mut content); - // let file_entry = fs.root_dir_list::<20>(0).into_iter().find(|f|f.get_name() == "TEST TXT").unwrap(); - // let mut buffer = [0;512]; - // fs.read_file(&file_entry, &mut buffer); - // for i in buffer{ - // log::warn!("{}", i as char); - // } let mut gfx = Ili9341GfxDevice::new(RESET_PIN_BCM, LED_PIN_BCM, TURBO, FRAME_LIMITER); let mut pause_menu_gfx = gfx.clone(); let mut joypad_provider = GpioJoypadProvider::new(button_to_bcm_pin); @@ -54,7 +55,8 @@ pub extern "C" fn main()->!{ let rom = unsafe{&mut ROM_BUFFER}; fs.read_file(selected_rom, rom); - let mbc = initialize_mbc(&rom[0..selected_rom.size as usize], None, None); + let save_data = try_read_save_file(selected_rom, fs); + let mbc = initialize_mbc(&rom[0..selected_rom.size as usize], save_data, None); let mut gameboy = GameBoy::new(mbc, joypad_provider, magenboy_rpi::BlankAudioDevice, gfx, Bootrom::None, None); log::info!("Initialized gameboy!"); @@ -84,6 +86,15 @@ pub extern "C" fn main()->!{ } } +fn try_read_save_file(selected_rom: &FileEntry, mut fs: Fat32) -> Option<&[u8]> { + let save_filename: StackString<11> = StackString::from_args(format_args!("{}SAV",&selected_rom.get_name()[..8])); + let file = search_file(&mut fs, save_filename.as_str())?; + let ram = unsafe{&mut RAM_BUFFER}; + fs.read_file(&file, ram); + log::info!("Found save file for selected rom: {}", file.get_name()); + return Some(ram); +} + fn read_menu_options(fs: &mut Fat32, menu_options: &mut [MenuOption>; 255]) -> usize { let mut menu_options_size = 0; let mut root_dir_offset = 0; @@ -98,6 +109,7 @@ fn read_menu_options(fs: &mut Fat32, menu_options: &mut [MenuOption!{ - log::error!("An error has occoured!: \r\n{}", info); - - unsafe{boot::hang_led()}; +fn search_file(fs:&mut Fat32, filename: &str)->Option{ + let mut menu_options_size = 0; + let mut root_dir_offset = 0; + const FILES_PER_LIST:usize = 20; + loop{ + let dir_entries = fs.root_dir_list::(root_dir_offset); + for entry in &dir_entries{ + if entry.get_name() == filename{ + return Some(entry.clone()); + } + } + if dir_entries.remaining_capacity() != 0{ + return None; + } + root_dir_offset += FILES_PER_LIST; + } } \ No newline at end of file diff --git a/rpi/src/peripherals/emmc.rs b/rpi/src/peripherals/emmc.rs index 8c48fc68..bd6b7f7d 100644 --- a/rpi/src/peripherals/emmc.rs +++ b/rpi/src/peripherals/emmc.rs @@ -100,7 +100,7 @@ struct SdCommand{ impl SdCommand{ fn get_command(self)->u32{ - // Reverting the app_command bit in case it will distrrupt with the emmc device + // Reverting the app_command bit in case it will disrupt with the emmc device self.with_app_command(false).0 } } From 111f63b3693bce6422f2993ee6545da78ec6a488 Mon Sep 17 00:00:00 2001 From: alloncm Date: Tue, 26 Sep 2023 01:43:05 +0300 Subject: [PATCH 15/39] Add the support for saves on baremetal --- Cargo.toml | 5 ++++- rpi/src/bin/baremetal/link.ld | 2 +- rpi/src/bin/baremetal/main.rs | 39 +++++++++++++++++++++-------------- rpi/src/drivers/disk.rs | 2 +- rpi/src/drivers/fat32.rs | 23 ++++++++++----------- rpi/src/peripherals/emmc.rs | 34 ++++++++++++++++++++++-------- rpi/src/peripherals/power.rs | 6 +++++- 7 files changed, 71 insertions(+), 40 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54dff7b8..34703cc3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,7 @@ members = [ [workspace.package] version = "4.0.0" authors = ["alloncm "] -rust-version = "1.70" # cause of once cell \ No newline at end of file +rust-version = "1.70" # cause of once cell + +[profile.release] +lto = true # Samller binaries and faster code \ No newline at end of file diff --git a/rpi/src/bin/baremetal/link.ld b/rpi/src/bin/baremetal/link.ld index 5208ab85..8e96c63b 100644 --- a/rpi/src/bin/baremetal/link.ld +++ b/rpi/src/bin/baremetal/link.ld @@ -1,7 +1,7 @@ /* Place _start procedure at the entry address for RPI */ __rpi_32_phys_binary_load_addr = 0x8000; __isr_table_addr = 0; -__stack_size = 0x200000; /* 2MB stack */ +__stack_size = 0x300000; /* 3MB stack */ ENTRY(__rpi_32_phys_binary_load_addr) /* enry point */ SECTIONS diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index 78f841c0..1d4c8c27 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -7,8 +7,8 @@ mod logging; use core::panic::PanicInfo; use magenboy_common::{joypad_menu::{joypad_gfx_menu::{self, GfxDeviceMenuRenderer}, JoypadMenu, }, menu::*, VERSION}; -use magenboy_core::{machine::{gameboy::GameBoy, mbc_initializer::initialize_mbc}, mmu::external_memory_bus::Bootrom, utils::stack_string::StackString}; -use magenboy_rpi::{drivers::*, peripherals::{PERIPHERALS, GpioPull}, configuration::{display::*, joypad::button_to_bcm_pin, emulation::*}, MENU_PIN_BCM, delay}; +use magenboy_core::{machine::{gameboy::GameBoy, mbc_initializer::initialize_mbc}, mmu::{external_memory_bus::Bootrom, carts::Mbc}, utils::stack_string::StackString}; +use magenboy_rpi::{drivers::*, peripherals::{PERIPHERALS, GpioPull, ResetMode, Power}, configuration::{display::*, joypad::button_to_bcm_pin, emulation::*}, MENU_PIN_BCM, delay}; #[panic_handler] fn panic(info:&PanicInfo)->!{ @@ -35,9 +35,9 @@ pub extern "C" fn main()->!{ log::info!("Initialized logger"); log::info!("running at exec mode: {:#X}", boot::get_cpu_execution_mode()); - let mut power_manager = unsafe{PERIPHERALS.take_power()}; + let power_manager = unsafe{PERIPHERALS.take_power()}; - let mut fs = Fat32::new(); + let mut fs = Fat32Fs::new(); let mut gfx = Ili9341GfxDevice::new(RESET_PIN_BCM, LED_PIN_BCM, TURBO, FRAME_LIMITER); let mut pause_menu_gfx = gfx.clone(); let mut joypad_provider = GpioJoypadProvider::new(button_to_bcm_pin); @@ -55,7 +55,7 @@ pub extern "C" fn main()->!{ let rom = unsafe{&mut ROM_BUFFER}; fs.read_file(selected_rom, rom); - let save_data = try_read_save_file(selected_rom, fs); + let save_data = try_read_save_file(selected_rom, &mut fs); let mbc = initialize_mbc(&rom[0..selected_rom.size as usize], save_data, None); let mut gameboy = GameBoy::new(mbc, joypad_provider, magenboy_rpi::BlankAudioDevice, gfx, Bootrom::None, None); @@ -72,13 +72,11 @@ pub extern "C" fn main()->!{ EmulatorMenuOption::Resume => {}, EmulatorMenuOption::Restart => { log::info!("Reseting system"); - delay::wait_ms(100); - power_manager.reset(magenboy_rpi::peripherals::ResetMode::Partition0) + reset_system(mbc, fs, power_manager, ResetMode::Partition0, selected_rom); } EmulatorMenuOption::Shutdown => { log::info!("Shuting down system"); - delay::wait_ms(100); - power_manager.reset(magenboy_rpi::peripherals::ResetMode::Halt) + reset_system(mbc, fs, power_manager, ResetMode::Halt, selected_rom); } } } @@ -86,16 +84,28 @@ pub extern "C" fn main()->!{ } } -fn try_read_save_file(selected_rom: &FileEntry, mut fs: Fat32) -> Option<&[u8]> { - let save_filename: StackString<11> = StackString::from_args(format_args!("{}SAV",&selected_rom.get_name()[..8])); +fn reset_system<'a>(mbc: &'a dyn Mbc, mut fs: Fat32Fs, mut power_manager: Power, mode: ResetMode, selected_rom: &FileEntry)->!{ + let filename = get_save_filename(selected_rom); + fs.write_file(filename.as_str(), mbc.get_ram()); + + delay::wait_ms(100); + power_manager.reset(mode); +} + +fn try_read_save_file(selected_rom: &FileEntry, mut fs: &mut Fat32Fs) -> Option<&'static [u8]> { + let save_filename = get_save_filename(selected_rom); let file = search_file(&mut fs, save_filename.as_str())?; - let ram = unsafe{&mut RAM_BUFFER}; + let ram = unsafe{&mut RAM_BUFFER[0..file.size as usize]}; fs.read_file(&file, ram); log::info!("Found save file for selected rom: {}", file.get_name()); return Some(ram); } -fn read_menu_options(fs: &mut Fat32, menu_options: &mut [MenuOption>; 255]) -> usize { +fn get_save_filename(selected_rom: &FileEntry) -> StackString<11> { + StackString::from_args(format_args!("{}SAV",&selected_rom.get_name()[..8])) +} + +fn read_menu_options(fs: &mut Fat32Fs, menu_options: &mut [MenuOption>; 255]) -> usize { let mut menu_options_size = 0; let mut root_dir_offset = 0; const FILES_PER_LIST:usize = 20; @@ -118,8 +128,7 @@ fn read_menu_options(fs: &mut Fat32, menu_options: &mut [MenuOptionOption{ - let mut menu_options_size = 0; +fn search_file(fs:&mut Fat32Fs, filename: &str)->Option{ let mut root_dir_offset = 0; const FILES_PER_LIST:usize = 20; loop{ diff --git a/rpi/src/drivers/disk.rs b/rpi/src/drivers/disk.rs index 729964b8..8750a34e 100644 --- a/rpi/src/drivers/disk.rs +++ b/rpi/src/drivers/disk.rs @@ -65,7 +65,7 @@ impl Disk{ } /// Returns the number of blocks the write operation modified - pub fn write(&mut self, block_index:u32, buffer:&mut [u8])->u32{ + pub fn write(&mut self, block_index:u32, buffer:&[u8])->u32{ self.prepare_for_disk_operation(block_index, buffer); if !self.emmc.write(buffer){ core::panic!("Error while writing object of size: {}", buffer.len()); diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index 0119742b..afb3a097 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -255,7 +255,7 @@ impl FatBuffer{ return Ok(entry & FAT_ENTRY_MASK); } - /// On error retusns the last valid fat index + /// On error returns the last valid fat index fn write(&mut self, mut value:u32)->Result<(), FatIndex>{ let interal_sector_index = self.get_interal_sector_index()?; let start_index = (interal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; @@ -269,7 +269,6 @@ impl FatBuffer{ self.fat_internal_index.sector_number += 1; self.fat_internal_index.sector_offset = 0; } - log::debug!("FAT buffer write, start_index: {:?}, buffer_start: {}, value: {}", self.fat_start_index, start_index, value); return Ok(()); } @@ -298,7 +297,7 @@ const MAX_FAT_SEGMENTS_COUNT: usize = MAX_FILES * 100; const FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; -pub struct Fat32{ +pub struct Fat32Fs{ disk: Disk, boot_sector:Fat32BootSector, partition_start_sector_index:u32, @@ -310,7 +309,7 @@ pub struct Fat32{ root_dir_allocated_clusters_count: u32, } -impl Fat32{ +impl Fat32Fs{ pub fn new()->Self{ let mut disk = Disk::new(); // This driver currently support only a single partition (some has more than one for backup or stuff I dont know) @@ -476,7 +475,7 @@ impl Fat32{ } /// Write a file to the root dir - pub fn write_file(&mut self, filename:&str, content:&mut [u8]){ + pub fn write_file(&mut self, filename:&str, content:&[u8]){ log::debug!("Writing file: {}, size: {}", filename, content.len()); let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster as u32; let cluster_size = sectors_per_cluster * SECTOR_SIZE as u32; @@ -555,22 +554,22 @@ impl Fat32{ self.write_root_dir_cache(); } - fn write_to_data_section(&mut self, content: &mut [u8], cluster_size: u32, first_cluster_index: u32) { - let mut chunks = content.chunks_exact_mut(cluster_size as usize); + fn write_to_data_section(&mut self, content: &[u8], cluster_size: u32, first_cluster_index: u32) { + let chunks = content.chunks_exact(cluster_size as usize); + let reminder_chunks = chunks.remainder().chunks_exact(SECTOR_SIZE); let mut cluster_index = first_cluster_index; - while let Some(chunk) = chunks.next() { + for chunk in chunks { let start_sector = self.get_cluster_start_sector_index(cluster_index); let _ = self.disk.write(start_sector, chunk); cluster_index += 1; } - let mut reminder_chunks = chunks.into_remainder().chunks_exact_mut(SECTOR_SIZE); let mut sector_index = self.get_cluster_start_sector_index(cluster_index); - while let Some(chunk) = reminder_chunks.next() { + let last_reminder_chunk = reminder_chunks.remainder(); + for chunk in reminder_chunks { sector_index += self.disk.write(sector_index, chunk); } - let reminder_chunk = reminder_chunks.into_remainder(); let mut buffer = [0;SECTOR_SIZE]; - buffer[..reminder_chunk.len()].copy_from_slice(reminder_chunk); + buffer[..last_reminder_chunk.len()].copy_from_slice(last_reminder_chunk); let _ = self.disk.write(sector_index, &mut buffer); } diff --git a/rpi/src/peripherals/emmc.rs b/rpi/src/peripherals/emmc.rs index bd6b7f7d..2eab2b34 100644 --- a/rpi/src/peripherals/emmc.rs +++ b/rpi/src/peripherals/emmc.rs @@ -161,6 +161,20 @@ struct Scr{ version:u32, } +enum InternalBuffer<'a>{ + Mutable(&'a mut [u8]), + Immutable(&'a [u8]), +} + +impl<'a> InternalBuffer<'a>{ + fn len(&self)->usize{ + match self{ + Self::Mutable(b) => b.len(), + Self::Immutable(b) => b.len(), + } + } +} + // Mailbox params const GPIO_TAG_PIN_1_8V_CONTROL:u32 = 132; const SD_CARD_DEVICE_ID:u32 = 0; @@ -284,21 +298,21 @@ impl Emmc{ pub fn read(&mut self, buffer:&mut [u8])->bool{ memory_barrier(); - let result = self.execute_data_transfer_command(false, buffer).is_ok(); + let result = self.execute_data_transfer_command(false, InternalBuffer::Mutable(buffer)).is_ok(); memory_barrier(); return result; } - pub fn write(&mut self, buffer: &mut [u8])->bool{ + pub fn write(&mut self, buffer: &[u8])->bool{ memory_barrier(); - let result = self.execute_data_transfer_command(true, buffer).is_ok(); + let result = self.execute_data_transfer_command(true, InternalBuffer::Immutable(buffer)).is_ok(); memory_barrier(); return result; } pub fn get_block_size(&self)->u32{self.block_size} - fn execute_data_transfer_command(&mut self, write: bool, buffer: &mut [u8])->Result<(), SdError>{ + fn execute_data_transfer_command(&mut self, write: bool, mut buffer: InternalBuffer)->Result<(), SdError>{ if self.offset % BLOCK_SIZE as u64 != 0{ return Err(SdError::Error); } @@ -324,7 +338,7 @@ impl Emmc{ else{SdCommandType::ReadBlock}; for _ in 0..3{ - if self.send_command(command_type, block_index, 5000, Some(buffer)).is_ok(){ + if self.send_command(command_type, block_index, 5000, Some(&mut buffer)).is_ok(){ return Ok(()); } } @@ -405,7 +419,7 @@ impl Emmc{ let mut scr_buffer = [0;8]; self.block_size = 8; self.transfer_blocks = 1; - self.send_command(SdCommandType::SendScr, 0, 30000, Some(&mut scr_buffer)).unwrap(); + self.send_command(SdCommandType::SendScr, 0, 30000, Some(&mut InternalBuffer::Mutable(&mut scr_buffer))).unwrap(); // continue later self.block_size = BLOCK_SIZE; self.scr.register[0] = u32::from_ne_bytes(scr_buffer[0..4].try_into().unwrap()); @@ -436,7 +450,7 @@ impl Emmc{ log::debug!("SD Spec version: {}", self.scr.version); } - fn transfer_data(&mut self, command:SdCommand, buffer:&mut [u8]){ + fn transfer_data(&mut self, command:SdCommand, buffer:&mut InternalBuffer){ let (wr_irpt, write) = if command.direction(){(INTERRUPT_READ_RDY, false)} else{(INTERRUPT_WRITE_RDY, true)}; for i in 0..self.transfer_blocks{ @@ -452,12 +466,14 @@ impl Emmc{ let iteration_len = self.block_size as usize / DATA_REG_SIZE; let block_index = i as usize * self.block_size as usize; if write{ + let InternalBuffer::Immutable(buffer) = buffer else {core::unreachable!("Internal Emmc Error!, Received Mutable buffer on emmc write operation")}; for j in 0..iteration_len{ let data:[u8; DATA_REG_SIZE as usize] = buffer[block_index + (j * DATA_REG_SIZE) .. block_index + ((j + 1) * DATA_REG_SIZE)].try_into().unwrap(); self.registers.data.write(u32::from_ne_bytes(data)); } } else{ + let InternalBuffer::Mutable(buffer) = buffer else {core::unreachable!("Internal Emmc Error!, Received Immutable buffer on emmc read operation")}; for j in 0..iteration_len{ let data = u32::to_ne_bytes(self.registers.data.read()); buffer[block_index + (j * DATA_REG_SIZE) .. block_index + ((j + 1) * DATA_REG_SIZE)].copy_from_slice(&data); @@ -472,7 +488,7 @@ impl Emmc{ return Self::wait_timeout(&self.registers.control[1], CONTROL1_SRST_CMD, true, 1, 10000).is_ok(); } - fn send_command(&mut self, command_type:SdCommandType, arg:u32, timeout_ms:u32, buffer:Option<&mut [u8]>)->Result<(), SdError>{ + fn send_command(&mut self, command_type:SdCommandType, arg:u32, timeout_ms:u32, buffer:Option<&mut InternalBuffer>)->Result<(), SdError>{ log::trace!("Received command type: {:#?}", command_type); let command = resolve_command(command_type); @@ -486,7 +502,7 @@ impl Emmc{ return self.send_raw_command(command, arg, timeout_ms, buffer); } - fn send_raw_command(&mut self, command:SdCommand, arg:u32, timeout_ms:u32, buffer:Option<&mut [u8]>)->Result<(), SdError>{ + fn send_raw_command(&mut self, command:SdCommand, arg:u32, timeout_ms:u32, buffer:Option<&mut InternalBuffer>)->Result<(), SdError>{ log::trace!("Command {:#X} is being processed", command.0); let block_size_count_value = self.block_size | (self.transfer_blocks << 16); diff --git a/rpi/src/peripherals/power.rs b/rpi/src/peripherals/power.rs index 3e454800..5c80fb33 100644 --- a/rpi/src/peripherals/power.rs +++ b/rpi/src/peripherals/power.rs @@ -65,7 +65,7 @@ impl Power{ Self { registers: get_static_peripheral(PM_BASE_OFFSET) } } - pub fn reset(&mut self, mode:ResetMode){ + pub fn reset(&mut self, mode:ResetMode)->!{ let mbox = unsafe{PERIPHERALS.get_mailbox()}; for device_id in 0..RPI_DEVICES_COUNT{ mbox.call(Tag::SetPowerState, [device_id as u32, 0 /* power off, no wait */]); @@ -88,5 +88,9 @@ impl Power{ rstc_reg |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; self.registers.rstc.write(rstc_reg); memory_barrier(); + + // The program should not return from reset + // If it returns panic + core::panic!("Failed reset attempt"); } } \ No newline at end of file From a30f2d7f759cce88871104c541301351601236b8 Mon Sep 17 00:00:00 2001 From: alloncm Date: Wed, 27 Sep 2023 23:38:21 +0300 Subject: [PATCH 16/39] Self CR clean code fixes --- rpi/src/bin/baremetal/main.rs | 1 + rpi/src/drivers/fat32.rs | 65 ++++++++++++++++++----------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index 1d4c8c27..905f3373 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -88,6 +88,7 @@ fn reset_system<'a>(mbc: &'a dyn Mbc, mut fs: Fat32Fs, mut power_manager: Power, let filename = get_save_filename(selected_rom); fs.write_file(filename.as_str(), mbc.get_ram()); + // delaying the reset operation so other low level tasks will have enough time to finish (like uart transmision) delay::wait_ms(100); power_manager.reset(mode); } diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index afb3a097..6e6774df 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -62,8 +62,8 @@ impl Default for Fat32BootSector{ #[derive(Clone, Copy, Default)] #[repr(C, packed)] struct FatShortDirEntry{ - file_name:[u8;8], - file_extension:[u8;3], + file_name:[u8;Self::FILE_NAME_SIZE], + file_extension:[u8;Self::FILE_EXTENSION_SIZE], attributes:u8, nt_reserve:u8, creation_time_tenth_secs:u8, @@ -79,7 +79,11 @@ struct FatShortDirEntry{ compile_time_size_assert!(FatShortDirEntry, 32); impl FatShortDirEntry{ - fn new(name:[u8;8], extension:[u8;3], size:u32)->Self{ + const FILE_NAME_SIZE:usize = 8; + const FILE_EXTENSION_SIZE:usize = 3; + const FULL_FILENAME_SIZE:usize = Self::FILE_NAME_SIZE + Self::FILE_EXTENSION_SIZE; + + fn new(name:[u8;Self::FILE_NAME_SIZE], extension:[u8;Self::FILE_EXTENSION_SIZE], size:u32)->Self{ Self { file_name: name, file_extension: extension, attributes: 0, nt_reserve: 0, creation_time_tenth_secs: 0, creation_time: 0, creation_date: 0, last_access_date: 0, first_cluster_index_high:0, last_write_time: 0, last_write_date: 0, first_cluster_index_low:0, size @@ -92,10 +96,10 @@ impl FatShortDirEntry{ self.first_cluster_index_low = (first_cluster_index & 0xFFFF) as u16; self.first_cluster_index_high = (first_cluster_index >> 16) as u16; } - fn get_filename(&self)->[u8;11]{ - let mut filename:[u8;11] = [0;11]; - filename[..8].copy_from_slice(&self.file_name); - filename[8..11].copy_from_slice(&self.file_extension); + fn get_filename(&self)->[u8;Self::FULL_FILENAME_SIZE]{ + let mut filename = [0;Self::FULL_FILENAME_SIZE]; + filename[.. Self::FILE_NAME_SIZE].copy_from_slice(&self.file_name); + filename[Self::FILE_NAME_SIZE ..].copy_from_slice(&self.file_extension); return filename; } } @@ -154,15 +158,6 @@ struct FatIndex{ sector_offset:usize, } -impl FatIndex{ - fn get_fat_entry(&mut self, buffer:&[u8;FAT_ENTRY_SIZE])->u32{ - u32::from_ne_bytes(*buffer) - } - fn get_raw_fat_entry(&mut self, entry:u32)->[u8;FAT_ENTRY_SIZE]{ - u32::to_ne_bytes(entry) - } -} - #[derive(Clone, Copy, PartialEq, Debug)] enum FatSegmentState{ Free, @@ -189,7 +184,7 @@ impl FatSegmentState{ fn should_continue_segment(&self, other: &Self)->bool{ // AllocatedEof is should never continue segment // otherwise fallback to check raw values of the enum - if *self as isize == Self::AllocatedEof as isize || *other as isize == Self::AllocatedEof as isize{ + if *self == Self::AllocatedEof || *other == Self::AllocatedEof{ return false; } return self == other; @@ -216,6 +211,10 @@ struct FatInfo{ fats_count:usize } +// This is the default size of a fat buffer +// the actual size is just twicking between fewer read operation and smaller buffer +const FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; + struct FatBuffer{ buffer:[u8;FBS], buffer_len: usize, @@ -245,7 +244,7 @@ impl FatBuffer{ let interal_sector_index = self.get_interal_sector_index()?; let start_index = (interal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; let end_index = start_index + FAT_ENTRY_SIZE; - let entry = self.fat_internal_index.get_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); + let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ self.fat_internal_index.sector_number += 1; @@ -260,10 +259,10 @@ impl FatBuffer{ let interal_sector_index = self.get_interal_sector_index()?; let start_index = (interal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; let end_index = start_index + FAT_ENTRY_SIZE; - let entry = self.fat_internal_index.get_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); + let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); let reserved_bits = entry & (!FAT_ENTRY_MASK); value = (value & FAT_ENTRY_MASK) | reserved_bits; - self.buffer[start_index .. end_index].copy_from_slice(&self.fat_internal_index.get_raw_fat_entry(value)); + self.buffer[start_index .. end_index].copy_from_slice(&Self::fat_entry_to_bytes(value)); self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ self.fat_internal_index.sector_number += 1; @@ -289,14 +288,15 @@ impl FatBuffer{ } return Ok(interal_sector_index); } + + fn bytes_to_fat_entry(buffer:&[u8;FAT_ENTRY_SIZE])->u32 {u32::from_ne_bytes(*buffer)} + fn fat_entry_to_bytes(entry:u32)->[u8;FAT_ENTRY_SIZE] {u32::to_ne_bytes(entry)} } // Currently the driver support only 0x100 files in the root directory const MAX_FILES: usize = 0x100; const MAX_FAT_SEGMENTS_COUNT: usize = MAX_FILES * 100; -const FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; - pub struct Fat32Fs{ disk: Disk, boot_sector:Fat32BootSector, @@ -369,9 +369,12 @@ impl Fat32Fs{ log::debug!("Root dir allocated clusters count: {}", self.root_dir_allocated_clusters_count); } - // Optimization: Perhaps I can read the files from the root dir, and once I have all the entries abort and mark the rest of the clusters as free - // Tried that, for some reason there were allcoated entries on the FAT that I couldnt understand what allocated them so Ill live it like that for now + // Failed Optimization Attempt: I treid to read the files from the root dir, and once I have all the entries abort and mark the rest of the clusters as free + // for some reason there were allcoated entries on the FAT that I couldnt understand what allocated them and couldnt predict and calculate the expected entries count + // Ill live it like that for now fn init_fat_table_cache(&mut self){ + // This buffer is buigger then the default in order to minimize the number of read operations + // The value is twicked for faster reads const INIT_FAT_BUFFER_SIZE:usize = FAT_BUFFER_SIZE * 10; let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, 0, None, &mut self.disk); @@ -446,7 +449,7 @@ impl Fat32Fs{ match fat_first_entry.state { FatSegmentState::Allocated => fat_first_entry.len += 1, FatSegmentState::AllocatedEof => {}, - _ => core::panic!("Error recevied not allocated segment"), + _ => core::panic!("FAT32 Driver Error! - tried to read file: {} but the fat segment was not allocated: {}", file_entry.get_name(), file_entry.first_cluster_index), } let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, file_entry.first_cluster_index as usize, Some(fat_first_entry.len as usize), &mut self.disk); @@ -574,16 +577,16 @@ impl Fat32Fs{ } fn create_filename(&self, filename:&str)->Result<([u8;8],[u8;3]), ()>{ - const ILLEGAL_CHARS:[u8;16] = [b'"', b'*', b'+', b',', b'.', b'/', b':', b';', b'<', b'=', b'>', b'?', b'[',b'\\', b']', b'|' ]; - if filename.len() != 11 || + const FAT32_ILLEGAL_CHARS:[u8;16] = [b'"', b'*', b'+', b',', b'.', b'/', b':', b';', b'<', b'=', b'>', b'?', b'[',b'\\', b']', b'|' ]; + if filename.len() != FatShortDirEntry::FULL_FILENAME_SIZE || !filename.is_ascii() || - filename.as_bytes().into_iter().any(|b|ILLEGAL_CHARS.contains(b) && *b > 0x20) || + filename.as_bytes().into_iter().any(|b|FAT32_ILLEGAL_CHARS.contains(b) && *b > 0x20) || filename.as_bytes().into_iter().any(|c| *c >= b'a' && *c <= b'z'){ return Err(()); } - let filename:[u8;11] = filename.as_bytes().try_into().unwrap(); - let name:[u8;8] = filename[..8].try_into().unwrap(); - let extension:[u8;3] = filename[8..].try_into().unwrap(); + let raw_filename:[u8;FatShortDirEntry::FULL_FILENAME_SIZE] = filename.as_bytes().try_into().unwrap(); + let name:[u8;FatShortDirEntry::FILE_NAME_SIZE] = raw_filename[.. FatShortDirEntry::FILE_NAME_SIZE].try_into().unwrap(); + let extension:[u8;FatShortDirEntry::FILE_EXTENSION_SIZE] = raw_filename[FatShortDirEntry::FILE_NAME_SIZE ..].try_into().unwrap(); return Ok((name, extension)); } From 41aeb6a6ba53e92c14369b8b1ec29d3754bf96e8 Mon Sep 17 00:00:00 2001 From: alloncm Date: Sat, 30 Sep 2023 15:12:22 +0300 Subject: [PATCH 17/39] WIP --- rpi/src/drivers/disk.rs | 15 ++++++++++----- rpi/src/drivers/fat32.rs | 4 ++-- rpi/src/peripherals/emmc.rs | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/rpi/src/drivers/disk.rs b/rpi/src/drivers/disk.rs index 8750a34e..0957215c 100644 --- a/rpi/src/drivers/disk.rs +++ b/rpi/src/drivers/disk.rs @@ -57,11 +57,16 @@ impl Disk{ /// Returns the number of blocks the read operation fetched /// The user knows how much of the buffer is filled pub fn read(&mut self, block_index:u32, buffer:&mut [u8]) -> u32 { - self.prepare_for_disk_operation(block_index, buffer); + let block_size = Self::get_block_size(); + if buffer.len() % block_size as usize != 0{ + // handle if the buffer is not alligened for block size + } + self.emmc.seek((block_index * block_size) as u64); + // let end_index = core::cmp::min(buffer.len(), ) if !self.emmc.read(buffer){ core::panic!("Error while reading object of size: {}", buffer.len()); } - return buffer.len() as u32 / self.get_block_size(); + return buffer.len() as u32 / Self::get_block_size(); } /// Returns the number of blocks the write operation modified @@ -70,17 +75,17 @@ impl Disk{ if !self.emmc.write(buffer){ core::panic!("Error while writing object of size: {}", buffer.len()); } - return buffer.len() as u32 / self.get_block_size(); + return buffer.len() as u32 / Self::get_block_size(); } pub fn get_partition_first_sector_index(&self, partition_index:u8)->u32{ self.mbr.partitions[partition_index as usize].first_sector_index } - pub fn get_block_size(&self)->u32{self.emmc.get_block_size()} + pub const fn get_block_size()->u32{Emmc::get_block_size()} fn prepare_for_disk_operation(&mut self, block_index:u32, buffer:&[u8]){ - let block_size = self.get_block_size(); + let block_size = Self::get_block_size(); if buffer.len() % block_size as usize != 0{ core::panic!("buffer size must be a division of block size: {}, actual buffer_size: {}", block_size, buffer.len()); } diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index 6e6774df..51f3e956 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -120,7 +120,7 @@ struct FatLongDirEntry{ } const DISK_PARTITION_INDEX:u8 = 0; -const SECTOR_SIZE:usize = 512; +const SECTOR_SIZE:usize = Disk::get_block_size() as usize; const FAT_ENTRY_SIZE:usize = size_of::(); // each fat entry in fat32 is 4 the size of u32 const FAT_ENTRY_EOF_INDEX:u32 = 0x0FFF_FFFF; const FAT_ENTRY_MASK:u32 = 0x0FFF_FFFF; @@ -327,7 +327,7 @@ impl Fat32Fs{ core::panic!("Detected FAT16 and not FAT32 file system"); } let bytes_per_sector = boot_sector.fat32_bpb.bytes_per_sector as u32; - if bytes_per_sector != disk.get_block_size() || bytes_per_sector != SECTOR_SIZE as u32{ + if bytes_per_sector != SECTOR_SIZE as u32{ core::panic!("Currently dont support fat32 disks with sectors size other than {}", SECTOR_SIZE); } let fat_count = boot_sector.fat32_bpb.fats_count; diff --git a/rpi/src/peripherals/emmc.rs b/rpi/src/peripherals/emmc.rs index 2eab2b34..0245afe0 100644 --- a/rpi/src/peripherals/emmc.rs +++ b/rpi/src/peripherals/emmc.rs @@ -310,7 +310,7 @@ impl Emmc{ return result; } - pub fn get_block_size(&self)->u32{self.block_size} + pub const fn get_block_size()->u32{BLOCK_SIZE} fn execute_data_transfer_command(&mut self, write: bool, mut buffer: InternalBuffer)->Result<(), SdError>{ if self.offset % BLOCK_SIZE as u64 != 0{ From d5700137d62a15719a96ebd857bd74cd52791962 Mon Sep 17 00:00:00 2001 From: alloncm Date: Sat, 30 Sep 2023 22:44:26 +0300 Subject: [PATCH 18/39] The disk operations now works with any size buffer Also fixed a bunch of typos thanks to a new vscode extension --- rpi/src/bin/baremetal/main.rs | 12 ++--- rpi/src/drivers/disk.rs | 67 +++++++++++++++--------- rpi/src/drivers/fat32.rs | 99 +++++++++++++++-------------------- rpi/src/peripherals/utils.rs | 6 +-- 4 files changed, 95 insertions(+), 89 deletions(-) diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index 905f3373..536df405 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -12,7 +12,7 @@ use magenboy_rpi::{drivers::*, peripherals::{PERIPHERALS, GpioPull, ResetMode, P #[panic_handler] fn panic(info:&PanicInfo)->!{ - log::error!("An error has occoured!: \r\n{}", info); + log::error!("An error has occurred!: \r\n{}", info); unsafe{boot::hang_led()}; } @@ -21,7 +21,7 @@ const MAX_ROM_SIZE:usize = 0x80_0000; // 8 MiB, Max size of MBC5 rom const MAX_RAM_SIZE:usize = 0x2_0000; // 128 KiB // Allocating as static buffer (on the .bss) because it is a very large buffer and -// I dont want to cause problems in stack making it overflow and shit (I can increase it when needed but I afraid Id forget) +// I don't want to cause problems in stack making it overflow and shit (I can increase it when needed but I afraid Id forget) static mut ROM_BUFFER:[u8; MAX_ROM_SIZE] = [0;MAX_ROM_SIZE]; static mut RAM_BUFFER:[u8; MAX_RAM_SIZE] = [0;MAX_RAM_SIZE]; @@ -42,7 +42,7 @@ pub extern "C" fn main()->!{ let mut pause_menu_gfx = gfx.clone(); let mut joypad_provider = GpioJoypadProvider::new(button_to_bcm_pin); let mut pause_menu_joypad_provider = joypad_provider.clone(); - log::info!("Initialize all drivers succesfully"); + log::info!("Initialize all drivers successfully"); let menu_renderer = joypad_gfx_menu::GfxDeviceMenuRenderer::new(&mut gfx); @@ -71,7 +71,7 @@ pub extern "C" fn main()->!{ match pause_menu.get_menu_selection(&mut pause_menu_joypad_provider){ EmulatorMenuOption::Resume => {}, EmulatorMenuOption::Restart => { - log::info!("Reseting system"); + log::info!("Resetting system"); reset_system(mbc, fs, power_manager, ResetMode::Partition0, selected_rom); } EmulatorMenuOption::Shutdown => { @@ -88,7 +88,7 @@ fn reset_system<'a>(mbc: &'a dyn Mbc, mut fs: Fat32Fs, mut power_manager: Power, let filename = get_save_filename(selected_rom); fs.write_file(filename.as_str(), mbc.get_ram()); - // delaying the reset operation so other low level tasks will have enough time to finish (like uart transmision) + // delaying the reset operation so other low level tasks will have enough time to finish (like uart transmission) delay::wait_ms(100); power_manager.reset(mode); } @@ -120,7 +120,7 @@ fn read_menu_options(fs: &mut Fat32Fs, menu_options: &mut [MenuOption Self { - Self { status: Default::default(), frist_sector_chs_address: Default::default(), partition_type: Default::default(), last_sector_chs_address: Default::default(), first_sector_index: Default::default(), sectors_count: Default::default() } + Self { status: Default::default(), first_sector_chs_address: Default::default(), partition_type: Default::default(), last_sector_chs_address: Default::default(), first_sector_index: Default::default(), sectors_count: Default::default() } } } @@ -37,6 +37,8 @@ pub struct Disk{ } impl Disk{ + const BLOCK_SIZE:u32 = Emmc::get_block_size(); + pub fn new()->Self{ let mut emmc = unsafe{PERIPHERALS.take_emmc()}; emmc.init(); @@ -54,41 +56,58 @@ impl Disk{ Self { emmc, mbr } } - /// Returns the number of blocks the read operation fetched - /// The user knows how much of the buffer is filled - pub fn read(&mut self, block_index:u32, buffer:&mut [u8]) -> u32 { - let block_size = Self::get_block_size(); - if buffer.len() % block_size as usize != 0{ - // handle if the buffer is not alligened for block size + pub fn read(&mut self, block_index:u32, buffer:&mut [u8]){ + let buffer_len_reminder = buffer.len() % Self::BLOCK_SIZE as usize; + let max_aligned_buffer_len = buffer.len() - buffer_len_reminder; + let aligned_buffer = &mut buffer[..max_aligned_buffer_len]; + + self.emmc.seek((block_index * Self::BLOCK_SIZE) as u64); + // Verify the buffer is larger than a single block + if aligned_buffer.len() != 0{ + self.emmc_read(aligned_buffer); + // early return if the buffer is aligned + if buffer_len_reminder == 0 {return}; } - self.emmc.seek((block_index * block_size) as u64); - // let end_index = core::cmp::min(buffer.len(), ) + // handle the case buffer length is not aligned for block size + let mut temp_buffer:[u8;Self::BLOCK_SIZE as usize] = [0;Self::BLOCK_SIZE as usize]; + self.emmc.seek(((block_index + (max_aligned_buffer_len as u32 / Self::BLOCK_SIZE)) * Self::BLOCK_SIZE) as u64); + self.emmc_read(&mut temp_buffer); + buffer[max_aligned_buffer_len..].copy_from_slice(&mut temp_buffer[..buffer_len_reminder]); + } + + fn emmc_read(&mut self, buffer: &mut [u8]) { if !self.emmc.read(buffer){ core::panic!("Error while reading object of size: {}", buffer.len()); } - return buffer.len() as u32 / Self::get_block_size(); } - /// Returns the number of blocks the write operation modified - pub fn write(&mut self, block_index:u32, buffer:&[u8])->u32{ - self.prepare_for_disk_operation(block_index, buffer); + pub fn write(&mut self, block_index:u32, buffer:&[u8]){ + let buffer_len_reminder = buffer.len() % Self::BLOCK_SIZE as usize; + let max_aligned_buffer_len = buffer.len() - buffer_len_reminder; + let aligned_buffer = &buffer[..max_aligned_buffer_len]; + + self.emmc.seek((block_index * Self::BLOCK_SIZE) as u64); + if aligned_buffer.len() != 0{ + self.emmc_write(aligned_buffer); + // early return since the buffer is aligned + if buffer_len_reminder == 0 {return}; + } + // handle the case buffer length is not aligned for block size + let mut temp_buffer:[u8;Self::BLOCK_SIZE as usize] = [0;Self::BLOCK_SIZE as usize]; + temp_buffer[max_aligned_buffer_len..].copy_from_slice(&buffer[..buffer_len_reminder]); + self.emmc.seek(((block_index + (max_aligned_buffer_len as u32 / Self::BLOCK_SIZE)) * Self::BLOCK_SIZE) as u64); + self.emmc_write(&temp_buffer); + } + + fn emmc_write(&mut self, buffer: &[u8]) { if !self.emmc.write(buffer){ core::panic!("Error while writing object of size: {}", buffer.len()); } - return buffer.len() as u32 / Self::get_block_size(); } pub fn get_partition_first_sector_index(&self, partition_index:u8)->u32{ self.mbr.partitions[partition_index as usize].first_sector_index } - pub const fn get_block_size()->u32{Emmc::get_block_size()} - - fn prepare_for_disk_operation(&mut self, block_index:u32, buffer:&[u8]){ - let block_size = Self::get_block_size(); - if buffer.len() % block_size as usize != 0{ - core::panic!("buffer size must be a division of block size: {}, actual buffer_size: {}", block_size, buffer.len()); - } - self.emmc.seek((block_index * block_size) as u64); - } + pub const fn get_block_size()->u32{Self::BLOCK_SIZE} } \ No newline at end of file diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index 51f3e956..ed338e20 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -13,7 +13,7 @@ struct Fat32BiosParameterBlock{ sectors_per_cluster: u8, reserved_sectors_count: u16, fats_count: u8, - root_entrires_count:u16, + root_entries_count:u16, total_sectors_count_16: u16, media: u8, sectors_per_fat_16:u16, @@ -212,7 +212,7 @@ struct FatInfo{ } // This is the default size of a fat buffer -// the actual size is just twicking between fewer read operation and smaller buffer +// the actual size is just tweaking between fewer read operation and smaller buffer const FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; struct FatBuffer{ @@ -225,24 +225,24 @@ struct FatBuffer{ impl FatBuffer{ fn new(fat_info:FatInfo, first_cluster_index:usize, entries_count: Option, disk: &mut Disk)->Self{ - let entries_count = entries_count.unwrap_or((FBS - SECTOR_SIZE) / FAT_ENTRY_SIZE); + let entries_count = entries_count.unwrap_or(FBS / FAT_ENTRY_SIZE); let mut buffer = [0; FBS]; let fat_offset = first_cluster_index * FAT_ENTRY_SIZE; - let fat_index = FatIndex{ sector_number: (fat_info.first_fat_start_sector + fat_offset / SECTOR_SIZE) as u32, sector_offset: fat_offset % SECTOR_SIZE }; + let fat_index = FatIndex{ sector_number: (fat_info.first_fat_start_sector + (fat_offset / SECTOR_SIZE)) as u32, sector_offset: fat_offset % SECTOR_SIZE }; - // Align the end read to SECTOR_SIZE - let fat_end_read = (entries_count * FAT_ENTRY_SIZE) + (SECTOR_SIZE - ((entries_count * FAT_ENTRY_SIZE) % SECTOR_SIZE)); + // The emmc can't read between sectors so align the start of the read to a sector + let fat_end_read = fat_index.sector_offset + (entries_count * FAT_ENTRY_SIZE); if fat_end_read > FBS{ core::panic!("Error fat entries count is too much: expected:{}, actual: {}", FBS / FAT_ENTRY_SIZE, entries_count); } - let _ = disk.read(fat_index.sector_number, &mut buffer[..fat_end_read]); + disk.read(fat_index.sector_number, &mut buffer[..fat_end_read]); return Self { buffer, fat_start_index: fat_index.clone(), fat_internal_index: fat_index, buffer_len: fat_end_read, fat_info }; } - /// On sucess returns the FAT entry, on error returns the last valid fat index + /// On success returns the FAT entry, on error returns the last valid fat index fn read(&mut self)->Result{ - let interal_sector_index = self.get_interal_sector_index()?; - let start_index = (interal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; + let internal_sector_index = self.get_internal_sector_index()?; + let start_index = (internal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; let end_index = start_index + FAT_ENTRY_SIZE; let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; @@ -256,8 +256,8 @@ impl FatBuffer{ /// On error returns the last valid fat index fn write(&mut self, mut value:u32)->Result<(), FatIndex>{ - let interal_sector_index = self.get_interal_sector_index()?; - let start_index = (interal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; + let internal_sector_index = self.get_internal_sector_index()?; + let start_index = (internal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; let end_index = start_index + FAT_ENTRY_SIZE; let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); let reserved_bits = entry & (!FAT_ENTRY_MASK); @@ -275,18 +275,17 @@ impl FatBuffer{ fn flush(&mut self, disk:&mut Disk){ // Sync all the fat sectors to disk for i in 0..self.fat_info.fats_count{ - // let fat_start_sector = self.fat_info.first_fat_start_sector + self.get_interal_sector_index().ok().unwrap() /*+ (self.fat_info.sectors_per_fat * i)*/; let start_sector = self.fat_start_index.sector_number + (self.fat_info.sectors_per_fat * i) as u32; let _ = disk.write(start_sector, &mut self.buffer[..self.buffer_len]); } } - fn get_interal_sector_index(&self)->Result{ - let interal_sector_index = (self.fat_internal_index.sector_number - self.fat_start_index.sector_number) as usize; - if interal_sector_index * SECTOR_SIZE >= self.buffer_len{ + fn get_internal_sector_index(&self)->Result{ + let internal_sector_index = (self.fat_internal_index.sector_number - self.fat_start_index.sector_number) as usize; + if internal_sector_index * SECTOR_SIZE >= self.buffer_len{ return Err(self.fat_internal_index.clone()); } - return Ok(interal_sector_index); + return Ok(internal_sector_index); } fn bytes_to_fat_entry(buffer:&[u8;FAT_ENTRY_SIZE])->u32 {u32::from_ne_bytes(*buffer)} @@ -312,12 +311,12 @@ pub struct Fat32Fs{ impl Fat32Fs{ pub fn new()->Self{ let mut disk = Disk::new(); - // This driver currently support only a single partition (some has more than one for backup or stuff I dont know) + // This driver currently support only a single partition (some has more than one for backup or stuff I don't know) let bpb_sector_index = disk.get_partition_first_sector_index(DISK_PARTITION_INDEX); let mut boot_sector:Fat32BootSector = Default::default(); let buffer = unsafe{as_mut_buffer(&mut boot_sector)}; - let _ = disk.read(bpb_sector_index, buffer); + disk.read(bpb_sector_index, buffer); let fs_type_label = boot_sector.fs_type_label.clone(); if &fs_type_label[0..3] != b"FAT"{ @@ -328,7 +327,7 @@ impl Fat32Fs{ } let bytes_per_sector = boot_sector.fat32_bpb.bytes_per_sector as u32; if bytes_per_sector != SECTOR_SIZE as u32{ - core::panic!("Currently dont support fat32 disks with sectors size other than {}", SECTOR_SIZE); + core::panic!("Currently not supporting fat32 disks with sectors size other than {}", SECTOR_SIZE); } let fat_count = boot_sector.fat32_bpb.fats_count; log::debug!("FAT count: {}", fat_count); @@ -355,9 +354,10 @@ impl Fat32Fs{ 'search: loop{ let mut root_dir = [FatShortDirEntry::default();FAT_DIR_ENTRIES_PER_SECTOR]; let buffer = unsafe{as_mut_buffer(&mut root_dir)}; - sector_offset += self.disk.read(root_start_sector_index + sector_offset, buffer); + self.disk.read(root_start_sector_index + sector_offset, buffer); + sector_offset += 1; // Since root_dir buffer contains enough entries for exactly 1 sector for dir in root_dir{ - // Pusing also the DIR_EOF in order to support syncing the whole dir easily + // Pushing also the DIR_EOF in order to support syncing the whole dir easily self.root_dir_cache.push(dir); if dir.file_name[0] == DIR_EOF_PREFIX { break 'search; @@ -369,12 +369,12 @@ impl Fat32Fs{ log::debug!("Root dir allocated clusters count: {}", self.root_dir_allocated_clusters_count); } - // Failed Optimization Attempt: I treid to read the files from the root dir, and once I have all the entries abort and mark the rest of the clusters as free - // for some reason there were allcoated entries on the FAT that I couldnt understand what allocated them and couldnt predict and calculate the expected entries count + // Failed Optimization Attempt: I tried to read the files from the root dir, and once I have all the entries abort and mark the rest of the clusters as free + // for some reason there were allocated entries on the FAT that I couldn't understand what allocated them and couldn't predict and calculate the expected entries count // Ill live it like that for now fn init_fat_table_cache(&mut self){ - // This buffer is buigger then the default in order to minimize the number of read operations - // The value is twicked for faster reads + // This buffer is bigger then the default in order to minimize the number of read operations + // The value is tweaked for faster reads const INIT_FAT_BUFFER_SIZE:usize = FAT_BUFFER_SIZE * 10; let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, 0, None, &mut self.disk); @@ -383,7 +383,7 @@ impl Fat32Fs{ let fat_entries_count = self.clusters_count + 1; log::debug!("fat entries count {}", fat_entries_count); - // Since indices [0,1] are resereved ignore and discard them + // Since indices [0,1] are reserved ignore and discard them let _ = fat_buffer.read().ok().unwrap(); let _ = fat_buffer.read().ok().unwrap(); @@ -438,7 +438,7 @@ impl Fat32Fs{ return output_dir; } - // In this implemenation Im trying to read as much many clusters as possible at a time + // In this implementation Im trying to read as much many clusters as possible at a time // in order to improve performance /// Reads a file from the first FAT pub fn read_file(&mut self, file_entry:&FileEntry, output:&mut [u8]){ @@ -467,7 +467,7 @@ impl Fat32Fs{ let start_sector = self.get_cluster_start_sector_index(next_read_cluster); let start_index = sectors_per_cluster as usize * cluster_counter * SECTOR_SIZE as usize; let end_index = core::cmp::min(output.len(), start_index + (sectors_per_cluster as usize * SECTOR_SIZE as usize * clusters_sequence)); - let _ = self.disk.read(start_sector, &mut output[start_index..end_index]); + self.disk.read(start_sector, &mut output[start_index..end_index]); next_read_cluster = fat_entry; current_cluster = fat_entry; @@ -490,18 +490,18 @@ impl Fat32Fs{ // TODO: mark the fat entries as free } else{ - let existing_entry = existing_entry.clone(); // Shadow the original in order to statisify the borrow checker + let existing_entry = existing_entry.clone(); // Shadow the original in order to satisfy the borrow checker let mut segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == existing_entry.get_first_cluster_index()).unwrap().clone(); match segment.state { FatSegmentState::Allocated => segment.len += 1, FatSegmentState::AllocatedEof => {}, - _ => core::panic!("Error recevied not allocated segment"), + _ => core::panic!("Error received not allocated segment"), } let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, existing_entry.get_first_cluster_index() as usize, Some(segment.len as usize), &mut self.disk); let mut current_cluster = existing_entry.get_first_cluster_index(); let mut cluster_count = 0; while cluster_count < segment.len{ - self.write_to_data_section(content, cluster_size, current_cluster); + self.write_to_data_section(content, current_cluster); current_cluster = fat_buffer.read().ok().unwrap(); cluster_count += 1; @@ -525,17 +525,17 @@ impl Fat32Fs{ core::panic!("root dir is too small: {:#X} and driver do not support resizing of the root dir", root_dir_allocation_size); } // Allocate new entry in the root dir - self.root_dir_cache.insert(self.root_dir_cache.len() - 1, FatShortDirEntry::new(name, extension, content.len() as u32)); // write to the last place pusing the last item to index len(), in order to keep the DIR_EOF last + self.root_dir_cache.insert(self.root_dir_cache.len() - 1, FatShortDirEntry::new(name, extension, content.len() as u32)); // write to the last place pushing the last item to index len(), in order to keep the DIR_EOF last let root_dir_cache_updated_len = self.root_dir_cache.len(); - // Root dir cache len must be atleast 2 (entry for the root dir itself and a EOF) and not the one I inserted (so actually 3) - // This retuns the last non EOF entry + // Root dir cache len must be at least 2 (entry for the root dir itself and a EOF) and not the one I inserted (so actually 3) + // This returns the last non EOF entry &mut self.root_dir_cache[root_dir_cache_updated_len - 2] }, }; let required_clusters_count = (content.len() as u32 / cluster_size) + (content.len() as u32 % cluster_size != 0) as u32; - let free_fat_seqment = self.fat_table_cache.as_slice().into_iter().find(|t|t.state == FatSegmentState::Free && t.len >= required_clusters_count).unwrap(); - let first_cluster_index = free_fat_seqment.start_index; + let free_fat_segment = self.fat_table_cache.as_slice().into_iter().find(|t|t.state == FatSegmentState::Free && t.len >= required_clusters_count).unwrap(); + let first_cluster_index = free_fat_segment.start_index; // Update the fat and the root directory log::debug!("File first cluster index: {}", first_cluster_index); @@ -550,30 +550,16 @@ impl Fat32Fs{ fat_buffer.write(FAT_ENTRY_EOF_INDEX).unwrap(); // write the data to the clusters, since the cluster index is the initial index in the fat I can know which one is free or allocated - self.write_to_data_section(content, cluster_size, first_cluster_index); + self.write_to_data_section(content, first_cluster_index); // sync the modifications fat_buffer.flush(&mut self.disk); self.write_root_dir_cache(); } - fn write_to_data_section(&mut self, content: &[u8], cluster_size: u32, first_cluster_index: u32) { - let chunks = content.chunks_exact(cluster_size as usize); - let reminder_chunks = chunks.remainder().chunks_exact(SECTOR_SIZE); - let mut cluster_index = first_cluster_index; - for chunk in chunks { - let start_sector = self.get_cluster_start_sector_index(cluster_index); - let _ = self.disk.write(start_sector, chunk); - cluster_index += 1; - } - let mut sector_index = self.get_cluster_start_sector_index(cluster_index); - let last_reminder_chunk = reminder_chunks.remainder(); - for chunk in reminder_chunks { - sector_index += self.disk.write(sector_index, chunk); - } - let mut buffer = [0;SECTOR_SIZE]; - buffer[..last_reminder_chunk.len()].copy_from_slice(last_reminder_chunk); - let _ = self.disk.write(sector_index, &mut buffer); + fn write_to_data_section(&mut self, content: &[u8], first_cluster_index: u32) { + let start_sector = self.get_cluster_start_sector_index(first_cluster_index); + self.disk.write(start_sector, content); } fn create_filename(&self, filename:&str)->Result<([u8;8],[u8;3]), ()>{ @@ -597,7 +583,8 @@ impl Fat32Fs{ while let Some(chunk) = chunks.next(){ buffer.copy_from_slice(chunk); let mut buffer = unsafe{as_mut_buffer(&mut buffer)}; - root_sector_index += self.disk.write(root_sector_index, &mut buffer); + self.disk.write(root_sector_index, &mut buffer); + root_sector_index += 1; // Since the buffer contains exactly single sector } let reminder = chunks.into_remainder(); buffer[..reminder.len()].copy_from_slice(reminder); diff --git a/rpi/src/peripherals/utils.rs b/rpi/src/peripherals/utils.rs index 464a81d7..fae7ddbf 100644 --- a/rpi/src/peripherals/utils.rs +++ b/rpi/src/peripherals/utils.rs @@ -30,7 +30,7 @@ impl BulkWrite for [MmioReg32; SIZE]{ } } -// According to the docs the raspberrypi requires memory barrier between reads and writes to differnet peripherals +// According to the docs the raspberrypi requires memory barrier between reads and writes to different peripherals #[inline] pub(super) fn memory_barrier(){ core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst); @@ -49,7 +49,7 @@ impl Peripheral{ } return match self{ Self::Init(t) => t, - Self::Taken => core::panic!("Peripheral is unavaliable, its been taken "), + Self::Taken => core::panic!("Peripheral is unavailable, its been taken "), Self::Uninit => core::unreachable!("At this point the peripheral must be initialized"), }; } @@ -59,7 +59,7 @@ impl Peripheral{ return match s{ Self::Uninit => init_callback(), Self::Init(t) => t, - Self::Taken => core::panic!("Peripheral is unavaliable, its been taken"), + Self::Taken => core::panic!("Peripheral is unavailable, its been taken"), }; } } From ec8825efcaab89d43bff6c59113864e869b127e3 Mon Sep 17 00:00:00 2001 From: alloncm Date: Tue, 3 Oct 2023 20:47:06 +0300 Subject: [PATCH 19/39] The disk changes works now The fat buffer still must be aligned for sector size --- rpi/src/drivers/disk.rs | 4 +++- rpi/src/drivers/fat32.rs | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/rpi/src/drivers/disk.rs b/rpi/src/drivers/disk.rs index 141d903c..2aaddba9 100644 --- a/rpi/src/drivers/disk.rs +++ b/rpi/src/drivers/disk.rs @@ -68,6 +68,7 @@ impl Disk{ // early return if the buffer is aligned if buffer_len_reminder == 0 {return}; } + log::warn!("Triggered unaligned read"); // handle the case buffer length is not aligned for block size let mut temp_buffer:[u8;Self::BLOCK_SIZE as usize] = [0;Self::BLOCK_SIZE as usize]; self.emmc.seek(((block_index + (max_aligned_buffer_len as u32 / Self::BLOCK_SIZE)) * Self::BLOCK_SIZE) as u64); @@ -92,9 +93,10 @@ impl Disk{ // early return since the buffer is aligned if buffer_len_reminder == 0 {return}; } + log::warn!("Triggered unaligned write: len: {}", buffer.len()); // handle the case buffer length is not aligned for block size let mut temp_buffer:[u8;Self::BLOCK_SIZE as usize] = [0;Self::BLOCK_SIZE as usize]; - temp_buffer[max_aligned_buffer_len..].copy_from_slice(&buffer[..buffer_len_reminder]); + temp_buffer[..buffer_len_reminder].copy_from_slice(&buffer[max_aligned_buffer_len..]); self.emmc.seek(((block_index + (max_aligned_buffer_len as u32 / Self::BLOCK_SIZE)) * Self::BLOCK_SIZE) as u64); self.emmc_write(&temp_buffer); } diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index ed338e20..b9690b4d 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -224,14 +224,16 @@ struct FatBuffer{ } impl FatBuffer{ + // The buffer Im reading will be the same buffer that Im writing back + // so it must be aligned in order to not corrupt the fat table fn new(fat_info:FatInfo, first_cluster_index:usize, entries_count: Option, disk: &mut Disk)->Self{ - let entries_count = entries_count.unwrap_or(FBS / FAT_ENTRY_SIZE); + let entries_count = entries_count.unwrap_or((FBS - SECTOR_SIZE) / FAT_ENTRY_SIZE); // The max size is smaller cause I need some padding space for alignment let mut buffer = [0; FBS]; let fat_offset = first_cluster_index * FAT_ENTRY_SIZE; let fat_index = FatIndex{ sector_number: (fat_info.first_fat_start_sector + (fat_offset / SECTOR_SIZE)) as u32, sector_offset: fat_offset % SECTOR_SIZE }; - // The emmc can't read between sectors so align the start of the read to a sector - let fat_end_read = fat_index.sector_offset + (entries_count * FAT_ENTRY_SIZE); + // Align the end read to SECTOR_SIZE, since the FAT table is not aligned we need to read exactly X sectors in order to be able to write them back later + let fat_end_read = (entries_count * FAT_ENTRY_SIZE) + (SECTOR_SIZE - ((entries_count * FAT_ENTRY_SIZE) % SECTOR_SIZE)); if fat_end_read > FBS{ core::panic!("Error fat entries count is too much: expected:{}, actual: {}", FBS / FAT_ENTRY_SIZE, entries_count); } From 22cc1463b7fa96eefd0c48bf07614cbfeb3f7934 Mon Sep 17 00:00:00 2001 From: alloncm Date: Tue, 3 Oct 2023 20:54:21 +0300 Subject: [PATCH 20/39] Refactor write root dir to use the new disk write --- rpi/src/drivers/disk.rs | 4 +--- rpi/src/drivers/fat32.rs | 22 ++++++++-------------- rpi/src/drivers/mod.rs | 5 ++--- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/rpi/src/drivers/disk.rs b/rpi/src/drivers/disk.rs index 2aaddba9..c73a1709 100644 --- a/rpi/src/drivers/disk.rs +++ b/rpi/src/drivers/disk.rs @@ -44,7 +44,7 @@ impl Disk{ emmc.init(); let mut mbr = MasterBootRecord::default(); - let buffer = unsafe{as_mut_buffer(&mut mbr)}; + let buffer = as_mut_buffer(&mut mbr); if !emmc.read(buffer){ core::panic!("Cant read MBR from disk"); @@ -68,7 +68,6 @@ impl Disk{ // early return if the buffer is aligned if buffer_len_reminder == 0 {return}; } - log::warn!("Triggered unaligned read"); // handle the case buffer length is not aligned for block size let mut temp_buffer:[u8;Self::BLOCK_SIZE as usize] = [0;Self::BLOCK_SIZE as usize]; self.emmc.seek(((block_index + (max_aligned_buffer_len as u32 / Self::BLOCK_SIZE)) * Self::BLOCK_SIZE) as u64); @@ -93,7 +92,6 @@ impl Disk{ // early return since the buffer is aligned if buffer_len_reminder == 0 {return}; } - log::warn!("Triggered unaligned write: len: {}", buffer.len()); // handle the case buffer length is not aligned for block size let mut temp_buffer:[u8;Self::BLOCK_SIZE as usize] = [0;Self::BLOCK_SIZE as usize]; temp_buffer[..buffer_len_reminder].copy_from_slice(&buffer[max_aligned_buffer_len..]); diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index b9690b4d..a145a243 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -317,7 +317,7 @@ impl Fat32Fs{ let bpb_sector_index = disk.get_partition_first_sector_index(DISK_PARTITION_INDEX); let mut boot_sector:Fat32BootSector = Default::default(); - let buffer = unsafe{as_mut_buffer(&mut boot_sector)}; + let buffer = as_mut_buffer(&mut boot_sector); disk.read(bpb_sector_index, buffer); let fs_type_label = boot_sector.fs_type_label.clone(); @@ -355,7 +355,7 @@ impl Fat32Fs{ let mut sector_offset = 0; 'search: loop{ let mut root_dir = [FatShortDirEntry::default();FAT_DIR_ENTRIES_PER_SECTOR]; - let buffer = unsafe{as_mut_buffer(&mut root_dir)}; + let buffer = as_mut_buffer(&mut root_dir); self.disk.read(root_start_sector_index + sector_offset, buffer); sector_offset += 1; // Since root_dir buffer contains enough entries for exactly 1 sector for dir in root_dir{ @@ -579,18 +579,8 @@ impl Fat32Fs{ } fn write_root_dir_cache(&mut self){ - let mut root_sector_index = self.get_cluster_start_sector_index(self.boot_sector.fat32_bpb.root_dir_first_cluster); - let mut chunks = self.root_dir_cache.chunks_exact_mut(FAT_DIR_ENTRIES_PER_SECTOR); - let mut buffer = [FatShortDirEntry::default(); FAT_DIR_ENTRIES_PER_SECTOR]; - while let Some(chunk) = chunks.next(){ - buffer.copy_from_slice(chunk); - let mut buffer = unsafe{as_mut_buffer(&mut buffer)}; - self.disk.write(root_sector_index, &mut buffer); - root_sector_index += 1; // Since the buffer contains exactly single sector - } - let reminder = chunks.into_remainder(); - buffer[..reminder.len()].copy_from_slice(reminder); - let buffer = unsafe{as_mut_buffer(&mut buffer)}; + let root_sector_index = self.get_cluster_start_sector_index(self.boot_sector.fat32_bpb.root_dir_first_cluster); + let buffer = Self::arrayvec_as_buffer(&self.root_dir_cache); self.disk.write(root_sector_index, buffer); } @@ -601,4 +591,8 @@ impl Fat32Fs{ ((cluster - FIRST_DATA_CLUSTER) * self.boot_sector.fat32_bpb.sectors_per_cluster as u32) + (self.boot_sector.fat32_bpb.sectors_per_fat_32 * self.boot_sector.fat32_bpb.fats_count as u32) } + + fn arrayvec_as_buffer<'a, T, const CAP:usize>(vec:&'a ArrayVec)->&'a [u8]{ + unsafe{core::slice::from_raw_parts(vec.as_ptr() as *const u8, vec.len() * core::mem::size_of::())} + } } \ No newline at end of file diff --git a/rpi/src/drivers/mod.rs b/rpi/src/drivers/mod.rs index 5f6ba12a..8b130aa1 100644 --- a/rpi/src/drivers/mod.rs +++ b/rpi/src/drivers/mod.rs @@ -11,7 +11,6 @@ pub use ili9341_gfx_device::*; #[cfg(not(feature = "os"))] -pub(crate) unsafe fn as_mut_buffer<'a, T>(t:&'a mut T)->&'a mut [u8]{ - let buffer = &mut *core::ptr::slice_from_raw_parts_mut(t as *mut T as *mut _, core::mem::size_of::()); - return buffer; +pub(crate) fn as_mut_buffer<'a, T>(t:&'a mut T)->&'a mut [u8]{ + unsafe{&mut *core::ptr::slice_from_raw_parts_mut(t as *mut T as *mut _, core::mem::size_of::())} } \ No newline at end of file From 16c4bfd91d456538a1add36272774c82bb4848b4 Mon Sep 17 00:00:00 2001 From: alloncm Date: Wed, 4 Oct 2023 05:38:21 +0300 Subject: [PATCH 21/39] For some reason this is working now --- core/src/mmu/carts/mod.rs | 2 +- rpi/src/drivers/fat32.rs | 81 +++++++++++++++++++++++++-------------- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/core/src/mmu/carts/mod.rs b/core/src/mmu/carts/mod.rs index 88898752..d6e59c97 100644 --- a/core/src/mmu/carts/mod.rs +++ b/core/src/mmu/carts/mod.rs @@ -32,7 +32,7 @@ pub fn init_ram(ram_reg:u8, external_ram:Option<&'static mut[u8]>)->&'static mut match external_ram{ Some(ram)=>{ if ram.len() != ram_size{ - core::panic!("external rom is not in the correct size for the cartridge"); + core::panic!("External ram is not in the correct size for the cartridge, the save seems corrupted, either fix or delete it and try again"); } return ram; diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32.rs index a145a243..a460c899 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32.rs @@ -1,4 +1,4 @@ -use core::mem::size_of; +use core::{mem::size_of, ops::ControlFlow}; use arrayvec::ArrayVec; @@ -124,6 +124,7 @@ const SECTOR_SIZE:usize = Disk::get_block_size() as usize; const FAT_ENTRY_SIZE:usize = size_of::(); // each fat entry in fat32 is 4 the size of u32 const FAT_ENTRY_EOF_INDEX:u32 = 0x0FFF_FFFF; const FAT_ENTRY_MASK:u32 = 0x0FFF_FFFF; +const FAT_ENTRY_FREE_INDEX:u32 = 0; const DELETED_DIR_ENTRY_PREFIX:u8 = 0xE5; const DIR_EOF_PREFIX:u8 = 0; @@ -445,6 +446,7 @@ impl Fat32Fs{ /// Reads a file from the first FAT pub fn read_file(&mut self, file_entry:&FileEntry, output:&mut [u8]){ log::debug!("Reading file {}, size {}, cluster: {}", file_entry.get_name(), file_entry.size, file_entry.first_cluster_index); + if file_entry.size == 0 {return} let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster; let mut fat_first_entry = self.fat_table_cache.as_slice().into_iter().find(|t|t.start_index == file_entry.first_cluster_index).unwrap().clone(); @@ -476,7 +478,6 @@ impl Fat32Fs{ cluster_counter += clusters_sequence; clusters_sequence = 1; } - // TODO: verify all the file has been read } /// Write a file to the root dir @@ -485,41 +486,20 @@ impl Fat32Fs{ let sectors_per_cluster = self.boot_sector.fat32_bpb.sectors_per_cluster as u32; let cluster_size = sectors_per_cluster * SECTOR_SIZE as u32; let (name, extension) = self.create_filename(filename).unwrap_or_else(|_|core::panic!("File name format is bad: {}", filename)); - // check if file exists, if exists try to overwrite it, if cant mark it as deleted - if let Some(existing_entry) = self.root_dir_cache.as_mut_slice().into_iter().find(|d|d.file_name == name && d.file_extension == extension){ - if (existing_entry.size as usize) < content.len(){ - existing_entry.file_name[0] = DELETED_DIR_ENTRY_PREFIX; - // TODO: mark the fat entries as free - } - else{ - let existing_entry = existing_entry.clone(); // Shadow the original in order to satisfy the borrow checker - let mut segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == existing_entry.get_first_cluster_index()).unwrap().clone(); - match segment.state { - FatSegmentState::Allocated => segment.len += 1, - FatSegmentState::AllocatedEof => {}, - _ => core::panic!("Error received not allocated segment"), - } - let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, existing_entry.get_first_cluster_index() as usize, Some(segment.len as usize), &mut self.disk); - let mut current_cluster = existing_entry.get_first_cluster_index(); - let mut cluster_count = 0; - while cluster_count < segment.len{ - self.write_to_data_section(content, current_cluster); - current_cluster = fat_buffer.read().ok().unwrap(); - cluster_count += 1; - } - return; - } - } + // check if file exists, if exists try to overwrite it, if cant mark it as deleted + if let ControlFlow::Break(()) = self.handle_existing_filename(name, extension, content) {return} // create a new file by allocating place in the root dir and then picking some free fat segment to use it's clusters let new_dir_entry = match self.root_dir_cache.as_mut_slice().into_iter().find(|d|d.file_name[0] == DELETED_DIR_ENTRY_PREFIX){ Some(dir) => { + log::warn!("Using the space of another deleted dir entry"); dir.file_name = name; dir.file_extension = extension; dir } None => { + log::warn!("Adding another dir entry"); // Check the root dir allocation size to check it needs to be reallocated let root_dir_allocation_size = (self.root_dir_allocated_clusters_count * self.boot_sector.fat32_bpb.sectors_per_cluster as u32) as usize * SECTOR_SIZE; let expected_root_dir_size_after_allocation = (self.root_dir_cache.len() + 1) * size_of::(); @@ -533,7 +513,7 @@ impl Fat32Fs{ // Root dir cache len must be at least 2 (entry for the root dir itself and a EOF) and not the one I inserted (so actually 3) // This returns the last non EOF entry &mut self.root_dir_cache[root_dir_cache_updated_len - 2] - }, + } }; let required_clusters_count = (content.len() as u32 / cluster_size) + (content.len() as u32 % cluster_size != 0) as u32; let free_fat_segment = self.fat_table_cache.as_slice().into_iter().find(|t|t.state == FatSegmentState::Free && t.len >= required_clusters_count).unwrap(); @@ -559,6 +539,51 @@ impl Fat32Fs{ self.write_root_dir_cache(); } + fn handle_existing_filename(&mut self, name: [u8; 8], extension: [u8; 3], content: &[u8]) -> ControlFlow<()> { + if let Some(existing_entry) = self.root_dir_cache.as_mut_slice().into_iter().find(|d|d.file_name == name && d.file_extension == extension){ + log::debug!("File already exists, overwriting it"); + if existing_entry.size == 0 { + existing_entry.file_name[0] = DELETED_DIR_ENTRY_PREFIX; + return ControlFlow::Continue(()) + }; + + let segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == existing_entry.get_first_cluster_index()).unwrap().clone(); + let segment_len = match segment.state { + FatSegmentState::Allocated => segment.len + 1, + FatSegmentState::AllocatedEof => 1, + _ => core::panic!("FAT32 FS Error: received not allocated segment"), + }; + let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, existing_entry.get_first_cluster_index() as usize, Some(segment_len as usize), &mut self.disk); + + // Possible Optimization: Allow more cases to reuse the allocation + // 1. if its in the range of the cluster alignment + // 2. If its smaller than the required size (can use some of the allocation) + if (existing_entry.size as usize) == content.len(){ + log::debug!("Using existing allocation"); + let existing_entry = existing_entry.clone(); // Shadow the original in order to satisfy the borrow checker + let mut current_cluster = existing_entry.get_first_cluster_index(); + let mut cluster_count = 0; + while cluster_count < segment_len{ + self.write_to_data_section(content, current_cluster); + current_cluster = fat_buffer.read().ok().unwrap(); + cluster_count += 1; + } + return ControlFlow::Break(()); + } + else{ + existing_entry.file_name[0] = DELETED_DIR_ENTRY_PREFIX; + // Mark the fat entries as free + for _ in 0..segment_len{ + fat_buffer.write(FAT_ENTRY_FREE_INDEX).ok().unwrap(); + } + // while fat_buffer.write(FAT_ENTRY_FREE_INDEX).is_ok() {} + fat_buffer.flush(&mut self.disk); + // The root dir cache is flushed at the end of the function + } + } + return ControlFlow::Continue(()); + } + fn write_to_data_section(&mut self, content: &[u8], first_cluster_index: u32) { let start_sector = self.get_cluster_start_sector_index(first_cluster_index); self.disk.write(start_sector, content); From c735ef3bb42edb5422c495bf64e916dfbb8c4477 Mon Sep 17 00:00:00 2001 From: alloncm Date: Wed, 4 Oct 2023 05:50:51 +0300 Subject: [PATCH 22/39] Extract FatBuffer to its own module --- rpi/src/drivers/fat32/fat_buffer.rs | 154 +++++++++++++++++++++ rpi/src/drivers/{fat32.rs => fat32/mod.rs} | 147 +------------------- 2 files changed, 158 insertions(+), 143 deletions(-) create mode 100644 rpi/src/drivers/fat32/fat_buffer.rs rename rpi/src/drivers/{fat32.rs => fat32/mod.rs} (78%) diff --git a/rpi/src/drivers/fat32/fat_buffer.rs b/rpi/src/drivers/fat32/fat_buffer.rs new file mode 100644 index 00000000..3a4d5725 --- /dev/null +++ b/rpi/src/drivers/fat32/fat_buffer.rs @@ -0,0 +1,154 @@ +use crate::drivers::disk::Disk; + +use super::SECTOR_SIZE; + +const FAT_ENTRY_SIZE:usize = 4; +const FAT_ENTRY_MASK:u32 = 0x0FFF_FFFF; + +#[derive(Clone, Debug)] +pub struct FatIndex{ + sector_number:u32, + sector_offset:usize, +} + +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum FatSegmentState{ + Free, + Allocated, + AllocatedEof, + Reserved, + Bad, +} + +impl From for FatSegmentState{ + fn from(value: u32) -> Self { + match value{ + 0 => Self::Free, + 2..=0xFFF_FFF5 => Self::Allocated, + 0xFFF_FFFF => Self::AllocatedEof, + 0xFFF_FFF7 => Self::Bad, + _ => Self::Reserved + } + } +} + +impl FatSegmentState{ + /// Checks whether a value should be part of this segment or not + pub fn should_continue_segment(&self, other: &Self)->bool{ + // AllocatedEof is should never continue segment + // otherwise fallback to check raw values of the enum + if *self == Self::AllocatedEof || *other == Self::AllocatedEof{ + return false; + } + return self == other; + } +} + +#[derive(Clone, Debug)] +pub struct FatSegment{ + pub state:FatSegmentState, + pub len:u32, + pub start_index:u32, +} + +impl FatSegment{ + pub fn new(value:u32, start_index:u32)->Self{ + Self { state: value.into(), len: 1, start_index} + } +} + +#[derive(Clone, Copy)] +pub struct FatInfo{ + first_fat_start_sector:usize, + sectors_per_fat:usize, + fats_count:usize +} + +impl FatInfo{ + pub fn new(first_fat_start_sector:usize, sectors_per_fat:usize, fats_count: usize)->Self{ + Self { first_fat_start_sector, sectors_per_fat, fats_count } + } +} + +// This is the default size of a fat buffer +// the actual size is just tweaking between fewer read operation and smaller buffer +pub const FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; + +pub struct FatBuffer{ + buffer:[u8;FBS], + buffer_len: usize, + fat_start_index:FatIndex, + fat_internal_index:FatIndex, + fat_info:FatInfo, +} + +impl FatBuffer{ + // The buffer Im reading will be the same buffer that Im writing back + // so it must be aligned in order to not corrupt the fat table + pub fn new(fat_info:FatInfo, first_cluster_index:usize, entries_count: Option, disk: &mut Disk)->Self{ + let entries_count = entries_count.unwrap_or((FBS - SECTOR_SIZE) / FAT_ENTRY_SIZE); // The max size is smaller cause I need some padding space for alignment + let mut buffer = [0; FBS]; + let fat_offset = first_cluster_index * FAT_ENTRY_SIZE; + let fat_index = FatIndex{ sector_number: (fat_info.first_fat_start_sector + (fat_offset / SECTOR_SIZE)) as u32, sector_offset: fat_offset % SECTOR_SIZE }; + + // Align the end read to SECTOR_SIZE, since the FAT table is not aligned we need to read exactly X sectors in order to be able to write them back later + let fat_end_read = (entries_count * FAT_ENTRY_SIZE) + (SECTOR_SIZE - ((entries_count * FAT_ENTRY_SIZE) % SECTOR_SIZE)); + if fat_end_read > FBS{ + core::panic!("Error fat entries count is too much: expected:{}, actual: {}", FBS / FAT_ENTRY_SIZE, entries_count); + } + disk.read(fat_index.sector_number, &mut buffer[..fat_end_read]); + return Self { buffer, fat_start_index: fat_index.clone(), fat_internal_index: fat_index, buffer_len: fat_end_read, fat_info }; + } + + /// On success returns the FAT entry, on error returns the last valid fat index + pub fn read(&mut self)->Result{ + let internal_sector_index = self.get_internal_sector_index()?; + let start_index = (internal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; + let end_index = start_index + FAT_ENTRY_SIZE; + let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); + self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; + if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ + self.fat_internal_index.sector_number += 1; + self.fat_internal_index.sector_offset = 0; + } + // Mask the entry to hide the reserved bits + return Ok(entry & FAT_ENTRY_MASK); + } + + /// On error returns the last valid fat index + pub fn write(&mut self, mut value:u32)->Result<(), FatIndex>{ + let internal_sector_index = self.get_internal_sector_index()?; + let start_index = (internal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; + let end_index = start_index + FAT_ENTRY_SIZE; + let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); + let reserved_bits = entry & (!FAT_ENTRY_MASK); + value = (value & FAT_ENTRY_MASK) | reserved_bits; + self.buffer[start_index .. end_index].copy_from_slice(&Self::fat_entry_to_bytes(value)); + self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; + if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ + self.fat_internal_index.sector_number += 1; + self.fat_internal_index.sector_offset = 0; + } + return Ok(()); + } + + /// Sync the fat buffer to the disk + pub fn flush(&mut self, disk:&mut Disk){ + // Sync all the fat sectors to disk + for i in 0..self.fat_info.fats_count{ + let start_sector = self.fat_start_index.sector_number + (self.fat_info.sectors_per_fat * i) as u32; + let _ = disk.write(start_sector, &mut self.buffer[..self.buffer_len]); + } + } + + fn get_internal_sector_index(&self)->Result{ + let internal_sector_index = (self.fat_internal_index.sector_number - self.fat_start_index.sector_number) as usize; + if internal_sector_index * SECTOR_SIZE >= self.buffer_len{ + return Err(self.fat_internal_index.clone()); + } + return Ok(internal_sector_index); + } + + fn bytes_to_fat_entry(buffer:&[u8;FAT_ENTRY_SIZE])->u32 {u32::from_ne_bytes(*buffer)} + fn fat_entry_to_bytes(entry:u32)->[u8;FAT_ENTRY_SIZE] {u32::to_ne_bytes(entry)} +} \ No newline at end of file diff --git a/rpi/src/drivers/fat32.rs b/rpi/src/drivers/fat32/mod.rs similarity index 78% rename from rpi/src/drivers/fat32.rs rename to rpi/src/drivers/fat32/mod.rs index a460c899..b15cb5da 100644 --- a/rpi/src/drivers/fat32.rs +++ b/rpi/src/drivers/fat32/mod.rs @@ -1,9 +1,12 @@ +mod fat_buffer; + use core::{mem::size_of, ops::ControlFlow}; use arrayvec::ArrayVec; use crate::peripherals::compile_time_size_assert; use super::{as_mut_buffer, disk::*}; +use fat_buffer::*; #[derive(Default)] #[repr(C, packed)] @@ -121,9 +124,7 @@ struct FatLongDirEntry{ const DISK_PARTITION_INDEX:u8 = 0; const SECTOR_SIZE:usize = Disk::get_block_size() as usize; -const FAT_ENTRY_SIZE:usize = size_of::(); // each fat entry in fat32 is 4 the size of u32 const FAT_ENTRY_EOF_INDEX:u32 = 0x0FFF_FFFF; -const FAT_ENTRY_MASK:u32 = 0x0FFF_FFFF; const FAT_ENTRY_FREE_INDEX:u32 = 0; const DELETED_DIR_ENTRY_PREFIX:u8 = 0xE5; const DIR_EOF_PREFIX:u8 = 0; @@ -153,147 +154,7 @@ impl FileEntry{ } } -#[derive(Clone, Debug)] -struct FatIndex{ - sector_number:u32, - sector_offset:usize, -} - -#[derive(Clone, Copy, PartialEq, Debug)] -enum FatSegmentState{ - Free, - Allocated, - AllocatedEof, - Reserved, - Bad, -} - -impl From for FatSegmentState{ - fn from(value: u32) -> Self { - match value{ - 0 => Self::Free, - 2..=0xFFF_FFF5 => Self::Allocated, - 0xFFF_FFFF => Self::AllocatedEof, - 0xFFF_FFF7 => Self::Bad, - _ => Self::Reserved - } - } -} - -impl FatSegmentState{ - /// Checks whether a value should be part of this segment or not - fn should_continue_segment(&self, other: &Self)->bool{ - // AllocatedEof is should never continue segment - // otherwise fallback to check raw values of the enum - if *self == Self::AllocatedEof || *other == Self::AllocatedEof{ - return false; - } - return self == other; - } -} - -#[derive(Clone, Debug)] -struct FatSegment{ - state:FatSegmentState, - len:u32, - start_index:u32, -} - -impl FatSegment{ - fn new(value:u32, start_index:u32)->Self{ - Self { state: value.into(), len: 1, start_index} - } -} - -#[derive(Clone, Copy)] -struct FatInfo{ - first_fat_start_sector:usize, - sectors_per_fat:usize, - fats_count:usize -} - -// This is the default size of a fat buffer -// the actual size is just tweaking between fewer read operation and smaller buffer -const FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; - -struct FatBuffer{ - buffer:[u8;FBS], - buffer_len: usize, - fat_start_index:FatIndex, - fat_internal_index:FatIndex, - fat_info:FatInfo, -} - -impl FatBuffer{ - // The buffer Im reading will be the same buffer that Im writing back - // so it must be aligned in order to not corrupt the fat table - fn new(fat_info:FatInfo, first_cluster_index:usize, entries_count: Option, disk: &mut Disk)->Self{ - let entries_count = entries_count.unwrap_or((FBS - SECTOR_SIZE) / FAT_ENTRY_SIZE); // The max size is smaller cause I need some padding space for alignment - let mut buffer = [0; FBS]; - let fat_offset = first_cluster_index * FAT_ENTRY_SIZE; - let fat_index = FatIndex{ sector_number: (fat_info.first_fat_start_sector + (fat_offset / SECTOR_SIZE)) as u32, sector_offset: fat_offset % SECTOR_SIZE }; - - // Align the end read to SECTOR_SIZE, since the FAT table is not aligned we need to read exactly X sectors in order to be able to write them back later - let fat_end_read = (entries_count * FAT_ENTRY_SIZE) + (SECTOR_SIZE - ((entries_count * FAT_ENTRY_SIZE) % SECTOR_SIZE)); - if fat_end_read > FBS{ - core::panic!("Error fat entries count is too much: expected:{}, actual: {}", FBS / FAT_ENTRY_SIZE, entries_count); - } - disk.read(fat_index.sector_number, &mut buffer[..fat_end_read]); - return Self { buffer, fat_start_index: fat_index.clone(), fat_internal_index: fat_index, buffer_len: fat_end_read, fat_info }; - } - - /// On success returns the FAT entry, on error returns the last valid fat index - fn read(&mut self)->Result{ - let internal_sector_index = self.get_internal_sector_index()?; - let start_index = (internal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; - let end_index = start_index + FAT_ENTRY_SIZE; - let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); - self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; - if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ - self.fat_internal_index.sector_number += 1; - self.fat_internal_index.sector_offset = 0; - } - // Mask the entry to hide the reserved bits - return Ok(entry & FAT_ENTRY_MASK); - } - - /// On error returns the last valid fat index - fn write(&mut self, mut value:u32)->Result<(), FatIndex>{ - let internal_sector_index = self.get_internal_sector_index()?; - let start_index = (internal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; - let end_index = start_index + FAT_ENTRY_SIZE; - let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); - let reserved_bits = entry & (!FAT_ENTRY_MASK); - value = (value & FAT_ENTRY_MASK) | reserved_bits; - self.buffer[start_index .. end_index].copy_from_slice(&Self::fat_entry_to_bytes(value)); - self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; - if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ - self.fat_internal_index.sector_number += 1; - self.fat_internal_index.sector_offset = 0; - } - return Ok(()); - } - - /// Sync the fat buffer to the disk - fn flush(&mut self, disk:&mut Disk){ - // Sync all the fat sectors to disk - for i in 0..self.fat_info.fats_count{ - let start_sector = self.fat_start_index.sector_number + (self.fat_info.sectors_per_fat * i) as u32; - let _ = disk.write(start_sector, &mut self.buffer[..self.buffer_len]); - } - } - - fn get_internal_sector_index(&self)->Result{ - let internal_sector_index = (self.fat_internal_index.sector_number - self.fat_start_index.sector_number) as usize; - if internal_sector_index * SECTOR_SIZE >= self.buffer_len{ - return Err(self.fat_internal_index.clone()); - } - return Ok(internal_sector_index); - } - fn bytes_to_fat_entry(buffer:&[u8;FAT_ENTRY_SIZE])->u32 {u32::from_ne_bytes(*buffer)} - fn fat_entry_to_bytes(entry:u32)->[u8;FAT_ENTRY_SIZE] {u32::to_ne_bytes(entry)} -} // Currently the driver support only 0x100 files in the root directory const MAX_FILES: usize = 0x100; @@ -339,7 +200,7 @@ impl Fat32Fs{ let clusters_count = fat32_data_sectors / boot_sector.fat32_bpb.sectors_per_cluster as u32; let fat_start_sector = (bpb_sector_index + boot_sector.fat32_bpb.reserved_sectors_count as u32) as usize; let mut fat32 = Self { - fat_info:FatInfo { first_fat_start_sector: fat_start_sector, sectors_per_fat: boot_sector.fat32_bpb.sectors_per_fat_32 as usize, fats_count: boot_sector.fat32_bpb.fats_count as usize }, + fat_info:FatInfo::new( fat_start_sector, boot_sector.fat32_bpb.sectors_per_fat_32 as usize, boot_sector.fat32_bpb.fats_count as usize ), disk, boot_sector, partition_start_sector_index:bpb_sector_index, clusters_count, fat_table_cache: ArrayVec::::new(), root_dir_cache: ArrayVec::::new(), From 75cc2d4cba0c756967a2e92e2ed6b4ed899d580c Mon Sep 17 00:00:00 2001 From: alloncm Date: Wed, 4 Oct 2023 15:20:41 +0300 Subject: [PATCH 23/39] Remove redundant logs --- rpi/src/drivers/fat32/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/rpi/src/drivers/fat32/mod.rs b/rpi/src/drivers/fat32/mod.rs index b15cb5da..7d973c8b 100644 --- a/rpi/src/drivers/fat32/mod.rs +++ b/rpi/src/drivers/fat32/mod.rs @@ -354,13 +354,11 @@ impl Fat32Fs{ // create a new file by allocating place in the root dir and then picking some free fat segment to use it's clusters let new_dir_entry = match self.root_dir_cache.as_mut_slice().into_iter().find(|d|d.file_name[0] == DELETED_DIR_ENTRY_PREFIX){ Some(dir) => { - log::warn!("Using the space of another deleted dir entry"); dir.file_name = name; dir.file_extension = extension; dir } None => { - log::warn!("Adding another dir entry"); // Check the root dir allocation size to check it needs to be reallocated let root_dir_allocation_size = (self.root_dir_allocated_clusters_count * self.boot_sector.fat32_bpb.sectors_per_cluster as u32) as usize * SECTOR_SIZE; let expected_root_dir_size_after_allocation = (self.root_dir_cache.len() + 1) * size_of::(); From 38e0517a07a47b270e43890a2bf7ab8d606831da Mon Sep 17 00:00:00 2001 From: alloncm Date: Thu, 26 Dec 2024 19:05:39 +0200 Subject: [PATCH 24/39] Update bitfield-struct --- Cargo.lock | 4 ++-- rpi/Cargo.toml | 4 ++-- rpi/src/peripherals/power.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 341dc877..f262808c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,9 +63,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitfield-struct" -version = "0.5.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef59f0fcc43c87f48e1be2fb5bae934819066bef8be717850944bb882ea232d" +checksum = "6d7a33e7b9505a52e33ed0ad66db6434f18cda0b1c72665fabf14e85cdd39e43" dependencies = [ "proc-macro2", "quote", diff --git a/rpi/Cargo.toml b/rpi/Cargo.toml index 22f6720e..e1f8d8c2 100644 --- a/rpi/Cargo.toml +++ b/rpi/Cargo.toml @@ -11,7 +11,7 @@ magenboy_core = {path = "../core"} magenboy_common = {path = "../common"} log = "0.4" cfg-if = "1" -bitfield-struct = "0.5" +bitfield-struct = {version = "0.9", optional = true} libc = {version = "0.2", optional = true} nix = {version = "0.24", optional = true} crossbeam-channel = {version = "0.5", optional = true} @@ -20,7 +20,7 @@ arrayvec = {version = "0.7.6", default-features = false, optional = true} [features] os = ["magenboy_common/std", "libc", "nix/ioctl", "crossbeam-channel", "rppal"] -bm = ["arrayvec"] +bm = ["arrayvec", "bitfield-struct"] [[bin]] name = "rpios" diff --git a/rpi/src/peripherals/power.rs b/rpi/src/peripherals/power.rs index 5c80fb33..ffd3efbb 100644 --- a/rpi/src/peripherals/power.rs +++ b/rpi/src/peripherals/power.rs @@ -91,6 +91,6 @@ impl Power{ // The program should not return from reset // If it returns panic - core::panic!("Failed reset attempt"); + core::unreachable!("Failed reset attempt"); } } \ No newline at end of file From 3b9a50730d881a6e1a731d28d8d4fb20f0b9ef06 Mon Sep 17 00:00:00 2001 From: alloncm Date: Thu, 26 Dec 2024 20:36:20 +0200 Subject: [PATCH 25/39] Self cr fixes --- rpi/src/bin/baremetal/main.rs | 3 ++- rpi/src/drivers/disk.rs | 3 ++- rpi/src/drivers/fat32/fat_buffer.rs | 27 +++++++------------------- rpi/src/drivers/fat32/mod.rs | 30 ++++++++++++++++++++++++----- rpi/src/drivers/mod.rs | 8 ++++++-- 5 files changed, 42 insertions(+), 29 deletions(-) diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index 57bddbae..1ad6239f 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -110,9 +110,10 @@ fn get_save_filename(selected_rom: &FileEntry) -> ArrayString<11> { } fn read_menu_options(fs: &mut Fat32Fs, menu_options: &mut [MenuOption>; 255]) -> usize { + const FILES_PER_LIST:usize = 20; + let mut menu_options_size = 0; let mut root_dir_offset = 0; - const FILES_PER_LIST:usize = 20; loop{ let dir_entries = fs.root_dir_list::(root_dir_offset); for entry in &dir_entries{ diff --git a/rpi/src/drivers/disk.rs b/rpi/src/drivers/disk.rs index c73a1709..b6c260ee 100644 --- a/rpi/src/drivers/disk.rs +++ b/rpi/src/drivers/disk.rs @@ -44,7 +44,8 @@ impl Disk{ emmc.init(); let mut mbr = MasterBootRecord::default(); - let buffer = as_mut_buffer(&mut mbr); + // SAFETY: MasterBootRecord is repr(C) + let buffer = unsafe{as_mut_buffer(&mut mbr)}; if !emmc.read(buffer){ core::panic!("Cant read MBR from disk"); diff --git a/rpi/src/drivers/fat32/fat_buffer.rs b/rpi/src/drivers/fat32/fat_buffer.rs index 3a4d5725..af0ff906 100644 --- a/rpi/src/drivers/fat32/fat_buffer.rs +++ b/rpi/src/drivers/fat32/fat_buffer.rs @@ -7,7 +7,7 @@ const FAT_ENTRY_MASK:u32 = 0x0FFF_FFFF; #[derive(Clone, Debug)] pub struct FatIndex{ - sector_number:u32, + sector_index:u32, sector_offset:usize, } @@ -44,19 +44,6 @@ impl FatSegmentState{ } } -#[derive(Clone, Debug)] -pub struct FatSegment{ - pub state:FatSegmentState, - pub len:u32, - pub start_index:u32, -} - -impl FatSegment{ - pub fn new(value:u32, start_index:u32)->Self{ - Self { state: value.into(), len: 1, start_index} - } -} - #[derive(Clone, Copy)] pub struct FatInfo{ first_fat_start_sector:usize, @@ -89,14 +76,14 @@ impl FatBuffer{ let entries_count = entries_count.unwrap_or((FBS - SECTOR_SIZE) / FAT_ENTRY_SIZE); // The max size is smaller cause I need some padding space for alignment let mut buffer = [0; FBS]; let fat_offset = first_cluster_index * FAT_ENTRY_SIZE; - let fat_index = FatIndex{ sector_number: (fat_info.first_fat_start_sector + (fat_offset / SECTOR_SIZE)) as u32, sector_offset: fat_offset % SECTOR_SIZE }; + let fat_index = FatIndex{ sector_index: (fat_info.first_fat_start_sector + (fat_offset / SECTOR_SIZE)) as u32, sector_offset: fat_offset % SECTOR_SIZE }; // Align the end read to SECTOR_SIZE, since the FAT table is not aligned we need to read exactly X sectors in order to be able to write them back later let fat_end_read = (entries_count * FAT_ENTRY_SIZE) + (SECTOR_SIZE - ((entries_count * FAT_ENTRY_SIZE) % SECTOR_SIZE)); if fat_end_read > FBS{ core::panic!("Error fat entries count is too much: expected:{}, actual: {}", FBS / FAT_ENTRY_SIZE, entries_count); } - disk.read(fat_index.sector_number, &mut buffer[..fat_end_read]); + disk.read(fat_index.sector_index, &mut buffer[..fat_end_read]); return Self { buffer, fat_start_index: fat_index.clone(), fat_internal_index: fat_index, buffer_len: fat_end_read, fat_info }; } @@ -108,7 +95,7 @@ impl FatBuffer{ let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ - self.fat_internal_index.sector_number += 1; + self.fat_internal_index.sector_index += 1; self.fat_internal_index.sector_offset = 0; } // Mask the entry to hide the reserved bits @@ -126,7 +113,7 @@ impl FatBuffer{ self.buffer[start_index .. end_index].copy_from_slice(&Self::fat_entry_to_bytes(value)); self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ - self.fat_internal_index.sector_number += 1; + self.fat_internal_index.sector_index += 1; self.fat_internal_index.sector_offset = 0; } return Ok(()); @@ -136,13 +123,13 @@ impl FatBuffer{ pub fn flush(&mut self, disk:&mut Disk){ // Sync all the fat sectors to disk for i in 0..self.fat_info.fats_count{ - let start_sector = self.fat_start_index.sector_number + (self.fat_info.sectors_per_fat * i) as u32; + let start_sector = self.fat_start_index.sector_index + (self.fat_info.sectors_per_fat * i) as u32; let _ = disk.write(start_sector, &mut self.buffer[..self.buffer_len]); } } fn get_internal_sector_index(&self)->Result{ - let internal_sector_index = (self.fat_internal_index.sector_number - self.fat_start_index.sector_number) as usize; + let internal_sector_index = (self.fat_internal_index.sector_index - self.fat_start_index.sector_index) as usize; if internal_sector_index * SECTOR_SIZE >= self.buffer_len{ return Err(self.fat_internal_index.clone()); } diff --git a/rpi/src/drivers/fat32/mod.rs b/rpi/src/drivers/fat32/mod.rs index 7d973c8b..c81174b9 100644 --- a/rpi/src/drivers/fat32/mod.rs +++ b/rpi/src/drivers/fat32/mod.rs @@ -154,7 +154,18 @@ impl FileEntry{ } } +#[derive(Clone, Debug)] +pub struct FatSegment{ + pub state:FatSegmentState, + pub len:u32, + pub start_index:u32, +} +impl FatSegment{ + pub fn new(value:u32, start_index:u32)->Self{ + Self { state: value.into(), len: 1, start_index} + } +} // Currently the driver support only 0x100 files in the root directory const MAX_FILES: usize = 0x100; @@ -179,7 +190,8 @@ impl Fat32Fs{ let bpb_sector_index = disk.get_partition_first_sector_index(DISK_PARTITION_INDEX); let mut boot_sector:Fat32BootSector = Default::default(); - let buffer = as_mut_buffer(&mut boot_sector); + // SAFETY: Fat32BootSector is repr(C) and therefore safe to transmute to byte slice + let buffer = unsafe{as_mut_buffer(&mut boot_sector)}; disk.read(bpb_sector_index, buffer); let fs_type_label = boot_sector.fs_type_label.clone(); @@ -217,7 +229,8 @@ impl Fat32Fs{ let mut sector_offset = 0; 'search: loop{ let mut root_dir = [FatShortDirEntry::default();FAT_DIR_ENTRIES_PER_SECTOR]; - let buffer = as_mut_buffer(&mut root_dir); + // SAFETY: FatShortDirEntry is repr(C) and packed and since arrays has the same alingnment as T it is safe + let buffer = unsafe{as_mut_buffer(&mut root_dir)}; self.disk.read(root_start_sector_index + sector_offset, buffer); sector_offset += 1; // Since root_dir buffer contains enough entries for exactly 1 sector for dir in root_dir{ @@ -464,7 +477,8 @@ impl Fat32Fs{ fn write_root_dir_cache(&mut self){ let root_sector_index = self.get_cluster_start_sector_index(self.boot_sector.fat32_bpb.root_dir_first_cluster); - let buffer = Self::arrayvec_as_buffer(&self.root_dir_cache); + // SAFETY: FatShortDirEntry layout is repr(C) + let buffer = unsafe{Self::arrayvec_as_buffer(&self.root_dir_cache)}; self.disk.write(root_sector_index, buffer); } @@ -476,7 +490,13 @@ impl Fat32Fs{ (self.boot_sector.fat32_bpb.sectors_per_fat_32 * self.boot_sector.fat32_bpb.fats_count as u32) } - fn arrayvec_as_buffer<'a, T, const CAP:usize>(vec:&'a ArrayVec)->&'a [u8]{ - unsafe{core::slice::from_raw_parts(vec.as_ptr() as *const u8, vec.len() * core::mem::size_of::())} + /// Takes an `ArrayVec` and converts it to a byte slice + /// This is a function in order to borrow the input properly and bind in to the output slice + /// The function borrows the vec and returns a slice binded to the vec borrow + /// + /// ## SAFETY + /// T layout must be known + unsafe fn arrayvec_as_buffer<'a, T, const CAP:usize>(vec:&'a ArrayVec)->&'a [u8]{ + core::slice::from_raw_parts(vec.as_ptr() as *const u8, vec.len() * core::mem::size_of::()) } } \ No newline at end of file diff --git a/rpi/src/drivers/mod.rs b/rpi/src/drivers/mod.rs index 8b130aa1..5ef53268 100644 --- a/rpi/src/drivers/mod.rs +++ b/rpi/src/drivers/mod.rs @@ -11,6 +11,10 @@ pub use ili9341_gfx_device::*; #[cfg(not(feature = "os"))] -pub(crate) fn as_mut_buffer<'a, T>(t:&'a mut T)->&'a mut [u8]{ - unsafe{&mut *core::ptr::slice_from_raw_parts_mut(t as *mut T as *mut _, core::mem::size_of::())} +/// Casts a type to slice of bytes while keeping the lifetime (fancy reinterepter cast to byte array) +/// +/// ## SAFETY +/// `T` byte representation must be known (aka `repr(C)`) in order for the slice to be usable without UB +pub(crate) unsafe fn as_mut_buffer<'a, T>(t:&'a mut T)->&'a mut [u8]{ + core::slice::from_raw_parts_mut(t as *mut T as *mut _, core::mem::size_of::()) } \ No newline at end of file From 40f9f2c6716f9bdeb18cdc72e75d88a940e037cf Mon Sep 17 00:00:00 2001 From: alloncm Date: Fri, 27 Dec 2024 11:58:45 +0200 Subject: [PATCH 26/39] Add safety comments to main --- rpi/src/bin/baremetal/main.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index 1ad6239f..17871944 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -16,6 +16,7 @@ use magenboy_rpi::{drivers::*, peripherals::{PERIPHERALS, GpioPull, ResetMode, P fn panic(info:&PanicInfo)->!{ log::error!("An error has occurred!: \r\n{}", info); + // SAFETY: Defined in boot asm code, no params passed and this function does not returned so no calling convention is even needed unsafe{boot::hang_led()}; } @@ -55,6 +56,7 @@ pub extern "C" fn main()->!{ let selected_rom = menu.get_menu_selection(&mut joypad_provider); log::info!("Selected ROM: {}", selected_rom.get_name()); + // SAFETY: Only ref to this static mut var let rom = unsafe{&mut ROM_BUFFER}; fs.read_file(selected_rom, rom); let save_data = try_read_save_file(selected_rom, &mut fs); @@ -99,6 +101,8 @@ fn reset_system<'a>(mbc: &'a mut dyn Mbc, mut fs: Fat32Fs, mut power_manager: Po fn try_read_save_file(selected_rom: &FileEntry, mut fs: &mut Fat32Fs) -> Option<&'static [u8]> { let save_filename = get_save_filename(selected_rom); let file = search_file(&mut fs, save_filename.as_str())?; + + // SAFETY: The only reference to this static mut var let ram = unsafe{&mut RAM_BUFFER[0..file.size as usize]}; fs.read_file(&file, ram); log::info!("Found save file for selected rom: {}", file.get_name()); From f9ded378a36cc034064b58b632e9d455b89645de Mon Sep 17 00:00:00 2001 From: alloncm Date: Fri, 27 Dec 2024 12:37:32 +0200 Subject: [PATCH 27/39] Self CR fixes and add bm feature properly --- rpi/src/drivers/disk.rs | 22 ++++++++++++---------- rpi/src/drivers/fat32/mod.rs | 2 +- rpi/src/drivers/mod.rs | 4 ++-- rpi/src/lib.rs | 8 ++++---- rpi/src/peripherals/gpio.rs | 4 ++-- rpi/src/peripherals/mod.rs | 20 +++++++++++--------- 6 files changed, 32 insertions(+), 28 deletions(-) diff --git a/rpi/src/drivers/disk.rs b/rpi/src/drivers/disk.rs index b6c260ee..f9ada387 100644 --- a/rpi/src/drivers/disk.rs +++ b/rpi/src/drivers/disk.rs @@ -37,7 +37,7 @@ pub struct Disk{ } impl Disk{ - const BLOCK_SIZE:u32 = Emmc::get_block_size(); + pub const BLOCK_SIZE:u32 = Emmc::get_block_size(); pub fn new()->Self{ let mut emmc = unsafe{PERIPHERALS.take_emmc()}; @@ -58,8 +58,7 @@ impl Disk{ } pub fn read(&mut self, block_index:u32, buffer:&mut [u8]){ - let buffer_len_reminder = buffer.len() % Self::BLOCK_SIZE as usize; - let max_aligned_buffer_len = buffer.len() - buffer_len_reminder; + let (max_aligned_buffer_len, buffer_len_reminder) = Self::get_max_alligned_buffer_len_and_reminder(buffer); let aligned_buffer = &mut buffer[..max_aligned_buffer_len]; self.emmc.seek((block_index * Self::BLOCK_SIZE) as u64); @@ -83,8 +82,7 @@ impl Disk{ } pub fn write(&mut self, block_index:u32, buffer:&[u8]){ - let buffer_len_reminder = buffer.len() % Self::BLOCK_SIZE as usize; - let max_aligned_buffer_len = buffer.len() - buffer_len_reminder; + let (max_aligned_buffer_len, buffer_len_reminder) = Self::get_max_alligned_buffer_len_and_reminder(buffer); let aligned_buffer = &buffer[..max_aligned_buffer_len]; self.emmc.seek((block_index * Self::BLOCK_SIZE) as u64); @@ -99,16 +97,20 @@ impl Disk{ self.emmc.seek(((block_index + (max_aligned_buffer_len as u32 / Self::BLOCK_SIZE)) * Self::BLOCK_SIZE) as u64); self.emmc_write(&temp_buffer); } + + pub fn get_partition_first_sector_index(&self, partition_index:u8)->u32{ + self.mbr.partitions[partition_index as usize].first_sector_index + } fn emmc_write(&mut self, buffer: &[u8]) { if !self.emmc.write(buffer){ core::panic!("Error while writing object of size: {}", buffer.len()); } } - - pub fn get_partition_first_sector_index(&self, partition_index:u8)->u32{ - self.mbr.partitions[partition_index as usize].first_sector_index + + fn get_max_alligned_buffer_len_and_reminder(buffer: &[u8]) -> (usize, usize) { + let buffer_len_reminder = buffer.len() % Self::BLOCK_SIZE as usize; + let max_aligned_buffer_len = buffer.len() - buffer_len_reminder; + return (max_aligned_buffer_len, buffer_len_reminder); } - - pub const fn get_block_size()->u32{Self::BLOCK_SIZE} } \ No newline at end of file diff --git a/rpi/src/drivers/fat32/mod.rs b/rpi/src/drivers/fat32/mod.rs index c81174b9..9d4c8750 100644 --- a/rpi/src/drivers/fat32/mod.rs +++ b/rpi/src/drivers/fat32/mod.rs @@ -123,7 +123,7 @@ struct FatLongDirEntry{ } const DISK_PARTITION_INDEX:u8 = 0; -const SECTOR_SIZE:usize = Disk::get_block_size() as usize; +const SECTOR_SIZE:usize = Disk::BLOCK_SIZE as usize; const FAT_ENTRY_EOF_INDEX:u32 = 0x0FFF_FFFF; const FAT_ENTRY_FREE_INDEX:u32 = 0; const DELETED_DIR_ENTRY_PREFIX:u8 = 0xE5; diff --git a/rpi/src/drivers/mod.rs b/rpi/src/drivers/mod.rs index 5ef53268..664b3d9a 100644 --- a/rpi/src/drivers/mod.rs +++ b/rpi/src/drivers/mod.rs @@ -1,6 +1,6 @@ mod gpio_joypad; mod ili9341_gfx_device; -cfg_if::cfg_if!{ if #[cfg(not(feature = "os"))]{ +cfg_if::cfg_if!{ if #[cfg(feature = "bm")]{ pub(super) mod disk; mod fat32; pub use fat32::*; @@ -10,7 +10,7 @@ pub use gpio_joypad::*; pub use ili9341_gfx_device::*; -#[cfg(not(feature = "os"))] +#[cfg(feature = "bm")] /// Casts a type to slice of bytes while keeping the lifetime (fancy reinterepter cast to byte array) /// /// ## SAFETY diff --git a/rpi/src/lib.rs b/rpi/src/lib.rs index bb744b58..25dd797d 100644 --- a/rpi/src/lib.rs +++ b/rpi/src/lib.rs @@ -1,12 +1,12 @@ -#![cfg_attr(not(feature = "os"), no_std)] +#![cfg_attr(feature = "bm", no_std)] -#[cfg(all(feature = "os", rpi))] -core::compile_error!("The os feature and the rpi cfg value cant be set at the same time"); +#[cfg(all(feature = "os", feature = "bm"))] +core::compile_error!("The os feature and bm feature cant be set at the same time"); pub mod configuration; pub mod peripherals; pub mod drivers; -cfg_if::cfg_if!{ if #[cfg(not(feature = "os"))]{ +cfg_if::cfg_if!{ if #[cfg(feature = "bm")]{ pub mod syncronization; pub mod delay; }} diff --git a/rpi/src/peripherals/gpio.rs b/rpi/src/peripherals/gpio.rs index b202bdf9..83908fec 100644 --- a/rpi/src/peripherals/gpio.rs +++ b/rpi/src/peripherals/gpio.rs @@ -1,4 +1,4 @@ -#[cfg(not(feature = "os"))] +#[cfg(feature = "bm")] pub use no_std_impl::*; #[cfg(feature = "os")] pub use std_impl::*; @@ -23,7 +23,7 @@ pub enum Trigger{ RisingEdge } -#[cfg(not(feature = "os"))] +#[cfg(feature = "bm")] pub mod no_std_impl{ use crate::{syncronization::Mutex, peripherals::utils::{compile_time_size_assert, MmioReg32, get_static_peripheral, memory_barrier, BulkWrite}}; use super::*; diff --git a/rpi/src/peripherals/mod.rs b/rpi/src/peripherals/mod.rs index 47785d3c..1ebda5f1 100644 --- a/rpi/src/peripherals/mod.rs +++ b/rpi/src/peripherals/mod.rs @@ -6,15 +6,17 @@ mod gpu; mod spi; mod dma; mod timer; -#[cfg(feature = "os")] -mod bcm_host; -cfg_if::cfg_if!{ if #[cfg(not(feature = "os"))]{ + +cfg_if::cfg_if!{ if #[cfg(feature = "bm")]{ mod emmc; mod power; pub(crate) use utils::compile_time_size_assert; pub use utils::PERIPHERALS_BASE_ADDRESS; pub use emmc::Emmc; pub use power::*; +} +else if #[cfg(feature = "os")]{ + mod bcm_host; }} pub use gpio::*; @@ -32,9 +34,9 @@ pub struct Peripherals{ mailbox: Peripheral, timer: Peripheral, spi0: Peripheral, - #[cfg(not(feature = "os"))] + #[cfg(feature = "bm")] emmc: Peripheral, - #[cfg(not(feature = "os"))] + #[cfg(feature = "bm")] power: Peripheral } @@ -62,11 +64,11 @@ impl Peripherals{ pub fn take_spi0(&mut self)->Spi0{ self.spi0.take(||spi::Spi0::new(SPI0_DC_BCM_PIN)) } - #[cfg(not(feature = "os"))] + #[cfg(feature = "bm")] pub fn take_emmc(&mut self)->emmc::Emmc{ self.emmc.take(||emmc::Emmc::new()) } - #[cfg(not(feature = "os"))] + #[cfg(feature = "bm")] pub fn take_power(&mut self)->Power{ self.power.take(||Power::new()) } @@ -78,8 +80,8 @@ pub static mut PERIPHERALS: Peripherals = Peripherals{ mailbox: Peripheral::Uninit, timer: Peripheral::Uninit, spi0: Peripheral::Uninit, - #[cfg(not(feature = "os"))] + #[cfg(feature = "bm")] emmc: Peripheral::Uninit, - #[cfg(not(feature = "os"))] + #[cfg(feature = "bm")] power: Peripheral::Uninit }; \ No newline at end of file From 78b992333cf95b54f4005266a9b21bcefba14e23 Mon Sep 17 00:00:00 2001 From: alloncm Date: Fri, 27 Dec 2024 17:43:05 +0200 Subject: [PATCH 28/39] Continue to review fat_buffer --- rpi/src/drivers/fat32/fat_buffer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpi/src/drivers/fat32/fat_buffer.rs b/rpi/src/drivers/fat32/fat_buffer.rs index af0ff906..eda877bb 100644 --- a/rpi/src/drivers/fat32/fat_buffer.rs +++ b/rpi/src/drivers/fat32/fat_buffer.rs @@ -35,7 +35,7 @@ impl From for FatSegmentState{ impl FatSegmentState{ /// Checks whether a value should be part of this segment or not pub fn should_continue_segment(&self, other: &Self)->bool{ - // AllocatedEof is should never continue segment + // AllocatedEof should never continue segment // otherwise fallback to check raw values of the enum if *self == Self::AllocatedEof || *other == Self::AllocatedEof{ return false; @@ -58,7 +58,7 @@ impl FatInfo{ } // This is the default size of a fat buffer -// the actual size is just tweaking between fewer read operation and smaller buffer +// This size is just a result of tweaking between fewer read operation and smaller working buffers pub const FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; pub struct FatBuffer{ From b4844f7d9c59ead118810e4b7d530fda173244ef Mon Sep 17 00:00:00 2001 From: alloncm Date: Sat, 28 Dec 2024 15:22:32 +0200 Subject: [PATCH 29/39] Some more refactors --- rpi/src/drivers/fat32/fat_buffer.rs | 60 ++++++++++++++++++----------- rpi/src/drivers/fat32/mod.rs | 2 +- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/rpi/src/drivers/fat32/fat_buffer.rs b/rpi/src/drivers/fat32/fat_buffer.rs index eda877bb..0bec0313 100644 --- a/rpi/src/drivers/fat32/fat_buffer.rs +++ b/rpi/src/drivers/fat32/fat_buffer.rs @@ -57,14 +57,16 @@ impl FatInfo{ } } -// This is the default size of a fat buffer -// This size is just a result of tweaking between fewer read operation and smaller working buffers -pub const FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; +/// This is the default size of a fat buffer. +/// This size is just a result of tweaking between fewer read operations and smaller working buffers +pub const DEFAULT_FAT_BUFFER_SIZE:usize = SECTOR_SIZE as usize * 100; -pub struct FatBuffer{ +pub struct FatBuffer{ buffer:[u8;FBS], buffer_len: usize, + /// Start of the buffer (immutable) fat_start_index:FatIndex, + /// Running counter of the current postion on the buffer (mutable) fat_internal_index:FatIndex, fat_info:FatInfo, } @@ -76,7 +78,10 @@ impl FatBuffer{ let entries_count = entries_count.unwrap_or((FBS - SECTOR_SIZE) / FAT_ENTRY_SIZE); // The max size is smaller cause I need some padding space for alignment let mut buffer = [0; FBS]; let fat_offset = first_cluster_index * FAT_ENTRY_SIZE; - let fat_index = FatIndex{ sector_index: (fat_info.first_fat_start_sector + (fat_offset / SECTOR_SIZE)) as u32, sector_offset: fat_offset % SECTOR_SIZE }; + let fat_index = FatIndex{ + sector_index: (fat_info.first_fat_start_sector + (fat_offset / SECTOR_SIZE)) as u32, + sector_offset: fat_offset % SECTOR_SIZE + }; // Align the end read to SECTOR_SIZE, since the FAT table is not aligned we need to read exactly X sectors in order to be able to write them back later let fat_end_read = (entries_count * FAT_ENTRY_SIZE) + (SECTOR_SIZE - ((entries_count * FAT_ENTRY_SIZE) % SECTOR_SIZE)); @@ -84,38 +89,33 @@ impl FatBuffer{ core::panic!("Error fat entries count is too much: expected:{}, actual: {}", FBS / FAT_ENTRY_SIZE, entries_count); } disk.read(fat_index.sector_index, &mut buffer[..fat_end_read]); - return Self { buffer, fat_start_index: fat_index.clone(), fat_internal_index: fat_index, buffer_len: fat_end_read, fat_info }; + + return Self { + buffer, + fat_start_index: fat_index.clone(), + fat_internal_index: fat_index, + buffer_len: fat_end_read, + fat_info + }; } /// On success returns the FAT entry, on error returns the last valid fat index pub fn read(&mut self)->Result{ - let internal_sector_index = self.get_internal_sector_index()?; - let start_index = (internal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; - let end_index = start_index + FAT_ENTRY_SIZE; + let (start_index, end_index) = self.get_internal_sector_boundries_indicies()?; let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); - self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; - if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ - self.fat_internal_index.sector_index += 1; - self.fat_internal_index.sector_offset = 0; - } + self.increment_fat_internal_index(); // Mask the entry to hide the reserved bits return Ok(entry & FAT_ENTRY_MASK); } /// On error returns the last valid fat index pub fn write(&mut self, mut value:u32)->Result<(), FatIndex>{ - let internal_sector_index = self.get_internal_sector_index()?; - let start_index = (internal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; - let end_index = start_index + FAT_ENTRY_SIZE; + let (start_index, end_index) = self.get_internal_sector_boundries_indicies()?; let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); let reserved_bits = entry & (!FAT_ENTRY_MASK); value = (value & FAT_ENTRY_MASK) | reserved_bits; self.buffer[start_index .. end_index].copy_from_slice(&Self::fat_entry_to_bytes(value)); - self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; - if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ - self.fat_internal_index.sector_index += 1; - self.fat_internal_index.sector_offset = 0; - } + self.increment_fat_internal_index(); return Ok(()); } @@ -128,6 +128,22 @@ impl FatBuffer{ } } + // Returns the internal sector index start and end indicies, on error returns the last valid fat index + fn get_internal_sector_boundries_indicies(&mut self) -> Result<(usize, usize), FatIndex> { + let internal_sector_index = self.get_internal_sector_index()?; + let start_index = (internal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; + let end_index = start_index + FAT_ENTRY_SIZE; + return Ok((start_index, end_index)); + } + + fn increment_fat_internal_index(&mut self) { + self.fat_internal_index.sector_offset += FAT_ENTRY_SIZE; + if self.fat_internal_index.sector_offset >= SECTOR_SIZE{ + self.fat_internal_index.sector_index += 1; + self.fat_internal_index.sector_offset = 0; + } + } + fn get_internal_sector_index(&self)->Result{ let internal_sector_index = (self.fat_internal_index.sector_index - self.fat_start_index.sector_index) as usize; if internal_sector_index * SECTOR_SIZE >= self.buffer_len{ diff --git a/rpi/src/drivers/fat32/mod.rs b/rpi/src/drivers/fat32/mod.rs index 9d4c8750..20475a64 100644 --- a/rpi/src/drivers/fat32/mod.rs +++ b/rpi/src/drivers/fat32/mod.rs @@ -252,7 +252,7 @@ impl Fat32Fs{ fn init_fat_table_cache(&mut self){ // This buffer is bigger then the default in order to minimize the number of read operations // The value is tweaked for faster reads - const INIT_FAT_BUFFER_SIZE:usize = FAT_BUFFER_SIZE * 10; + const INIT_FAT_BUFFER_SIZE:usize = DEFAULT_FAT_BUFFER_SIZE * 10; let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, 0, None, &mut self.disk); // The fat has entry per cluster in the volume, were adding 2 for the first 2 reserved entries (0,1) From 69f08f81a6a436f9acf912b65eb28873b9ae9771 Mon Sep 17 00:00:00 2001 From: alloncm Date: Sat, 28 Dec 2024 15:32:26 +0200 Subject: [PATCH 30/39] Some refactors to fat_buffer --- rpi/src/drivers/fat32/fat_buffer.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/rpi/src/drivers/fat32/fat_buffer.rs b/rpi/src/drivers/fat32/fat_buffer.rs index 0bec0313..c709c024 100644 --- a/rpi/src/drivers/fat32/fat_buffer.rs +++ b/rpi/src/drivers/fat32/fat_buffer.rs @@ -101,8 +101,8 @@ impl FatBuffer{ /// On success returns the FAT entry, on error returns the last valid fat index pub fn read(&mut self)->Result{ - let (start_index, end_index) = self.get_internal_sector_boundries_indicies()?; - let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); + let entry_slice = self.get_internal_sector_index_entry_slice()?; + let entry = Self::bytes_to_fat_entry((*entry_slice).try_into().unwrap()); self.increment_fat_internal_index(); // Mask the entry to hide the reserved bits return Ok(entry & FAT_ENTRY_MASK); @@ -110,11 +110,11 @@ impl FatBuffer{ /// On error returns the last valid fat index pub fn write(&mut self, mut value:u32)->Result<(), FatIndex>{ - let (start_index, end_index) = self.get_internal_sector_boundries_indicies()?; - let entry = Self::bytes_to_fat_entry(self.buffer[start_index .. end_index].try_into().unwrap()); + let entry_slice = self.get_internal_sector_index_entry_slice()?; + let entry = Self::bytes_to_fat_entry((*entry_slice).try_into().unwrap()); let reserved_bits = entry & (!FAT_ENTRY_MASK); value = (value & FAT_ENTRY_MASK) | reserved_bits; - self.buffer[start_index .. end_index].copy_from_slice(&Self::fat_entry_to_bytes(value)); + entry_slice.copy_from_slice(&Self::fat_entry_to_bytes(value)); self.increment_fat_internal_index(); return Ok(()); } @@ -128,12 +128,11 @@ impl FatBuffer{ } } - // Returns the internal sector index start and end indicies, on error returns the last valid fat index - fn get_internal_sector_boundries_indicies(&mut self) -> Result<(usize, usize), FatIndex> { + // Returns the internal sector index slice, on error returns the last valid fat index + fn get_internal_sector_index_entry_slice(&mut self) -> Result<&mut [u8], FatIndex> { let internal_sector_index = self.get_internal_sector_index()?; let start_index = (internal_sector_index * SECTOR_SIZE) + self.fat_internal_index.sector_offset; - let end_index = start_index + FAT_ENTRY_SIZE; - return Ok((start_index, end_index)); + return Ok(&mut self.buffer[start_index .. start_index + FAT_ENTRY_SIZE]); } fn increment_fat_internal_index(&mut self) { From 71f5ebb4409d6ed02c7f7588e704de121a99baec Mon Sep 17 00:00:00 2001 From: alloncm Date: Sat, 28 Dec 2024 16:56:25 +0200 Subject: [PATCH 31/39] Silent invalid reads logs (made them trace) --- core/src/machine/mbc_initializer.rs | 1 + core/src/mmu/gb_mmu.rs | 12 ++++++------ core/src/ppu/gb_ppu.rs | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/core/src/machine/mbc_initializer.rs b/core/src/machine/mbc_initializer.rs index 1f7e2b5c..d3f8fc16 100644 --- a/core/src/machine/mbc_initializer.rs +++ b/core/src/machine/mbc_initializer.rs @@ -6,6 +6,7 @@ pub fn initialize_mbc(program:&[u8], save_data:Option<&[u8]>)->&'static mut dyn let program_clone:&mut [u8] = static_alloc_array(program.len()); program_clone.clone_from_slice(program); let save_data_clone:Option<&'static mut[u8]> = if let Some(sd) = save_data{ + log::info!("Found save data!"); let static_alloc_array = static_alloc_array(sd.len()); static_alloc_array.clone_from_slice(&sd); Some(static_alloc_array) diff --git a/core/src/mmu/gb_mmu.rs b/core/src/mmu/gb_mmu.rs index 66027cec..8204d653 100644 --- a/core/src/mmu/gb_mmu.rs +++ b/core/src/mmu/gb_mmu.rs @@ -41,7 +41,7 @@ impl<'a, D:AudioDevice, G:GfxDevice, J:JoypadProvider> Memory for GbMmu<'a, D, G return self.io_bus.ppu.vram.read_current_bank(address-0x8000); } else{ - log::warn!("bad vram read"); + log::trace!("bad vram read"); return BAD_READ_VALUE; } }, @@ -50,7 +50,7 @@ impl<'a, D:AudioDevice, G:GfxDevice, J:JoypadProvider> Memory for GbMmu<'a, D, G return self.io_bus.ppu.oam[(address-0xFE00) as usize]; } else{ - log::warn!("bad oam read"); + log::trace!("bad oam read"); return BAD_READ_VALUE; } } @@ -80,7 +80,7 @@ impl<'a, D:AudioDevice, G:GfxDevice, J:JoypadProvider> Memory for GbMmu<'a, D, G self.io_bus.ppu.vram.write_current_bank(address-0x8000, value); } else{ - log::warn!("bad vram write: address - {:#X}, value - {:#X}, bank - {}", address, value, self.io_bus.ppu.vram.get_bank_reg()); + log::trace!("bad vram write: address - {:#X}, value - {:#X}, bank - {}", address, value, self.io_bus.ppu.vram.get_bank_reg()); } }, 0xFE00..=0xFE9F=>{ @@ -88,7 +88,7 @@ impl<'a, D:AudioDevice, G:GfxDevice, J:JoypadProvider> Memory for GbMmu<'a, D, G self.io_bus.ppu.oam[(address-0xFE00) as usize] = value; } else{ - log::warn!("bad oam write") + log::trace!("bad oam write") } }, _=>self.write_unprotected(address, value) @@ -249,12 +249,12 @@ impl<'a, D:AudioDevice, G:GfxDevice, J:JoypadProvider> GbMmu<'a, D, G, J>{ } fn bad_dma_read(address:u16)->u8{ - log::warn!("bad memory read during dma. {:#X}", address); + log::trace!("bad memory read during dma. {:#X}", address); return BAD_READ_VALUE; } fn bad_dma_write(address:u16){ - log::warn!("bad memory write during dma. {:#X}", address) + log::trace!("bad memory write during dma. {:#X}", address) } fn write_color_ram(&mut self, address:u16, color: Color){ diff --git a/core/src/ppu/gb_ppu.rs b/core/src/ppu/gb_ppu.rs index 21f8d129..33147d52 100644 --- a/core/src/ppu/gb_ppu.rs +++ b/core/src/ppu/gb_ppu.rs @@ -616,7 +616,7 @@ impl GbPpu{ color_ram[(*pallete_index_register & 0b11_1111) as usize] = value; } else{ - log::warn!("bad color ram write: index - {:#X}, value: - {:#X}", pallete_index_register, value); + log::trace!("bad color ram write: index - {:#X}, value: - {:#X}", pallete_index_register, value); } // if bit 7 is set inderement the dest adderess after write From 5180f4166e2f1dad2628f929e848b9392534107a Mon Sep 17 00:00:00 2001 From: alloncm Date: Sat, 28 Dec 2024 20:44:28 +0200 Subject: [PATCH 32/39] This might fix There is a problem where overwriting a file cause it to corrupt --- core/src/machine/mbc_initializer.rs | 1 - rpi/src/drivers/fat32/mod.rs | 10 ++-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/core/src/machine/mbc_initializer.rs b/core/src/machine/mbc_initializer.rs index d3f8fc16..1f7e2b5c 100644 --- a/core/src/machine/mbc_initializer.rs +++ b/core/src/machine/mbc_initializer.rs @@ -6,7 +6,6 @@ pub fn initialize_mbc(program:&[u8], save_data:Option<&[u8]>)->&'static mut dyn let program_clone:&mut [u8] = static_alloc_array(program.len()); program_clone.clone_from_slice(program); let save_data_clone:Option<&'static mut[u8]> = if let Some(sd) = save_data{ - log::info!("Found save data!"); let static_alloc_array = static_alloc_array(sd.len()); static_alloc_array.clone_from_slice(&sd); Some(static_alloc_array) diff --git a/rpi/src/drivers/fat32/mod.rs b/rpi/src/drivers/fat32/mod.rs index 20475a64..cd238fd7 100644 --- a/rpi/src/drivers/fat32/mod.rs +++ b/rpi/src/drivers/fat32/mod.rs @@ -432,14 +432,8 @@ impl Fat32Fs{ // 2. If its smaller than the required size (can use some of the allocation) if (existing_entry.size as usize) == content.len(){ log::debug!("Using existing allocation"); - let existing_entry = existing_entry.clone(); // Shadow the original in order to satisfy the borrow checker - let mut current_cluster = existing_entry.get_first_cluster_index(); - let mut cluster_count = 0; - while cluster_count < segment_len{ - self.write_to_data_section(content, current_cluster); - current_cluster = fat_buffer.read().ok().unwrap(); - cluster_count += 1; - } + let first_cluster_index = existing_entry.get_first_cluster_index(); + self.write_to_data_section(content, first_cluster_index); return ControlFlow::Break(()); } else{ From 06c2f33b448c7346edd083ef5f39ae96b78cd62e Mon Sep 17 00:00:00 2001 From: alloncm Date: Tue, 31 Dec 2024 19:22:01 +0200 Subject: [PATCH 33/39] Try fix CI --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8ddd55bb..d1978008 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -33,7 +33,7 @@ jobs: add-to-path: true - name: install cargo make - run: cargo install --no-default-features --locked --version 0.37.23 cargo-make + run: cargo install --force --no-default-features --locked --version 0.37.23 cargo-make - name: Run tests run: cargo make test From 4964f01f91f4b4e0a92fcbda530372248660def2 Mon Sep 17 00:00:00 2001 From: alloncm Date: Tue, 31 Dec 2024 19:54:44 +0200 Subject: [PATCH 34/39] revert ci fix --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d1978008..8ddd55bb 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -33,7 +33,7 @@ jobs: add-to-path: true - name: install cargo make - run: cargo install --force --no-default-features --locked --version 0.37.23 cargo-make + run: cargo install --no-default-features --locked --version 0.37.23 cargo-make - name: Run tests run: cargo make test From d807e363da816b6a1ac19ef096ebc5d77d89c4b4 Mon Sep 17 00:00:00 2001 From: alloncm Date: Fri, 3 Jan 2025 17:45:35 +0200 Subject: [PATCH 35/39] Update readme with more accurate instructions for instaltion of barematel rpi --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 66afadbc..8a0833b9 100644 --- a/README.md +++ b/README.md @@ -97,13 +97,14 @@ Choose a game with the Joypad bindings (Dpad and A to confirm) ### Raspberry Pi Baremetal Currently only Raspberry Pi 4 is supported using the following instructions: -* Format a sd card and make a single `FAT32` partition called `boot` -* Copy the file `config.txt` to the root dir of the sd card -* Copy the following files from the [Raspberry Pi firmware repo](https://github.com/raspberrypi/firmware/tree/master/boot) onto the SD card: - - [fixup4.dat](https://github.com/raspberrypi/firmware/raw/master/boot/fixup4.dat) - - [start4.elf](https://github.com/raspberrypi/firmware/raw/master/boot/start4.elf) - - [bcm2711-rpi-4-b.dtb](https://github.com/raspberrypi/firmware/raw/master/boot/bcm2711-rpi-4-b.dtb) -* Copy `kernel7.img` onto the SD card +* Format a sd card to MBR (not GPT) and create a single `FAT32` partition (On windows you can use Rufus) +* Copy the following files from the [Raspberry Pi firmware repo](https://github.com/raspberrypi/firmware/tree/191360eaf2e5933eaa0ed76ac0d62722b6f9a58f/boot) onto the SD card: + - [fixup4.dat](https://github.com/raspberrypi/firmware/raw/191360eaf2e5933eaa0ed76ac0d62722b6f9a58f/boot/fixup4.dat) + - [start4.elf](https://github.com/raspberrypi/firmware/raw/191360eaf2e5933eaa0ed76ac0d62722b6f9a58f/boot/start4.elf) + - [bcm2711-rpi-4-b.dtb](https://github.com/raspberrypi/firmware/raw/191360eaf2e5933eaa0ed76ac0d62722b6f9a58f/boot/bcm2711-rpi-4-b.dtb) + + _**Notice**: This is a specific revision, for some reason it broke on the latest version of those files_ +* Copy `kernel7.img` and `config.txt` to the SD card * Connect all the peripherals (ili9341 display and gpio buttons) * Insert the SD card to the RPI4 and boot it From ebb9bae3ed67467897ec7ad243d9770b2638fdbe Mon Sep 17 00:00:00 2001 From: alloncm Date: Sat, 4 Jan 2025 20:04:20 +0200 Subject: [PATCH 36/39] More self cr fixes and comments --- rpi/src/drivers/fat32/fat_buffer.rs | 33 --------------- rpi/src/drivers/fat32/mod.rs | 62 +++++++++++++++++++++++------ 2 files changed, 50 insertions(+), 45 deletions(-) diff --git a/rpi/src/drivers/fat32/fat_buffer.rs b/rpi/src/drivers/fat32/fat_buffer.rs index c709c024..96531fa7 100644 --- a/rpi/src/drivers/fat32/fat_buffer.rs +++ b/rpi/src/drivers/fat32/fat_buffer.rs @@ -11,39 +11,6 @@ pub struct FatIndex{ sector_offset:usize, } -#[derive(Clone, Copy, PartialEq, Debug)] -pub enum FatSegmentState{ - Free, - Allocated, - AllocatedEof, - Reserved, - Bad, -} - -impl From for FatSegmentState{ - fn from(value: u32) -> Self { - match value{ - 0 => Self::Free, - 2..=0xFFF_FFF5 => Self::Allocated, - 0xFFF_FFFF => Self::AllocatedEof, - 0xFFF_FFF7 => Self::Bad, - _ => Self::Reserved - } - } -} - -impl FatSegmentState{ - /// Checks whether a value should be part of this segment or not - pub fn should_continue_segment(&self, other: &Self)->bool{ - // AllocatedEof should never continue segment - // otherwise fallback to check raw values of the enum - if *self == Self::AllocatedEof || *other == Self::AllocatedEof{ - return false; - } - return self == other; - } -} - #[derive(Clone, Copy)] pub struct FatInfo{ first_fat_start_sector:usize, diff --git a/rpi/src/drivers/fat32/mod.rs b/rpi/src/drivers/fat32/mod.rs index cd238fd7..5d9b5a32 100644 --- a/rpi/src/drivers/fat32/mod.rs +++ b/rpi/src/drivers/fat32/mod.rs @@ -155,18 +155,51 @@ impl FileEntry{ } #[derive(Clone, Debug)] -pub struct FatSegment{ - pub state:FatSegmentState, - pub len:u32, - pub start_index:u32, +struct FatSegment{ + state:FatSegmentState, + len:u32, + start_index:u32, } impl FatSegment{ - pub fn new(value:u32, start_index:u32)->Self{ + fn new(value:u32, start_index:u32)->Self{ Self { state: value.into(), len: 1, start_index} } } +#[derive(Clone, Copy, PartialEq, Debug)] +enum FatSegmentState{ + Free, + Allocated, + AllocatedEof, + Reserved, + Bad, +} + +impl From for FatSegmentState{ + fn from(value: u32) -> Self { + match value{ + 0 => Self::Free, + 2..=0xFFF_FFF5 => Self::Allocated, + 0xFFF_FFFF => Self::AllocatedEof, + 0xFFF_FFF7 => Self::Bad, + _ => Self::Reserved + } + } +} + +impl FatSegmentState{ + /// Checks whether a value should be part of this segment or not + fn should_continue_segment(&self, other: &Self)->bool{ + // AllocatedEof should never continue segment + // otherwise fallback to check raw values of the enum + if *self == Self::AllocatedEof || *other == Self::AllocatedEof{ + return false; + } + return self == other; + } +} + // Currently the driver support only 0x100 files in the root directory const MAX_FILES: usize = 0x100; const MAX_FAT_SEGMENTS_COUNT: usize = MAX_FILES * 100; @@ -297,7 +330,7 @@ impl Fat32Fs{ } if dir.attributes == ATTR_LONG_NAME{ continue; - // handle long file names here + // TODO: handle long file names here } if discard > 0{ discard -= 1; @@ -419,17 +452,23 @@ impl Fat32Fs{ return ControlFlow::Continue(()) }; - let segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == existing_entry.get_first_cluster_index()).unwrap().clone(); + let first_cluster_index = existing_entry.get_first_cluster_index(); + let segment = self.fat_table_cache.as_slice().into_iter().find(|f|f.start_index == first_cluster_index).unwrap().clone(); let segment_len = match segment.state { FatSegmentState::Allocated => segment.len + 1, FatSegmentState::AllocatedEof => 1, _ => core::panic!("FAT32 FS Error: received not allocated segment"), }; - let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, existing_entry.get_first_cluster_index() as usize, Some(segment_len as usize), &mut self.disk); + let mut fat_buffer:FatBuffer = FatBuffer::new(self.fat_info, first_cluster_index as usize, Some(segment_len as usize), &mut self.disk); // Possible Optimization: Allow more cases to reuse the allocation // 1. if its in the range of the cluster alignment // 2. If its smaller than the required size (can use some of the allocation) + // + // This check also verifes that the allocation is continuous, allocation done by this driver are continous but other drivers can allocate differently. + // If the allocation is not continous the overwrite logic will not work as it assumes continous allocation. + // The check done by the fact that it checks for allocated segment for this file allocation + // and the if the allocated segment is the len of the file -> the allocation is continous. if (existing_entry.size as usize) == content.len(){ log::debug!("Using existing allocation"); let first_cluster_index = existing_entry.get_first_cluster_index(); @@ -438,13 +477,12 @@ impl Fat32Fs{ } else{ existing_entry.file_name[0] = DELETED_DIR_ENTRY_PREFIX; - // Mark the fat entries as free + // Mark the fat entries as free in order to make them usable for _ in 0..segment_len{ fat_buffer.write(FAT_ENTRY_FREE_INDEX).ok().unwrap(); } - // while fat_buffer.write(FAT_ENTRY_FREE_INDEX).is_ok() {} fat_buffer.flush(&mut self.disk); - // The root dir cache is flushed at the end of the function + // The root dir cache is written to disk at the end of the write operation } } return ControlFlow::Continue(()); @@ -489,7 +527,7 @@ impl Fat32Fs{ /// The function borrows the vec and returns a slice binded to the vec borrow /// /// ## SAFETY - /// T layout must be known + /// T layout must be known (AKA `repr(C)`) unsafe fn arrayvec_as_buffer<'a, T, const CAP:usize>(vec:&'a ArrayVec)->&'a [u8]{ core::slice::from_raw_parts(vec.as_ptr() as *const u8, vec.len() * core::mem::size_of::()) } From 9bce96fcab6631a7ef7a38c1092a81ceebce2c86 Mon Sep 17 00:00:00 2001 From: alloncm Date: Sat, 4 Jan 2025 20:17:49 +0200 Subject: [PATCH 37/39] More fixes --- rpi/src/drivers/fat32/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/rpi/src/drivers/fat32/mod.rs b/rpi/src/drivers/fat32/mod.rs index 5d9b5a32..27477678 100644 --- a/rpi/src/drivers/fat32/mod.rs +++ b/rpi/src/drivers/fat32/mod.rs @@ -108,7 +108,7 @@ impl FatShortDirEntry{ } // This struct is for support to the long filenames that I will add later -// unused for now +#[allow(unused)] #[derive(Clone, Copy)] #[repr(C,packed)] struct FatLongDirEntry{ @@ -228,8 +228,9 @@ impl Fat32Fs{ disk.read(bpb_sector_index, buffer); let fs_type_label = boot_sector.fs_type_label.clone(); - if &fs_type_label[0..3] != b"FAT"{ - core::panic!("File system is not FAT"); + let fat_magic = &fs_type_label[0..3]; + if fat_magic != b"FAT"{ + core::panic!("File system is not FAT, found magic: {:?}", fat_magic); } if boot_sector.fat32_bpb.sectors_per_fat_16 != 0{ core::panic!("Detected FAT16 and not FAT32 file system"); @@ -281,7 +282,7 @@ impl Fat32Fs{ // Failed Optimization Attempt: I tried to read the files from the root dir, and once I have all the entries abort and mark the rest of the clusters as free // for some reason there were allocated entries on the FAT that I couldn't understand what allocated them and couldn't predict and calculate the expected entries count - // Ill live it like that for now + // Ill leave it like that for now fn init_fat_table_cache(&mut self){ // This buffer is bigger then the default in order to minimize the number of read operations // The value is tweaked for faster reads @@ -447,6 +448,7 @@ impl Fat32Fs{ fn handle_existing_filename(&mut self, name: [u8; 8], extension: [u8; 3], content: &[u8]) -> ControlFlow<()> { if let Some(existing_entry) = self.root_dir_cache.as_mut_slice().into_iter().find(|d|d.file_name == name && d.file_extension == extension){ log::debug!("File already exists, overwriting it"); + // Early return if the existing file is empty (and contain no allocated space) if existing_entry.size == 0 { existing_entry.file_name[0] = DELETED_DIR_ENTRY_PREFIX; return ControlFlow::Continue(()) @@ -465,7 +467,7 @@ impl Fat32Fs{ // 1. if its in the range of the cluster alignment // 2. If its smaller than the required size (can use some of the allocation) // - // This check also verifes that the allocation is continuous, allocation done by this driver are continous but other drivers can allocate differently. + // This check also verifies that the allocation is continuous, allocation done by this driver are continous but other drivers can allocate differently. // If the allocation is not continous the overwrite logic will not work as it assumes continous allocation. // The check done by the fact that it checks for allocated segment for this file allocation // and the if the allocated segment is the len of the file -> the allocation is continous. From 880a90e07d7fdc26222ee75e42cf54d7a8597cee Mon Sep 17 00:00:00 2001 From: alloncm Date: Sun, 5 Jan 2025 15:02:01 +0200 Subject: [PATCH 38/39] Self cr fixes --- rpi/src/bin/baremetal/main.rs | 2 +- rpi/src/drivers/fat32/mod.rs | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/rpi/src/bin/baremetal/main.rs b/rpi/src/bin/baremetal/main.rs index 17871944..e6052322 100644 --- a/rpi/src/bin/baremetal/main.rs +++ b/rpi/src/bin/baremetal/main.rs @@ -67,7 +67,7 @@ pub extern "C" fn main()->!{ log::info!("Initialized gameboy!"); let menu_pin = unsafe {PERIPHERALS.get_gpio().take_pin(MENU_PIN_BCM).into_input(GpioPull::PullUp)}; - let pause_menu_header:ArrayString<30> = ArrayString::try_from(format_args!("MagenBoy bm v{}", VERSION)).unwrap(); + let pause_menu_header:ArrayString<30> = ArrayString::try_from(format_args!("MagenBoy v{}", VERSION)).unwrap(); let pause_menu_renderer = GfxDeviceMenuRenderer::new(&mut pause_menu_gfx); let mut pause_menu = JoypadMenu::new(&GAME_MENU_OPTIONS, pause_menu_header.as_str(), pause_menu_renderer); loop{ diff --git a/rpi/src/drivers/fat32/mod.rs b/rpi/src/drivers/fat32/mod.rs index 27477678..1944fffb 100644 --- a/rpi/src/drivers/fat32/mod.rs +++ b/rpi/src/drivers/fat32/mod.rs @@ -154,6 +154,8 @@ impl FileEntry{ } } +/// Represent a consecutive fat entries with the same value. +/// This is an implementation detail and not defined by the specefications. #[derive(Clone, Debug)] struct FatSegment{ state:FatSegmentState, @@ -200,10 +202,6 @@ impl FatSegmentState{ } } -// Currently the driver support only 0x100 files in the root directory -const MAX_FILES: usize = 0x100; -const MAX_FAT_SEGMENTS_COUNT: usize = MAX_FILES * 100; - pub struct Fat32Fs{ disk: Disk, boot_sector:Fat32BootSector, @@ -211,12 +209,19 @@ pub struct Fat32Fs{ clusters_count:u32, fat_info:FatInfo, - fat_table_cache: ArrayVec, - root_dir_cache: ArrayVec, + fat_table_cache: ArrayVec, + root_dir_cache: ArrayVec, root_dir_allocated_clusters_count: u32, } impl Fat32Fs{ + // Currently the driver support only 0x100 files in the root directory + const MAX_FILES: usize = 0x100; + + // Assuming each file contains at max 2 segments (allocated and eof) and between every 2 files + // there is another free segment I minimized it and added a buffer just in case + const MAX_FAT_SEGMENTS_COUNT: usize = Self::MAX_FILES * 5; + pub fn new()->Self{ let mut disk = Disk::new(); // This driver currently support only a single partition (some has more than one for backup or stuff I don't know) @@ -248,13 +253,15 @@ impl Fat32Fs{ let mut fat32 = Self { fat_info:FatInfo::new( fat_start_sector, boot_sector.fat32_bpb.sectors_per_fat_32 as usize, boot_sector.fat32_bpb.fats_count as usize ), disk, boot_sector, partition_start_sector_index:bpb_sector_index, clusters_count, - fat_table_cache: ArrayVec::::new(), - root_dir_cache: ArrayVec::::new(), + fat_table_cache: ArrayVec::::new(), + root_dir_cache: ArrayVec::::new(), root_dir_allocated_clusters_count: 0 }; fat32.init_root_directory_cache(); fat32.init_fat_table_cache(); + log::info!("Initialized the FAT32 driver"); + return fat32; } From 49084d40ffb92277f900931de711dd19bc00106c Mon Sep 17 00:00:00 2001 From: alloncm Date: Sun, 5 Jan 2025 15:02:20 +0200 Subject: [PATCH 39/39] Remove those for now as they are for nightly 1.84 --- rpi/build.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rpi/build.rs b/rpi/build.rs index f871bdf3..af0f26ae 100644 --- a/rpi/build.rs +++ b/rpi/build.rs @@ -44,11 +44,5 @@ fn main(){ let rpi_version = std::env::var(config::RPI_ENV_VAR_NAME) .expect(std::format!("{} env must be set", config::RPI_ENV_VAR_NAME).as_str()); println!("cargo:rustc-cfg=rpi=\"{}\"", rpi_version); - - // Silent warnings for this cfg - println!("cargo:rustc-check-cfg=cfg(rpi, values(\"4\", \"2\"))"); } - - // Silent warnings for this cfg - println!("cargo:rustc-check-cfg=cfg(rpi)"); } \ No newline at end of file