跳到主要内容

rdrive + rdif 驱动框架

本文记录 #606 的宿主物理设备重构目标。新的设备路径硬切到 rdrive + rdifrdrive 负责发现、probe、注册和查询,rdif-* 负责能力接口,必要时由对应领域 crate 提供运行时封装,上层系统按领域能力消费设备。旧驱动接口包组已移除,宿主物理设备初始化与交付主线不再经过 legacy driver crates;块设备路径中原有 runtime 已删除,统一以 rdif-block 作为 block capability boundary。

axdeviceaxdevice_base 不纳入本轮迁移。它们继续作为 Axvisor / axvm 的 guest emulated device model,不参与宿主物理设备 probe,不作为 FS、NET、display、input、vsock 的设备来源。

非目标与硬约束

本轮只处理宿主侧物理设备,包括 ArceOS、StarryOS、Axvisor 在真实平台或 QEMU 平台上使用的块设备、网卡、中断控制器、时钟、显示、输入、vsock、PCIe、USB host 等设备。

架构硬约束如下:

  • 不新增长期存在的 rdrive <-> ax-driver 双向适配层。
  • 不新增 RDriveDeviceContainerAllRDriveDevices 这类换名后的 AllDevices 大容器。
  • 不用一个 KernelHalPlatformSystem 或其它大结构体包办 Static、FDT、ACPI、PCI、MMIO、DMA、IRQ、runtime。
  • 不把 FDT 当作唯一或默认平台抽象;Static、FDT、ACPI 是并列平台来源。
  • 不在 portable driver core 中调用 iomapioremapaxklibsomehal、任务调度或 IRQ 注册。
  • 不用字符串拼接或 ad-hoc 匹配替代 FDT compatible、ACPI HID/CID、PCI vendor/device 的结构化匹配。
  • 不在文档或代码中保留“以后补”的占位路径;ACPI 第一版必须返回明确 unsupported error。
  • 除测试外,新增或重构后的单个 .rs 文件不超过 600 行。

ax-driver 现在作为共享驱动聚合 crate 接入 rdrive + rdif,不再依赖旧驱动接口包组。迁移目标模块完成后,不应再引入 AllDevicesAxDeviceContainerAxBlockDeviceAxNetDevice 这类旧全局容器模型。

总体结构

新的宿主设备路径分为五层:平台发现来源、rdrive backend 分发、具体驱动、rdif 能力边界、领域 service 与上层消费方。

rdrive::Manager 只保存 DriverRegister 和类型化设备 registry。Static、FDT、ACPI、PCI 各自拥有独立 probe::*::{System, Info, FnOnProbe},不把平台状态合并成一个大 System

rdrive Backend 模型

rdrive 公共 API 的目标形态是多来源初始化和按 ProbeKind 分发:

pub enum PlatformSource {
Static,
Fdt(core::ptr::NonNull<u8>),
Acpi(AcpiRoot),
}

pub enum ProbeKind {
Static { on_probe: static_::FnOnProbe },
Fdt { compatibles: &'static [&'static str], on_probe: fdt::FnOnProbe },
Acpi { ids: &'static [AcpiId], on_probe: acpi::FnOnProbe },
Pci { on_probe: pci::FnOnProbe },
}

各 backend 的职责如下:

backend独立状态匹配输入probe 输入第一版行为
probe::static_System { probed_names }ProbeKind::Static register namePlatformDevice平台 crate 自己注册静态 model driver 并在回调中使用平台常量
probe::fdtSystem { fdt, phandle_map, probed }compatible + node statusFdtInfo + PlatformDevice保留当前 FDT 能力
probe::acpiSystem { root, probed }HID/CID + ACPI deviceAcpiInfo + PlatformDeviceAPI 存在,返回 unsupported
probe::pciPCIe controller enumeratorvendor/device/classendpoint + PlatformDevice保留当前 PCIe 二阶段 probe

probe_pre_kernel() 只运行 ProbeLevel::PreKernel,并通过 backend 分发器执行 Static、FDT、ACPI 中的早期 probe。PCI endpoint 枚举依赖已注册的 PCIe controller,因此仍在普通 probe 阶段触发。

probe_all(stop_if_fail) 运行普通设备 probe,再执行 PCI endpoint 枚举。它不能被塞进 early init,也不能变成 FDT 专用流程。

初始化时序

初始化顺序固定为:

  1. ax_hal::init_early(cpu_id, arg) 只记录 boot arg / DTB,初始化 early trap、console、time 等最低层能力,不 probe 宿主设备。
  2. allocator 和 paging 初始化完成后,ax_hal::init_later(cpu_id, arg) 或平台 post-paging 阶段执行 rdrive::init(...)rdrive::register_append(...)rdrive::probe_pre_kernel()
  3. probe_pre_kernel() 只初始化后续平台依赖,例如 interrupt controller、clock、timer、systick、pinmux、PCIe root complex。
  4. 平台 later init 完成后,ax-runtime 调用 rdrive::probe_all(false)
  5. FS、NET、display、input、vsock、StarryOS、Axvisor 通过领域 service 或 rdif-* 能力接口消费设备。

