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.

MethodImplementation PatternKey Characteristics
new()Size alignment + zero-filled vectorAlways succeeds, rounds up to block boundary
from()Copy existing data + size alignmentPreserves input data, pads to block boundary
read_block()Direct slice copy from vectorValidates bounds and block alignment
write_block()Direct slice copy to vectorValidates 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:

AspectRamDiskSDHCIDriver
InitializationAlways succeeds (new(),from())Can fail (try_new()returnsDevResult)
Storage BackendVecin memoryHardware SD card viabcm2835_sdhci
Error HandlingMinimal (only bounds/alignment)Comprehensive error mapping
Buffer RequirementsAny byte-aligned buffer32-bit aligned buffers required
Block SizeFixed 512 bytes (BLOCK_SIZEconstant)Variable (ctrl.get_block_size())
PerformanceSynchronous memory operationsHardware-dependent timing
Use CasesTesting, temporary storageProduction 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)