Skip to content

Commit 5ec2ed7

Browse files
committed
[feat] 添加动态驱动支持,更新依赖项并实现 GICv2 和 GICv3 驱动
[fix] 优化错误处理格式,简化 MMIO 区域映射失败的错误信息 feat(axdriver): update rdrive dependency and add block driver support - Updated rdrive dependency version from 0.14 to 0.14.4 in Cargo.toml. - Introduced a new block driver module with implementations for block operations. - Added virtio block driver support with MMIO transport. - Refactored interrupt controller (GIC) driver probes to use OnProbeError for error handling. - Enhanced dynamic driver probing to include block devices when the "block" feature is enabled. - Improved error handling in block driver operations by mapping errors between driver and I/O layers.
1 parent e531b52 commit 5ec2ed7

File tree

15 files changed

+979
-144
lines changed

15 files changed

+979
-144
lines changed

Cargo.lock

Lines changed: 541 additions & 131 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/axfeat/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ display = ["alloc", "paging", "axdriver/virtio-gpu", "dep:axdisplay", "axruntime
5252
rtc = ["axhal/rtc", "axruntime/rtc"]
5353

5454
# Device drivers
55+
driver-dyn = ["axruntime/driver-dyn","axdriver?/dyn"]
5556
bus-mmio = ["axdriver?/bus-mmio"]
5657
bus-pci = ["axdriver?/bus-pci"]
5758
driver-ramdisk = ["axdriver?/ramdisk", "axfs?/use-ramdisk"]

modules/axdriver/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ repository = "https://github.com/arceos-org/arceos/tree/main/modules/axdriver"
1010
documentation = "https://arceos-org.github.io/arceos/axdriver/index.html"
1111

1212
[features]
13-
dyn = []
13+
dyn = ["dep:rdrive", "dep:arm-gic-driver"]
1414
bus-mmio = []
1515
bus-pci = ["dep:axdriver_pci", "dep:axhal", "dep:axconfig"]
1616
net = ["axdriver_net"]
@@ -46,3 +46,9 @@ axalloc = { workspace = true, optional = true }
4646
axhal = { workspace = true, optional = true }
4747
axconfig = { workspace = true, optional = true }
4848
axdma = { workspace = true, optional = true }
49+
rdrive = { version = "0.15", optional = true }
50+
axerrno = "0.1"
51+
lazyinit = "0.2"
52+
53+
[target.'cfg(target_arch = "aarch64")'.dependencies]
54+
arm-gic-driver = { version = "0.14", optional = true }
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use axdriver_base::{BaseDriverOps, DevError, DevResult, DeviceType};
2+
use axdriver_block::BlockDriverOps;
3+
use rdrive::{Device, driver::block::io};
4+
5+
#[cfg(feature = "virtio-blk")]
6+
mod virtio;
7+
8+
pub struct Block(Device<rdrive::driver::Block>);
9+
10+
impl BaseDriverOps for Block {
11+
fn device_type(&self) -> DeviceType {
12+
DeviceType::Block
13+
}
14+
fn device_name(&self) -> &str {
15+
self.0.descriptor().name
16+
}
17+
}
18+
19+
impl BlockDriverOps for Block {
20+
fn num_blocks(&self) -> u64 {
21+
self.0.lock().unwrap().num_blocks() as _
22+
}
23+
fn block_size(&self) -> usize {
24+
self.0.lock().unwrap().block_size()
25+
}
26+
fn flush(&mut self) -> DevResult {
27+
self.0
28+
.lock()
29+
.unwrap()
30+
.flush()
31+
.map_err(maping_io_err_to_dev_err)
32+
}
33+
34+
fn read_block(&mut self, block_id: u64, buf: &mut [u8]) -> DevResult {
35+
self.0
36+
.lock()
37+
.unwrap()
38+
.read_block(block_id as _, buf)
39+
.map_err(maping_io_err_to_dev_err)
40+
}
41+
42+
fn write_block(&mut self, block_id: u64, buf: &[u8]) -> DevResult {
43+
self.0
44+
.lock()
45+
.unwrap()
46+
.write_block(block_id as _, buf)
47+
.map_err(maping_io_err_to_dev_err)
48+
}
49+
}
50+
51+
impl From<Device<rdrive::driver::Block>> for Block {
52+
fn from(base: Device<rdrive::driver::Block>) -> Self {
53+
Self(base)
54+
}
55+
}
56+
57+
fn maping_io_err_to_dev_err(err: io::Error) -> DevError {
58+
match err.kind {
59+
io::ErrorKind::Other(_error) => DevError::Io,
60+
io::ErrorKind::NotAvailable => DevError::BadState,
61+
io::ErrorKind::BrokenPipe => DevError::BadState,
62+
io::ErrorKind::InvalidParameter { name: _ } => DevError::InvalidParam,
63+
io::ErrorKind::InvalidData => DevError::InvalidParam,
64+
io::ErrorKind::TimedOut => DevError::Io,
65+
io::ErrorKind::Interrupted => DevError::Again,
66+
io::ErrorKind::Unsupported => DevError::Unsupported,
67+
io::ErrorKind::OutOfMemory => DevError::NoMemory,
68+
io::ErrorKind::WriteZero => DevError::InvalidParam,
69+
}
70+
}
71+
72+
fn maping_dev_err_to_io_err(err: DevError) -> io::Error {
73+
let kind = match err {
74+
DevError::Again => io::ErrorKind::Interrupted,
75+
DevError::AlreadyExists => io::ErrorKind::Other("Already exists".into()),
76+
DevError::BadState => io::ErrorKind::BrokenPipe,
77+
DevError::InvalidParam => io::ErrorKind::InvalidData,
78+
DevError::Io => io::ErrorKind::Other("I/O error".into()),
79+
DevError::NoMemory => io::ErrorKind::OutOfMemory,
80+
DevError::ResourceBusy => io::ErrorKind::Other("Resource busy".into()),
81+
DevError::Unsupported => io::ErrorKind::Unsupported,
82+
};
83+
io::Error {
84+
kind,
85+
success_pos: 0,
86+
}
87+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
extern crate alloc;
2+
3+
use alloc::format;
4+
use axdriver_base::DeviceType;
5+
use axdriver_block::BlockDriverOps;
6+
use axdriver_virtio::MmioTransport;
7+
use axhal::mem::PhysAddr;
8+
use rdrive::{
9+
DriverGeneric, PlatformDevice, driver::block::*, module_driver, probe::OnProbeError,
10+
register::FdtInfo,
11+
};
12+
13+
use crate::dyn_drivers::blk::maping_dev_err_to_io_err;
14+
use crate::dyn_drivers::iomap;
15+
use crate::virtio::VirtIoHalImpl;
16+
17+
type Device<T> = axdriver_virtio::VirtIoBlkDev<VirtIoHalImpl, T>;
18+
19+
module_driver!(
20+
name: "Virtio Block",
21+
level: ProbeLevel::PostKernel,
22+
priority: ProbePriority::DEFAULT,
23+
probe_kinds: &[
24+
ProbeKind::Fdt {
25+
compatibles: &["virtio,mmio"],
26+
on_probe: probe
27+
}
28+
],
29+
);
30+
31+
fn probe(info: FdtInfo<'_>, plat_dev: PlatformDevice) -> Result<(), OnProbeError> {
32+
let base_reg = info
33+
.node
34+
.reg()
35+
.and_then(|mut regs| regs.next())
36+
.ok_or(OnProbeError::other(alloc::format!(
37+
"[{}] has no reg",
38+
info.node.name()
39+
)))?;
40+
41+
let mmio_size = base_reg.size.unwrap_or(0x1000);
42+
let mmio_base = PhysAddr::from_usize(base_reg.address as usize);
43+
44+
let mmio_base = iomap(mmio_base, mmio_size)?.as_ptr();
45+
46+
let (ty, transport) =
47+
axdriver_virtio::probe_mmio_device(mmio_base, mmio_size).ok_or(OnProbeError::NotMatch)?;
48+
49+
if ty != DeviceType::Block {
50+
return Err(OnProbeError::NotMatch);
51+
}
52+
53+
let dev = Device::try_new(transport).map_err(|e| {
54+
OnProbeError::other(format!(
55+
"failed to initialize Virtio Block device at [PA:{:?},): {:?}",
56+
mmio_base, e
57+
))
58+
})?;
59+
60+
let dev = BlockDivce(dev);
61+
plat_dev.register_block(dev);
62+
debug!("virtio block device registered successfully");
63+
Ok(())
64+
}
65+
66+
struct BlockDivce(Device<MmioTransport>);
67+
68+
impl DriverGeneric for BlockDivce {
69+
fn open(&mut self) -> Result<(), rdrive::KError> {
70+
Ok(())
71+
}
72+
73+
fn close(&mut self) -> Result<(), rdrive::KError> {
74+
Ok(())
75+
}
76+
}
77+
78+
impl rdrive::driver::block::Interface for BlockDivce {
79+
fn num_blocks(&self) -> usize {
80+
self.0.num_blocks() as _
81+
}
82+
83+
fn block_size(&self) -> usize {
84+
self.0.block_size()
85+
}
86+
87+
fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> Result<(), io::Error> {
88+
self.0
89+
.read_block(block_id as u64, buf)
90+
.map_err(maping_dev_err_to_io_err)
91+
}
92+
fn write_block(&mut self, block_id: usize, buf: &[u8]) -> Result<(), io::Error> {
93+
self.0
94+
.write_block(block_id as u64, buf)
95+
.map_err(maping_dev_err_to_io_err)
96+
}
97+
fn flush(&mut self) -> Result<(), io::Error> {
98+
self.0.flush().map_err(maping_dev_err_to_io_err)
99+
}
100+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
extern crate alloc;
2+
3+
use alloc::format;
4+
use arm_gic_driver::v2::Gic;
5+
use rdrive::{PlatformDevice, module_driver, probe::OnProbeError, register::FdtInfo};
6+
7+
use crate::dyn_drivers::iomap;
8+
9+
module_driver!(
10+
name: "GICv2",
11+
level: ProbeLevel::PreKernel,
12+
priority: ProbePriority::INTC,
13+
probe_kinds: &[
14+
ProbeKind::Fdt {
15+
compatibles: &["arm,cortex-a15-gic", "arm,gic-400"],
16+
on_probe: probe_gic
17+
},
18+
] ,
19+
);
20+
21+
fn probe_gic(info: FdtInfo<'_>, dev: PlatformDevice) -> Result<(), OnProbeError> {
22+
let mut reg = info.node.reg().ok_or(OnProbeError::other(format!(
23+
"[{}] has no reg",
24+
info.node.name()
25+
)))?;
26+
27+
let gicd_reg = reg.next().unwrap();
28+
let gicc_reg = reg.next().unwrap();
29+
30+
let gicd = iomap(
31+
(gicd_reg.address as usize).into(),
32+
gicd_reg.size.unwrap_or(0x1000),
33+
)?;
34+
let gicc = iomap(
35+
(gicc_reg.address as usize).into(),
36+
gicc_reg.size.unwrap_or(0x1000),
37+
)?;
38+
39+
let gic = Gic::new(gicd, gicc);
40+
41+
dev.register_intc(gic);
42+
43+
Ok(())
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
extern crate alloc;
2+
3+
use alloc::format;
4+
use arm_gic_driver::v3::Gic;
5+
use rdrive::{PlatformDevice, module_driver, probe::OnProbeError, register::FdtInfo};
6+
7+
use crate::dyn_drivers::iomap;
8+
9+
module_driver!(
10+
name: "GICv3",
11+
level: ProbeLevel::PreKernel,
12+
priority: ProbePriority::INTC,
13+
probe_kinds: &[
14+
ProbeKind::Fdt {
15+
compatibles: &["arm,gic-v3"],
16+
on_probe: probe_gic
17+
}
18+
],
19+
);
20+
21+
fn probe_gic(info: FdtInfo<'_>, dev: PlatformDevice) -> Result<(), OnProbeError> {
22+
let mut reg = info.node.reg().ok_or(OnProbeError::other(format!(
23+
"[{}] has no reg",
24+
info.node.name()
25+
)))?;
26+
27+
let gicd_reg = reg.next().unwrap();
28+
let gicr_reg = reg.next().unwrap();
29+
30+
let gicd = iomap(
31+
(gicd_reg.address as usize).into(),
32+
gicd_reg.size.unwrap_or(0x1000),
33+
)?;
34+
let gicr = iomap(
35+
(gicr_reg.address as usize).into(),
36+
gicr_reg.size.unwrap_or(0x1000),
37+
)?;
38+
39+
let gic = Gic::new(gicd, gicr, Default::default());
40+
41+
dev.register_intc(gic);
42+
43+
Ok(())
44+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#[cfg(target_arch = "aarch64")]
2+
mod gicv2;
3+
#[cfg(target_arch = "aarch64")]
4+
mod gicv3;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use core::{error::Error, ops::Deref, ptr::NonNull};
2+
3+
use alloc::{boxed::Box, format};
4+
use axerrno::{AxError, AxResult};
5+
use axhal::mem::{MemoryAddr, PhysAddr, VirtAddr, phys_to_virt};
6+
use lazyinit::LazyInit;
7+
use rdrive::register::{DriverRegister, DriverRegisterSlice};
8+
9+
mod intc;
10+
11+
#[cfg(feature = "block")]
12+
pub mod blk;
13+
14+
/// A function type that maps a physical address to a virtual address. map flags should be read/write/device.
15+
pub type IoMapFunc = fn(PhysAddr, usize) -> AxResult<VirtAddr>;
16+
17+
static IO_MAP_FUNC: LazyInit<IoMapFunc> = LazyInit::new();
18+
19+
/// Sets up the device driver subsystem.
20+
pub fn setup(dtb: usize, io_map_func: IoMapFunc) {
21+
IO_MAP_FUNC.init_once(io_map_func);
22+
if dtb == 0 {
23+
warn!("Device tree base address is 0, skipping device driver setup.");
24+
return;
25+
}
26+
27+
let dtb_virt = phys_to_virt(dtb.into());
28+
if let Some(dtb) = NonNull::new(dtb_virt.as_mut_ptr()) {
29+
rdrive::init(rdrive::Platform::Fdt { addr: dtb }).unwrap();
30+
rdrive::register_append(&driver_registers());
31+
rdrive::probe_pre_kernel().unwrap();
32+
}
33+
}
34+
35+
#[allow(unused)]
36+
/// maps a mmio physical address to a virtual address.
37+
fn iomap(addr: PhysAddr, size: usize) -> Result<NonNull<u8>, Box<dyn Error>> {
38+
let end = (addr + size).align_up_4k();
39+
let start = addr.align_down_4k();
40+
let offset = addr - start;
41+
let size = end - start;
42+
let iomap = *IO_MAP_FUNC
43+
.get()
44+
.ok_or_else(|| format!("IO map function not initialized"))?;
45+
46+
let virt = match iomap(start, size) {
47+
Ok(val) => val,
48+
Err(AxError::AlreadyExists) => phys_to_virt(start),
49+
Err(e) => {
50+
return Err(format!(
51+
"Failed to map MMIO region: {:?} (addr: {:?}, size: {:#x})",
52+
e, start, size
53+
)
54+
.into());
55+
}
56+
};
57+
let start_virt = virt + offset;
58+
Ok(unsafe { NonNull::new_unchecked(start_virt.as_mut_ptr()) })
59+
}
60+
61+
fn driver_registers() -> impl Deref<Target = [DriverRegister]> {
62+
unsafe extern "C" {
63+
fn __sdriver_register();
64+
fn __edriver_register();
65+
}
66+
67+
unsafe {
68+
let len = __edriver_register as usize - __sdriver_register as usize;
69+
70+
if len == 0 {
71+
return DriverRegisterSlice::empty();
72+
}
73+
74+
let data = core::slice::from_raw_parts(__sdriver_register as _, len);
75+
76+
DriverRegisterSlice::from_raw(data)
77+
}
78+
}

0 commit comments

Comments
 (0)