Block Device Implementations
Relevant source files
This document covers the concrete implementations of block storage devices in the axdriver framework. These implementations demonstrate how the abstract BlockDriverOps trait is realized for different types of storage hardware and virtual devices. For information about the block driver interface and trait definitions, see Block Driver Interface.
The implementations covered include both software-based virtual devices and hardware-specific drivers, showcasing the flexibility of the block driver abstraction layer.
Implementation Overview
The axdriver framework provides two primary block device implementations, each serving different use cases and demonstrating different implementation patterns.
flowchart TD
subgraph subGraph3["Implementation Characteristics"]
RamCharacteristics["• Synchronous operations• No initialization required• Perfect reliability• 512-byte blocks"]
SDHCICharacteristics["• Hardware initialization• Error mapping required• Buffer alignment constraints• Variable block sizes"]
end
subgraph subGraph2["Hardware Implementation"]
SDHCIDriver["SDHCIDriver"]
EmmcCtl["EmmcCtl (from bcm2835_sdhci)"]
SDCardHW["SD Card Hardware"]
end
subgraph subGraph1["Virtual Device Implementation"]
RamDisk["RamDisk"]
VecData["Vec<u8> data"]
MemoryOps["In-memory operations"]
end
subgraph subGraph0["Block Driver Trait System"]
BaseDriverOps["BaseDriverOps"]
BlockDriverOps["BlockDriverOps"]
end
BaseDriverOps --> BlockDriverOps
BlockDriverOps --> RamDisk
BlockDriverOps --> SDHCIDriver
EmmcCtl --> SDCardHW
RamDisk --> MemoryOps
RamDisk --> RamCharacteristics
RamDisk --> VecData
SDHCIDriver --> EmmcCtl
SDHCIDriver --> SDHCICharacteristics
Block Device Implementation Architecture
Sources: axdriver_block/src/ramdisk.rs(L1 - L101) axdriver_block/src/bcm2835sdhci.rs(L1 - L89)
RamDisk Implementation
The RamDisk implementation provides an in-memory block device primarily used for testing and development. It stores all data in a contiguous Vec<u8> and performs all operations synchronously without any possibility of failure.
Core Structure and Initialization
flowchart TD
subgraph subGraph2["Block Operations"]
read_block["read_block()"]
write_block["write_block()"]
num_blocks["num_blocks()"]
block_size["block_size()"]
end
subgraph subGraph1["RamDisk Creation Patterns"]
new["RamDisk::new(size_hint)"]
from["RamDisk::from(buf)"]
default["RamDisk::default()"]
align_up["align_up() function"]
vec_alloc["vec![0; size]"]
subgraph subGraph0["Internal State"]
size_field["size: usize"]
data_field["data: Vec<u8>"]
end
end
align_up --> vec_alloc
data_field --> read_block
data_field --> write_block
from --> align_up
new --> align_up
size_field --> num_blocks
vec_alloc --> data_field
vec_alloc --> size_field
RamDisk Internal Structure and Operations
The RamDisk struct contains two fields: size for the total allocated size and data for the actual storage vector. All operations work directly with this vector using standard slice operations.
| Method | Implementation Pattern | Key Characteristics |
|---|---|---|
| new() | Size alignment + zero-filled vector | Always succeeds, rounds up to block boundary |
| from() | Copy existing data + size alignment | Preserves input data, pads to block boundary |
| read_block() | Direct slice copy from vector | Validates bounds and block alignment |
| write_block() | Direct slice copy to vector | Validates bounds and block alignment |
Sources: axdriver_block/src/ramdisk.rs(L12 - L46) axdriver_block/src/ramdisk.rs(L58 - L96)
Memory Management and Block Operations
The RamDisk implementation uses a fixed block size of 512 bytes and enforces strict alignment requirements:
flowchart TD
subgraph subGraph2["Data Operations"]
ReadOp["buf.copy_from_slice(&self.data[offset..])"]
WriteOp["self.data[offset..].copy_from_slice(buf)"]
end
subgraph subGraph1["Validation Rules"]
BoundsCheck["offset + buf.len() <= self.size"]
AlignmentCheck["buf.len() % BLOCK_SIZE == 0"]
end
subgraph subGraph0["Block Operation Flow"]
ValidateParams["Validate Parameters"]
CheckBounds["Check Bounds"]
CheckAlignment["Check Block Alignment"]
CopyData["Copy Data"]
end
CheckAlignment --> AlignmentCheck
CheckAlignment --> CopyData
CheckBounds --> BoundsCheck
CheckBounds --> CheckAlignment
CopyData --> ReadOp
CopyData --> WriteOp
ValidateParams --> CheckBounds
RamDisk Block Operation Validation and Execution
Sources: axdriver_block/src/ramdisk.rs(L69 - L91) axdriver_block/src/ramdisk.rs(L98 - L100)
SDHCI Implementation
The SDHCIDriver provides access to SD cards on BCM2835-based systems (such as Raspberry Pi). This implementation demonstrates hardware integration patterns and error handling complexity.
Hardware Abstraction and Initialization
flowchart TD
subgraph subGraph2["Driver Wrapper"]
SDHCIDriver_struct["SDHCIDriver(EmmcCtl)"]
deal_sdhci_err["deal_sdhci_err() mapper"]
end
subgraph subGraph1["Hardware Abstraction Layer"]
try_new["SDHCIDriver::try_new()"]
emmc_new["EmmcCtl::new()"]
emmc_init["ctrl.init()"]
bcm2835_sdhci["bcm2835_sdhci crate"]
EmmcCtl_extern["EmmcCtl"]
SDHCIError_extern["SDHCIError"]
BLOCK_SIZE_extern["BLOCK_SIZE constant"]
end
subgraph subGraph0["Initialization Flow"]
try_new["SDHCIDriver::try_new()"]
emmc_new["EmmcCtl::new()"]
emmc_init["ctrl.init()"]
check_result["Check init result"]
success["Ok(SDHCIDriver(ctrl))"]
failure["Err(DevError::Io)"]
bcm2835_sdhci["bcm2835_sdhci crate"]
end
EmmcCtl_extern --> SDHCIDriver_struct
SDHCIError_extern --> deal_sdhci_err
bcm2835_sdhci --> BLOCK_SIZE_extern
bcm2835_sdhci --> EmmcCtl_extern
bcm2835_sdhci --> SDHCIError_extern
check_result --> failure
check_result --> success
emmc_init --> check_result
emmc_new --> emmc_init
try_new --> emmc_new
SDHCI Driver Hardware Integration Architecture
Sources: axdriver_block/src/bcm2835sdhci.rs(L12 - L24) axdriver_block/src/bcm2835sdhci.rs(L26 - L37)
Buffer Alignment and Hardware Operations
The SDHCI implementation requires careful buffer alignment and provides comprehensive error mapping:
flowchart TD
subgraph subGraph2["Hardware Operations"]
read_block_hw["ctrl.read_block(block_id, 1, aligned_buf)"]
write_block_hw["ctrl.write_block(block_id, 1, aligned_buf)"]
get_block_num["ctrl.get_block_num()"]
get_block_size["ctrl.get_block_size()"]
end
subgraph subGraph1["Error Handling Pipeline"]
sdhci_errors["SDHCIError variants"]
deal_sdhci_err_fn["deal_sdhci_err()"]
dev_errors["DevError variants"]
end
subgraph subGraph0["Buffer Alignment Process"]
input_buf["Input buffer: &[u8] or &mut [u8]"]
align_check["buf.align_to::()"]
validate_alignment["Check prefix/suffix empty"]
hardware_call["Call EmmcCtl methods"]
end
align_check --> validate_alignment
deal_sdhci_err_fn --> dev_errors
hardware_call --> get_block_num
hardware_call --> get_block_size
hardware_call --> read_block_hw
hardware_call --> sdhci_errors
hardware_call --> write_block_hw
input_buf --> align_check
sdhci_errors --> deal_sdhci_err_fn
validate_alignment --> hardware_call
SDHCI Buffer Alignment and Hardware Operation Flow
Sources: axdriver_block/src/bcm2835sdhci.rs(L49 - L88)
Implementation Comparison
The two block device implementations demonstrate contrasting approaches to the same abstract interface:
| Aspect | RamDisk | SDHCIDriver |
|---|---|---|
| Initialization | Always succeeds (new(),from()) | Can fail (try_new()returnsDevResult) |
| Storage Backend | Vec | Hardware SD card viabcm2835_sdhci |
| Error Handling | Minimal (only bounds/alignment) | Comprehensive error mapping |
| Buffer Requirements | Any byte-aligned buffer | 32-bit aligned buffers required |
| Block Size | Fixed 512 bytes (BLOCK_SIZEconstant) | Variable (ctrl.get_block_size()) |
| Performance | Synchronous memory operations | Hardware-dependent timing |
| Use Cases | Testing, temporary storage | Production SD card access |
Error Mapping Patterns
flowchart TD
subgraph subGraph2["Common DevError Interface"]
dev_error_unified["DevError enum"]
end
subgraph subGraph1["SDHCI Error Sources"]
sdhci_hardware["Hardware failures"]
sdhci_state["Device state issues"]
sdhci_resources["Resource constraints"]
sdhci_complex["9 distinct SDHCIError variants"]
sdhci_mapped["Mapped to appropriate DevError"]
end
subgraph subGraph0["RamDisk Error Sources"]
ram_bounds["Bounds checking"]
ram_alignment["Block alignment"]
ram_simple["Simple DevError::Io or DevError::InvalidParam"]
end
ram_alignment --> ram_simple
ram_bounds --> ram_simple
ram_simple --> dev_error_unified
sdhci_complex --> sdhci_mapped
sdhci_hardware --> sdhci_complex
sdhci_mapped --> dev_error_unified
sdhci_resources --> sdhci_complex
sdhci_state --> sdhci_complex
Error Handling Strategy Comparison
The error mapping function deal_sdhci_err() provides a complete translation between hardware-specific errors and the unified DevError enum, ensuring consistent error handling across different block device types.
Sources: axdriver_block/src/ramdisk.rs(L69 - L95) axdriver_block/src/bcm2835sdhci.rs(L26 - L37) axdriver_block/src/bcm2835sdhci.rs(L49 - L88)