Files
DragonOS/kernel/src/driver/base/block/block_device.rs
LoGin 06d5e24726 完善设备驱动模型,基于kset、kobj来维护对象之间的关系 (#401)
* 使用kobj和kset管理/sys文件夹下的对象

* 修改notifier,把action从u64换为泛型。

* 完善设备驱动模型,基于kset、kobj来维护对象之间的关系
2023-10-11 00:53:15 +08:00

495 lines
18 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// 引入Module
use crate::{
driver::base::{
device::{mkdev, Device, DeviceError, DeviceNumber, IdTable, BLOCKDEVS},
map::{
DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END, DEV_MAJOR_DYN_EXT_START,
DEV_MAJOR_HASH_SIZE, DEV_MAJOR_MAX, MINOR_MASK,
},
},
kerror,
syscall::SystemError,
};
use alloc::{sync::Arc, vec::Vec};
use core::any::Any;
use super::disk_info::Partition;
/// 该文件定义了 Device 和 BlockDevice 的接口
/// Notice 设备错误码使用 Posix 规定的 int32_t 的错误码表示而不是自己定义错误enum
// 使用方法:
// 假设 blk_dev 是块设备
// <blk_dev as Device>::read_at() 调用的是Device的函数
// <blk_dev as BlockDevice>::read_at() 调用的是BlockDevice的函数
/// 定义类型
pub type BlockId = usize;
/// 定义常量
pub const BLK_SIZE_LOG2_LIMIT: u8 = 12; // 设定块设备的块大小不能超过 1 << 12.
/// 在DragonOS中我们认为磁盘的每个LBA大小均为512字节。注意文件系统的1个扇区可能事实上是多个LBA
pub const LBA_SIZE: usize = 512;
/// @brief 块设备的迭代器
/// @usage 某次操作读/写块设备的[L,R]范围内的字节,
/// 那么可以使用此结构体进行迭代遍历每次调用next()返回一个BlockRange
pub struct BlockIter {
pub begin: usize, // 迭代器的起始位置 -> 块设备的地址 (单位是字节)
pub end: usize,
pub blk_size_log2: u8,
pub multiblock: bool, // 是否启用连续整块同时遍历
}
/// @brief Range搭配迭代器BlockIter使用[L,R]区间被分割成多个小的Range
/// Range要么是整块要么是一块的某一部分
/// 细节: range = [begin, end) 左闭右开
pub struct BlockRange {
pub lba_start: usize, // 起始块的lba_id
pub lba_end: usize, // 终止块的lba_id
pub begin: usize, // 起始位置在块内的偏移量, 如果BlockIter启用Multiblock则是多个块的偏移量
pub end: usize, // 结束位置在块内的偏移量,单位是字节
pub blk_size_log2: u8,
}
impl BlockIter {
#[allow(dead_code)]
pub fn new(start_addr: usize, end_addr: usize, blk_size_log2: u8) -> BlockIter {
return BlockIter {
begin: start_addr,
end: end_addr,
blk_size_log2: blk_size_log2,
multiblock: false,
};
}
pub fn new_multiblock(start_addr: usize, end_addr: usize, blk_size_log2: u8) -> BlockIter {
return BlockIter {
begin: start_addr,
end: end_addr,
blk_size_log2: blk_size_log2,
multiblock: true,
};
}
/// 获取下一个整块或者不完整的块
pub fn next_block(&mut self) -> BlockRange {
let blk_size_log2 = self.blk_size_log2;
let blk_size = 1usize << self.blk_size_log2;
let lba_id = self.begin / blk_size;
let begin = self.begin % blk_size;
let end = if lba_id == self.end / blk_size {
self.end % blk_size
} else {
blk_size
};
self.begin += end - begin;
return BlockRange {
lba_start: lba_id,
lba_end: lba_id + 1,
begin: begin,
end: end,
blk_size_log2: blk_size_log2,
};
}
/// 如果能返回多个连续的整块则返回否则调用next_block()返回不完整的块
pub fn next_multiblock(&mut self) -> BlockRange {
let blk_size_log2 = self.blk_size_log2;
let blk_size = 1usize << self.blk_size_log2;
let lba_start = self.begin / blk_size;
let lba_end = self.end / blk_size;
// 如果不是整块,先返回非整块的小部分
if __bytes_to_lba(self.begin, blk_size)
!= __bytes_to_lba(self.begin + blk_size - 1, blk_size)
|| lba_start == lba_end
{
return self.next_block();
}
let begin = self.begin % blk_size; // 因为是多个整块这里必然是0
let end = __lba_to_bytes(lba_end, blk_size) - self.begin;
self.begin += end - begin;
return BlockRange {
lba_start: lba_start,
lba_end: lba_end,
begin: begin,
end: end,
blk_size_log2: blk_size_log2,
};
}
}
/// BlockIter 函数实现
impl Iterator for BlockIter {
type Item = BlockRange;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
if self.begin >= self.end {
return None;
}
if self.multiblock {
return Some(self.next_multiblock());
} else {
return Some(self.next_block());
}
}
}
/// BlockRange 函数实现
impl BlockRange {
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
return self.end == self.begin;
}
pub fn len(&self) -> usize {
return self.end - self.begin;
}
/// 判断是不是整块
pub fn is_full(&self) -> bool {
return self.len() == (1usize << self.blk_size_log2);
}
/// 判断是不是多个整块连在一起
pub fn is_multi(&self) -> bool {
return self.len() >= (1usize << self.blk_size_log2)
&& (self.len() % (1usize << self.blk_size_log2) == 0);
}
/// 获取 BlockRange 在块设备内部的起始位置 (单位是字节)
pub fn origin_begin(&self) -> usize {
return (self.lba_start << self.blk_size_log2) + self.begin;
}
/// 获取 BlockRange 在块设备内部的结尾位置 (单位是字节)
pub fn origin_end(&self) -> usize {
return (self.lba_start << self.blk_size_log2) + self.end;
}
}
/// 从字节地址转换到lba id
#[inline]
pub fn __bytes_to_lba(addr: usize, blk_size: usize) -> BlockId {
return addr / blk_size;
}
/// 从lba id转换到字节地址 返回lba_id的最左侧字节
#[inline]
pub fn __lba_to_bytes(lba_id: usize, blk_size: usize) -> BlockId {
return lba_id * blk_size;
}
/// @brief 块设备应该实现的操作
pub trait BlockDevice: Device {
/// @brief: 在块设备中从第lba_id_start个块开始读取count个块数据存放到buf中
///
/// @parameter lba_id_start: 起始块
/// @parameter count: 读取块的数量
/// @parameter buf: 目标数组
/// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
/// 否则返回Err(错误码),其中错误码为负数;
/// 如果操作异常但是并没有检查出什么错误将返回Err(已操作的长度)
fn read_at(
&self,
lba_id_start: BlockId,
count: usize,
buf: &mut [u8],
) -> Result<usize, SystemError>;
/// @brief: 在块设备中从第lba_id_start个块开始把buf中的count个块数据存放到设备中
/// @parameter lba_id_start: 起始块
/// @parameter count: 写入块的数量
/// @parameter buf: 目标数组
/// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
/// 否则返回Err(错误码),其中错误码为负数;
/// 如果操作异常但是并没有检查出什么错误将返回Err(已操作的长度)
fn write_at(
&self,
lba_id_start: BlockId,
count: usize,
buf: &[u8],
) -> Result<usize, SystemError>;
/// @brief: 同步磁盘信息把所有的dirty数据写回硬盘 - 待实现
fn sync(&self) -> Result<(), SystemError>;
/// @brief: 每个块设备都必须固定自己块大小而且该块大小必须是2的幂次
/// @return: 返回一个固定量,硬编码(编程的时候固定的常量).
fn blk_size_log2(&self) -> u8;
// TODO: 待实现 open, close
/// @brief 本函数用于实现动态转换。
/// 具体的文件系统在实现本函数时最简单的方式就是直接返回self
fn as_any_ref(&self) -> &dyn Any;
/// @brief 本函数用于将BlockDevice转换为Device。
/// 由于实现了BlockDevice的结构体本身也实现了Device Trait, 因此转换是可能的。
/// 思路在BlockDevice的结构体中新增一个self_ref变量返回self_ref.upgrade()即可。
fn device(&self) -> Arc<dyn Device>;
/// @brief 返回块设备的块大小(单位:字节)
fn block_size(&self) -> usize;
/// @brief 返回当前磁盘上的所有分区的Arc指针数组
fn partitions(&self) -> Vec<Arc<Partition>>;
fn write_at_bytes(&self, offset: usize, len: usize, buf: &[u8]) -> Result<usize, SystemError> {
// assert!(len <= buf.len());
if len > buf.len() {
return Err(SystemError::E2BIG);
}
let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
let multi = iter.multiblock;
for range in iter {
let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
let buf_end = range.origin_end() - offset;
let buf_slice = &buf[buf_begin..buf_end];
let count: usize = (range.lba_end - range.lba_start).try_into().unwrap();
let full = multi && range.is_multi() || !multi && range.is_full();
if full {
self.write_at(range.lba_start, count, buf_slice)?;
} else {
if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
return Err(SystemError::E2BIG);
}
let mut temp = Vec::new();
temp.resize(1usize << self.blk_size_log2(), 0);
// 由于块设备每次读写都是整块的,在不完整写入之前,必须把不完整的地方补全
self.write_at(range.lba_start, 1, &mut temp[..])?;
// 把数据从临时buffer复制到目标buffer
temp[range.begin..range.end].copy_from_slice(&buf_slice);
self.write_at(range.lba_start, 1, &temp[..])?;
}
}
return Ok(len);
//self.0.lock().write_at(lba_id_start, count, buf)
}
fn read_at_bytes(
&self,
offset: usize,
len: usize,
buf: &mut [u8],
) -> Result<usize, SystemError> {
if len > buf.len() {
return Err(SystemError::E2BIG);
}
let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
let multi = iter.multiblock;
// 枚举每一个range
for range in iter {
let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
let buf_end = range.origin_end() - offset;
let buf_slice = &mut buf[buf_begin..buf_end];
let count: usize = (range.lba_end - range.lba_start).try_into().unwrap();
let full = multi && range.is_multi() || !multi && range.is_full();
if full {
// 调用 BlockDevice::read_at() 直接把引用传进去不是把整个数组move进去
self.read_at(range.lba_start, count, buf)?;
} else {
// 判断块的长度不能超过最大值
if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
return Err(SystemError::E2BIG);
}
let mut temp = Vec::new();
temp.resize(1usize << self.blk_size_log2(), 0);
self.read_at(range.lba_start, 1, &mut temp[..])?;
// 把数据从临时buffer复制到目标buffer
buf_slice.copy_from_slice(&temp[range.begin..range.end]);
}
}
return Ok(len);
// kdebug!(
// "ahci read at {lba_id_start}, count={count}, lock={:?}",
// self.0
// );
}
}
/// @brief 块设备框架函数集
pub struct BlockDeviceOps;
impl BlockDeviceOps {
/// @brief: 主设备号转下标
/// @parameter: major: 主设备号
/// @return: 返回下标
#[allow(dead_code)]
fn major_to_index(major: usize) -> usize {
return major % DEV_MAJOR_HASH_SIZE;
}
/// @brief: 动态获取主设备号
/// @parameter: None
/// @return: 如果成功,返回主设备号,否则,返回错误码
#[allow(dead_code)]
fn find_dynamic_major() -> Result<usize, SystemError> {
let blockdevs = BLOCKDEVS.lock();
// 寻找主设备号为234255的设备
for index in (DEV_MAJOR_DYN_END..DEV_MAJOR_HASH_SIZE).rev() {
if let Some(item) = blockdevs.get(index) {
if item.is_empty() {
return Ok(index); // 返回可用的主设备号
}
}
}
// 寻找主设备号在384511的设备
for index in (DEV_MAJOR_DYN_EXT_END + 1..DEV_MAJOR_DYN_EXT_START + 1).rev() {
if let Some(blockdevss) = blockdevs.get(Self::major_to_index(index)) {
let mut flag = true;
for item in blockdevss {
if item.device_number().major() == index {
flag = false;
break;
}
}
if flag {
// 如果数组中不存在主设备号等于index的设备
return Ok(index); // 返回可用的主设备号
}
}
}
return Err(SystemError::EBUSY);
}
/// @brief: 注册设备号,该函数需要指定主设备号
/// @parameter: from: 主设备号
/// count: 次设备号数量
/// name: 字符设备名
/// @return: 如果注册成功,返回设备号,否则,返回错误码
#[allow(dead_code)]
pub fn register_blockdev_region(
from: DeviceNumber,
count: usize,
name: &'static str,
) -> Result<DeviceNumber, SystemError> {
Self::__register_blockdev_region(from, count, name)
}
/// @brief: 注册设备号,该函数自动分配主设备号
/// @parameter: baseminor: 主设备号
/// count: 次设备号数量
/// name: 字符设备名
/// @return: 如果注册成功返回否则返回false
#[allow(dead_code)]
pub fn alloc_blockdev_region(
baseminor: usize,
count: usize,
name: &'static str,
) -> Result<DeviceNumber, SystemError> {
Self::__register_blockdev_region(mkdev(0, baseminor), count, name)
}
/// @brief: 注册设备号
/// @parameter: device_number: 设备号主设备号如果为0则动态分配
/// minorct: 次设备号数量
/// name: 字符设备名
/// @return: 如果注册成功,返回设备号,否则,返回错误码
fn __register_blockdev_region(
device_number: DeviceNumber,
minorct: usize,
name: &'static str,
) -> Result<DeviceNumber, SystemError> {
let mut major = device_number.major();
let baseminor = device_number.minor();
if major >= DEV_MAJOR_MAX {
kerror!(
"DEV {} major requested {} is greater than the maximum {}\n",
name,
major,
DEV_MAJOR_MAX - 1
);
}
if minorct > MINOR_MASK + 1 - baseminor {
kerror!("DEV {} minor range requested ({}-{}) is out of range of maximum range ({}-{}) for a single major\n",
name, baseminor, baseminor + minorct - 1, 0, MINOR_MASK);
}
let blockdev = DeviceStruct::new(mkdev(major, baseminor), minorct, name);
if major == 0 {
// 如果主设备号为0,则自动分配主设备号
major = Self::find_dynamic_major().expect("Find synamic major error.\n");
}
if let Some(items) = BLOCKDEVS.lock().get_mut(Self::major_to_index(major)) {
let mut insert_index: usize = 0;
for (index, item) in items.iter().enumerate() {
insert_index = index;
match item.device_number().major().cmp(&major) {
core::cmp::Ordering::Less => continue,
core::cmp::Ordering::Greater => {
break; // 大于则向后插入
}
core::cmp::Ordering::Equal => {
if item.device_number().minor() + item.minorct() <= baseminor {
continue; // 下一个主设备号大于或者次设备号大于被插入的次设备号最大值
}
if item.base_minor() >= baseminor + minorct {
break; // 在此处插入
}
return Err(SystemError::EBUSY); // 存在重合的次设备号
}
}
}
items.insert(insert_index, blockdev);
}
return Ok(mkdev(major, baseminor));
}
/// @brief: 注销设备号
/// @parameter: major: 主设备号如果为0动态分配
/// baseminor: 起始次设备号
/// minorct: 次设备号数量
/// @return: 如果注销成功,返回(),否则,返回错误码
fn __unregister_blockdev_region(
device_number: DeviceNumber,
minorct: usize,
) -> Result<(), SystemError> {
if let Some(items) = BLOCKDEVS
.lock()
.get_mut(Self::major_to_index(device_number.major()))
{
for (index, item) in items.iter().enumerate() {
if item.device_number() == device_number && item.minorct() == minorct {
// 设备号和数量都相等
items.remove(index);
return Ok(());
}
}
}
return Err(SystemError::EBUSY);
}
/// @brief: 块设备注册
/// @parameter: cdev: 字符设备实例
/// dev_t: 字符设备号
/// range: 次设备号范围
/// @return: none
#[allow(dead_code)]
pub fn bdev_add(_bdev: Arc<dyn BlockDevice>, id_table: IdTable) -> Result<(), DeviceError> {
if Into::<usize>::into(id_table.device_number()) == 0 {
kerror!("Device number can't be 0!\n");
}
todo!("bdev_add")
// return device_manager().add_device(bdev.id_table(), bdev.device());
}
/// @brief: block设备注销
/// @parameter: dev_t: 字符设备号
/// range: 次设备号范围
/// @return: none
#[allow(dead_code)]
pub fn bdev_del(_devnum: DeviceNumber, _range: usize) {
unimplemented!();
}
}