dev/block: add a simple block subsystem
This commit is contained in:
parent
8b7a7b9295
commit
5ffd4ca4e2
@ -22,6 +22,7 @@ device-api-macros = { path = "lib/device-api/macros" }
|
||||
# Drivers
|
||||
ygg_driver_pci = { path = "driver/bus/pci" }
|
||||
ygg_driver_nvme = { path = "driver/block/nvme" }
|
||||
ygg_driver_block = { path = "driver/block/block" }
|
||||
kernel-fs = { path = "driver/fs/kernel-fs" }
|
||||
|
||||
atomic_enum = "0.2.0"
|
||||
|
12
driver/block/block/Cargo.toml
Normal file
12
driver/block/block/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "ygg_driver_block"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
||||
kernel-util = { path = "../../../lib/kernel-util" }
|
||||
|
||||
log = "0.4.20"
|
57
driver/block/block/src/cache.rs
Normal file
57
driver/block/block/src/cache.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use core::{fmt, mem::MaybeUninit};
|
||||
|
||||
use alloc::collections::BTreeMap;
|
||||
use kernel_util::mem::PageBox;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
// TODO LRU
|
||||
pub struct BlockCache<K: Ord + Eq> {
|
||||
table: BTreeMap<K, CachedBlock>,
|
||||
block_size: usize,
|
||||
}
|
||||
|
||||
pub type CachedBlock = PageBox<[u8]>;
|
||||
|
||||
trait TryGetOrInsertWith<K, V> {
|
||||
fn try_get_or_insert_with<E, F: FnOnce() -> Result<V, E>>(
|
||||
&mut self,
|
||||
key: K,
|
||||
f: F,
|
||||
) -> Result<&mut V, E>;
|
||||
}
|
||||
|
||||
impl<K: Ord + Eq> BlockCache<K> {
|
||||
pub fn new(block_size: usize) -> Self {
|
||||
log::debug!("Block cache created with bs={}", block_size);
|
||||
Self {
|
||||
table: BTreeMap::new(),
|
||||
block_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_fetch_with<
|
||||
E: From<Error>,
|
||||
F: FnOnce(&mut PageBox<[MaybeUninit<u8>]>) -> Result<(), E>,
|
||||
>(
|
||||
&mut self,
|
||||
index: K,
|
||||
f: F,
|
||||
) -> Result<&mut CachedBlock, E>
|
||||
where
|
||||
K: Copy + fmt::Display,
|
||||
{
|
||||
if !self.table.contains_key(&index) {
|
||||
let mut block = PageBox::new_uninit_slice(self.block_size)?;
|
||||
log::debug!("Missed block with index {}, fetching", index);
|
||||
f(&mut block)?;
|
||||
self.table
|
||||
.insert(index, unsafe { block.assume_init_slice() });
|
||||
}
|
||||
|
||||
Ok(self.table.get_mut(&index).unwrap())
|
||||
}
|
||||
|
||||
pub fn evict(&mut self, index: K) {
|
||||
self.table.remove(&index);
|
||||
}
|
||||
}
|
39
driver/block/block/src/lib.rs
Normal file
39
driver/block/block/src/lib.rs
Normal file
@ -0,0 +1,39 @@
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use yggdrasil_abi::{error::Error, io::DeviceRequest};
|
||||
|
||||
pub mod cache;
|
||||
|
||||
/// Block device interface
|
||||
#[allow(unused)]
|
||||
pub trait BlockDevice: Sync {
|
||||
/// Reads data frmo the given offset of the device
|
||||
fn read(&'static self, pos: u64, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
/// Writes the data to the given offset of the device
|
||||
fn write(&'static self, pos: u64, buf: &[u8]) -> Result<usize, Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
/// Returns the size of the block device in bytes
|
||||
fn size(&self) -> Result<u64, Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
/// Returns `true` if the device can be read from
|
||||
fn is_readable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
/// Returns `true` if the device can be written to
|
||||
fn is_writable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Performs a device-specific function
|
||||
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ device-api = { path = "../../../lib/device-api", features = ["derive"] }
|
||||
vfs = { path = "../../../lib/vfs" }
|
||||
|
||||
ygg_driver_pci = { path = "../../bus/pci" }
|
||||
ygg_driver_block = { path = "../../block/block" }
|
||||
kernel-fs = { path = "../../fs/kernel-fs" }
|
||||
|
||||
log = "0.4.20"
|
||||
|
@ -1,15 +1,23 @@
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use alloc::{boxed::Box, format};
|
||||
use kernel_fs::devfs;
|
||||
use vfs::BlockDevice;
|
||||
use kernel_util::{
|
||||
block,
|
||||
mem::{address::AsPhysicalAddress, PageBox},
|
||||
sync::IrqSafeSpinlock,
|
||||
};
|
||||
use ygg_driver_block::{cache::BlockCache, BlockDevice};
|
||||
use yggdrasil_abi::{error::Error, io::DeviceRequest};
|
||||
|
||||
use crate::command::IdentifyNamespaceRequest;
|
||||
use crate::{command::IdentifyNamespaceRequest, IoDirection};
|
||||
|
||||
use super::{error::NvmeError, NvmeController};
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct NvmeDrive {
|
||||
controller: &'static NvmeController,
|
||||
cache: IrqSafeSpinlock<BlockCache<u64>>,
|
||||
nsid: u32,
|
||||
total_lba_count: u64,
|
||||
lba_size: u64,
|
||||
@ -37,6 +45,7 @@ impl NvmeDrive {
|
||||
|
||||
let dev = Box::leak(Box::new(NvmeDrive {
|
||||
controller,
|
||||
cache: IrqSafeSpinlock::new(BlockCache::new(lba_size as _)),
|
||||
nsid,
|
||||
total_lba_count,
|
||||
lba_size,
|
||||
@ -49,11 +58,54 @@ impl NvmeDrive {
|
||||
|
||||
Ok(dev)
|
||||
}
|
||||
|
||||
async fn read_block(
|
||||
&self,
|
||||
lba: u64,
|
||||
block: &mut PageBox<[MaybeUninit<u8>]>,
|
||||
) -> Result<(), NvmeError> {
|
||||
self.controller
|
||||
.perform_io(
|
||||
self.nsid,
|
||||
lba,
|
||||
unsafe { block.as_physical_address() },
|
||||
IoDirection::Read,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockDevice for NvmeDrive {
|
||||
fn read(&'static self, _pos: u64, _buf: &mut [u8]) -> Result<usize, Error> {
|
||||
todo!()
|
||||
fn read(&'static self, mut pos: u64, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
let mut cache = self.cache.lock();
|
||||
let mut rem = buf.len();
|
||||
let mut off = 0;
|
||||
|
||||
while rem != 0 {
|
||||
let lba = pos / self.lba_size;
|
||||
|
||||
if lba == self.total_lba_count {
|
||||
break;
|
||||
}
|
||||
|
||||
let block_offset = (pos % self.lba_size) as usize;
|
||||
let count = core::cmp::min(self.lba_size as usize - block_offset, rem);
|
||||
|
||||
let block = cache.get_or_fetch_with(lba, |block| {
|
||||
block! {
|
||||
self.read_block(lba, block).await
|
||||
}?
|
||||
.map_err(|_| Error::InvalidOperation)
|
||||
})?;
|
||||
|
||||
buf[off..off + count].copy_from_slice(&block[block_offset..block_offset + count]);
|
||||
|
||||
rem -= count;
|
||||
off += count;
|
||||
pos += count as u64;
|
||||
}
|
||||
|
||||
Ok(off)
|
||||
}
|
||||
|
||||
fn write(&'static self, _pos: u64, _buf: &[u8]) -> Result<usize, Error> {
|
||||
|
@ -10,4 +10,6 @@ yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
||||
vfs = { path = "../../../lib/vfs" }
|
||||
kernel-util = { path = "../../../lib/kernel-util" }
|
||||
|
||||
ygg_driver_block = { path = "../../block/block" }
|
||||
|
||||
log = "0.4.20"
|
||||
|
@ -3,7 +3,8 @@ use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use alloc::{format, string::String};
|
||||
use kernel_util::util::OneTimeInit;
|
||||
use vfs::{impls::MemoryDirectory, BlockDevice, CharDevice, Node, NodeFlags, NodeRef};
|
||||
use vfs::{impls::MemoryDirectory, CharDevice, Node, NodeFlags, NodeRef};
|
||||
use ygg_driver_block::BlockDevice;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
/// Describes the kind of a character device
|
||||
|
@ -9,6 +9,8 @@ edition = "2021"
|
||||
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git", features = ["alloc"] }
|
||||
kernel-util = { path = "../kernel-util" }
|
||||
|
||||
ygg_driver_block = { path = "../../driver/block/block" }
|
||||
|
||||
log = "0.4.20"
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -1,39 +1,8 @@
|
||||
use ygg_driver_block::BlockDevice;
|
||||
use yggdrasil_abi::{error::Error, io::DeviceRequest};
|
||||
|
||||
use crate::node::{CommonImpl, NodeRef};
|
||||
|
||||
/// Block device interface
|
||||
#[allow(unused)]
|
||||
pub trait BlockDevice: Sync {
|
||||
/// Reads data frmo the given offset of the device
|
||||
fn read(&'static self, pos: u64, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
/// Writes the data to the given offset of the device
|
||||
fn write(&'static self, pos: u64, buf: &[u8]) -> Result<usize, Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
/// Returns the size of the block device in bytes
|
||||
fn size(&self) -> Result<u64, Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
/// Returns `true` if the device can be read from
|
||||
fn is_readable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
/// Returns `true` if the device can be written to
|
||||
fn is_writable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Performs a device-specific function
|
||||
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
/// Character device interface
|
||||
#[allow(unused)]
|
||||
pub trait CharDevice: Sync {
|
||||
|
@ -17,7 +17,7 @@ pub(crate) mod node;
|
||||
pub(crate) mod path;
|
||||
pub(crate) mod traits;
|
||||
|
||||
pub use device::{BlockDevice, CharDevice};
|
||||
pub use device::CharDevice;
|
||||
pub use file::{DirectoryOpenPosition, File, FileRef, InstanceData};
|
||||
pub use ioctx::{Action, IoContext};
|
||||
pub use node::{
|
||||
|
@ -2,6 +2,7 @@ use core::{any::Any, fmt};
|
||||
|
||||
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
|
||||
use kernel_util::sync::IrqSafeSpinlock;
|
||||
use ygg_driver_block::BlockDevice;
|
||||
use yggdrasil_abi::{
|
||||
bitflags,
|
||||
error::Error,
|
||||
@ -19,7 +20,7 @@ mod tree;
|
||||
pub use access::AccessToken;
|
||||
pub use traits::{CommonImpl, DirectoryImpl, RegularImpl, SymlinkImpl};
|
||||
|
||||
use crate::device::{BlockDevice, BlockDeviceWrapper, CharDevice, CharDeviceWrapper};
|
||||
use crate::device::{BlockDeviceWrapper, CharDevice, CharDeviceWrapper};
|
||||
|
||||
/// Wrapper type for a [Node] shared reference
|
||||
pub type NodeRef = Arc<Node>;
|
||||
@ -295,7 +296,7 @@ mod tests {
|
||||
use core::any::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{node::NodeFlags, NodeRef};
|
||||
use crate::node::NodeFlags;
|
||||
|
||||
use super::{CommonImpl, DirectoryImpl, Node, RegularImpl};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user