ax-runtime 不再拆 AllDevices.block/net/display/input/vsock 后逐个传给模块。它只触发 probe 和领域 service 初始化。

Capability Boundary

rdif-* 是能力边界,只定义某类设备向上暴露什么能力,不负责设备发现、iomap、IRQ 注册、任务调度或系统启动顺序。块设备已移除原 runtime crate,rdif-block 直接承载设备 LBA 语义的 submit/poll block capability boundary;其它领域如网络仍可按需保留 runtime wrapper,负责 waker、poll、blocking API、buffer pool 等运行时行为。

能力interface crateruntime crate上层消费
块设备rdif-block已删除,直接消费 rdif-block submit/poll 边界block volume service、FS
网络设备rdif-ethrd-netnet interface service、NET/NET-NG
显示rdif-displayrd-displaydisplay service、Starry fb
输入rdif-inputrd-inputinput service、Starry input
vsockrdif-vsockrd-vsockvsock service
平台设备rdif-intcrdif-pcierdif-clkrdif-timerrdif-systickrdif-serial按需HAL、Axvisor backend、平台 glue

rdif-block 的块请求不暴露 Linux block layer 的 512B sector 公共单位,而使用真实设备的 lba / block_count / logical_block_size。OS glue 负责把上层 byte offset、FS block、Linux-like sector 或分区 region 转换成设备 LBA。接口保留 blk-mq 风格的结构能力:设备可报告 QueueTopology,OS 可创建一个或多个 queue,每个 queue 使用 queue-local RequestId/tag,经 submit_request() 提交、经 poll_request() 回收完成。

块 IRQ 事件按 source 和 queue 分离。Interface::irq_sources() 返回可用 IRQ source 列表,每个 IrqSourceInfo { id, queues } 描述该 source 可能影响的 queue mask;take_irq_handler(source_id) 只能取走对应 handler。单 INTx/legacy 设备使用 source 0,未来 NVMe MSI-X 可以把不同 vector 暴露为不同 source。当前 ArceOS ax-driver / ax-runtime glue 仍只消费 legacy source 0,保持一个 block 设备一个 IRQ handler 的注册方式。

IrqHandler::handle_irq() 只确认中断源并返回可 poll 的 queue mask,不做 OS wake、不阻塞、不持有 OS 锁,也不在中断上下文推进慢路径完成。收到事件后,runtime 或 task-side wrapper 再对相应 queue 调用 poll_request()

新增接口按多文件拆分:

  • rdif-display/src/lib.rs 只 re-export;types.rs 定义 DisplayInfoPixelFormatFrameBuffer<'_>error.rs 定义 DisplayErrorinterface.rs 定义 InterfaceEvent
  • rdif-input/src/lib.rs 只 re-export;event.rs 定义 EventTypeInputEventAbsInfoid.rs 定义 InputDeviceIderror.rs 定义 InputErrorinterface.rs 定义 InterfaceEvent
  • rdif-vsock/src/lib.rs 只 re-export;addr.rs 定义 VsockAddrVsockConnIdevent.rs 定义 VsockEventerror.rs 定义 VsockErrorinterface.rs 定义 InterfaceEvent

接口目标形态:

pub trait DisplayInterface: rdif_base::DriverGeneric {
fn info(&self) -> DisplayInfo;
fn framebuffer(&mut self) -> Result<FrameBuffer<'_>, DisplayError>;
fn need_flush(&self) -> bool;
fn flush(&mut self) -> Result<(), DisplayError>;
fn handle_irq(&mut self) -> DisplayEvent;
}
pub trait InputInterface: rdif_base::DriverGeneric {
fn device_id(&self) -> InputDeviceId;
fn physical_location(&self) -> &str;
fn unique_id(&self) -> &str;
fn get_event_bits(&mut self, ty: EventType, out: &mut [u8]) -> Result<bool, InputError>;
fn read_event(&mut self) -> Result<InputEvent, InputError>;
fn get_prop_bits(&mut self, out: &mut [u8]) -> Result<usize, InputError>;
fn get_abs_info(&mut self, axis: u8) -> Result<AbsInfo, InputError>;
fn handle_irq(&mut self) -> InputEventState;
}
pub trait VsockInterface: rdif_base::DriverGeneric {
fn guest_cid(&self) -> u64;
fn listen(&mut self, port: u32) -> Result<(), VsockError>;
fn connect(&mut self, id: VsockConnId) -> Result<(), VsockError>;
fn send(&mut self, id: VsockConnId, buf: &[u8]) -> Result<usize, VsockError>;
fn recv(&mut self, id: VsockConnId, buf: &mut [u8]) -> Result<usize, VsockError>;
fn recv_avail(&mut self, id: VsockConnId) -> Result<usize, VsockError>;
fn disconnect(&mut self, id: VsockConnId) -> Result<(), VsockError>;
fn abort(&mut self, id: VsockConnId) -> Result<(), VsockError>;
fn poll_event(&mut self) -> Result<Option<VsockEvent>, VsockError>;
fn handle_irq(&mut self) -> VsockIrqEvent;
}

