Remove the last of the Matcha stuff from the tock tree. Change-Id: I6f94241778708ec772e4b711493405a39076b1ee
diff --git a/Cargo.toml b/Cargo.toml index 09c0d5b..4970e92 100644 --- a/Cargo.toml +++ b/Cargo.toml
@@ -42,7 +42,6 @@ "chips/stm32f412g", "chips/stm32f4xx", "kernel", - "libraries/blob_fs", "libraries/enum_primitive", "libraries/riscv-csr", "libraries/tock-cells",
diff --git a/capsules/Cargo.toml b/capsules/Cargo.toml index ce77686..f98c797 100644 --- a/capsules/Cargo.toml +++ b/capsules/Cargo.toml
@@ -7,4 +7,3 @@ [dependencies] kernel = { path = "../kernel" } enum_primitive = { path = "../libraries/enum_primitive" } -blob_fs = { path = "../libraries/blob_fs" }
diff --git a/capsules/src/debug_uart.rs b/capsules/src/debug_uart.rs deleted file mode 100644 index a9ec8a4..0000000 --- a/capsules/src/debug_uart.rs +++ /dev/null
@@ -1,73 +0,0 @@ -//! Trivial capsule to provide minimal debug printing support for userspace. -//! -//! The default TockOS Console class does heavier-weight stuff with UART -//! multiplexing and asynchronous sending and such, which is usually _not_ what -//! is wanted in a debug serial port. This capsule implements only one command, -//! which dumps data from an allow'ed buffer directly to a memory-mapped UART -//! peripheral. -//! -//! Instantiation: -//! let debug_uart = static_init!( -//! DebugUart, -//! DebugUart { -//! tx_busy: StaticRef::new(TX_BUSY_ADDR as *const ReadOnly<u32>), -//! tx_port: StaticRef::new(TX_PORT_ADDR as *const WriteOnly<u32>), -//! app_data_grant: board_kernel.create_grant(&memory_allocation_cap) -//! } -//! ); -//! -//! where TX_BUSY_ADDR is a register whose low bit is 1 if the UART's fifo is -//! full and TX_PORT_ADDR is the register we write bytes to. -//! -//! Usage - send buffer directly to UART: -//! let driver_num = capsules::debug_uart::DRIVER_NUM; -//! let allow = syscalls::allow(driver_num, 0, &mut buffer); -//! let result = syscalls::command(driver_num, 0, buffer.len(), 0); -//! drop(allow); - -use crate::driver; -use kernel::common::registers::{ReadOnly, WriteOnly}; -use kernel::common::StaticRef; -use kernel::{AppId, AppSlice, Callback, Driver, Grant, ReturnCode, Shared}; - -pub const DRIVER_NUM: usize = driver::NUM::DebugUart as usize; - -#[derive(Default)] -pub struct AppData { - pub buffer: Option<AppSlice<Shared, u8>>, -} - -pub struct DebugUart { - pub tx_busy: StaticRef<ReadOnly<u32>>, - pub tx_port: StaticRef<WriteOnly<u32>>, - pub app_data_grant: Grant<AppData>, -} - -impl Driver for DebugUart { - fn subscribe(&self, _: usize, _: Option<Callback>, _: AppId) -> ReturnCode { - ReturnCode::EINVAL - } - - fn command(&self, minor_num: usize, r2: usize, _: usize, app_id: AppId) -> ReturnCode { - if minor_num != 0 { - return ReturnCode::EINVAL; - } - - let _ = self.app_data_grant.enter(app_id, |app_data, _| { - if let Some(buf) = &app_data.buffer { - for i in 0..r2 { - while (self.tx_busy.get() & 1) != 0 {} - self.tx_port.set(buf.as_ref()[i] as u32); - } - } - }); - return ReturnCode::SUCCESS; - } - - fn allow(&self, app_id: AppId, _: usize, slice: Option<AppSlice<Shared, u8>>) -> ReturnCode { - let _ = self.app_data_grant.enter(app_id, |app_data, _| { - app_data.buffer = slice; - }); - return ReturnCode::SUCCESS; - } -}
diff --git a/capsules/src/lib.rs b/capsules/src/lib.rs index c7743f1..1b32616 100644 --- a/capsules/src/lib.rs +++ b/capsules/src/lib.rs
@@ -22,7 +22,6 @@ pub mod crc; pub mod dac; pub mod debug_process_restart; -pub mod debug_uart; pub mod driver; pub mod fm25cl; pub mod ft6x06;
diff --git a/libraries/blob_fs/.gitignore b/libraries/blob_fs/.gitignore deleted file mode 100644 index a9d37c5..0000000 --- a/libraries/blob_fs/.gitignore +++ /dev/null
@@ -1,2 +0,0 @@ -target -Cargo.lock
diff --git a/libraries/blob_fs/Cargo.toml b/libraries/blob_fs/Cargo.toml deleted file mode 100644 index b99aa17..0000000 --- a/libraries/blob_fs/Cargo.toml +++ /dev/null
@@ -1,4 +0,0 @@ -[package] -name = "blob_fs" -version = "0.1.0" -edition = "2018"
diff --git a/libraries/blob_fs/src/bit_vector.rs b/libraries/blob_fs/src/bit_vector.rs deleted file mode 100644 index 336b4a2..0000000 --- a/libraries/blob_fs/src/bit_vector.rs +++ /dev/null
@@ -1,293 +0,0 @@ -use crate::errors::*; -use crate::utils::*; - -pub struct BitVector<'a> { - pub bits: &'a mut [u32], -} - -impl<'a> BitVector<'a> { - pub fn new(bits: &'a mut [u32]) -> Self { - return BitVector { bits: bits }; - } - - pub fn check_pos(&self, pos: usize) -> Result<(), BFSErr> { - dcheck!(pos <= self.bits.len() * 32, BFSErr::OutOfBounds); - return Ok(()); - } - - pub fn check_range(&self, begin: usize, end: usize) -> Result<(), BFSErr> { - self.check_pos(begin)?; - self.check_pos(end)?; - dcheck!(end >= begin, BFSErr::OutOfBounds); - return Ok(()); - } - - pub fn clear_all(&mut self) { - for i in 0..self.bits.len() { - self.bits[i] = 0x00000000; - } - } - - pub fn set_all(&mut self) { - for i in 0..self.bits.len() { - self.bits[i] = 0xFFFFFFFF; - } - } - - pub fn get_bit(&self, pos: usize) -> Result<u32, BFSErr> { - self.check_pos(pos)?; - return Ok((self.bits[pos >> 5] >> (pos & 31)) & 1); - } - - pub fn set_bit(&mut self, pos: usize) -> Result<(), BFSErr> { - self.check_pos(pos)?; - self.bits[pos >> 5] |= 1 << (pos & 31); - return Ok(()); - } - - pub fn clear_bit(&mut self, pos: usize) -> Result<(), BFSErr> { - self.check_pos(pos)?; - self.bits[pos >> 5] &= !(1 << (pos & 31)); - return Ok(()); - } - - fn bit_mask(head: usize, tail: usize) -> Result<u32, BFSErr> { - dcheck!(head < 32, BFSErr::OutOfBounds); - dcheck!(tail < 32, BFSErr::OutOfBounds); - - let a = 0xFFFFFFFF << head; - let b = 0xFFFFFFFF >> (32 - tail - 1); - return Ok(a & b); - } - - pub fn set_range(&mut self, begin: usize, end: usize) -> Result<(), BFSErr> { - self.check_range(begin, end)?; - - let block_head = begin >> 5; - let block_tail = (end - 1) >> 5; - let bit_head = begin & 31; - let bit_tail = (end - 1) & 31; - - if block_head == block_tail { - let mask = BitVector::bit_mask(bit_head, bit_tail)?; - self.bits[block_head as usize] |= mask; - } else { - let mask_head = BitVector::bit_mask(bit_head, 31)?; - self.bits[block_head as usize] |= mask_head; - - for i in block_head + 1..block_tail { - self.bits[i as usize] = 0xFFFFFFFF; - } - - let mask_tail = BitVector::bit_mask(0, bit_tail)?; - self.bits[block_tail as usize] |= mask_tail; - } - - return Ok(()); - } - - pub fn clear_range(&mut self, begin: usize, end: usize) -> Result<(), BFSErr> { - self.check_range(begin, end)?; - - let block_head = begin >> 5; - let block_tail = (end - 1) >> 5; - let bit_head = begin & 31; - let bit_tail = (end - 1) & 31; - - if block_head == block_tail { - let mask = BitVector::bit_mask(bit_head, bit_tail)?; - self.bits[block_head] &= !mask; - } else { - let mask_head = BitVector::bit_mask(bit_head, 31)?; - self.bits[block_head] &= !mask_head; - - for i in block_head + 1..block_tail { - self.bits[i] = 0x00000000; - } - - let mask_tail = BitVector::bit_mask(0, bit_tail)?; - self.bits[block_tail] &= !mask_tail; - } - - return Ok(()); - } - - pub fn count_range(&mut self, begin: usize, end: usize) -> Result<usize, BFSErr> { - self.check_range(begin, end)?; - - let block_head = begin >> 5; - let block_tail = (end - 1) >> 5; - let bit_head = begin & 31; - let bit_tail = (end - 1) & 31; - - let mut count: usize = 0; - - if block_head == block_tail { - let mask = BitVector::bit_mask(bit_head, bit_tail)?; - count += (self.bits[block_head] & mask).count_ones() as usize; - } else { - let mask_head = BitVector::bit_mask(bit_head, 31)?; - count += (self.bits[block_head] & mask_head).count_ones() as usize; - - for i in block_head + 1..block_tail { - count += self.bits[i].count_ones() as usize; - } - - let mask_tail = BitVector::bit_mask(0, bit_tail)?; - count += (self.bits[block_tail] & mask_tail).count_ones() as usize; - } - - return Ok(count); - } - - pub fn find_hole(&self, mut begin: usize, end: usize, width: usize) -> Result<usize, BFSErr> { - self.check_range(begin, end)?; - dcheck!(width <= end - begin, BFSErr::NotFound); - - let mut skip = false; - let mut block_head = begin >> 5; - let block_tail = (end - 1) >> 5; - - while (block_head <= block_tail) && (self.bits[block_head] == 0xFFFFFFFF) { - skip = true; - block_head = block_head + 1; - } - - if block_head > block_tail { - return Err(BFSErr::NotFound); - } - - if skip { - begin = block_head << 5; - } - - for mut i in begin..=(end - width) { - skip = false; - for j in (i..i + width).rev() { - if self.get_bit(j)? == 1 { - i = j + 1; - skip = true; - break; - } - } - if !skip { - return Ok(i); - } - } - - return Err(BFSErr::NotFound); - } - - pub fn find_span(&self, mut begin: usize, end: usize, width: usize) -> Result<usize, BFSErr> { - self.check_range(begin, end)?; - dcheck!(width <= end - begin, BFSErr::NotFound); - - let mut skip = false; - let mut block_head = begin >> 5; - let block_tail = (end - 1) >> 5; - - while (block_head <= block_tail) && (self.bits[block_head] == 0x00000000) { - skip = true; - block_head = block_head + 1; - } - - if block_head > block_tail { - return Err(BFSErr::NotFound); - } - - if skip { - begin = block_head << 5; - } - - for mut i in begin..=(end - width) { - skip = false; - for j in (i..i + width).rev() { - if self.get_bit(j)? == 0 { - i = j + 1; - skip = true; - break; - } - } - if !skip { - return Ok(i); - } - } - - return Err(BFSErr::NotFound); - } -} - -/// For all vector sizes up to <N> and all possible hole sizes & positions in -/// that range, create a vector consisting of set bits outside the hole and -/// cleared bits inside the hole. -/// -/// Verify that findHole() always finds holes equal to or smaller than the one -/// punched and fails to find holes larger than the one punched. -/// -/// (This test is a bit slow, so we limit maximum bit vector size to 96 and run -/// tests in this crate in optimized mode) - -#[test] -fn test_find_hole() { - for size in 1..=96 as usize { - let block_count = (size + 31) / 32; - let mut bits: Vec<u32> = vec![0xFFFFFFFF as u32; block_count]; - let mut bit_vec = BitVector::new(bits.as_mut()); - for width in 1..=size - 1 { - for begin in 0..=(size - width) { - // Punch a hole in the bit vector. - let end = begin + width; - assert_ok!(bit_vec.clear_range(begin, end)); - - // We should be able to find the hole if we look for it. - assert_ok!(bit_vec.find_hole(0, size, width)); - - // We should be able to find a hole smaller than the one we punched. - assert_ok!(bit_vec.find_hole(0, size, width - 1)); - - // If we look for a hole larger than the one we punched, we should - // find nothing. - assert_err!(bit_vec.find_hole(0, size, width + 1)); - - // Fill the hole back up. - bit_vec.set_range(begin, end).unwrap(); - - // We should no longer be able to find it. - assert_err!(bit_vec.find_hole(0, size, width)); - } - } - } -} - -/// Same as above, but set bits (spans) instead of holes. -#[test] -fn test_find_span() { - for size in 1..=96 { - let block_count = (size + 31) / 32; - let mut bits: Vec<u32> = vec![0x00000000 as u32; block_count]; - let mut bit_vec = BitVector::new(bits.as_mut()); - for width in 1..=size - 1 { - for begin in 0..=(size - width) { - // Create a span in the bit vector. - let end = begin + width; - assert_ok!(bit_vec.set_range(begin, end)); - - // We should be able to find the hole if we look for it. - assert_ok!(bit_vec.find_span(0, size, width)); - - // We should be able to find a hole smaller than the one we punched. - assert_ok!(bit_vec.find_span(0, size, width - 1)); - - // If we look for a hole larger than the one we punched, we should - // find nothing. - assert_err!(bit_vec.find_span(0, size, width + 1)); - - // Erase the span - bit_vec.clear_range(begin, end).unwrap(); - - // We should no longer be able to find it. - assert_err!(bit_vec.find_span(0, size, width)); - } - } - } -}
diff --git a/libraries/blob_fs/src/blob_device.rs b/libraries/blob_fs/src/blob_device.rs deleted file mode 100644 index 0a6c48f..0000000 --- a/libraries/blob_fs/src/blob_device.rs +++ /dev/null
@@ -1,206 +0,0 @@ -/// A wrapper around BlockDevice that adds helper methods for navigating a -/// BlobFS filesystem. -use crate::bit_vector::*; -use crate::block_device::*; -use crate::errors::*; -use crate::structs::*; -use crate::utils::*; - -use core::mem; - -pub struct BlobDevice<'a> { - pub bd: &'a mut dyn BlockDevice, -} - -impl<'a> BlobDevice<'a> { - const MAGIC_0: u64 = 0xac2153479e694d21; - const MAGIC_1: u64 = 0x985000d4d4d3d314; - - pub fn new(bd: &'a mut dyn BlockDevice) -> Self { - return BlobDevice { bd: bd }; - } - - pub fn sanity_check(&self) -> Result<(), BFSErr> { - return Ok(()); - } - - /// Base address fetchers - - pub fn superblock_base(&self) -> usize { - return self.bd.geom().block_size * 0; - } - - pub fn blockmap_base(&self) -> usize { - return self.bd.geom().block_size * 1; - } - - pub fn nodemap_base(&self) -> usize { - return self.bd.geom().block_size * 2; - } - - pub fn journal_base(&self) -> usize { - return self.bd.geom().block_size * 3; - } - - pub fn block_base(&self) -> usize { - return self.bd.geom().block_size * 4; - } - - /// Format a whole device to support BlobFS. - - pub fn format(&mut self) -> Result<(), BFSErr> { - // Erase the whole device. - for i in 0..self.bd.geom().block_count { - self.bd.erase_block(i)?; - } - - // Write the initial superblock. - self.format_superblock()?; - - // Write the initial blockmap. - self.format_blockmap()?; - - return Ok(()); - } - - pub fn read_superblock(&self, superblock: &mut Superblock) -> Result<(), BFSErr> { - let blob = as_unsafe_blob_mut(superblock); - self.bd.read_range(0, blob)?; - - // Sanity check the superblock - dcheck!(superblock.magic0 == BlobDevice::MAGIC_0, BFSErr::Corrupt); - dcheck!(superblock.magic1 == BlobDevice::MAGIC_1, BFSErr::Corrupt); - - return Ok(()); - } - - pub fn write_superblock(&mut self, superblock: &Superblock) -> Result<(), BFSErr> { - // Sanity check the superblock - dcheck!(superblock.magic0 == BlobDevice::MAGIC_0, BFSErr::Corrupt); - dcheck!(superblock.magic1 == BlobDevice::MAGIC_1, BFSErr::Corrupt); - - let blob = as_unsafe_blob(superblock); - self.bd.write_range(0, blob)?; - return Ok(()); - } - - pub fn format_superblock(&mut self) -> Result<(), BFSErr> { - let block_size = self.bd.geom().block_size; - let block_count = self.bd.geom().block_count; - - let superblock_count = 1; - let bitmap_block_count = 1; - let node_block_count = 1; - let journal_block_count = 1; - let data_block_count = block_count - - superblock_count - - bitmap_block_count - - node_block_count - - journal_block_count; - - let inodes_per_block = block_size / mem::size_of::<Inode>(); - - // Write the superblock to offset 0 - let superblock = Superblock { - magic0: BlobDevice::MAGIC_0, - magic1: BlobDevice::MAGIC_1, - version: 0, - flags: 0, - block_size: block_size as u32, - unused: 0, - data_block_count: data_block_count as u64, - journal_block_count: journal_block_count as u64, - inode_count: inodes_per_block as u64, - alloc_block_count: 0, - alloc_inode_count: 0, - }; - self.write_superblock(&superblock)?; - return Ok(()); - } - - pub fn format_blockmap(&mut self) -> Result<(), BFSErr> { - let bits: [u8; 1] = [0xF0]; - self.bd.write_range(self.blockmap_base(), &bits)?; - return Ok(()); - } - - pub fn read_blockmap(&self, bitmap: &mut BitVector) -> Result<(), BFSErr> { - self.bd.read_range(self.blockmap_base(), slice_as_unsafe_blob_mut(bitmap.bits))?; - return Ok(()); - } - - pub fn write_blockmap(&mut self, bitmap: &mut BitVector) -> Result<(), BFSErr> { - self.bd.write_range(self.blockmap_base(), slice_as_unsafe_blob(bitmap.bits))?; - return Ok(()); - } - - pub fn read_node_header(&self, index: usize, node: &mut NodeHeader) -> Result<(), BFSErr> { - let base = self.nodemap_base(); - let offset = index * mem::size_of::<Inode>() * index; - let blob = as_unsafe_blob_mut(node); - self.bd.read_range(base + offset, blob)?; - return Ok(()); - } - - pub fn read_inode(&self, index: usize, inode: &mut Inode) -> Result<(), BFSErr> { - let base = self.nodemap_base(); - let offset = index * mem::size_of::<Inode>(); - let blob = as_unsafe_blob_mut(inode); - self.bd.read_range(base + offset, blob)?; - return Ok(()); - } - - pub fn write_inode(&mut self, index: usize, inode: &Inode) -> Result<(), BFSErr> { - dcheck!((inode.header.flags & NodeHeader::FLAG_INODE) != 0, BFSErr::InvalidArg); - let base = self.nodemap_base(); - let offset = index * mem::size_of::<Inode>(); - let blob = as_unsafe_blob(inode); - self.bd.write_range(base + offset, blob)?; - return Ok(()); - } - - /// Invalidate an inode by zeroing out its header. The inode cannot be reused - /// until the block containing it is erased. - pub fn invalidate_inode(&mut self, index: usize) -> Result<(), BFSErr> { - let base = self.nodemap_base(); - let offset = index * mem::size_of::<Inode>(); - let blob = [0; mem::size_of::<NodeHeader>()]; - self.bd.overwrite_range(base + offset, &blob)?; - return Ok(()); - } - - pub fn blob_size_in_blocks(&self, blob: &[u8]) -> u16 { - let block_size = self.bd.geom().block_size; - let result = (blob.len() + block_size + 1) / block_size; - assert!(result < u16::MAX as usize); - return result as u16; - } - - pub fn read_blob(&self, extent: Extent, blob_out: &mut [u8]) -> Result<(), BFSErr> { - let block_size = self.bd.geom().block_size; - let mut cursor = extent.offset(); - for chunk in blob_out.chunks_mut(block_size) { - self.bd.read_block(cursor, chunk)?; - cursor = cursor + 1; - } - return Ok(()); - } - - pub fn write_blob(&mut self, extent: Extent, blob_in: &[u8]) -> Result<(), BFSErr> { - let block_size = self.bd.geom().block_size; - let mut cursor = extent.offset(); - for chunk in blob_in.chunks(block_size) { - self.bd.write_block(cursor, &chunk)?; - cursor = cursor + 1; - } - return Ok(()); - } - - pub fn delete_blob(&mut self, extent: Extent) -> Result<(), BFSErr> { - let offset = extent.offset(); - for i in 0..extent.size as usize { - self.bd.erase_block(offset + i)?; - } - return Ok(()); - } -}
diff --git a/libraries/blob_fs/src/blob_fs.rs b/libraries/blob_fs/src/blob_fs.rs deleted file mode 100644 index 72e72d5..0000000 --- a/libraries/blob_fs/src/blob_fs.rs +++ /dev/null
@@ -1,234 +0,0 @@ -use crate::bit_vector::*; -use crate::blob_device::*; -use crate::block_device::*; -use crate::errors::*; -use crate::structs::*; -use crate::utils::*; - -pub struct BlobFS<'a> { - pub bd: BlobDevice<'a>, - pub superblock: Superblock, - pub blockmap: BitVector<'a>, -} - -// Public impl - -impl<'a> BlobFS<'a> { - pub fn new(bd: &'a mut dyn BlockDevice, blockmap_bits: &'a mut [u32]) -> Self { - let result = BlobFS { - bd: BlobDevice::new(bd), - superblock: Superblock::default(), - blockmap: BitVector::new(blockmap_bits), - }; - - return result; - } - - pub fn format(&mut self) -> Result<(), BFSErr> { - // Format the device. - self.bd.format()?; - - return Ok(()); - } - - pub fn mount(&mut self) -> Result<(), BFSErr> { - // Read the superblock from the device. - self.bd.read_superblock(&mut self.superblock)?; - - // Read the allocation bitmap from the device - self.bd.read_blockmap(&mut self.blockmap)?; - - return Ok(()); - } - - pub fn sanity_check(&self) -> Result<(), BFSErr> { - return Ok(()); - } - - pub fn get_blob_size(&self, hash: u64) -> Result<usize, BFSErr> { - let result = self.find_inode(hash)?; - let inode = result.1; - return Ok(inode.blob_size as usize); - } - - pub fn get_blob(&self, hash: u64, blob_out: &mut [u8]) -> Result<(), BFSErr> { - let result = self.find_inode(hash)?; - let inode = result.1; - dcheck!(inode.blob_size as usize <= blob_out.len(), BFSErr::OutOfBounds); - - let dst = &mut blob_out[..inode.blob_size as usize]; - self.bd.read_blob(inode.inline_extent, dst)?; - - return Ok(()); - } - - pub fn put_blob(&mut self, hash: u64, blob_in: &[u8]) -> Result<(), BFSErr> { - if self.find_inode(hash).is_ok() { - return Err(BFSErr::Duplicate); - } - - let blob_block_count = self.bd.blob_size_in_blocks(blob_in); - - // Find a place to put the blob. - let extent = self.find_extent(blob_block_count)?; - - // Copy the blob to the block device. - self.bd.write_blob(extent, blob_in)?; - - // Set the corresponding bits in our local bitmap - self.blockmap.clear_range(extent.offset(), extent.offset() + extent.size as usize)?; - // FIXME flush bitmap to disk? - - // Create the inode for the new blob - let inode = Inode { - header: NodeHeader { - flags: NodeHeader::FLAG_INODE, - version: 0x0, - next_node: 0xFFFFFFFF, // FIXME - }, - hash0: hash, // FIXME just using 64-bit hash - hash1: hash, - hash2: hash, - hash3: hash, - blob_size: blob_in.len() as u64, - block_count: blob_block_count as u32, - extent_count: 1, - padding: 0xFFFF, - inline_extent: extent, - }; - - // Put the inode in the inode table - let inode_idx = self.find_free_inode()?; - self.bd.write_inode(inode_idx, &inode)?; - - return Ok(()); - } - - pub fn delete_blob(&mut self, hash: u64) -> Result<(), BFSErr> { - let result = self.find_inode(hash)?; - let inode_idx = result.0; - let extent = result.1.inline_extent; - - self.bd.invalidate_inode(inode_idx)?; - self.blockmap.set_range(extent.offset(), extent.offset() + extent.size as usize)?; - self.bd.delete_blob(extent)?; - self.bd.delete_blob(extent)?; - return Ok(()); - } -} - -// Private impl - -impl<'a> BlobFS<'a> { - fn find_inode(&self, hash: u64) -> Result<(usize, Inode), BFSErr> { - for i in 0..self.superblock.inode_count as usize { - let mut inode = Inode::default(); - self.bd.read_inode(i, &mut inode)?; - if inode.header.flags == NodeHeader::FLAG_INODE && inode.hash0 == hash { - return Ok((i, inode)); - } - } - return Err(BFSErr::NotFound); - } - - // FIXME quick and dirty scan entire inode table for empty slot - - fn find_free_inode(&self) -> Result<usize, BFSErr> { - for i in 0..self.superblock.inode_count as usize { - let mut header = NodeHeader::default(); - self.bd.read_node_header(i, &mut header)?; - if header.flags == u16::MAX { - return Ok(i); - } - } - assert!(false); - return Err(BFSErr::NotFound); - } - - #[allow(dead_code)] - fn count_inodes(&self) -> Result<usize, BFSErr> { - let mut count = 0; - for i in 0..self.superblock.inode_count as usize { - let mut header = NodeHeader::default(); - self.bd.read_node_header(i, &mut header)?; - if header.flags == NodeHeader::FLAG_INODE { - count = count + 1; - } - } - return Ok(count); - } - - fn find_extent(&self, blob_block_count: u16) -> Result<Extent, BFSErr> { - let block_count = self.bd.bd.geom().block_count; - let offset = self.blockmap.find_span(0, block_count, blob_block_count as usize)?; - - return Ok(Extent { - size: blob_block_count as u16, - //offset_hi: (offset >> 32) as u16, - offset_hi: 0 as u16, - offset_lo: offset as u32, - }); - } -} - -// Unit tests - -#[test] -fn test_basic() { - use crate::test_device::*; - const BLOCK_SIZE: usize = 8192; - const BLOCK_COUNT: usize = 32; - - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; - let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; - let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; - let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits); - - let mut blockmap_bits: [u32; BLOCK_COUNT / 32] = [0xFFFFFFFF; BLOCK_COUNT / 32]; - - let mut fs = BlobFS::new(bd, blockmap_bits.as_mut()); - - assert_ok!(fs.format()); - assert_ok!(fs.mount()); - assert_ok!(fs.sanity_check()); - - // Block map should start with 4 reserved blocks for metadata - assert_eq!(fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(), BLOCK_COUNT - 4); - - // Store a small blob in the filesystem - let blob_hash: u64 = 0xDEADBEEFF00DCAFE; - let blob_text = "This is the contents of a blob"; - let blob_contents = blob_text.as_bytes(); - assert_ok!(fs.put_blob(blob_hash, blob_contents)); - - // Block map should have lost one free block - assert_eq!(fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(), BLOCK_COUNT - 5); - - // Storing it a second time should fail. - assert_err!(fs.put_blob(blob_hash, blob_contents)); - - // Read it back out - let blob_len = fs.get_blob_size(blob_hash).unwrap(); - let mut blob_contents: Vec<u8> = vec![0; blob_len]; - assert_ok!(fs.get_blob(blob_hash, &mut blob_contents)); - - // Contents should match. - let new_blob_text = core::str::from_utf8(&blob_contents).unwrap(); - assert_eq!(blob_text, new_blob_text); - - // Delete it and lookups should fail - assert_ok!(fs.delete_blob(blob_hash)); - assert_err!(fs.get_blob_size(blob_hash)); - - // Deleting it a second time should also fail. - assert_err!(fs.delete_blob(blob_hash)); - - // Block map should have gained one free block - assert_eq!(fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(), BLOCK_COUNT - 4); - - // Reading a non-existent blob should cause an error - let bad_hash: u64 = 0xAAAAAAAAAAAAAAAA; - assert_err!(fs.get_blob_size(bad_hash)); - let mut blob_contents: [u8; 256] = [0; 256]; - assert_err!(fs.get_blob(bad_hash, &mut blob_contents)); -}
diff --git a/libraries/blob_fs/src/block_device.rs b/libraries/blob_fs/src/block_device.rs deleted file mode 100644 index 71c76f2..0000000 --- a/libraries/blob_fs/src/block_device.rs +++ /dev/null
@@ -1,18 +0,0 @@ -use crate::errors::*; - -#[derive(Debug, Copy, Clone)] -pub struct BlockDeviceGeometry { - pub block_size: usize, - pub block_count: usize, -} - -pub trait BlockDevice { - fn geom(&self) -> BlockDeviceGeometry; - fn read_block(&self, block: usize, block: &mut [u8]) -> Result<(), BFSErr>; - fn write_block(&mut self, block: usize, block: &[u8]) -> Result<(), BFSErr>; - fn erase_block(&mut self, block: usize) -> Result<(), BFSErr>; - - fn read_range(&self, addr: usize, data: &mut [u8]) -> Result<(), BFSErr>; - fn write_range(&mut self, addr: usize, data: &[u8]) -> Result<(), BFSErr>; - fn overwrite_range(&mut self, addr: usize, data: &[u8]) -> Result<(), BFSErr>; -}
diff --git a/libraries/blob_fs/src/errors.rs b/libraries/blob_fs/src/errors.rs deleted file mode 100644 index cf92156..0000000 --- a/libraries/blob_fs/src/errors.rs +++ /dev/null
@@ -1,14 +0,0 @@ -#[derive(Debug, PartialEq)] -pub enum BFSErr { - DeviceErr, // The underlying block device had an error. - NotFound, // The resource was not found. - CleanRead, // Tried to read a byte that had never been written. - DirtyWrite, // Tried to write a byte that had already been written. - OutOfBounds, // Tried to read off the end of the device. - BadOverwrite, // Tried to change a bit from 0->1 without an erase. - BadErase, // Tried to erase a clean block - Corrupt, // Something was corrupt... - Full, // No free blocks left. - Duplicate, // Tried to add a blob that already existed. - InvalidArg, // Bad argument passed to API -}
diff --git a/libraries/blob_fs/src/lib.rs b/libraries/blob_fs/src/lib.rs deleted file mode 100644 index ce93b78..0000000 --- a/libraries/blob_fs/src/lib.rs +++ /dev/null
@@ -1,14 +0,0 @@ -#![cfg_attr(not(test), no_std)] -#![macro_use] - -pub mod bit_vector; -pub mod blob_device; -pub mod blob_fs; -pub mod block_device; -pub mod errors; -pub mod memmap_device; -pub mod structs; -pub mod utils; - -#[cfg(test)] -pub mod test_device;
diff --git a/libraries/blob_fs/src/memmap_device.rs b/libraries/blob_fs/src/memmap_device.rs deleted file mode 100644 index 3e570d5..0000000 --- a/libraries/blob_fs/src/memmap_device.rs +++ /dev/null
@@ -1,276 +0,0 @@ -use crate::block_device::*; -use crate::errors::*; -use crate::utils::*; - -pub struct MemmapDevice { - pub geom: BlockDeviceGeometry, - pub flash_base: *mut u8, -} - -impl MemmapDevice { - pub fn new(geom: BlockDeviceGeometry, flash_base: *mut u8) -> Self { - let result = MemmapDevice { geom: geom, flash_base: flash_base }; - return result; - } -} - -impl MemmapDevice { - pub fn check_is_block_sized(&self, data: &[u8]) -> Result<(), BFSErr> { - dcheck!(data.len() == self.geom.block_size, BFSErr::OutOfBounds); - return Ok(()); - } - - pub fn check_block_index(&self, iblock: usize) -> Result<(), BFSErr> { - dcheck!(iblock < self.geom.block_count, BFSErr::OutOfBounds); - return Ok(()); - } - - pub fn check_fits_in_block(&self, addr: usize, data: &[u8]) -> Result<(), BFSErr> { - let block_a = addr / self.geom.block_size; - let block_b = (addr + data.len() - 1) / self.geom.block_size; - dcheck!(block_a == block_b, BFSErr::OutOfBounds); - return Ok(()); - } - - pub fn check_read_block(&self, iblock: usize, block: &[u8]) -> Result<(), BFSErr> { - self.check_block_index(iblock)?; - self.check_fits_in_block(iblock * self.geom.block_size, block)?; - return Ok(()); - } - - pub fn check_write_block(&self, iblock: usize, block: &[u8]) -> Result<(), BFSErr> { - self.check_block_index(iblock)?; - self.check_fits_in_block(iblock * self.geom.block_size, block)?; - return Ok(()); - } - - pub fn check_erase_block(&self, iblock: usize) -> Result<(), BFSErr> { - self.check_block_index(iblock)?; - return Ok(()); - } - - pub fn check_erase_dirty_block(&self, iblock: usize) -> Result<(), BFSErr> { - self.check_erase_block(iblock)?; - return Ok(()); - } - - pub fn check_range(&self, addr: usize, size: usize) -> Result<(), BFSErr> { - let bs = self.geom.block_size; - let bc = self.geom.block_count; - dcheck!(addr + size < (bc * bs), BFSErr::OutOfBounds); - return Ok(()); - } - - pub fn check_read_range(&self, addr: usize, data: &mut [u8]) -> Result<(), BFSErr> { - self.check_range(addr, data.len())?; - return Ok(()); - } - - pub fn check_write_range(&self, addr: usize, data: &[u8]) -> Result<(), BFSErr> { - self.check_range(addr, data.len())?; - return Ok(()); - } - - /// Check that this overwrite only changes bits from 1->0 - pub fn check_overwrite_range(&self, addr: usize, data: &[u8]) -> Result<(), BFSErr> { - self.check_range(addr, data.len())?; - for i in 0..data.len() { - let src = data[i]; - unsafe { - let dst = self.flash_base.add(addr + i).read(); - dcheck!((src & !dst) == 0, BFSErr::BadOverwrite); - } - } - return Ok(()); - } -} - -impl BlockDevice for MemmapDevice { - fn geom(&self) -> BlockDeviceGeometry { - self.geom - } - - /// Read a chunk of flash contained in a single block. - fn read_block(&self, iblock: usize, block: &mut [u8]) -> Result<(), BFSErr> { - self.check_read_block(iblock, block)?; - - let bs = self.geom.block_size; - unsafe { - self.flash_base.add(iblock * bs).copy_to(block.as_mut_ptr(), block.len()); - } - - return Ok(()); - } - - /// Write a a chunk of flash contained in a single block. - fn write_block(&mut self, iblock: usize, block: &[u8]) -> Result<(), BFSErr> { - self.check_write_block(iblock, block)?; - - let bs = self.geom.block_size; - unsafe { - self.flash_base.add(iblock * bs).copy_from(block.as_ptr(), bs); - } - - return Ok(()); - } - - /// Erase an entire block of flash. - fn erase_block(&mut self, iblock: usize) -> Result<(), BFSErr> { - self.check_erase_block(iblock)?; - - let bs = self.geom.block_size; - unsafe { - self.flash_base.add(iblock * bs).write_bytes(0xFF, bs); - } - - return Ok(()); - } - - /// Read a range of bytes in flash, checking first that those bytes have - /// been written since they were erased. - fn read_range(&self, addr: usize, data: &mut [u8]) -> Result<(), BFSErr> { - self.check_read_range(addr, data)?; - - unsafe { - self.flash_base.add(addr).copy_to(data.as_mut_ptr(), data.len()); - } - - return Ok(()); - } - - /// Write to a range of bytes in flash, checking first that those bytes have - /// not been written since they were erased. - fn write_range(&mut self, addr: usize, data: &[u8]) -> Result<(), BFSErr> { - self.check_write_range(addr, data)?; - - unsafe { - self.flash_base.add(addr).copy_from(data.as_ptr(), data.len()); - } - - return Ok(()); - } - - /// Write to a range of bytes in flash, but _do_ allow writing over dirty - /// bytes - the result in flash will be the logical AND of the old and new - /// data. - fn overwrite_range(&mut self, addr: usize, data: &[u8]) -> Result<(), BFSErr> { - self.check_overwrite_range(addr, data)?; - - unsafe { - for i in 0..data.len() { - let ptr = self.flash_base.add(addr + i); - ptr.write(ptr.read() & data[i]); - } - } - - return Ok(()); - } -} - -/// Overwriting existing data should write the logical AND of the old and new -/// data. - -#[test] -fn test_overwrite() { - let geom = BlockDeviceGeometry { block_size: 16, block_count: 4 }; - let mut buf: Vec<u8> = vec![0; geom.block_count * geom.block_size]; - let bd: &mut dyn BlockDevice = &mut MemmapDevice::new(geom, buf.as_mut_ptr()); - - let write1: u32 = 0xFF0FF0FF; - let write2: u32 = 0x0F00F000; - - assert_ok!(bd.write_range(0, &write1.to_le_bytes())); - assert_ok!(bd.overwrite_range(0, &write2.to_le_bytes())); - - let mut result: u32 = 0; - assert_ok!(bd.read_range(0, as_unsafe_blob_mut(&mut result))); - assert_eq!(result, 0xFF0FF0FF & 0x0FF0FF00); -} - -/// Trying to set bits that have already been cleared by a previous write should -/// cause a panic in the test device. - -#[test] -#[should_panic] -fn test_bad_overwrite() { - let geom = BlockDeviceGeometry { block_size: 16, block_count: 4 }; - let mut buf: Vec<u8> = vec![0; geom.block_count * geom.block_size]; - let bd: &mut dyn BlockDevice = &mut MemmapDevice::new(geom, buf.as_mut_ptr()); - - let all_1: u32 = 0xFFFFFFFF; - let all_0: u32 = 0x00000000; - - assert_ok!(bd.write_range(0, &all_0.to_le_bytes())); - assert_err!(bd.overwrite_range(0, &all_1.to_le_bytes())); -} - -/// Trying to read blocks that have never been written should cause a panic in -/// the test device. - -#[test] -#[should_panic] -fn test_read_unwritten_block() { - let geom = BlockDeviceGeometry { block_size: 16, block_count: 4 }; - let mut buf: Vec<u8> = vec![0; geom.block_count * geom.block_size]; - let bd: &mut dyn BlockDevice = &mut MemmapDevice::new(geom, buf.as_mut_ptr()); - - let mut dst_block = vec![0; geom.block_size]; - assert_err!(bd.read_block(0, &mut dst_block)); -} - -/// Trying to read blocks that have been written and then erased should cause a -/// panic in the test device. - -#[test] -#[should_panic] -fn test_read_erased_block() { - let geom = BlockDeviceGeometry { block_size: 16, block_count: 4 }; - let mut buf: Vec<u8> = vec![0; geom.block_count * geom.block_size]; - let bd: &mut dyn BlockDevice = &mut MemmapDevice::new(geom, buf.as_mut_ptr()); - - let mut src_block = vec![0; geom.block_size]; - let mut dst_block = vec![0; geom.block_size]; - - for i in 0..geom.block_size { - src_block[i] = i as u8; - } - - assert_ok!(bd.write_block(0, &mut src_block)); - assert_ok!(bd.erase_block(0)); - assert_err!(bd.read_block(0, &mut dst_block)); -} - -/// All blocks in a device should be readable and writable. - -#[test] -fn test_read_write() { - let geom = BlockDeviceGeometry { block_size: 16, block_count: 4 }; - let mut buf: Vec<u8> = vec![0; geom.block_count * geom.block_size]; - let bd: &mut dyn BlockDevice = &mut MemmapDevice::new(geom, buf.as_mut_ptr()); - - let mut src_block = vec![0; geom.block_size]; - let mut dst_block = vec![0; geom.block_size]; - - for i in 0..geom.block_size { - src_block[i] = i as u8; - } - - // Writing clean blocks should succeed. - for i in 0..geom.block_count { - assert_ok!(bd.write_block(i, &src_block)); - } - - // Reading those blocks back should succeed, and the contents should match - // the original block. - for i in 0..geom.block_count { - assert_ok!(bd.read_block(i, &mut dst_block)); - for j in 0..geom.block_size { - assert_eq!(src_block[j], dst_block[j]); - } - } - - // Erasing blocks should succeed. - for i in 0..geom.block_count { - assert_ok!(bd.erase_block(i)); - } -}
diff --git a/libraries/blob_fs/src/structs.rs b/libraries/blob_fs/src/structs.rs deleted file mode 100644 index 6bcd1f7..0000000 --- a/libraries/blob_fs/src/structs.rs +++ /dev/null
@@ -1,86 +0,0 @@ -#[repr(C, packed)] -#[derive(Debug, Copy, Clone, Default)] -pub struct Superblock { - pub magic0: u64, - pub magic1: u64, - pub version: u32, - pub flags: u32, - pub block_size: u32, - pub unused: u32, - pub data_block_count: u64, - pub journal_block_count: u64, - pub inode_count: u64, - pub alloc_block_count: u64, - pub alloc_inode_count: u64, -} - -#[repr(C, packed)] -#[derive(Debug, Copy, Clone, Default)] -pub struct Extent { - pub size: u16, - pub offset_hi: u16, - pub offset_lo: u32, -} - -impl Extent { - pub fn offset(&self) -> usize { - //let hi = self.offset_hi as usize; - //let lo = self.offset_lo as usize; - //return (hi << 32) | lo; - return self.offset_lo as usize; - } -} - -#[repr(C, packed)] -#[derive(Debug, Copy, Clone, Default)] -pub struct NodeHeader { - pub flags: u16, - pub version: u16, - pub next_node: u32, -} - -impl NodeHeader { - pub const FLAG_INODE: u16 = 0b0000000000000001; - pub const FLAG_EXTENT: u16 = 0b0000000000000010; -} - -#[repr(C, packed)] -#[derive(Debug, Copy, Clone, Default)] -pub struct Inode { - pub header: NodeHeader, - pub hash0: u64, - pub hash1: u64, - pub hash2: u64, - pub hash3: u64, - pub blob_size: u64, - pub block_count: u32, - pub extent_count: u16, - pub padding: u16, - pub inline_extent: Extent, -} - -#[repr(C, packed)] -#[derive(Debug, Copy, Clone)] -pub struct ExtentContainer { - pub header: NodeHeader, - pub previous_node: u32, - pub extent_count: u16, - pub reserved: u16, - pub extents: [Extent; 6], -} - -#[repr(C, packed)] -#[derive(Debug, Copy, Clone)] -pub struct Transaction { - pub op: u16, - pub size: u16, - pub addr: u32, -} - -#[test] -fn size_check() { - use core::mem::*; - assert_eq!(size_of::<Extent>(), 8); - assert_eq!(size_of::<Inode>(), 64); - assert_eq!(size_of::<ExtentContainer>(), 64); -}
diff --git a/libraries/blob_fs/src/test_device.rs b/libraries/blob_fs/src/test_device.rs deleted file mode 100644 index 69fbf2e..0000000 --- a/libraries/blob_fs/src/test_device.rs +++ /dev/null
@@ -1,341 +0,0 @@ -use crate::bit_vector::*; -use crate::block_device::*; -use crate::errors::*; -use crate::utils::*; - -pub struct TestDevice<'a> { - pub geom: BlockDeviceGeometry, - pub flash_base: *mut u8, - pub dirty: BitVector<'a>, -} - -impl<'a> TestDevice<'a> { - pub fn new(geom: BlockDeviceGeometry, flash_base: *mut u8, dirty_bits: &'a mut [u32]) -> Self { - assert_eq!(geom.block_size * geom.block_count, dirty_bits.len() * 32); - let result = - TestDevice { geom: geom, flash_base: flash_base, dirty: BitVector::new(dirty_bits) }; - return result; - } - - pub fn dirty_count(&self, addr: usize, size: usize) -> Result<usize, BFSErr> { - let mut result: usize = 0; - for i in addr..addr + size { - result += self.dirty.get_bit(i)? as usize; - } - return Ok(result); - } - - pub fn mark_dirty(&mut self, addr: usize, size: usize) -> Result<(), BFSErr> { - self.dirty.set_range(addr, addr + size)?; - return Ok(()); - } - - pub fn mark_clean(&mut self, addr: usize, size: usize) -> Result<(), BFSErr> { - self.dirty.clear_range(addr, addr + size)?; - return Ok(()); - } -} - -/// Preconditions for TestDevice. -/// FIXME - I loosened these up because they were annoying, not sure how strict -/// we should be... - -impl<'a> TestDevice<'a> { - pub fn check_dirty(&self, addr: usize, size: usize) -> Result<(), BFSErr> { - for i in addr..addr + size { - dcheck!(self.dirty.get_bit(i)? == 1, BFSErr::CleanRead); - } - return Ok(()); - } - - pub fn check_clean(&self, addr: usize, size: usize) -> Result<(), BFSErr> { - for i in addr..addr + size { - dcheck!(self.dirty.get_bit(i)? == 0, BFSErr::DirtyWrite); - } - return Ok(()); - } - - pub fn check_is_block_sized(&self, data: &[u8]) -> Result<(), BFSErr> { - dcheck!(data.len() == self.geom.block_size, BFSErr::OutOfBounds); - return Ok(()); - } - - pub fn check_block_index(&self, iblock: usize) -> Result<(), BFSErr> { - dcheck!(iblock < self.geom.block_count, BFSErr::OutOfBounds); - return Ok(()); - } - - pub fn check_fits_in_block(&self, addr: usize, data: &[u8]) -> Result<(), BFSErr> { - let block_a = addr / self.geom.block_size; - let block_b = (addr + data.len() - 1) / self.geom.block_size; - dcheck!(block_a == block_b, BFSErr::OutOfBounds); - return Ok(()); - } - - pub fn check_read_block(&self, iblock: usize, block: &[u8]) -> Result<(), BFSErr> { - self.check_block_index(iblock)?; - self.check_fits_in_block(iblock * self.geom.block_size, block)?; - //self.check_dirty(iblock * self.geom.block_size, block.len())?; - return Ok(()); - } - - pub fn check_write_block(&self, iblock: usize, block: &[u8]) -> Result<(), BFSErr> { - self.check_block_index(iblock)?; - self.check_fits_in_block(iblock * self.geom.block_size, block)?; - self.check_clean(iblock * self.geom.block_size, block.len())?; - return Ok(()); - } - - pub fn check_erase_block(&self, iblock: usize) -> Result<(), BFSErr> { - self.check_block_index(iblock)?; - return Ok(()); - } - - pub fn check_erase_dirty_block(&self, iblock: usize) -> Result<(), BFSErr> { - self.check_erase_block(iblock)?; - let dirty_count = self.dirty_count(iblock * self.geom.block_size, self.geom.block_size)?; - dcheck!(dirty_count > 0, BFSErr::BadErase); - return Ok(()); - } - - pub fn check_range(&self, addr: usize, size: usize) -> Result<(), BFSErr> { - let bs = self.geom.block_size; - let bc = self.geom.block_count; - dcheck!(addr + size < (bc * bs), BFSErr::OutOfBounds); - return Ok(()); - } - - pub fn check_read_range(&self, addr: usize, data: &mut [u8]) -> Result<(), BFSErr> { - self.check_range(addr, data.len())?; - //self.check_dirty(addr, data.len())?; - return Ok(()); - } - - pub fn check_write_range(&self, addr: usize, data: &[u8]) -> Result<(), BFSErr> { - self.check_range(addr, data.len())?; - self.check_clean(addr, data.len())?; - return Ok(()); - } - - /// Check that this overwrite only changes bits from 1->0 - pub fn check_overwrite_range(&self, addr: usize, data: &[u8]) -> Result<(), BFSErr> { - self.check_range(addr, data.len())?; - for i in 0..data.len() { - let src = data[i]; - unsafe { - let dst = self.flash_base.add(addr + i).read(); - dcheck!((src & !dst) == 0, BFSErr::BadOverwrite); - } - } - return Ok(()); - } -} - -impl<'a> BlockDevice for TestDevice<'a> { - fn geom(&self) -> BlockDeviceGeometry { - self.geom - } - - /// Read a chunk of flash contained in a single block. - fn read_block(&self, iblock: usize, block: &mut [u8]) -> Result<(), BFSErr> { - self.check_read_block(iblock, block)?; - - let bs = self.geom.block_size; - unsafe { - self.flash_base.add(iblock * bs).copy_to(block.as_mut_ptr(), block.len()); - } - - return Ok(()); - } - - /// Write a a chunk of flash contained in a single block. - fn write_block(&mut self, iblock: usize, block: &[u8]) -> Result<(), BFSErr> { - self.check_write_block(iblock, block)?; - - let bs = self.geom.block_size; - unsafe { - self.flash_base.add(iblock * bs).copy_from(block.as_ptr(), bs); - } - - self.mark_dirty(iblock * bs, bs)?; - return Ok(()); - } - - /// Erase an entire block of flash. - fn erase_block(&mut self, iblock: usize) -> Result<(), BFSErr> { - self.check_erase_block(iblock)?; - - let bs = self.geom.block_size; - self.mark_clean(iblock * bs, bs)?; - unsafe { - self.flash_base.add(iblock * bs).write_bytes(0xFF, bs); - } - - return Ok(()); - } - - /// Read a range of bytes in flash, checking first that those bytes have - /// been written since they were erased. - fn read_range(&self, addr: usize, data: &mut [u8]) -> Result<(), BFSErr> { - self.check_read_range(addr, data)?; - - unsafe { - self.flash_base.add(addr).copy_to(data.as_mut_ptr(), data.len()); - } - - return Ok(()); - } - - /// Write to a range of bytes in flash, checking first that those bytes have - /// not been written since they were erased. - fn write_range(&mut self, addr: usize, data: &[u8]) -> Result<(), BFSErr> { - self.check_write_range(addr, data)?; - - unsafe { - self.flash_base.add(addr).copy_from(data.as_ptr(), data.len()); - } - - self.mark_dirty(addr, data.len())?; - return Ok(()); - } - - /// Write to a range of bytes in flash, but _do_ allow writing over dirty - /// bytes - the result in flash will be the logical AND of the old and new - /// data. - fn overwrite_range(&mut self, addr: usize, data: &[u8]) -> Result<(), BFSErr> { - self.check_overwrite_range(addr, data)?; - - unsafe { - for i in 0..data.len() { - let ptr = self.flash_base.add(addr + i); - ptr.write(ptr.read() & data[i]); - } - } - - self.mark_dirty(addr, data.len())?; - return Ok(()); - } -} - -/// Overwriting existing data should write the logical AND of the old and new -/// data. - -#[test] -fn test_overwrite() { - const BLOCK_SIZE: usize = 16; - const BLOCK_COUNT: usize = 4; - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; - let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; - let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; - let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits); - - let write1: u32 = 0xFF0FF0FF; - let write2: u32 = 0x0F00F000; - - assert_ok!(bd.write_range(0, &write1.to_le_bytes())); - assert_ok!(bd.overwrite_range(0, &write2.to_le_bytes())); - - let mut result: u32 = 0; - assert_ok!(bd.read_range(0, as_unsafe_blob_mut(&mut result))); - assert_eq!(result, 0xFF0FF0FF & 0x0FF0FF00); -} - -/// Trying to set bits that have already been cleared by a previous write should -/// cause a panic in the test device. - -#[test] -#[should_panic] -fn test_bad_overwrite() { - const BLOCK_SIZE: usize = 16; - const BLOCK_COUNT: usize = 4; - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; - let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; - let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; - let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits); - - let all_1: u32 = 0xFFFFFFFF; - let all_0: u32 = 0x00000000; - - assert_ok!(bd.write_range(0, &all_0.to_le_bytes())); - assert_err!(bd.overwrite_range(0, &all_1.to_le_bytes())); -} - -/// Trying to read blocks that have never been written should cause a panic in -/// the test device. - -#[test] -#[should_panic] -fn test_read_unwritten_block() { - const BLOCK_SIZE: usize = 16; - const BLOCK_COUNT: usize = 4; - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; - let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; - let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; - let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits); - - let mut dst_block = [0; BLOCK_SIZE]; - assert_err!(bd.read_block(0, &mut dst_block)); -} - -/// Trying to read blocks that have been written and then erased should cause a -/// panic in the test device. - -#[test] -#[should_panic] -fn test_read_erased_block() { - const BLOCK_SIZE: usize = 16; - const BLOCK_COUNT: usize = 4; - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; - let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; - let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; - let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits); - - let mut src_block = [0; BLOCK_SIZE]; - let mut dst_block = [0; BLOCK_SIZE]; - - for i in 0..geom.block_size { - src_block[i] = i as u8; - } - - assert_ok!(bd.write_block(0, &mut src_block)); - assert_ok!(bd.erase_block(0)); - assert_err!(bd.read_block(0, &mut dst_block)); -} - -/// All blocks in a device should be readable and writable. - -#[test] -fn test_read_write() { - const BLOCK_SIZE: usize = 16; - const BLOCK_COUNT: usize = 4; - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; - let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; - let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; - let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits); - - let mut src_block = [0; BLOCK_SIZE]; - let mut dst_block = [0; BLOCK_SIZE]; - - for i in 0..geom.block_size { - src_block[i] = i as u8; - } - - // Writing clean blocks should succeed. - for i in 0..geom.block_count { - assert_ok!(bd.write_block(i, &src_block)); - } - - // Reading those blocks back should succeed, and the contents should match - // the original block. - for i in 0..geom.block_count { - assert_ok!(bd.read_block(i, &mut dst_block)); - for j in 0..geom.block_size { - assert_eq!(src_block[j], dst_block[j]); - } - } - - // Erasing blocks should succeed. - for i in 0..geom.block_count { - assert_ok!(bd.erase_block(i)); - } -}
diff --git a/libraries/blob_fs/src/utils.rs b/libraries/blob_fs/src/utils.rs deleted file mode 100644 index e0c9814..0000000 --- a/libraries/blob_fs/src/utils.rs +++ /dev/null
@@ -1,88 +0,0 @@ -use core::mem; -use core::slice; - -/// Trigger an assertion if "cond" fails in debug builds, return an error in -/// release builds. -macro_rules! dcheck { - ($cond:expr, $err:expr) => { - let cond = $cond; - debug_assert!(cond); - if !(cond) { - return Err($err); - } - }; -} -pub(crate) use dcheck; - -/// Assert that a Result is_ok(). Why is this not in the standard library? -#[cfg(test)] -macro_rules! assert_ok { - ($cond:expr) => { - let result = $cond; - assert!(result.is_ok()); - }; -} -#[cfg(test)] -pub(crate) use assert_ok; - -/// Assert that a Result is_err(). Why is this not in the standard library? -#[cfg(test)] -macro_rules! assert_err { - ($cond:expr) => { - let result = $cond; - assert!(result.is_err()); - }; -} -#[cfg(test)] -pub(crate) use assert_err; - -// FIXME these are quick and dirty hacks to make serialization of POD types -// easier - -pub fn as_unsafe_blob<T: Sized>(p: &T) -> &[u8] { - unsafe { - let tp: *const T = p as *const T; - let pp: *const u8 = tp as *const u8; - slice::from_raw_parts(pp, mem::size_of::<T>()) - } -} - -pub fn as_unsafe_blob_mut<T: Sized>(p: &mut T) -> &mut [u8] { - unsafe { - let tp: *mut T = p as *mut T; - let pp: *mut u8 = tp as *mut u8; - slice::from_raw_parts_mut(pp, mem::size_of::<T>()) - } -} - -pub fn from_unsafe_blob<T: Sized>(p: &[u8]) -> &T { - unsafe { - let pp: *const u8 = p.as_ptr(); - let tp: *const T = pp as *const T; - return &*tp; - } -} - -pub fn from_unsafe_blob_mut<T: Sized>(p: &mut [u8]) -> &mut T { - unsafe { - let pp: *mut u8 = p.as_mut_ptr(); - let tp: *mut T = pp as *mut T; - return &mut *tp; - } -} - -pub fn slice_as_unsafe_blob_mut<T: Sized>(p: &mut [T]) -> &mut [u8] { - unsafe { - let tp: *mut T = p.as_mut_ptr(); - let pp: *mut u8 = tp as *mut u8; - slice::from_raw_parts_mut(pp, mem::size_of::<T>()) - } -} - -pub fn slice_as_unsafe_blob<T: Sized>(p: &[T]) -> &[u8] { - unsafe { - let tp: *const T = p.as_ptr(); - let pp: *const u8 = tp as *const u8; - slice::from_raw_parts(pp, mem::size_of::<T>()) - } -}