Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions driver/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ build_rust("blueos_driver") {
deps = [
"//external/vendor/bitflags-2.10.0:bitflags",
"//external/vendor/cfg-if-1.0.4:cfg_if",
"//external/vendor/embedded-hal-1.0.0:embedded_hal",
"//external/vendor/safe-mmio-0.2.5:safe_mmio",
"//external/vendor/spin-0.9.8:spin",
"//external/vendor/tock-registers-0.9.0:tock_registers",
Expand Down
1 change: 1 addition & 0 deletions driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#![feature(const_nonnull_new)]

pub mod clock_control;
pub mod gpio;
pub mod hwinfo;
pub mod gpio;
pub mod i2c;
Expand Down
3 changes: 3 additions & 0 deletions kconfig/config/qemu_virt64_aarch64/coverage/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ CONFIG_DNS_MAX_RESULT_COUNT=1
CONFIG_DNS_MAX_SERVER_COUNT=1
# end of smoltcp TCP/IP Stack Configuration

CONFIG_ENABLE_BLOCK=y
CONFIG_FATFS=y

#
# os adapter configuration
#
Expand Down
3 changes: 3 additions & 0 deletions kconfig/config/qemu_virt64_aarch64/debug/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ CONFIG_DNS_MAX_RESULT_COUNT=1
CONFIG_DNS_MAX_SERVER_COUNT=1
# end of smoltcp TCP/IP Stack Configuration

CONFIG_ENABLE_BLOCK=y
CONFIG_FATFS=y

#
# os adapter configuration
#
Expand Down
3 changes: 3 additions & 0 deletions kconfig/config/qemu_virt64_aarch64/release/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ CONFIG_DNS_MAX_RESULT_COUNT=1
CONFIG_DNS_MAX_SERVER_COUNT=1
# end of smoltcp TCP/IP Stack Configuration

CONFIG_ENABLE_BLOCK=y
CONFIG_FATFS=y

#
# os adapter configuration
#
Expand Down
2 changes: 2 additions & 0 deletions kconfig/config/seeed_xiao_esp32c3/debug/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ CONFIG_SERIAL_TX_FIFO_SIZE=256
CONFIG_ENABLE_VFS=y
CONFIG_ENABLE_NET=n
CONFIG_PROCFS=n
CONFIG_ENABLE_BLOCK=y
CONFIG_FATFS=y
CONFIG_UNITTEST_THREAD_NUM=16
2 changes: 2 additions & 0 deletions kconfig/config/seeed_xiao_esp32c3/release/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ CONFIG_SERIAL_TX_FIFO_SIZE=256
CONFIG_ENABLE_VFS=y
CONFIG_ENABLE_NET=n
CONFIG_PROCFS=n
CONFIG_ENABLE_BLOCK=y
CONFIG_FATFS=y
CONFIG_UNITTEST_THREAD_NUM=16
9 changes: 9 additions & 0 deletions kernel/src/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ config THREAD_STATS
default n
bool "Enable statistics of thread"

config ENABLE_BLOCK
default n
bool "Enable block device support"

config FATFS
default n
bool "Enable FAT filesystem"
depends on ENABLE_BLOCK

# os adapter configuration
menu "os adapter configuration"
choice
Expand Down
9 changes: 9 additions & 0 deletions kernel/src/boards/qemu_virt64_aarch64/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ pub const DRAM_BASE: usize = mmu::kernel_phys_to_virt(0x4000_0000);

crate::define_pin_states!(None);

#[cfg(fatfs)]
pub const BLOCK_STORAGE_DEVICE_NAME: &str = "virt-storage";
#[cfg(fatfs)]
pub const BLOCK_STORAGE_MOUNT_POINT: &str = "fat";

// virtio block device is registered in virtio::init_virtio(); no extra init.
#[cfg(enable_block)]
pub(crate) fn init_block_devices() {}

pub struct TimerIrq;
impl IsrDesc for TimerIrq {
fn service_isr(&self) {
Expand Down
34 changes: 34 additions & 0 deletions kernel/src/boards/seeed_xiao_esp32c3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,44 @@ crate::define_peripheral! {
blueos_driver::uart::esp32_usb_serial::Esp32UsbSerial::new()),
(intc, blueos_driver::interrupt_controller::esp32_intc::Esp32Intc,
blueos_driver::interrupt_controller::esp32_intc::Esp32Intc::new(0x600c_2000)),
(spi2, blueos_driver::spi::esp32_spi2::Esp32Spi2,
blueos_driver::spi::esp32_spi2::Esp32Spi2::new()),
}

crate::define_pin_states!(None);

pub const BLOCK_STORAGE_DEVICE_NAME: &str = "flash-storage";
pub const BLOCK_STORAGE_MOUNT_POINT: &str = "data";

#[cfg(enable_block)]
pub(crate) fn init_block_devices() {
use crate::devices::{spi_core::block_spi::BlockSpiBus, storage::spi_flash};
use blueos_driver::{
gpio::esp32_gpio::Esp32GpioOutputPin, pinctrl::esp32_pinctrl::Esp32IoMuxPinctrl,
};
use blueos_hal::pinctrl::AlterFuncPin;
use embedded_hal_bus::spi::ExclusiveDevice;

// SPI2 pins: SCK=GPIO8, MISO=GPIO9, MOSI=GPIO10, CS=GPIO5.
const PIN_STATES: [Esp32IoMuxPinctrl; 4] = [
Esp32IoMuxPinctrl::new(8, 1, false, false, false, 2, Some(63), None, false), // SCK
Esp32IoMuxPinctrl::new(9, 1, true, false, false, 2, None, Some(64), false), // MISO
Esp32IoMuxPinctrl::new(10, 1, false, false, false, 2, Some(65), None, false), // MOSI
Esp32IoMuxPinctrl::new(5, 1, false, true, false, 2, None, None, true), // CS
];
for pin in PIN_STATES {
pin.init();
}

let spi2 = get_device!(spi2);
let bus = BlockSpiBus::new(spi2).expect("Failed to configure SPI2 for flash");
let cs = Esp32GpioOutputPin::<5>::new();
let spi_dev = ExclusiveDevice::new(bus, cs, crate::sync::KernelDelay)
.expect("Failed to create SPI flash device");
spi_flash::init_spi_flash(spi_dev, BLOCK_STORAGE_DEVICE_NAME)
.expect("SPI flash initialization failed");
}

#[inline(always)]
pub(crate) fn send_ipi(_hart: usize) {}

Expand Down
2 changes: 2 additions & 0 deletions kernel/src/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ extern "C" fn init() {
net::init();
net::net_manager::init();
}
#[cfg(enable_block)]
boards::init_block_devices();
#[cfg(enable_vfs)]
init_vfs();
// it's an bug in fact, but at now we use a workaround let newlib do the c++ runtime initialization
Expand Down
104 changes: 99 additions & 5 deletions kernel/src/devices/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,37 @@
// limitations under the License.

use crate::{
devices::{virtio::VirtioHal, Device, DeviceClass, DeviceId, DeviceManager},
devices::{Device, DeviceClass, DeviceId, DeviceManager},
sync::SpinLock,
};
use alloc::{string::String, sync::Arc, vec};
use core::cmp::min;
use embedded_io::{Error as IOError, ErrorKind};

#[cfg(enable_block)]
use crate::devices::storage::spi_flash::FlashBlockError;
#[cfg(enable_block)]
use crate::devices::storage::spi_flash_cmd::FlashError;

#[cfg(virtio)]
use crate::devices::virtio::VirtioHal;
#[cfg(virtio)]
use virtio_drivers::{
device::blk::{VirtIOBlk, SECTOR_SIZE},
transport::SomeTransport,
Hal,
};

#[cfg(virtio)]
pub const VIRTUAL_STORAGE_NAME: &str = "virt-storage";

#[derive(Debug, Clone, Eq, PartialEq, thiserror::Error)]
pub enum BlockError<T> {
#[error("Error from the drviver: {0}")]
#[error("Error from the driver: {0}")]
Driver(#[from] T),
}

#[cfg(virtio)]
impl embedded_io::Error for BlockError<virtio_drivers::Error> {
fn kind(&self) -> ErrorKind {
match self {
Expand All @@ -53,6 +64,25 @@ impl embedded_io::Error for BlockError<virtio_drivers::Error> {
}
}

#[cfg(enable_block)]
impl embedded_io::Error for BlockError<FlashBlockError> {
fn kind(&self) -> ErrorKind {
match self {
BlockError::Driver(error) => match error {
FlashBlockError::Flash(flash_err) => match flash_err {
FlashError::Spi(_) => ErrorKind::Other,
FlashError::NotReady => ErrorKind::Other,
FlashError::JedecMismatch { .. } => ErrorKind::NotFound,
FlashError::WriteEnableFailed => ErrorKind::Other,
FlashError::Timeout => ErrorKind::TimedOut,
FlashError::AddrOverflow { .. } => ErrorKind::InvalidInput,
FlashError::InvalidParam(_) => ErrorKind::InvalidInput,
},
},
}
}
}

pub trait ErrorType {
type Error: embedded_io::Error;
}
Expand All @@ -70,10 +100,12 @@ pub trait BlockDriverOps: Send + Sync + ErrorType {
fn flush(&mut self) -> Result<(), Self::Error>;
}

#[cfg(virtio)]
impl<H: Hal> ErrorType for VirtIOBlk<H, SomeTransport<'static>> {
type Error = BlockError<virtio_drivers::Error>; // : io::Error
}

#[cfg(virtio)]
impl<H: Hal> BlockDriverOps for VirtIOBlk<H, SomeTransport<'static>> {
fn capacity(&self) -> u64 {
self.capacity()
Expand Down Expand Up @@ -105,10 +137,14 @@ impl<H: Hal> BlockDriverOps for VirtIOBlk<H, SomeTransport<'static>> {
}
}

#[cfg(virtio)]
pub fn init_virtio_block(
driver: VirtIOBlk<VirtioHal, SomeTransport<'static>>,
) -> Result<(), ErrorKind> {
let block = Block::new(VIRTUAL_STORAGE_NAME, Arc::new(SpinLock::new(driver)));
let block = Block::<BlockError<virtio_drivers::Error>, SECTOR_SIZE>::new(
VIRTUAL_STORAGE_NAME,
Arc::new(SpinLock::new(driver)),
);
DeviceManager::get().register_device(String::from(VIRTUAL_STORAGE_NAME), Arc::new(block))
}

Expand All @@ -118,7 +154,7 @@ pub struct Block<E: embedded_io::Error, const SECTOR_SIZE: usize> {
total_size: u64, // in bytes
}

impl<E: embedded_io::Error> Block<E, SECTOR_SIZE> {
impl<E: embedded_io::Error, const SECTOR_SIZE: usize> Block<E, SECTOR_SIZE> {
pub fn new(name: &str, driver: Arc<SpinLock<dyn BlockDriverOps<Error = E>>>) -> Self {
let total_size = {
let capacity = driver.lock().capacity();
Expand All @@ -132,7 +168,7 @@ impl<E: embedded_io::Error> Block<E, SECTOR_SIZE> {
}
}

impl<E: embedded_io::Error> Device for Block<E, SECTOR_SIZE> {
impl<E: embedded_io::Error, const SECTOR_SIZE: usize> Device for Block<E, SECTOR_SIZE> {
fn name(&self) -> String {
self.name.clone()
}
Expand Down Expand Up @@ -246,6 +282,64 @@ impl<E: embedded_io::Error> Device for Block<E, SECTOR_SIZE> {
}
}

#[cfg(enable_block)]
#[cfg(test)]
mod flash_tests {
use super::*;
use crate::devices::storage::{spi_flash::FlashBlockError, spi_flash_cmd::FlashError};
use blueos_test_macro::test;
use embedded_hal::spi::ErrorKind as SpiErrorKind;
use embedded_io::Error as IOError;

#[test]
fn test_flash_error_spi_maps_to_other() {
let err = BlockError::Driver(FlashBlockError::Flash(FlashError::Spi(SpiErrorKind::Other)));
assert_eq!(IOError::kind(&err), ErrorKind::Other);
}

#[test]
fn test_flash_error_not_ready_maps_to_other() {
let err = BlockError::Driver(FlashBlockError::Flash(FlashError::NotReady));
assert_eq!(IOError::kind(&err), ErrorKind::Other);
}

#[test]
fn test_flash_error_jedec_mismatch_maps_to_not_found() {
let err = BlockError::Driver(FlashBlockError::Flash(FlashError::JedecMismatch {
expected: 0xEF4018,
got: 0x000000,
}));
assert_eq!(IOError::kind(&err), ErrorKind::NotFound);
}

#[test]
fn test_flash_error_write_enable_failed_maps_to_other() {
let err = BlockError::Driver(FlashBlockError::Flash(FlashError::WriteEnableFailed));
assert_eq!(IOError::kind(&err), ErrorKind::Other);
}

#[test]
fn test_flash_error_timeout_maps_to_timed_out() {
let err = BlockError::Driver(FlashBlockError::Flash(FlashError::Timeout));
assert_eq!(IOError::kind(&err), ErrorKind::TimedOut);
}

#[test]
fn test_flash_error_addr_overflow_maps_to_invalid_input() {
let err = BlockError::Driver(FlashBlockError::Flash(FlashError::AddrOverflow {
addr: 0x01000000,
}));
assert_eq!(IOError::kind(&err), ErrorKind::InvalidInput);
}

#[test]
fn test_flash_error_invalid_param_maps_to_invalid_input() {
let err = BlockError::Driver(FlashBlockError::Flash(FlashError::InvalidParam("test")));
assert_eq!(IOError::kind(&err), ErrorKind::InvalidInput);
}
}

#[cfg(virtio)]
#[cfg(test)]
mod tests {
use super::*;
Expand Down
3 changes: 2 additions & 1 deletion kernel/src/devices/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ use core::{
use embedded_io::ErrorKind;
use libc::*;
use spin::{Once, RwLock as SpinRwLock};
#[cfg(virtio)]
// Block storage subsystem: virtio backend or flash backend.
#[cfg(any(virtio, enable_block))]
pub mod block;
pub mod bus;
pub mod clock;
Expand Down
Loading