IRQ 路径只返回稳定事件和唤醒等待方;不能在 IRQ handler 中执行阻塞 I/O、长流程状态推进或广域锁持有。

Driver Core / OS Glue / Runtime

驱动按四层拆分:

位置允许依赖不允许
Driver Coredrivers/<type>/<device>no_std、寄存器/队列/描述符、mmio-apidma-api 小边界ax-driverax-halaxplat-dynrdrive::PlatformDevice
Capability Boundarydrivers/interface/rdif-*rdif-base、小型错误和事件类型平台、runtime、任务调度
OS Glueplatforms/axplat-dyn/src/drivers/* 或平台 craterdrive::module_driver!、FDT/PCI/Static probe、iomap、IRQ 注册、DMA op上层 FS/NET 策略
Runtimedrivers/*/rd-*,块设备除外rdif-*、waker、poll/blocking wrapper、buffer poolprobe、设备树、ACPI、平台选择

Driver Core 只推进硬件状态机。OS Glue 将硬件实例包装成 rdif-*::Interface 后通过 PlatformDevice::register(...) 注册。除块设备外,Runtime wrapper 从 rdif-*::Interface 构建领域运行时对象,供服务层和上层模块使用;块设备服务直接基于 rdif-block 的 submit/poll 能力边界组织 volume 和文件系统入口。

领域 Service 与上层消费

上层业务模块不直接处理 AllDevices,也不直接把 rdrive 当作全局设备篮子。每个领域有自己的 service,service 可以从 rdrive 查询 typed device 并整理成上层需要的能力集合。

领域新 service 职责上层边界
block枚举 disk,扫描 partition,生成 BlockVolume,根据 bootargs 选择 root candidateFS 只拿 volume / FS block trait
net枚举 rd-net,建立 interface,处理 DHCP/static IP policyNET/NET-NG 只拿 net interface
display枚举 rdif-display / rd-display,选择 primary displaydisplay 模块和 Starry fb 只拿 display handle
input枚举 rdif-input / rd-input,建立 event streaminput 模块和 Starry input 只拿 event source
vsock枚举 rdif-vsock / rd-vsock,维护 connection/event APIvsock socket 层只拿 vsock device

直接使用 rdrive::get_* 只允许出现在设备管理型或低层 HAL 型代码中,例如 Starry USBFS host 管理和 Axvisor AArch64 GIC backend。普通 FS、NET、display、input、vsock 上层模块不得裸查 rdrive

Block Volume 与分区扫描

分区扫描抽成唯一实现,位于独立 block volume 层,而不是 FS 层或旧块驱动接口路径。

目标数据模型:

pub struct BlockVolume {
pub disk_id: DiskId,
pub partition_id: Option<PartitionId>,
pub region: BlockRegion,
pub table_kind: PartitionTableKind,
pub partuuid: Option<PartUuid>,
pub partlabel: Option<PartLabel>,
}

block volume 层负责:

  • rdif-block 枚举 physical disk。
  • 支持 GPT、MBR、raw disk。
  • 产出稳定 volume metadata。
  • 提供裁剪到 BlockRegion 的 block reader。

FS 负责:

  • 根据 root=/dev/sdXnroot=/dev/mmcblkXpYPARTUUID=PARTLABEL= 选择 root volume。
  • 检测 ext4、FAT 等 filesystem magic。
  • 挂载选定 volume。

FS 不再 import ax_driver::{AxBlockDevice, AxDeviceContainer, PartitionInfo, PartitionRegion, PartitionTableKind},也不调用 ax_driver::scan_partitions

Feature 映射

Feature 的职责从“选择 ax-driver 子模块和单个 Ax*Device 类型”调整为“选择要链接的 rdrive probe module、driver core、rdif 能力和 runtime wrapper”。

旧 feature 语义新 feature 语义
ax-driver启用宿主设备 probe 主线,即 rdrive
virtio-blk / virtio-net链接 VirtIO probe 和对应 rdif-block / rdif-eth 注册
virtio-gpu链接 rdif-display / rd-display probe
virtio-input链接 rdif-input / rd-input probe
virtio-socket链接 rdif-vsock / rd-vsock probe
driver-*链接具体硬件 driver core 和 OS glue probe
bus-*链接总线枚举或控制器 probe,例如 PCIe
plat-dyn选择 FDT 动态平台来源,不走 ax_driver_*Ops 回灌

