Skip to content

Commit a5c7ffb

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 a5c7ffb

File tree

18 files changed

+980
-145
lines changed

18 files changed

+980
-145
lines changed

Cargo.lock

Lines changed: 539 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","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: 6 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:axmm", "dep:arm-gic-driver"]
1414
bus-mmio = []
1515
bus-pci = ["dep:axdriver_pci", "dep:axhal", "dep:axconfig"]
1616
net = ["axdriver_net"]
@@ -46,3 +46,8 @@ 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+
axmm = { workspace = true, optional = true }
51+
52+
[target.'cfg(target_arch = "aarch64")'.dependencies]
53+
arm-gic-driver = { version = "0.14", optional = true }

modules/axdriver/src/bus/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#[cfg(bus = "mmio")]
2+
#[allow(unused)]
23
mod mmio;
34
#[cfg(bus = "pci")]
5+
#[allow(unused)]
46
mod pci;
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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.lock().unwrap().flush().map_err(io_error_to_deverror)
28+
}
29+
30+
fn read_block(&mut self, block_id: u64, buf: &mut [u8]) -> DevResult {
31+
self.0
32+
.lock()
33+
.unwrap()
34+
.read_block(block_id as _, buf)
35+
.map_err(io_error_to_deverror)
36+
}
37+
38+
fn write_block(&mut self, block_id: u64, buf: &[u8]) -> DevResult {
39+
self.0
40+
.lock()
41+
.unwrap()
42+
.write_block(block_id as _, buf)
43+
.map_err(io_error_to_deverror)
44+
}
45+
}
46+
47+
impl From<Device<rdrive::driver::Block>> for Block {
48+
fn from(base: Device<rdrive::driver::Block>) -> Self {
49+
Self(base)
50+
}
51+
}
52+
53+
fn io_error_to_deverror(err: io::Error) -> DevError {
54+
match err.kind {
55+
io::ErrorKind::Other(_error) => DevError::Io,
56+
io::ErrorKind::NotAvailable => DevError::BadState,
57+
io::ErrorKind::BrokenPipe => DevError::BadState,
58+
io::ErrorKind::InvalidParameter { name: _ } => DevError::InvalidParam,
59+
io::ErrorKind::InvalidData => DevError::InvalidParam,
60+
io::ErrorKind::TimedOut => DevError::Io,
61+
io::ErrorKind::Interrupted => DevError::Again,
62+
io::ErrorKind::Unsupported => DevError::Unsupported,
63+
io::ErrorKind::OutOfMemory => DevError::NoMemory,
64+
io::ErrorKind::WriteZero => DevError::InvalidParam,
65+
}
66+
}
67+
68+
fn deverror_to_io_error(err: DevError) -> io::Error {
69+
match err {
70+
DevError::Again => io::Error {
71+
kind: io::ErrorKind::Interrupted,
72+
success_pos: 0,
73+
},
74+
DevError::AlreadyExists => io::Error {
75+
kind: io::ErrorKind::Other("Already exists".into()),
76+
success_pos: 0,
77+
},
78+
DevError::BadState => io::Error {
79+
kind: io::ErrorKind::BrokenPipe,
80+
success_pos: 0,
81+
},
82+
DevError::InvalidParam => io::Error {
83+
kind: io::ErrorKind::InvalidData,
84+
success_pos: 0,
85+
},
86+
DevError::Io => io::Error {
87+
kind: io::ErrorKind::Other("I/O error".into()),
88+
success_pos: 0,
89+
},
90+
DevError::NoMemory => io::Error {
91+
kind: io::ErrorKind::OutOfMemory,
92+
success_pos: 0,
93+
},
94+
DevError::ResourceBusy => io::Error {
95+
kind: io::ErrorKind::Other("Resource busy".into()),
96+
success_pos: 0,
97+
},
98+
DevError::Unsupported => io::Error {
99+
kind: io::ErrorKind::Unsupported,
100+
success_pos: 0,
101+
},
102+
}
103+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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::{MemoryAddr, PhysAddr};
8+
use core::ptr::NonNull;
9+
use rdrive::{
10+
DriverGeneric, PlatformDevice, driver::block::*, module_driver, probe::OnProbeError,
11+
register::FdtInfo,
12+
};
13+
14+
use crate::dyn_drivers::blk::deverror_to_io_error;
15+
use crate::dyn_drivers::iomap;
16+
use crate::virtio::VirtIoHalImpl;
17+
18+
type Device<T> = axdriver_virtio::VirtIoBlkDev<VirtIoHalImpl, T>;
19+
20+
module_driver!(
21+
name: "Virtio Block",
22+
level: ProbeLevel::PostKernel,
23+
priority: ProbePriority::DEFAULT,
24+
probe_kinds: &[
25+
ProbeKind::Fdt {
26+
compatibles: &["virtio,mmio"],
27+
on_probe: probe
28+
}
29+
],
30+
);
31+
32+
fn probe(info: FdtInfo<'_>, plat_dev: PlatformDevice) -> Result<(), OnProbeError> {
33+
let mut reg = info.node.reg().ok_or(OnProbeError::other(alloc::format!(
34+
"[{}] has no reg",
35+
info.node.name()
36+
)))?;
37+
38+
let base_reg = reg.next().unwrap();
39+
let mmio_size = base_reg.size.unwrap_or(0x1000);
40+
let mmio_base = PhysAddr::from_usize(base_reg.address as usize);
41+
let aligned_base = mmio_base.align_down_4k();
42+
let offset = mmio_base - aligned_base;
43+
44+
let aligned_end = (mmio_base + mmio_size).align_up_4k();
45+
let aligned_mmio_size = aligned_end - aligned_base;
46+
47+
let aligned_mmio_base: NonNull<u8> = iomap(aligned_base, aligned_mmio_size)?;
48+
let mmio_base = unsafe { aligned_mmio_base.as_ptr().add(offset) };
49+
50+
debug!(
51+
"virtio block device MMIO base address: {:?}, size: {}",
52+
mmio_base, mmio_size
53+
);
54+
55+
let (ty, transport) =
56+
axdriver_virtio::probe_mmio_device(mmio_base, mmio_size).ok_or(OnProbeError::NotMatch)?;
57+
58+
if ty != DeviceType::Block {
59+
return Err(OnProbeError::NotMatch);
60+
}
61+
62+
let dev = Device::try_new(transport).map_err(|e| {
63+
OnProbeError::other(format!(
64+
"failed to initialize Virtio Block device at [PA:{:?},): {:?}",
65+
mmio_base, e
66+
))
67+
})?;
68+
69+
let dev = BlockDivce(dev);
70+
71+
plat_dev.register_block(dev);
72+
73+
debug!("virtio block device registered successfully");
74+
75+
Ok(())
76+
}
77+
78+
struct BlockDivce(Device<MmioTransport>);
79+
80+
impl DriverGeneric for BlockDivce {
81+
fn open(&mut self) -> Result<(), rdrive::KError> {
82+
Ok(())
83+
}
84+
85+
fn close(&mut self) -> Result<(), rdrive::KError> {
86+
Ok(())
87+
}
88+
}
89+
90+
impl rdrive::driver::block::Interface for BlockDivce {
91+
fn num_blocks(&self) -> usize {
92+
self.0.num_blocks() as _
93+
}
94+
95+
fn block_size(&self) -> usize {
96+
self.0.block_size()
97+
}
98+
99+
fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> Result<(), io::Error> {
100+
self.0
101+
.read_block(block_id as u64, buf)
102+
.map_err(deverror_to_io_error)
103+
}
104+
fn write_block(&mut self, block_id: usize, buf: &[u8]) -> Result<(), io::Error> {
105+
self.0
106+
.write_block(block_id as u64, buf)
107+
.map_err(deverror_to_io_error)
108+
}
109+
fn flush(&mut self) -> Result<(), io::Error> {
110+
self.0.flush().map_err(deverror_to_io_error)
111+
}
112+
}
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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use core::{error::Error, ptr::NonNull};
2+
3+
use alloc::{boxed::Box, format};
4+
use axhal::{
5+
mem::{MemoryAddr, PhysAddr, phys_to_virt},
6+
paging::MappingFlags,
7+
};
8+
use axmm::AxError;
9+
10+
mod intc;
11+
12+
#[cfg(feature = "block")]
13+
pub mod blk;
14+
15+
#[allow(unused)]
16+
/// maps a mmio physical address to a virtual address.
17+
fn iomap(addr: PhysAddr, size: usize) -> Result<NonNull<u8>, Box<dyn Error>> {
18+
let end = (addr.as_usize() + size).align_up_4k();
19+
let start = addr.align_down_4k();
20+
let size = end - start.as_usize();
21+
22+
let start_virt = phys_to_virt(start);
23+
24+
match axmm::kernel_aspace().lock().map_linear(
25+
start_virt,
26+
addr,
27+
size,
28+
MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE,
29+
) {
30+
Ok(_) | Err(AxError::AlreadyExists) => {}
31+
Err(e) => {
32+
Err(format!("Failed to map MMIO region {:?}: {}", start_virt, e))?;
33+
}
34+
}
35+
36+
Ok(NonNull::new(start_virt.as_mut_ptr()).unwrap())
37+
}

0 commit comments

Comments
 (0)