diff --git a/Cargo.lock b/Cargo.lock index c325744907..5d201fb9dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,7 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "block-io-wrapper 0.1.0", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", @@ -65,6 +66,10 @@ name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "block-io-wrapper" +version = "0.1.0" + [[package]] name = "build_const" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index b871350843..8ec096c08a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "ahcid", "alxd", "bgad", + "block-io-wrapper", "e1000d", "ihdad", "ixgbed", @@ -13,5 +14,5 @@ members = [ "rtl8168d", "vboxd", "vesad", - "xhcid" + "xhcid", ] diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index bfd9f21315..458d8cac56 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -8,3 +8,4 @@ bitflags = "1.2" byteorder = "1.2" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } redox_syscall = "0.1" +block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 1e13a744f3..3e87040b61 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -50,77 +50,40 @@ impl DiskWrapper { Ok(self.offset) } } - // Perhaps this impl should be used in the rest of the scheme. + // TODO: Perhaps this impl should be used in the rest of the scheme. impl<'a, 'b> Read for Device<'a, 'b> { - fn read(&mut self, mut buf: &mut [u8]) -> io::Result { - // TODO: Yield sometimes, perhaps after a few blocks or something. - use std::ops::{Add, Div, Rem}; - - fn div_round_up(a: T, b: T) -> T - where - T: Add + Div + Rem + PartialEq + From + Copy - { - if a % b != T::from(0u8) { - a / b + T::from(1u8) - } else { - a / b - } - } - - let orig_buf_len = buf.len(); - + fn read(&mut self, buf: &mut [u8]) -> io::Result { let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?; + let size_in_blocks = self.disk.size() / u64::from(blksize); - let start_block = self.offset / u64::from(blksize); - let end_block = div_round_up(self.offset + buf.len() as u64, u64::from(blksize)); // The first block not in the range + let disk = &mut self.disk; - let offset_from_start_block: u64 = self.offset % u64::from(blksize); - let offset_to_end_block: u64 = u64::from(blksize) - (self.offset + buf.len() as u64) % u64::from(blksize); - - let first_whole_block = start_block + if offset_from_start_block > 0 { 1 } else { 0 }; - let last_whole_block = end_block - if offset_to_end_block > 0 { 1 } else { 0 } - 1; - - let whole_blocks_to_read = last_whole_block - first_whole_block + 1; - - for block in start_block..end_block { - // TODO: Async/await? I mean, shouldn't AHCI be async? - - loop { - let block = self.offset / u64::from(blksize); - - match self.disk.read(block, self.block_bytes) { - Ok(Some(bytes)) => { - assert_eq!(bytes, self.block_bytes.len()); - assert_eq!(bytes, blksize as usize); - break; - } - Ok(None) => continue, - Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), - } + let read_block = |block: u64, block_bytes: &mut [u8]| { + if block >= size_in_blocks { + return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); } + loop { + match disk.read(block, block_bytes) { + Ok(Some(bytes)) => { + assert_eq!(bytes, block_bytes.len()); + assert_eq!(bytes, blksize as usize); + return Ok(()); + } + Ok(None) => continue, + Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), + } + } + }; + let bytes_read = block_io_wrapper::read(self.offset, blksize, buf, self.block_bytes, read_block)?; - let (bytes_to_read, src_buf): (u64, &[u8]) = if block == start_block { - (u64::from(blksize) - offset_from_start_block, &self.block_bytes[offset_from_start_block as usize..]) - } else if block == end_block { - (u64::from(blksize) - offset_to_end_block, &self.block_bytes[..offset_to_end_block as usize]) - } else { - (blksize.into(), &self.block_bytes[..]) - }; - let bytes_to_read = std::cmp::min(bytes_to_read as usize, buf.len()); - buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]); - buf = &mut buf[..bytes_to_read]; - } - - let bytes_read = std::cmp::min(orig_buf_len, whole_blocks_to_read as usize * blksize as usize + offset_from_start_block as usize + offset_to_end_block as usize); self.offset += bytes_read as u64; - Ok(bytes_read) } } let mut block_bytes = [0u8; 4096]; - partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() + partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).map_err(|x| dbg!(x)).ok().flatten() } fn new(mut disk: Box) -> Self { Self { diff --git a/block-io-wrapper/.gitignore b/block-io-wrapper/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/block-io-wrapper/.gitignore @@ -0,0 +1 @@ +/target diff --git a/block-io-wrapper/Cargo.toml b/block-io-wrapper/Cargo.toml new file mode 100644 index 0000000000..e40054ccf1 --- /dev/null +++ b/block-io-wrapper/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "block-io-wrapper" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/block-io-wrapper/src/lib.rs b/block-io-wrapper/src/lib.rs new file mode 100644 index 0000000000..6556067d42 --- /dev/null +++ b/block-io-wrapper/src/lib.rs @@ -0,0 +1,47 @@ +pub fn read(offset: u64, blksize: u32, mut buf: &mut [u8], block_bytes: &mut [u8], mut read: impl FnMut(u64, &mut [u8]) -> Result<(), E>) -> Result { + // TODO: Yield sometimes, perhaps after a few blocks or something. + use std::ops::{Add, Div, Rem}; + + fn div_round_up(a: T, b: T) -> T + where + T: Add + Div + Rem + PartialEq + From + Copy + { + if a % b != T::from(0u8) { + a / b + T::from(1u8) + } else { + a / b + } + } + + let orig_buf_len = buf.len(); + + let start_block = offset / u64::from(blksize); + let end_block = div_round_up(offset + buf.len() as u64, u64::from(blksize)); // The first block not in the range + + let offset_from_start_block: u64 = offset % u64::from(blksize); + let offset_to_end_block: u64 = u64::from(blksize) - (offset + buf.len() as u64) % u64::from(blksize); + + let first_whole_block = start_block + if offset_from_start_block > 0 { 1 } else { 0 }; + let last_whole_block = end_block - if offset_to_end_block > 0 { 1 } else { 0 } - 1; + + let whole_blocks_to_read = last_whole_block - first_whole_block + 1; + + for block in start_block..=end_block { + // TODO: Async/await? I mean, shouldn't AHCI be async? + + read(block, block_bytes)?; + + let (bytes_to_read, src_buf): (u64, &[u8]) = if block == start_block { + (u64::from(blksize) - offset_from_start_block, &block_bytes[offset_from_start_block as usize..]) + } else if block == end_block { + (u64::from(blksize) - offset_to_end_block, &block_bytes[..offset_to_end_block as usize]) + } else { + (blksize.into(), &block_bytes[..]) + }; + let bytes_to_read = std::cmp::min(bytes_to_read as usize, buf.len()); + buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]); + buf = &mut buf[bytes_to_read..]; + } + + Ok(std::cmp::min(orig_buf_len, whole_blocks_to_read as usize * blksize as usize + offset_from_start_block as usize + offset_to_end_block as usize)) +}