MMIO 与 PCI feature 要分开表达,例如 virtio-gpu-mmiovirtio-gpu-pci 都是 probe module,而不是上层设备类型选择。

文件拆分规则

新增 crate 默认遵循以下布局:

src/
lib.rs # re-export only
error.rs # error type and conversions
types.rs # public data types
interface.rs # trait and event contract
device.rs # runtime device wrapper, if this is rd-* crate
irq.rs # irq event handling, if needed
queue.rs # queue/request/event stream, if needed

已有大文件在迁移触及时必须拆分:

文件当前问题拆分方向
platforms/axplat-dyn/src/drivers/pci/rk3588.rs单文件超过 600 行RC init、ATU/window、MSI/IRQ、config space、FDT glue
platforms/axplat-dyn/src/drivers/blk/rockchip_sd.rs单文件超过 600 行probe/FDT、clock/tuning、card init、rdif-block adapter
platforms/axplat-dyn/src/drivers/blk/mod.rs容器、adapter、IRQ、FDT decode 混杂registry、adapter、irq、probe
platforms/axplat-dyn/src/drivers/mod.rs设备收集、iomap、DMA 混杂device collection、iomap、dma

lib.rs 只做模块声明和 re-export,不承载核心实现。

分阶段硬切实施

Phase 1: rdrive backend 分发

  • 增加 PlatformSource::{Static,Fdt,Acpi}ProbeKind::{Static,Fdt,Acpi,Pci}
  • 新增 probe::static_probe::acpi 模块;ACPI 第一版返回 unsupported error。
  • probe_pre_kernel()probe_all() 改为 backend 分发,保留当前 FDT 与 PCI 能力。
  • Manager 保持只管理 register 和 typed device registry。

Phase 2: 补齐 rdif-display/input/vsock

  • 新增三个 interface crate 并接入 workspace。
  • 每个 crate 按 error/types/interfaceaddr/event/interface 拆文件。
  • 不依赖 ax-driverax-runtimeax-hal 或平台 crate。

Phase 3: block volume service

  • 抽出唯一分区扫描实现,支持 GPT、MBR、raw disk。
  • 产出 BlockVolume 和裁剪后的 block reader。
  • ax-fs / ax-fs-ng 只消费 volume 和 FS block trait。

Phase 4: NET / NET-NG 硬切

  • ax-net / ax-net-ngAxNetDevice 切到 rd-net 或 net service。
  • DHCP/static IP policy 留在 net service 或 NET/NET-NG,不回到 platform glue。

Phase 5: display / input / vsock 硬切

  • 新增 runtime wrapper rd-displayrd-inputrd-vsock
  • 上层 display/input/vsock 模块消费领域 service,不接收 AxDeviceContainer

Phase 6: ax-runtime 切主线

  • 删除宿主初始化主线中的 ax-driver::init_drivers()AllDevices 拆包。
  • 平台 later init 后调用 rdrive::probe_all(false)
  • 调用领域 service 初始化 FS、NET、display、input、vsock。

Phase 7: feature 映射切换

  • ax-feat 中旧 ax-driver/virtio-*driver-*bus-* 映射到 rdrive probe feature。
  • legacy ax-driver feature 只保留给未迁移代码,不作为新宿主路径入口。

验收标准

文档验收:

git diff --check
cd docs
yarn build

本地 docs 未安装依赖时,先执行 corepack enableyarn install --frozen-lockfile,再运行 yarn build

代码验收:

cargo xtask clippy --package rdrive
cargo xtask clippy --package ax-runtime
cargo xtask clippy --package ax-fs-ng
cargo xtask clippy --package ax-net-ng
cargo xtask clippy --package starry-kernel
cargo xtask clippy --package axvisor

搜索验收:

rg "AllDevices|AxDeviceContainer|AxBlockDevice|AxNetDevice|ax_driver::scan_partitions" os/arceos/modules os/StarryOS/kernel os/axvisor
rg "rdrive::get_|rdrive::get_one|rdrive::get_list" os/arceos/modules os/StarryOS/kernel os/axvisor

第二条搜索只允许 Starry USBFS 设备管理路径和 Axvisor HAL/GIC backend 出现裸 rdrive::get_*

系统回归重点:

  • StarryOS QEMU smoke。
  • ext4 rootfs 启动与读写。
  • net-ng / DHCP。
  • qemu-aarch64-plat-dyn 动态平台。
  • Axvisor QEMU / GIC / rdif-intc 路径。