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)