From 9492e3c6f367533266cedacf2cb066ad9d1a626a Mon Sep 17 00:00:00 2001 From: elliott10 Date: Thu, 29 Jan 2026 10:34:46 +0800 Subject: [PATCH 1/5] feat: Add riscv64 platform: sg2002 --- Cargo.toml | 9 +++++++++ Makefile | 2 ++ arceos | 2 +- src/main.rs | 3 +++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e9e5fe37..432ceddf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,6 +109,8 @@ smp = ["axfeat/smp", "axplat-riscv64-visionfive2?/smp"] vf2 = ["dep:axplat-riscv64-visionfive2", "axfeat/driver-sdmmc"] +sg2002 = ["dep:axplat-riscv64-sg2002", "axfeat/driver-sdmmc"] + [dependencies] axdriver.workspace = true axerrno.workspace = true @@ -135,6 +137,13 @@ tag = "dev-v03" features = ["fp-simd", "irq", "rtc"] optional = true +[dependencies.axplat-riscv64-sg2002] +version = "0.1" +git = "https://github.com/elliott10/axplat-riscv64-sg2002.git" +rev = "810954ed" +features = ["fp-simd", "irq", "rtc"] +optional = true + [package.metadata.vendor-filter] platforms = ["riscv64gc-unknown-none-elf", "loongarch64-unknown-none-softfloat"] all-features = true diff --git a/Makefile b/Makefile index d214ce03..a0cd4a81 100644 --- a/Makefile +++ b/Makefile @@ -53,5 +53,7 @@ la: vf2: $(MAKE) ARCH=riscv64 APP_FEATURES=vf2 MYPLAT=axplat-riscv64-visionfive2 BUS=mmio build +sg2002: + $(MAKE) ARCH=riscv64 APP_FEATURES=sg2002 MYPLAT=axplat-riscv64-sg2002 BUS=mmio SMP=1 UIMAGE=y LOG=info build .PHONY: build run justrun debug disasm clean diff --git a/arceos b/arceos index 19a56587..691da8f8 160000 --- a/arceos +++ b/arceos @@ -1 +1 @@ -Subproject commit 19a565873638cd8d21a6124f8d7086ce4e78ae67 +Subproject commit 691da8f8aef9d419b89e0179ea9ead3597ae3640 diff --git a/src/main.rs b/src/main.rs index b88237cc..3071094f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,3 +41,6 @@ fn main() { #[cfg(feature = "vf2")] extern crate axplat_riscv64_visionfive2; + +#[cfg(feature = "sg2002")] +extern crate axplat_riscv64_sg2002; From a64af52b2100d9c592a7e8be2d293fb6ca28e4e1 Mon Sep 17 00:00:00 2001 From: elliott10 Date: Thu, 29 Jan 2026 17:42:12 +0800 Subject: [PATCH 2/5] feat: add cvsd driver, flush icache, modify sstatus for riscv64 sg2002 --- .gitmodules | 2 +- Cargo.toml | 21 ++++++++++++++++++++- api/src/syscall/sys.rs | 2 +- api/src/task.rs | 4 ++++ arceos | 2 +- core/src/mm.rs | 2 ++ 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/.gitmodules b/.gitmodules index 7706eb67..f1ae7c7f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "arceos"] path = arceos - url = https://github.com/Starry-OS/arceos + url = https://github.com/elliott10/arceos branch = dev diff --git a/Cargo.toml b/Cargo.toml index 432ceddf..e012e13c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,7 +109,8 @@ smp = ["axfeat/smp", "axplat-riscv64-visionfive2?/smp"] vf2 = ["dep:axplat-riscv64-visionfive2", "axfeat/driver-sdmmc"] -sg2002 = ["dep:axplat-riscv64-sg2002", "axfeat/driver-sdmmc"] +#sg2002 = ["dep:axplat-riscv64-sg2002", "starry-api/sg2002", "axfeat/plat-sg2002"] +sg2002 = ["dep:axplat-riscv64-sg2002", "axfeat/plat-sg2002"] [dependencies] axdriver.workspace = true @@ -147,3 +148,21 @@ optional = true [package.metadata.vendor-filter] platforms = ["riscv64gc-unknown-none-elf", "loongarch64-unknown-none-softfloat"] all-features = true + +[patch."https://github.com/arceos-org/axdriver_crates.git"] +axdriver_base = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } +axdriver_block = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } +axdriver_display = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } +axdriver_input = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } +axdriver_net = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } +axdriver_pci = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } +axdriver_virtio = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } +axdriver_vsock = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } + +[patch."https://github.com/arceos-org/axcpu.git"] +axcpu = { path = "/home/os/rust/crates/axcpu" } + +[patch."https://github.com/arceos-org/page_table_multiarch.git"] +page_table_multiarch = { git = "https://github.com/arceos-org//page_table_multiarch.git", rev = "53a08f4e" } +[patch.crates-io] +page_table_entry = { git = "https://github.com/arceos-org/page_table_multiarch.git", rev = "53a08f4e" } diff --git a/api/src/syscall/sys.rs b/api/src/syscall/sys.rs index 12e3cbba..5f58ca02 100644 --- a/api/src/syscall/sys.rs +++ b/api/src/syscall/sys.rs @@ -126,6 +126,6 @@ pub fn sys_seccomp(_op: u32, _flags: u32, _args: *const ()) -> AxResult { #[cfg(target_arch = "riscv64")] pub fn sys_riscv_flush_icache() -> AxResult { - riscv::asm::fence_i(); + axhal::asm::flush_icache(); Ok(0) } diff --git a/api/src/task.rs b/api/src/task.rs index aaadb6c3..19f21d6d 100644 --- a/api/src/task.rs +++ b/api/src/task.rs @@ -37,6 +37,10 @@ pub fn new_user_task(name: &str, mut uctx: UserContext, set_child_tid: usize) -> let thr = curr.as_thread(); while !thr.pending_exit() { + + #[cfg(target_arch = "riscv64")] + axhal::asm::flush_icache(); + let reason = uctx.run(); set_timer_state(&curr, TimerState::Kernel); diff --git a/arceos b/arceos index 691da8f8..2ba5a3f4 160000 --- a/arceos +++ b/arceos @@ -1 +1 @@ -Subproject commit 691da8f8aef9d419b89e0179ea9ead3597ae3640 +Subproject commit 2ba5a3f40351f1ba70cc1017fa834e2798391b7e diff --git a/core/src/mm.rs b/core/src/mm.rs index 6672a81a..ce805061 100644 --- a/core/src/mm.rs +++ b/core/src/mm.rs @@ -129,6 +129,8 @@ fn map_elf<'a>( )?; // TDOO: flush the I-cache + #[cfg(target_arch = "riscv64")] + axhal::asm::flush_icache(); } Ok(elf_parser) From 0feeddd69b1bfe332cc7c4b38c4146e9d1b0bf3f Mon Sep 17 00:00:00 2001 From: elliott10 Date: Tue, 24 Mar 2026 17:44:10 +0800 Subject: [PATCH 3/5] feat: update axcpu axplat and support sdcard MBR partitions for sg2002 --- Cargo.toml | 22 +++++++++++----------- arceos | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e012e13c..4ca38d0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -141,7 +141,7 @@ optional = true [dependencies.axplat-riscv64-sg2002] version = "0.1" git = "https://github.com/elliott10/axplat-riscv64-sg2002.git" -rev = "810954ed" +rev = "92a95ef8" features = ["fp-simd", "irq", "rtc"] optional = true @@ -150,19 +150,19 @@ platforms = ["riscv64gc-unknown-none-elf", "loongarch64-unknown-none-softfloat"] all-features = true [patch."https://github.com/arceos-org/axdriver_crates.git"] -axdriver_base = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } -axdriver_block = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } -axdriver_display = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } -axdriver_input = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } -axdriver_net = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } -axdriver_pci = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } -axdriver_virtio = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } -axdriver_vsock = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "d97dae8b" } +axdriver_base = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "4d73e06a" } +axdriver_block = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "4d73e06a" } +axdriver_display = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "4d73e06a" } +axdriver_input = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "4d73e06a" } +axdriver_net = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "4d73e06a" } +axdriver_pci = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "4d73e06a" } +axdriver_virtio = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "4d73e06a" } +axdriver_vsock = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "4d73e06a" } [patch."https://github.com/arceos-org/axcpu.git"] -axcpu = { path = "/home/os/rust/crates/axcpu" } +axcpu = { git = "https://github.com/elliott10/axcpu.git", rev = "47b2dbcb" } [patch."https://github.com/arceos-org/page_table_multiarch.git"] page_table_multiarch = { git = "https://github.com/arceos-org//page_table_multiarch.git", rev = "53a08f4e" } [patch.crates-io] -page_table_entry = { git = "https://github.com/arceos-org/page_table_multiarch.git", rev = "53a08f4e" } +page_table_entry = { git = "https://github.com/arceos-org/page_table_multiarch.git", rev = "53a08f4e" } # features = ["xuantie-c9xx"] diff --git a/arceos b/arceos index 2ba5a3f4..bc2cea7a 160000 --- a/arceos +++ b/arceos @@ -1 +1 @@ -Subproject commit 2ba5a3f40351f1ba70cc1017fa834e2798391b7e +Subproject commit bc2cea7af9681eb35cfdcb28510fb568c24a184b From 3defdbbf1011cad14342bd82eb293c1e9fa89cf1 Mon Sep 17 00:00:00 2001 From: elliott10 Date: Wed, 1 Apr 2026 16:10:56 +0800 Subject: [PATCH 4/5] feat: add device ion for sg2002 --- api/Cargo.toml | 2 + api/src/file/ion.rs | 110 ++++++++++++ api/src/file/mod.rs | 3 + api/src/syscall/mm/mmap.rs | 70 +++++++- api/src/task.rs | 4 - api/src/vfs/dev/fb.rs | 2 +- api/src/vfs/dev/ion/buffer.rs | 112 ++++++++++++ api/src/vfs/dev/ion/device.rs | 314 ++++++++++++++++++++++++++++++++++ api/src/vfs/dev/ion/error.rs | 56 ++++++ api/src/vfs/dev/ion/heap.rs | 92 ++++++++++ api/src/vfs/dev/ion/mod.rs | 61 +++++++ api/src/vfs/dev/ion/types.rs | 234 +++++++++++++++++++++++++ api/src/vfs/dev/loop.rs | 2 +- api/src/vfs/dev/mod.rs | 23 +++ core/src/mm.rs | 4 - core/src/vfs/dev.rs | 10 +- 16 files changed, 1083 insertions(+), 16 deletions(-) create mode 100644 api/src/file/ion.rs create mode 100644 api/src/vfs/dev/ion/buffer.rs create mode 100644 api/src/vfs/dev/ion/device.rs create mode 100644 api/src/vfs/dev/ion/error.rs create mode 100644 api/src/vfs/dev/ion/heap.rs create mode 100644 api/src/vfs/dev/ion/mod.rs create mode 100644 api/src/vfs/dev/ion/types.rs diff --git a/api/Cargo.toml b/api/Cargo.toml index 3864dea2..91ac84d0 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -12,6 +12,7 @@ input = ["dep:axinput"] memtrack = ["axfeat/dwarf", "axalloc/tracking", "dep:gimli"] vsock = ["axnet/vsock"] dev-log = [] +sg2002 = [] [dependencies] axalloc.workspace = true @@ -32,6 +33,7 @@ axnet.workspace = true axpoll.workspace = true axsync.workspace = true axtask.workspace = true +axdma.workspace = true bitflags.workspace = true bitmaps = { version = "3.2.1", default-features = false } bytemuck.workspace = true diff --git a/api/src/file/ion.rs b/api/src/file/ion.rs new file mode 100644 index 00000000..a3e3fd36 --- /dev/null +++ b/api/src/file/ion.rs @@ -0,0 +1,110 @@ +//! Ion Buffer 文件类型 +//! +//! 实现 FileLike trait,用于支持对 Ion 分配的缓冲区进行 mmap。 + +use alloc::borrow::Cow; + +use axerrno::AxResult; +use axpoll::{IoEvents, Pollable}; +use memory_addr::PhysAddrRange; +use starry_core::vfs::DeviceOps; + +use super::{FileLike, Kstat}; +use crate::vfs::dev::{ + ION_DEVICE, + ion::types::ioctl::{ION_IOC_FREE, IonHandleData}, +}; + +/// Ion Buffer 的物理地址信息 +#[derive(Debug, Clone)] +pub struct IonBufferInfo { + /// 物理地址 + pub phys_addr: usize, + /// 缓冲区大小 + pub size: usize, + /// 缓冲区 handle + pub handle: u32, +} + +/// Ion Buffer 文件 +/// +/// 用于支持对 Ion 分配的缓冲区进行 mmap +pub struct IonBufferFile { + /// 缓冲区信息 + info: IonBufferInfo, +} + +impl IonBufferFile { + /// 创建新的 Ion Buffer 文件 + pub fn new(info: IonBufferInfo) -> Self { + Self { info } + } + + /// 获取物理地址范围 + pub fn phys_range(&self) -> PhysAddrRange { + PhysAddrRange::from_start_size( + memory_addr::PhysAddr::from(self.info.phys_addr), + self.info.size, + ) + } + + /// 获取缓冲区信息 + pub fn info(&self) -> &IonBufferInfo { + &self.info + } +} + +impl Pollable for IonBufferFile { + fn poll(&self) -> IoEvents { + IoEvents::IN | IoEvents::OUT + } + + fn register(&self, _context: &mut core::task::Context<'_>, _events: IoEvents) { + // Ion buffer 总是就绪 + } +} + +impl FileLike for IonBufferFile { + fn read(&self, _dst: &mut super::IoDst) -> AxResult { + // Ion buffer 不支持直接读取 + Err(axerrno::AxError::InvalidInput) + } + + fn write(&self, _src: &mut super::IoSrc) -> AxResult { + // Ion buffer 不支持直接写入 + Err(axerrno::AxError::InvalidInput) + } + + fn stat(&self) -> AxResult { + Ok(Kstat { + size: self.info.size as u64, + ..Default::default() + }) + } + + fn path(&self) -> Cow<'_, str> { + Cow::Borrowed("/dev/ion_buffer") + } +} + +impl Drop for IonBufferFile { + fn drop(&mut self) { + debug!( + "Dropping IonBufferFile, freeing handle: {}", + self.info.handle + ); + if let Some(dev) = ION_DEVICE.get() { + let handle_data = IonHandleData { + handle: self.info.handle, + }; + // 调用 ioctl 释放内存 + // 这里忽略了返回值,因为在 drop 中很难处理错误 + let _ = dev.ioctl(ION_IOC_FREE, &handle_data as *const _ as usize); + } else { + error!( + "Failed to find ion device to free buffer handle: {}", + self.info.handle + ); + } + } +} diff --git a/api/src/file/mod.rs b/api/src/file/mod.rs index 54def198..30cbc683 100644 --- a/api/src/file/mod.rs +++ b/api/src/file/mod.rs @@ -6,6 +6,9 @@ mod pidfd; mod pipe; pub mod signalfd; +#[cfg(feature = "sg2002")] +pub mod ion; + use alloc::{borrow::Cow, sync::Arc}; use core::{ffi::c_int, time::Duration}; diff --git a/api/src/syscall/mm/mmap.rs b/api/src/syscall/mm/mmap.rs index 94793882..6193196a 100644 --- a/api/src/syscall/mm/mmap.rs +++ b/api/src/syscall/mm/mmap.rs @@ -13,7 +13,7 @@ use starry_core::{ }; use starry_vm::{vm_load, vm_write_slice}; -use crate::file::{File, FileLike}; +use crate::file::{File, FileLike, get_file_like, ion::IonBufferFile}; bitflags::bitflags! { /// `PROT_*` flags for use with [`sys_mmap`]. @@ -120,7 +120,19 @@ pub fn sys_mmap( ) { return Err(AxError::InvalidInput); } - if map_flags.contains(MmapFlags::ANONYMOUS) != (fd <= 0) { + + // 检查是否是 IonBufferFile,如果是则跳过 ANONYMOUS 检查 + let is_ion_buffer = if fd > 0 { + get_file_like(fd) + .map(|f| f.downcast_arc::().is_ok()) + .unwrap_or(false) + } else { + false + }; + + // 对于普通文件,ANONYMOUS 标志必须与 fd <= 0 一致 + // 对于 IonBufferFile,跳过这个检查 + if !is_ion_buffer && (map_flags.contains(MmapFlags::ANONYMOUS) != (fd <= 0)) { return Err(AxError::InvalidInput); } if fd <= 0 && offset != 0 { @@ -173,6 +185,58 @@ pub fn sys_mmap( }; let file = if fd > 0 { + // 首先尝试检查是否是 IonBufferFile + match get_file_like(fd) { + Ok(file_like) => { + if let Ok(ion_file) = file_like.downcast_arc::() { + // 处理 Ion buffer 的 mmap + let range = ion_file.phys_range(); + + // 计算实际映射长度,向上对齐到页大小 + let map_length = length.max(range.size()).align_up(page_size); + + info!( + "Ion buffer mmap: phys_addr=0x{:x}, buffer_size={}, requested_length={}, \ + map_length={}", + range.start.as_usize(), + range.size(), + length, + map_length + ); + + if map_length == 0 { + warn!("Ion buffer mmap: map_length is 0, this should not happen"); + return Err(AxError::InvalidInput); + } + + let backend = Backend::new_linear( + start.as_usize() as isize - range.start.as_usize() as isize, + ); + + let populate = map_flags.contains(MmapFlags::POPULATE); + aspace.map( + start, + map_length, + permission_flags.into(), + populate, + backend, + )?; + + info!( + "Ion buffer mmap success: vaddr=0x{:x}, length={}", + start.as_usize(), + map_length + ); + return Ok(start.as_usize() as _); + } else { + debug!("fd {} is not IonBufferFile, trying as regular File", fd); + } + } + Err(e) => { + debug!("get_file_like({}) failed: {:?}", fd, e); + } + } + Some(File::from_fd(fd)?) } else { None @@ -200,7 +264,7 @@ pub fn sys_mmap( .downcast::() .map_err(|_| AxError::NoSuchDevice)?; - match device.mmap() { + match device.mmap(offset, length) { DeviceMmap::None => { return Err(AxError::NoSuchDevice); } diff --git a/api/src/task.rs b/api/src/task.rs index 19f21d6d..aaadb6c3 100644 --- a/api/src/task.rs +++ b/api/src/task.rs @@ -37,10 +37,6 @@ pub fn new_user_task(name: &str, mut uctx: UserContext, set_child_tid: usize) -> let thr = curr.as_thread(); while !thr.pending_exit() { - - #[cfg(target_arch = "riscv64")] - axhal::asm::flush_icache(); - let reason = uctx.run(); set_timer_state(&curr, TimerState::Kernel); diff --git a/api/src/vfs/dev/fb.rs b/api/src/vfs/dev/fb.rs index 27069dea..a444ac27 100644 --- a/api/src/vfs/dev/fb.rs +++ b/api/src/vfs/dev/fb.rs @@ -225,7 +225,7 @@ impl DeviceOps for FrameBuffer { self } - fn mmap(&self) -> DeviceMmap { + fn mmap(&self, _offset: usize, _length: usize) -> DeviceMmap { DeviceMmap::Physical(PhysAddrRange::from_start_size( virt_to_phys(self.base), self.size, diff --git a/api/src/vfs/dev/ion/buffer.rs b/api/src/vfs/dev/ion/buffer.rs new file mode 100644 index 00000000..e649e3e2 --- /dev/null +++ b/api/src/vfs/dev/ion/buffer.rs @@ -0,0 +1,112 @@ +//! Ion 缓冲区管理 + +use alloc::{collections::BTreeMap, sync::Arc}; + +use axsync::Mutex; + +use super::{ + error::{IonError, IonResult}, + types::{IonBuffer, IonHandle}, +}; + +/// Ion 缓冲区管理器 +pub struct IonBufferManager { + /// 已分配的缓冲区映射 + buffers: Mutex>>, +} + +impl IonBufferManager { + /// 创建新的缓冲区管理器 + pub const fn new() -> Self { + Self { + buffers: Mutex::new(BTreeMap::new()), + } + } + + /// 注册缓冲区 + pub fn register_buffer(&self, buffer: Arc) -> IonResult<()> { + let mut buffers = self.buffers.lock(); + let handle = buffer.handle; + + if buffers.contains_key(&handle) { + return Err(IonError::BufferExists); + } + + buffers.insert(handle, buffer); + debug!("Registered Ion buffer with handle: {:?}", handle); + Ok(()) + } + + /// 取消注册缓冲区 + pub fn unregister_buffer(&self, handle: IonHandle) -> IonResult> { + let mut buffers = self.buffers.lock(); + let buffer = buffers.remove(&handle).ok_or(IonError::BufferNotFound)?; + + debug!("Unregistered Ion buffer with handle: {:?}", handle); + Ok(buffer) + } + + /// 获取缓冲区 + pub fn get_buffer(&self, handle: IonHandle) -> IonResult> { + let buffers = self.buffers.lock(); + buffers + .get(&handle) + .cloned() + .ok_or(IonError::BufferNotFound) + } + + /// 增加缓冲区引用计数 + pub fn inc_buffer_ref(&self, handle: IonHandle) -> IonResult { + let buffers = self.buffers.lock(); + let buffer = buffers.get(&handle).ok_or(IonError::BufferNotFound)?; + + let ref_count = buffer.inc_ref(); + debug!( + "Increased ref count for handle {:?} to {}", + handle, ref_count + ); + Ok(ref_count) + } + + /// 减少缓冲区引用计数 + pub fn dec_buffer_ref(&self, handle: IonHandle) -> IonResult { + let buffers = self.buffers.lock(); + let buffer = buffers.get(&handle).ok_or(IonError::BufferNotFound)?; + + let ref_count = buffer.dec_ref(); + debug!( + "Decreased ref count for handle {:?} to {}", + handle, ref_count + ); + + if ref_count == 0 { + warn!( + "Buffer ref count reached 0, but buffer still registered: {:?}", + handle + ); + } + + Ok(ref_count) + } + + /// 获取缓冲区数量 + pub fn buffer_count(&self) -> usize { + self.buffers.lock().len() + } + + /// 清理所有缓冲区 + pub fn cleanup_all(&self) { + let mut buffers = self.buffers.lock(); + let count = buffers.len(); + buffers.clear(); + if count > 0 { + warn!("Cleaned up {} Ion buffers", count); + } + } + + /// 获取所有句柄列表(用于调试) + #[cfg(debug_assertions)] + pub fn debug_list_handles(&self) -> alloc::vec::Vec { + self.buffers.lock().keys().copied().collect() + } +} diff --git a/api/src/vfs/dev/ion/device.rs b/api/src/vfs/dev/ion/device.rs new file mode 100644 index 00000000..9c79ddcd --- /dev/null +++ b/api/src/vfs/dev/ion/device.rs @@ -0,0 +1,314 @@ +//! Ion 设备实现 + +use alloc::sync::Arc; +use core::{any::Any, ptr}; + +use axfs_ng_vfs::{NodeFlags, VfsResult}; +use memory_addr::PhysAddrRange; +use starry_core::vfs::{DeviceMmap, DeviceOps}; + +use super::{ + buffer::IonBufferManager, + global_ion_buffer_manager, + heap::IonHeapManager, + types::{ioctl::*, *}, +}; +use crate::file::{ + add_file_like, + ion::{IonBufferFile, IonBufferInfo}, +}; + +/// Ion 设备 +pub struct IonDevice { + /// 堆管理器 + heap_manager: IonHeapManager, + /// 缓冲区管理器 (使用全局共享) + buffer_manager: Arc, +} + +impl IonDevice { + /// 创建 Ion 设备 + pub fn new() -> Self { + Self { + heap_manager: IonHeapManager::new(), + buffer_manager: global_ion_buffer_manager(), + } + } + + /// 处理 ION_IOC_ALLOC 命令 + fn handle_alloc(&self, user_ptr: usize) -> VfsResult { + debug!("Processing ION_IOC_ALLOC"); + + // 从用户空间读取分配数据 + let alloc_data = unsafe { ptr::read(user_ptr as *const IonAllocData) }; + + debug!( + "Alloc request: len={}, heap_id_mask=0x{:x}, flags=0x{:x}", + alloc_data.len, alloc_data.heap_id_mask, alloc_data.flags + ); + + // 选择堆类型(简化处理,优先选择 DMA coherent) + let heap_type = if (alloc_data.heap_id_mask & (1 << IonHeapType::DmaCoherent as u32)) != 0 { + IonHeapType::DmaCoherent + } else if (alloc_data.heap_id_mask & (1 << IonHeapType::Carveout as u32)) != 0 { + IonHeapType::Carveout + } else if (alloc_data.heap_id_mask & (1 << IonHeapType::System as u32)) != 0 { + IonHeapType::System + } else { + error!( + "No supported heap type in mask: 0x{:x}", + alloc_data.heap_id_mask + ); + return Err(axerrno::AxError::InvalidInput); + }; + + // 分配缓冲区 + let buffer = self + .heap_manager + .alloc_buffer( + alloc_data.len as usize, + 1, + heap_type, + IonFlags(alloc_data.flags), + ) + .map_err(|e| axerrno::AxError::from(e))?; + + // 注册缓冲区 + self.buffer_manager + .register_buffer(buffer.clone()) + .map_err(|e| axerrno::AxError::from(e))?; + + // 创建 IonBufferFile 并添加到文件描述符表 + let phys_addr = buffer.dma_info.bus_addr.as_u64() as usize; + let buffer_info = IonBufferInfo { + phys_addr, + size: buffer.size, + handle: buffer.handle.as_u32(), + }; + let ion_file = IonBufferFile::new(buffer_info); + let fd = add_file_like(alloc::sync::Arc::new(ion_file), false) + .map_err(|_| axerrno::AxError::TooManyOpenFiles)?; + + // 返回结果 + let mut result_data = alloc_data; + result_data.fd = fd as u32; + result_data.paddr = phys_addr as u64; + + unsafe { + ptr::write(user_ptr as *mut IonAllocData, result_data); + } + + info!( + "Allocated Ion buffer: fd={}, handle={}, phys_addr=0x{:x}, size={}", + fd, + buffer.handle.as_u32(), + phys_addr, + alloc_data.len + ); + + Ok(0) + } + + /// 处理 ION_IOC_FREE 命令 + fn handle_free(&self, user_ptr: usize) -> VfsResult { + debug!("Processing ION_IOC_FREE"); + + // 从用户空间读取句柄数据 + let handle_data = unsafe { ptr::read(user_ptr as *const IonHandleData) }; + + let handle = IonHandle(handle_data.handle); + debug!("Freeing buffer with handle: {:?}", handle); + + // 取消注册缓冲区 + let buffer = self + .buffer_manager + .unregister_buffer(handle) + .map_err(|e| axerrno::AxError::from(e))?; + + // 释放缓冲区 + self.heap_manager + .free_buffer(buffer) + .map_err(|e| axerrno::AxError::from(e))?; + + info!("Freed Ion buffer: handle={}", handle_data.handle); + Ok(0) + } + + /// 处理 ION_IOC_IMPORT 命令 + fn handle_import(&self, user_ptr: usize) -> VfsResult { + debug!("Processing ION_IOC_IMPORT"); + + // 从用户空间读取 FD 数据 + let fd_data = unsafe { ptr::read(user_ptr as *const IonFdData) }; + + debug!("Import request: fd={}", fd_data.fd); + + // 简化处理:将 fd 作为 handle 直接使用 + // 实际实现中应该检查 fd 的有效性 + let handle = IonHandle(fd_data.fd as u32); + + // 返回结果 + let mut result_data = fd_data; + result_data.handle = handle.as_u32(); + + unsafe { + ptr::write(user_ptr as *mut IonFdData, result_data); + } + + info!( + "Imported Ion buffer: fd={}, handle={}", + fd_data.fd, result_data.handle + ); + Ok(0) + } + + /// 处理 ION_IOC_HEAP_QUERY 命令 + fn handle_heap_query(&self, user_ptr: usize) -> VfsResult { + debug!("Processing ION_IOC_HEAP_QUERY"); + + // 从用户空间读取查询数据 + let mut heap_query = unsafe { ptr::read(user_ptr as *const IonHeapQuery) }; + + debug!( + "Heap query request: cnt={}, heaps=0x{:x}", + heap_query.cnt, heap_query.heaps + ); + + // 定义支持的堆类型信息 + let supported_heaps = [ + (IonHeapType::System, "system", 0), + (IonHeapType::DmaCoherent, "dma_coherent", 1), + (IonHeapType::Carveout, "carveout", 2), + ]; + + let available_heap_count = supported_heaps.len() as u32; + let requested_count = heap_query.cnt.min(available_heap_count); + + // 如果用户提供了堆缓冲区指针,填充堆信息 + if heap_query.heaps != 0 && requested_count > 0 { + let heap_data_ptr = heap_query.heaps as *mut IonHeapData; + + for (i, &(heap_type, name, heap_id)) in supported_heaps + .iter() + .enumerate() + .take(requested_count as usize) + { + let mut heap_data = IonHeapData { + name: [0; MAX_HEAP_NAME], + type_: heap_type as u32, + heap_id, + reserved0: 0, + reserved1: 0, + reserved2: 0, + }; + + // 复制堆名称 + let name_bytes = name.as_bytes(); + let copy_len = name_bytes.len().min(MAX_HEAP_NAME - 1); + heap_data.name[..copy_len].copy_from_slice(&name_bytes[..copy_len]); + + // 写入堆数据 + unsafe { + ptr::write(heap_data_ptr.add(i), heap_data); + } + + info!( + "Added heap {}: type={}, heap_id={}, name={}", + i, heap_type as u32, heap_id, name + ); + } + } + + // 更新返回的堆数量 + heap_query.cnt = available_heap_count; + + // 写回结果 + unsafe { + ptr::write(user_ptr as *mut IonHeapQuery, heap_query); + } + + info!( + "Heap query completed: {} heaps available, {} requested", + available_heap_count, requested_count + ); + Ok(0) + } +} + +impl DeviceOps for IonDevice { + fn read_at(&self, _buf: &mut [u8], _offset: u64) -> VfsResult { + // Ion 设备不支持直接读写 + Ok(0) + } + + fn write_at(&self, _buf: &[u8], _offset: u64) -> VfsResult { + // Ion 设备不支持直接读写 + Ok(0) + } + + fn ioctl(&self, cmd: u32, arg: usize) -> VfsResult { + match cmd { + ION_IOC_HEAP_QUERY => self.handle_heap_query(arg), + ION_IOC_ALLOC => self.handle_alloc(arg), + ION_IOC_FREE => self.handle_free(arg), + ION_IOC_IMPORT => self.handle_import(arg), + _ => { + warn!("Unsupported Ion ioctl command: 0x{:x}", cmd); + Err(axerrno::AxError::Unsupported) + } + } + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn flags(&self) -> NodeFlags { + NodeFlags::NON_CACHEABLE + } + + fn mmap(&self, offset: usize, length: usize) -> DeviceMmap { + // offset 被用作 Ion buffer 的 handle + // 用户空间通过 mmap(fd, offset=handle, ...) 来映射特定的 Ion buffer + let handle = IonHandle(offset as u32); + + match self.buffer_manager.get_buffer(handle) { + Ok(buffer) => { + // 获取缓冲区的物理地址 + let phys_addr = buffer.dma_info.bus_addr.as_u64() as usize; + let size = if length > 0 { + length.min(buffer.size) + } else { + buffer.size + }; + + debug!( + "Ion mmap: handle={}, phys_addr=0x{:x}, size={}", + offset, phys_addr, size + ); + + // 标记缓冲区为已映射 + buffer.set_mapped(); + + DeviceMmap::Physical(PhysAddrRange::from_start_size( + memory_addr::PhysAddr::from(phys_addr), + size, + )) + } + Err(e) => { + warn!( + "Ion mmap failed: cannot find buffer with handle {}: {:?}", + offset, e + ); + DeviceMmap::None + } + } + } +} + +impl Drop for IonDevice { + fn drop(&mut self) { + warn!("Ion device is being dropped, cleaning up buffers"); + self.buffer_manager.cleanup_all(); + } +} diff --git a/api/src/vfs/dev/ion/error.rs b/api/src/vfs/dev/ion/error.rs new file mode 100644 index 00000000..707c8443 --- /dev/null +++ b/api/src/vfs/dev/ion/error.rs @@ -0,0 +1,56 @@ +//! Ion 驱动错误类型定义 + +use core::fmt; + +use axerrno::AxError; + +/// Ion 驱动错误类型 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum IonError { + /// 无效参数 + InvalidArg, + /// 内存不足 + NoMemory, + /// 无效的缓冲区句柄 + InvalidBuffer, + /// 缓冲区已存在 + BufferExists, + /// 缓冲区未找到 + BufferNotFound, + /// 无效的堆类型 + InvalidHeap, + /// 操作不支持 + NotSupported, + /// 内部错误 + Internal, +} + +impl fmt::Display for IonError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InvalidArg => write!(f, "Invalid argument"), + Self::NoMemory => write!(f, "Out of memory"), + Self::InvalidBuffer => write!(f, "Invalid buffer handle"), + Self::BufferExists => write!(f, "Buffer already exists"), + Self::BufferNotFound => write!(f, "Buffer not found"), + Self::InvalidHeap => write!(f, "Invalid heap type"), + Self::NotSupported => write!(f, "Operation not supported"), + Self::Internal => write!(f, "Internal error"), + } + } +} + +impl From for AxError { + fn from(err: IonError) -> Self { + match err { + IonError::InvalidArg => AxError::InvalidInput, + IonError::NoMemory => AxError::NoMemory, + IonError::InvalidBuffer | IonError::BufferNotFound => AxError::NotFound, + IonError::BufferExists => AxError::AlreadyExists, + IonError::InvalidHeap | IonError::NotSupported => AxError::Unsupported, + IonError::Internal => AxError::Interrupted, + } + } +} + +pub type IonResult = Result; diff --git a/api/src/vfs/dev/ion/heap.rs b/api/src/vfs/dev/ion/heap.rs new file mode 100644 index 00000000..601fa820 --- /dev/null +++ b/api/src/vfs/dev/ion/heap.rs @@ -0,0 +1,92 @@ +//! Ion 堆管理 + +use alloc::sync::Arc; +use core::alloc::Layout; + +use axdma::{self, DMAInfo}; + +use super::{ + error::{IonError, IonResult}, + types::{IonBuffer, IonFlags, IonHeapType}, +}; + +/// Ion 堆管理器 +pub struct IonHeapManager; + +impl IonHeapManager { + /// 创建新的堆管理器 + pub const fn new() -> Self { + Self + } + + /// 从指定堆分配缓冲区 + pub fn alloc_buffer( + &self, + size: usize, + align: usize, + heap_type: IonHeapType, + flags: IonFlags, + ) -> IonResult> { + debug!( + "Allocating Ion buffer: size={}, align={}, heap_type={:?}, flags={:?}", + size, align, heap_type, flags + ); + + // 校验参数 + if size == 0 { + return Err(IonError::InvalidArg); + } + + let dma_info = match heap_type { + IonHeapType::System => { + // 系统堆使用普通的 DMA 内存 + self.alloc_dma_buffer(size, align)? + } + IonHeapType::DmaCoherent => { + // DMA coherent 堆 + self.alloc_dma_buffer(size, align)? + } + IonHeapType::Carveout => { + // Carveout 堆暂时不支持,使用 DMA 内存代替 + warn!("Carveout heap not implemented, using DMA heap instead"); + self.alloc_dma_buffer(size, align)? + } + }; + + let buffer = Arc::new(IonBuffer::new(dma_info, size, heap_type, flags)); + debug!("Allocated Ion buffer with handle: {:?}", buffer.handle); + + Ok(buffer) + } + + /// 释放缓冲区 + pub fn free_buffer(&self, buffer: Arc) -> IonResult<()> { + debug!("Freeing Ion buffer with handle: {:?}", buffer.handle); + + // 检查引用计数 + if buffer.ref_count() > 1 { + warn!( + "Freeing buffer with ref_count > 1: {}, handle: {:?}", + buffer.ref_count(), + buffer.handle + ); + } + + // 释放 DMA 内存 + let layout = Layout::from_size_align(buffer.size, 1).map_err(|_| IonError::InvalidArg)?; + + unsafe { + axdma::dealloc_coherent(buffer.dma_info, layout); + } + + debug!("Ion buffer freed successfully"); + Ok(()) + } + + /// 分配 DMA 内存 + fn alloc_dma_buffer(&self, size: usize, align: usize) -> IonResult { + let layout = Layout::from_size_align(size, align).map_err(|_| IonError::InvalidArg)?; + + unsafe { axdma::alloc_coherent(layout).map_err(|_| IonError::NoMemory) } + } +} diff --git a/api/src/vfs/dev/ion/mod.rs b/api/src/vfs/dev/ion/mod.rs new file mode 100644 index 00000000..9b55118c --- /dev/null +++ b/api/src/vfs/dev/ion/mod.rs @@ -0,0 +1,61 @@ +//! Ion (Android ION) memory allocator driver +//! +//! Ion 是一个用于 Android 系统的内存分配器,用于在不同的硬件组件 +//! (如 GPU、摄像头、显示器等)之间共享内存缓冲区。 +//! +//! 这个实现基于 ArceOS 的 axdma 模块,提供 DMA coherent 内存分配。 +//! +//! ## 特性 +//! +//! - 支持 DMA coherent 内存分配 +//! - 通过 IOCTL 接口进行内存管理 +//! - 缓冲区引用计数管理 +//! - 支持多种堆类型 +//! +//! ## IOCTL 命令 +//! +//! - `ION_IOC_ALLOC`: 分配内存缓冲区 +//! - `ION_IOC_FREE`: 释放内存缓冲区 +//! - `ION_IOC_IMPORT`: 导入外部文件描述符 +//! +//! ## 使用示例 +//! +//! ```c +//! // 分配 4KB DMA 内存 +//! struct ion_allocation_data alloc_data = { +//! .len = 4096, +//! .align = 0, +//! .heap_id_mask = 1 << ION_HEAP_TYPE_DMA, +//! .flags = 0, +//! }; +//! ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data); +//! +//! // 释放内存 +//! struct ion_handle_data handle_data = { +//! .handle = alloc_data.handle, +//! }; +//! ioctl(ion_fd, ION_IOC_FREE, &handle_data); +//! ``` + +mod buffer; +mod device; +mod error; +mod heap; +pub mod types; + +use alloc::sync::Arc; + +pub use buffer::IonBufferManager; +pub use device::IonDevice; +use spin::Once; +pub use types::IonHandle; + +/// 全局共享的 Ion Buffer 管理器 +static GLOBAL_ION_BUFFER_MANAGER: Once> = Once::new(); + +/// 获取全局 Ion Buffer 管理器 +pub fn global_ion_buffer_manager() -> Arc { + GLOBAL_ION_BUFFER_MANAGER + .call_once(|| Arc::new(IonBufferManager::new())) + .clone() +} diff --git a/api/src/vfs/dev/ion/types.rs b/api/src/vfs/dev/ion/types.rs new file mode 100644 index 00000000..043034c5 --- /dev/null +++ b/api/src/vfs/dev/ion/types.rs @@ -0,0 +1,234 @@ +//! Ion 驱动数据结构定义 + +use core::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; + +use axdma::DMAInfo; + +/// Ion 堆类型 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum IonHeapType { + /// 系统堆,使用普通的系统内存 + System = 0, + /// DMA 堆,使用 DMA coherent 内存 + DmaCoherent = 1, + /// Carveout 堆,预留的物理内存区域 + Carveout = 2, +} + +impl TryFrom for IonHeapType { + type Error = (); + + fn try_from(value: u32) -> Result { + match value { + 0 => Ok(Self::System), + 1 => Ok(Self::DmaCoherent), + 2 => Ok(Self::Carveout), + _ => Err(()), + } + } +} + +/// Ion 缓冲区标志 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(transparent)] +pub struct IonFlags(pub u32); + +impl IonFlags { + /// 缓存标志 + pub const CACHED: Self = Self(1 << 0); + /// 缓存需要同步 + pub const CACHED_NEEDS_SYNC: Self = Self(1 << 1); +} + +/// Ion 缓冲区句柄 +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct IonHandle(pub u32); + +impl IonHandle { + pub fn new() -> Self { + static COUNTER: AtomicU32 = AtomicU32::new(1); + Self(COUNTER.fetch_add(1, Ordering::SeqCst)) + } + + pub fn as_u32(self) -> u32 { + self.0 + } +} + +/// Ion 缓冲区信息 +#[derive(Debug)] +pub struct IonBuffer { + /// 缓冲区句柄 + pub handle: IonHandle, + /// DMA 信息(包含虚拟地址和总线地址) + pub dma_info: DMAInfo, + /// 缓冲区大小 + pub size: usize, + /// 堆类型 + pub heap_type: IonHeapType, + /// 标志 + pub flags: IonFlags, + /// 引用计数 + pub ref_count: AtomicUsize, + /// 是否已映射到用户空间 + pub mapped: AtomicUsize, +} + +impl IonBuffer { + pub fn new(dma_info: DMAInfo, size: usize, heap_type: IonHeapType, flags: IonFlags) -> Self { + Self { + handle: IonHandle::new(), + dma_info, + size, + heap_type, + flags, + ref_count: AtomicUsize::new(1), + mapped: AtomicUsize::new(0), + } + } + + pub fn inc_ref(&self) -> usize { + self.ref_count.fetch_add(1, Ordering::SeqCst) + 1 + } + + pub fn dec_ref(&self) -> usize { + let old = self.ref_count.fetch_sub(1, Ordering::SeqCst); + if old > 0 { old - 1 } else { 0 } + } + + pub fn ref_count(&self) -> usize { + self.ref_count.load(Ordering::SeqCst) + } + + pub fn set_mapped(&self) { + self.mapped.store(1, Ordering::SeqCst); + } + + pub fn is_mapped(&self) -> bool { + self.mapped.load(Ordering::SeqCst) != 0 + } +} + +// 手动实现 Send 和 Sync,因为 DMAInfo 中的 NonNull 默认不实现 Sync +// 但是在我们的使用场景中,DMA 内存地址是安全的,可以在线程间共享 +unsafe impl Send for IonBuffer {} +unsafe impl Sync for IonBuffer {} + +/// Ion 分配请求 +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct IonAllocData { + /// 请求的大小 + pub len: u64, + /// 堆掩码 + pub heap_id_mask: u32, + /// 标志 + pub flags: u32, + /// 返回的文件描述符 + pub fd: u32, + /// 未使用字段 + pub unused: u32, + /// 物理地址 + pub paddr: u64, + /// 缓冲区名称 + pub name: [u8; MAX_ION_BUFFER_NAME], +} + +/// Ion FD 数据(用于导入外部 fd) +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct IonFdData { + /// 外部文件描述符 + pub fd: i32, + /// 返回的 Ion 句柄 + pub handle: u32, +} + +/// Ion 句柄数据(用于释放缓冲区) +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct IonHandleData { + /// Ion 句柄 + pub handle: u32, +} + +pub const MAX_HEAP_NAME: usize = 32; +pub const MAX_ION_BUFFER_NAME: usize = 32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct IonHeapData { + pub name: [u8; MAX_HEAP_NAME], + pub type_: u32, + pub heap_id: u32, + pub reserved0: u32, + pub reserved1: u32, + pub reserved2: u32, +} + +/// Ion 堆查询数据 +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct IonHeapQuery { + /// 堆计数(输入:要查询的堆数量,输出:实际堆数量) + pub cnt: u32, + /// 保留字段 + pub reserved0: u32, + /// 堆数据指针(用户空间地址) + pub heaps: u64, + /// 保留字段 + pub reserved1: u32, + /// 保留字段 + pub reserved2: u32, +} + +/// Ion IOCTL 命令 +pub mod ioctl { + pub use super::*; + + /// 魔数 + pub const ION_IOC_MAGIC: u8 = b'I'; + + /// 分配内存 + pub const ION_IOC_ALLOC: u32 = ioctl_iowr!(ION_IOC_MAGIC, 0, IonAllocData); + /// 查询堆信息 + pub const ION_IOC_HEAP_QUERY: u32 = ioctl_iowr!(ION_IOC_MAGIC, 8, IonHeapQuery); + + /// 释放内存 + pub const ION_IOC_FREE: u32 = ioctl_iow!(ION_IOC_MAGIC, 1, IonHandleData); + /// 导入 fd + pub const ION_IOC_IMPORT: u32 = ioctl_iowr!(ION_IOC_MAGIC, 5, IonFdData); +} + +/// IOCTL 宏定义 +macro_rules! ioctl_iowr { + ($magic:expr, $nr:expr, $ty:ty) => { + (3u32 << 30) + | (($magic as u32) << 8) + | ($nr as u32) + | ((core::mem::size_of::<$ty>() as u32) << 16) + }; +} + +macro_rules! ioctl_iow { + ($magic:expr, $nr:expr, $ty:ty) => { + (1u32 << 30) + | (($magic as u32) << 8) + | ($nr as u32) + | ((core::mem::size_of::<$ty>() as u32) << 16) + }; +} + +#[allow(unused_macros)] +macro_rules! ioctl_ior { + ($magic:expr, $nr:expr, $ty:ty) => { + (2u32 << 30) + | (($magic as u32) << 8) + | ($nr as u32) + | ((core::mem::size_of::<$ty>() as u32) << 16) + }; +} + +pub(crate) use ioctl_iow; +pub(crate) use ioctl_iowr; diff --git a/api/src/vfs/dev/loop.rs b/api/src/vfs/dev/loop.rs index fc4d5d74..1de6106c 100644 --- a/api/src/vfs/dev/loop.rs +++ b/api/src/vfs/dev/loop.rs @@ -150,7 +150,7 @@ impl DeviceOps for LoopDevice { self } - fn mmap(&self) -> DeviceMmap { + fn mmap(&self, _offset: usize, _length: usize) -> DeviceMmap { if let Some(FileBackend::Cached(cache)) = self.file.lock().as_ref() { DeviceMmap::Cache(cache.clone()) } else { diff --git a/api/src/vfs/dev/mod.rs b/api/src/vfs/dev/mod.rs index c9a04d9d..6eb2f4a9 100644 --- a/api/src/vfs/dev/mod.rs +++ b/api/src/vfs/dev/mod.rs @@ -11,6 +11,9 @@ mod memtrack; mod rtc; pub mod tty; +#[cfg(feature = "sg2002")] +pub mod ion; + use alloc::{format, sync::Arc}; use core::any::Any; @@ -20,8 +23,12 @@ use axsync::Mutex; #[cfg(feature = "dev-log")] pub use log::bind_dev_log; use rand::{RngCore, SeedableRng, rngs::SmallRng}; +use spin::Once; use starry_core::vfs::{Device, DeviceOps, DirMaker, DirMapping, SimpleDir, SimpleFs}; +#[cfg(feature = "sg2002")] +pub static ION_DEVICE: Once> = Once::new(); + const RANDOM_SEED: &[u8; 32] = b"0123456789abcdef0123456789abcdef"; pub(crate) fn new_devfs() -> Filesystem { @@ -228,6 +235,22 @@ fn builder(fs: Arc) -> DirMaker { ), ); + #[cfg(feature = "sg2002")] + { + // Ion device + let ion_device = Arc::new(ion::IonDevice::new()); + ION_DEVICE.call_once(|| ion_device.clone()); + root.add( + "ion", + Device::new( + fs.clone(), + NodeType::CharacterDevice, + DeviceId::new(10, 56), // Ion 设备的标准设备号 + ion_device, + ), + ); + } + root.add( "ptmx", Device::new( diff --git a/core/src/mm.rs b/core/src/mm.rs index ce805061..65476dab 100644 --- a/core/src/mm.rs +++ b/core/src/mm.rs @@ -127,10 +127,6 @@ fn map_elf<'a>( false, backend, )?; - - // TDOO: flush the I-cache - #[cfg(target_arch = "riscv64")] - axhal::asm::flush_icache(); } Ok(elf_parser) diff --git a/core/src/vfs/dev.rs b/core/src/vfs/dev.rs index 7e0fb4ab..43fa5ac2 100644 --- a/core/src/vfs/dev.rs +++ b/core/src/vfs/dev.rs @@ -44,7 +44,11 @@ pub trait DeviceOps: Send + Sync { } /// Returns the memory mapping behavior of the device. - fn mmap(&self) -> DeviceMmap { + /// + /// # Arguments + /// * `offset` - The offset from the start of the device + /// * `length` - The length of the mapping + fn mmap(&self, _offset: usize, _length: usize) -> DeviceMmap { DeviceMmap::None } @@ -84,8 +88,8 @@ impl Device { } /// Returns the memory mapping behavior of the device. - pub fn mmap(&self) -> DeviceMmap { - self.ops.mmap() + pub fn mmap(&self, offset: usize, length: usize) -> DeviceMmap { + self.ops.mmap(offset, length) } } From f36d2224a2ae95b98b7b2d8f575b8e1a88f5987c Mon Sep 17 00:00:00 2001 From: elliott10 Date: Thu, 2 Apr 2026 14:30:40 +0800 Subject: [PATCH 5/5] feat: Support device: cvi-tpu to accelerate ai inference by pengzechen --- Cargo.lock | 568 ++++++++++++++++++------------ Cargo.toml | 8 +- api/src/vfs/dev/mod.rs | 13 + api/src/vfs/dev/tpu/device.rs | 591 ++++++++++++++++++++++++++++++++ api/src/vfs/dev/tpu/error.rs | 41 +++ api/src/vfs/dev/tpu/mod.rs | 29 ++ api/src/vfs/dev/tpu/platform.rs | 285 +++++++++++++++ api/src/vfs/dev/tpu/tdma.rs | 200 +++++++++++ api/src/vfs/dev/tpu/tiu.rs | 128 +++++++ api/src/vfs/dev/tpu/types.rs | 468 +++++++++++++++++++++++++ 10 files changed, 2110 insertions(+), 221 deletions(-) create mode 100644 api/src/vfs/dev/tpu/device.rs create mode 100644 api/src/vfs/dev/tpu/error.rs create mode 100644 api/src/vfs/dev/tpu/mod.rs create mode 100644 api/src/vfs/dev/tpu/platform.rs create mode 100644 api/src/vfs/dev/tpu/tdma.rs create mode 100644 api/src/vfs/dev/tpu/tiu.rs create mode 100644 api/src/vfs/dev/tpu/types.rs diff --git a/Cargo.lock b/Cargo.lock index 122aa957..5cf93e15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.25.1" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +checksum = "59317f77929f0e679d39364702289274de2f0f0b22cbf50b2b8cff2169a0b27a" dependencies = [ "cpp_demangle", "gimli", @@ -57,9 +57,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -72,15 +72,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -107,12 +107,12 @@ dependencies = [ [[package]] name = "arm-gic-driver" -version = "0.15.8" +version = "0.15.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f251a1a74133f802b55eaf5e340107b0024457aa9b2ac3c72074501bfa8509a5" +checksum = "f4439bfed45ec60e61de4905b54780f618c6887cb7ebb277f138663e2749251a" dependencies = [ "aarch64-cpu", - "bitflags 2.10.0", + "bitflags 2.11.0", "enum_dispatch", "log", "paste", @@ -163,7 +163,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "axbacktrace" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf9566516f5d799b2f791a6ec5af57eec87d17624346f7c876fa006b922c99e6" +checksum = "1ed127f24c722b06d19c9c1ff73907905bbc2f9463dfd7440652f3f0d6617a93" dependencies = [ "addr2line", "cfg-if", @@ -210,9 +210,9 @@ dependencies = [ [[package]] name = "axconfig-gen" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf14099a96dbb925e39a44c4f25555f1e24516194452a84a943aa7eda62383d" +checksum = "e8021a26bbd0b7e0760e28ded5dba2082fda8224c7cfd457ab370ff851626452" dependencies = [ "clap", "toml_edit", @@ -220,20 +220,20 @@ dependencies = [ [[package]] name = "axconfig-macros" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86a6711b80fbd1dc4c1d8e2fb77a5de6fc8e2eb2b96bbd0420ca8af370eb74c" +checksum = "4b2decc5437a10ddb659f0fbd819b9308362ea1d11455ddb5a1c47ea3973920d" dependencies = [ "axconfig-gen", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "axcpu" version = "0.3.0" -source = "git+https://github.com/arceos-org/axcpu.git?tag=dev-v03#72ef3859952b7340bae261c9a50c32705e602017" +source = "git+https://github.com/elliott10/axcpu.git?rev=628f1c99#628f1c99ab375723d965ca925a0c00ed43e38e71" dependencies = [ "aarch64-cpu", "axbacktrace", @@ -263,6 +263,21 @@ dependencies = [ "log", ] +[[package]] +name = "axdma" +version = "0.2.0" +dependencies = [ + "allocator", + "axalloc", + "axconfig", + "axerrno 0.2.2", + "axhal", + "axmm", + "kspin", + "log", + "memory_addr", +] + [[package]] name = "axdriver" version = "0.2.0" @@ -280,6 +295,7 @@ dependencies = [ "axhal", "cfg-if", "crate_interface", + "gpt_disk_io", "log", "smallvec", ] @@ -287,22 +303,23 @@ dependencies = [ [[package]] name = "axdriver_base" version = "0.1.2" -source = "git+https://github.com/arceos-org/axdriver_crates.git?tag=dev-v01#16f1ae864e1317f67d4e22a645fcb7399ae86596" +source = "git+https://github.com/elliott10/axdriver_crates.git?rev=4d73e06a#4d73e06a0af27c5daf1a0d67864c2adf902e720b" [[package]] name = "axdriver_block" version = "0.1.2" -source = "git+https://github.com/arceos-org/axdriver_crates.git?tag=dev-v01#16f1ae864e1317f67d4e22a645fcb7399ae86596" +source = "git+https://github.com/elliott10/axdriver_crates.git?rev=4d73e06a#4d73e06a0af27c5daf1a0d67864c2adf902e720b" dependencies = [ "axdriver_base", "log", + "sg200x-bsp", "simple-sdmmc", ] [[package]] name = "axdriver_display" version = "0.1.2" -source = "git+https://github.com/arceos-org/axdriver_crates.git?tag=dev-v01#16f1ae864e1317f67d4e22a645fcb7399ae86596" +source = "git+https://github.com/elliott10/axdriver_crates.git?rev=4d73e06a#4d73e06a0af27c5daf1a0d67864c2adf902e720b" dependencies = [ "axdriver_base", ] @@ -310,7 +327,7 @@ dependencies = [ [[package]] name = "axdriver_input" version = "0.1.2" -source = "git+https://github.com/arceos-org/axdriver_crates.git?tag=dev-v01#16f1ae864e1317f67d4e22a645fcb7399ae86596" +source = "git+https://github.com/elliott10/axdriver_crates.git?rev=4d73e06a#4d73e06a0af27c5daf1a0d67864c2adf902e720b" dependencies = [ "axdriver_base", "strum", @@ -319,7 +336,7 @@ dependencies = [ [[package]] name = "axdriver_net" version = "0.1.2" -source = "git+https://github.com/arceos-org/axdriver_crates.git?tag=dev-v01#16f1ae864e1317f67d4e22a645fcb7399ae86596" +source = "git+https://github.com/elliott10/axdriver_crates.git?rev=4d73e06a#4d73e06a0af27c5daf1a0d67864c2adf902e720b" dependencies = [ "axdriver_base", "log", @@ -329,7 +346,7 @@ dependencies = [ [[package]] name = "axdriver_pci" version = "0.1.2" -source = "git+https://github.com/arceos-org/axdriver_crates.git?tag=dev-v01#16f1ae864e1317f67d4e22a645fcb7399ae86596" +source = "git+https://github.com/elliott10/axdriver_crates.git?rev=4d73e06a#4d73e06a0af27c5daf1a0d67864c2adf902e720b" dependencies = [ "virtio-drivers", ] @@ -337,7 +354,7 @@ dependencies = [ [[package]] name = "axdriver_virtio" version = "0.1.2" -source = "git+https://github.com/arceos-org/axdriver_crates.git?tag=dev-v01#16f1ae864e1317f67d4e22a645fcb7399ae86596" +source = "git+https://github.com/elliott10/axdriver_crates.git?rev=4d73e06a#4d73e06a0af27c5daf1a0d67864c2adf902e720b" dependencies = [ "axdriver_base", "axdriver_block", @@ -352,7 +369,7 @@ dependencies = [ [[package]] name = "axdriver_vsock" version = "0.1.2" -source = "git+https://github.com/arceos-org/axdriver_crates.git?tag=dev-v01#16f1ae864e1317f67d4e22a645fcb7399ae86596" +source = "git+https://github.com/elliott10/axdriver_crates.git?rev=4d73e06a#4d73e06a0af27c5daf1a0d67864c2adf902e720b" dependencies = [ "axdriver_base", "log", @@ -384,6 +401,7 @@ version = "0.2.0" dependencies = [ "axalloc", "axbacktrace", + "axcpu", "axdisplay", "axdriver", "axfs", @@ -409,7 +427,7 @@ dependencies = [ "axio", "axpoll", "axsync", - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "chrono", "intrusive-collections", @@ -424,15 +442,15 @@ dependencies = [ [[package]] name = "axfs-ng-vfs" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf0d501c182116576111dc04ba89f48fea639b7080e0455393be5dbc41cfacef" +checksum = "75b3fc5c71051e9ae0b29700aa6eb676b7dadb91be3415d2b374cc8d2a2d37c6" dependencies = [ "axerrno 0.2.2", "axpoll", - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", - "hashbrown 0.15.5", + "hashbrown", "inherit-methods-macro", "log", "smallvec", @@ -459,7 +477,7 @@ dependencies = [ "linkme", "log", "memory_addr", - "page_table_multiarch 0.5.7 (git+https://github.com/arceos-org/page_table_multiarch.git?tag=dev-v05)", + "page_table_multiarch 0.5.7 (git+https://github.com/arceos-org//page_table_multiarch.git?rev=53a08f4e)", "percpu", ] @@ -513,7 +531,7 @@ dependencies = [ "log", "memory_addr", "memory_set", - "page_table_multiarch 0.5.7 (git+https://github.com/arceos-org/page_table_multiarch.git?tag=dev-v05)", + "page_table_multiarch 0.5.7 (git+https://github.com/arceos-org//page_table_multiarch.git?rev=53a08f4e)", ] [[package]] @@ -532,11 +550,11 @@ dependencies = [ "axpoll", "axsync", "axtask", - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "enum_dispatch", "event-listener", - "hashbrown 0.16.1", + "hashbrown", "lazy_static", "lazyinit", "log", @@ -551,7 +569,7 @@ version = "0.3.0" source = "git+https://github.com/arceos-org/axplat_crates.git?tag=dev-v03#0df0713b1c20eafaeebdc6b0e194b2985e857949" dependencies = [ "axplat-macros", - "bitflags 2.10.0", + "bitflags 2.11.0", "const-str", "crate_interface", "handler_table", @@ -616,7 +634,7 @@ source = "git+https://github.com/arceos-org/axplat_crates.git?tag=dev-v03#0df071 dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -637,6 +655,23 @@ dependencies = [ "uart_16550", ] +[[package]] +name = "axplat-riscv64-sg2002" +version = "0.1.0" +source = "git+https://github.com/elliott10/axplat-riscv64-sg2002.git?rev=92a95ef8#92a95ef84ff126bad82a5c762c954021f59a895b" +dependencies = [ + "axconfig-macros", + "axcpu", + "axplat", + "dw_apb_uart", + "kspin", + "lazyinit", + "log", + "riscv", + "riscv_plic 0.2.0 (git+https://github.com/arceos-org/riscv_plic.git?tag=dev-v02)", + "sbi-rt", +] + [[package]] name = "axplat-riscv64-visionfive2" version = "0.3.0" @@ -663,7 +698,7 @@ dependencies = [ "axconfig-macros", "axcpu", "axplat", - "bitflags 2.10.0", + "bitflags 2.11.0", "heapless 0.9.2", "int_ratio", "kspin", @@ -681,12 +716,12 @@ dependencies = [ [[package]] name = "axpoll" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06a0cf7cffe0e87c338f41d59bd0a05fa75cf9c4799b4107fa0fc6cf27d8d23" +checksum = "36b92f85c6903350f5146216ccb7d7a7e7b4dbd6f5927a1279db03ba52a53ae7" dependencies = [ - "bitflags 2.10.0", - "linux-raw-sys", + "bitflags 2.11.0", + "linux-raw-sys 0.12.1", "spin 0.10.0", ] @@ -768,7 +803,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cexpr", "clang-sys", "itertools", @@ -779,7 +814,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -788,6 +823,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b645c5c09a7d4035949cfce1a915785aaad6f17800c35fda8a8c311c491f284" +[[package]] +name = "bit-struct" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "270fbbb014407467f7a2c9b1fa0b74057d5cbc452f18bac3bb5aad601e590521" +dependencies = [ + "num-traits", + "serde", +] + [[package]] name = "bit_field" version = "0.10.3" @@ -802,7 +847,7 @@ checksum = "d3ca019570363e800b05ad4fd890734f28ac7b72f563ad8a35079efb793616f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -813,9 +858,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bitmap-allocator" @@ -840,9 +885,9 @@ checksum = "a7913f22349ffcfc6ca0ca9a656ec26cfbba538ed49c31a273dff2c5d1ea83d9" [[package]] name = "bytemuck" -version = "1.24.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" dependencies = [ "bytemuck_derive", ] @@ -855,7 +900,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -881,9 +926,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "num-traits", ] @@ -901,9 +946,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.53" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", "clap_derive", @@ -911,9 +956,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.53" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -923,27 +968,27 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "clap_lex" -version = "0.7.6" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "concurrent-queue" @@ -968,9 +1013,9 @@ checksum = "451d0640545a0553814b4c646eb549343561618838e9b42495f466131fe3ad49" [[package]] name = "const_fn" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f8a2ca5ac02d09563609681103aada9e1777d54fc57a5acd7a41404f9c93b6e" +checksum = "413d67b29ef1021b4d60f4aa1e925ca031751e213832b4b1d588fae623c05c60" [[package]] name = "convert_case" @@ -983,9 +1028,9 @@ dependencies = [ [[package]] name = "cpp_demangle" -version = "0.4.5" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253" +checksum = "0667304c32ea56cb4cd6d2d7c0cfe9a2f8041229db8c033af7f8d69492429def" dependencies = [ "cfg-if", ] @@ -1007,9 +1052,24 @@ checksum = "70272a03a2cef15589bac05d3d15c023752f5f8f2da8be977d983a9d9e6250fb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", ] +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "critical-section" version = "1.2.0" @@ -1039,7 +1099,7 @@ checksum = "9a49d5cd78b1c748184d41407b14a58af8403c13328ff2b9f49b0a418c24e3ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -1106,7 +1166,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -1120,24 +1180,24 @@ dependencies = [ [[package]] name = "derive_more" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 2.0.111", + "syn 2.0.117", "unicode-xid", ] @@ -1147,6 +1207,14 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" +[[package]] +name = "dw_apb_uart" +version = "0.2.0" +source = "git+https://github.com/elliott10/dw_apb_uart.git?rev=9de1bf0f#9de1bf0fb36a17ba2cc29cbed47131ed1b8de12f" +dependencies = [ + "tock-registers 0.8.1", +] + [[package]] name = "either" version = "1.15.0" @@ -1168,7 +1236,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -1179,7 +1247,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -1216,14 +1284,14 @@ checksum = "ba8f5038f5845165d06fe1453fe4130ad546d3314818bbda57e208e7b0cffe08" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "fdt-parser" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f95f0bda5ff920492f6573294d8e3a99b75ee2e5ef93ab313fc6d517fa46785" +checksum = "1e175b7c46c98b80c8130665802cb3d5407fb6042b70a3d25f1b6edcb8f3de41" [[package]] name = "flatten_objects" @@ -1240,12 +1308,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "foldhash" version = "0.2.0" @@ -1254,45 +1316,45 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-macro", "futures-task", "pin-project-lite", - "pin-utils", + "slab", ] [[package]] name = "gimli" -version = "0.32.3" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "19e16c5073773ccf057c282be832a59ee53ef5ff98db3aeff7f8314f52ffc196" dependencies = [ "stable_deref_trait", ] @@ -1303,6 +1365,28 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "gpt_disk_io" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb194b955ba40423510e4342a077df49c70a599cf692cd0e30a86a32d8a9c7b1" +dependencies = [ + "bytemuck", + "gpt_disk_types", +] + +[[package]] +name = "gpt_disk_types" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3972298dc4cef533492b66bdd75747133618917f44885a11dc8abd24c4e3f1f0" +dependencies = [ + "bytemuck", + "crc", + "ucs2", + "uguid", +] + [[package]] name = "handler_table" version = "0.1.2" @@ -1318,17 +1402,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.1.5", -] - [[package]] name = "hashbrown" version = "0.16.1" @@ -1337,7 +1410,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", - "foldhash 0.2.0", + "foldhash", ] [[package]] @@ -1380,12 +1453,12 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown", ] [[package]] @@ -1446,7 +1519,7 @@ source = "git+https://github.com/Starry-OS/kernel_elf_parser.git?rev=fdcce74#fdc dependencies = [ "xmas-elf", "zero", - "zerocopy 0.8.31", + "zerocopy 0.8.48", ] [[package]] @@ -1486,9 +1559,9 @@ checksum = "17f03abfebdaaf0fad16790237a0348baf84886d3ade460db13bae59e614a180" [[package]] name = "libc" -version = "0.2.178" +version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] name = "libloading" @@ -1523,7 +1596,7 @@ checksum = "e5cec0ec4228b4853bb129c84dbf093a27e6c7a20526da046defc334a1b017f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -1532,6 +1605,12 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "lock_api" version = "0.4.14" @@ -1554,16 +1633,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c9f0d275c70310e2a9d2fc23250c5ac826a73fa828a5f256401f85c5c554283" dependencies = [ "bit_field", - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] name = "lru" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96051b46fc183dc9cd4a223960ef37b9af631b55191852a8274bfef064cda20f" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" dependencies = [ - "hashbrown 0.16.1", + "hashbrown", ] [[package]] @@ -1583,9 +1662,9 @@ checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memoffset" @@ -1648,9 +1727,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", "rustversion", @@ -1658,20 +1737,20 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" @@ -1700,17 +1779,16 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "page_table_entry" version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda9891ec368fda90e4b2cc36592b4881073e25a339fe7e3eddd811f0cf6bf18" +source = "git+https://github.com/arceos-org/page_table_multiarch.git?rev=53a08f4e#53a08f4ecb68a7334d6f8dd55f2e2ce489de8ad1" dependencies = [ "aarch64-cpu", - "bitflags 2.10.0", + "bitflags 2.11.0", "memory_addr", "x86_64", ] @@ -1731,7 +1809,7 @@ dependencies = [ [[package]] name = "page_table_multiarch" version = "0.5.7" -source = "git+https://github.com/arceos-org/page_table_multiarch.git?tag=dev-v05#4594a765e361bca2a8b6ef6773a37ae6d8539840" +source = "git+https://github.com/arceos-org//page_table_multiarch.git?rev=53a08f4e#53a08f4ecb68a7334d6f8dd55f2e2ce489de8ad1" dependencies = [ "arrayvec", "axerrno 0.1.2", @@ -1751,9 +1829,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "percpu" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e56c0c558952222967b592899f98765b48590e7bd7403bfd7075f73afc6ed6" +checksum = "54ca06381bdd16a5397e23cf61d347b539c765e2c20b2ecc5cb36df88695c1f7" dependencies = [ "cfg-if", "kernel_guard", @@ -1764,38 +1842,33 @@ dependencies = [ [[package]] name = "percpu_macros" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9f4cc54a2e471ff72f1499461ba381ad4eae9cbd60d29c258545b995e406e0" +checksum = "a933d46113c0171aee86623311a9367f2ec3a86dab0a96aba1d5bc627473617e" dependencies = [ + "cfg-if", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" dependencies = [ "portable-atomic", ] @@ -1807,7 +1880,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -1829,14 +1902,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -1849,16 +1922,16 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", "version_check", "yansi", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -1874,9 +1947,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" [[package]] name = "raw-cpuid" @@ -1893,14 +1966,14 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -1910,9 +1983,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -1921,9 +1994,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "ringbuf" @@ -1956,7 +2029,7 @@ checksum = "e8c4aa1ea1af6dcc83a61be12e8189f9b293c3ba5a487778a4cd89fb060fdbbc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -1990,27 +2063,28 @@ dependencies = [ [[package]] name = "rlsf" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222fb240c3286247ecdee6fa5341e7cdad0ffdf8e7e401d9937f2d58482a20bf" +checksum = "1646a59a9734b8b7a0ac51689388a60fe1625d4b956348e9de07591a1478457a" dependencies = [ "cfg-if", "const-default", "libc", + "rustversion", "svgbobdoc", ] [[package]] name = "rustc-demangle" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustc_version" @@ -2044,12 +2118,12 @@ checksum = "e6e36312fb5ddc10d08ecdc65187402baba4ac34585cb9d1b78522ae2358d890" [[package]] name = "scope-local" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "231e441739fbe668e91acf8440a0b1ac83c73faec7a6d984190ee25354c2ec9a" +checksum = "4a7d5ed5013e6436fcd78f2bcd3892a6286ef9ce6c9b61504d4c4a08d6a40eab" dependencies = [ "percpu", - "spin 0.9.8", + "spin 0.10.0", ] [[package]] @@ -2064,6 +2138,46 @@ version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "sg200x-bsp" +version = "0.3.0" +source = "git+https://github.com/yfblock/sg200x-bsp#67915999f9d5db6aeef952d478cdbeef9fa8400b" +dependencies = [ + "bit-struct", + "log", + "tock-registers 0.9.0", +] + [[package]] name = "shlex" version = "1.3.0" @@ -2082,9 +2196,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "slab_allocator" @@ -2148,13 +2262,14 @@ dependencies = [ "axfs", "axhal", "axlog", + "axplat-riscv64-sg2002", "axplat-riscv64-visionfive2", "axruntime", "axsync", "axtask", "cfg-if", "linkme", - "linux-raw-sys", + "linux-raw-sys 0.11.0", "starry-api", "starry-core", "starry-process", @@ -2169,6 +2284,7 @@ dependencies = [ "axbacktrace", "axconfig", "axdisplay", + "axdma", "axdriver", "axerrno 0.2.2", "axfeat", @@ -2183,7 +2299,7 @@ dependencies = [ "axpoll", "axsync", "axtask", - "bitflags 2.10.0", + "bitflags 2.11.0", "bitmaps", "bytemuck", "cfg-if", @@ -2192,13 +2308,13 @@ dependencies = [ "event-listener", "flatten_objects", "gimli", - "hashbrown 0.16.1", + "hashbrown", "indoc", "inherit-methods-macro", "kspin", "lazy_static", "linkme", - "linux-raw-sys", + "linux-raw-sys 0.11.0", "memory_addr", "num_enum", "rand", @@ -2213,7 +2329,7 @@ dependencies = [ "starry-vm", "syscalls", "x86", - "zerocopy 0.8.31", + "zerocopy 0.8.48", ] [[package]] @@ -2233,19 +2349,19 @@ dependencies = [ "axpoll", "axsync", "axtask", - "bitflags 2.10.0", + "bitflags 2.11.0", "bytemuck", "cfg-if", "event-listener", "extern-trait", - "hashbrown 0.16.1", + "hashbrown", "inherit-methods-macro", "kernel-elf-parser", "kernel_guard", "kspin", "lazy_static", "linkme", - "linux-raw-sys", + "linux-raw-sys 0.11.0", "lock_api", "memory_addr", "ouroboros", @@ -2279,12 +2395,12 @@ version = "0.2.3" source = "git+https://github.com/Starry-OS/starry-signal.git?tag=dev-v02#0597c1695b7c724f6d40e0d5873eaa148679e8bd" dependencies = [ "axcpu", - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "derive_more", "event-listener", "kspin", - "linux-raw-sys", + "linux-raw-sys 0.11.0", "log", "starry-vm", "strum", @@ -2337,7 +2453,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -2366,9 +2482,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.111" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -2382,22 +2498,22 @@ source = "git+https://github.com/Starry-OS/syscalls.git?rev=efac241#efac241add62 [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -2448,11 +2564,29 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94d293f51425981fdb1b766beae254dbb711a17e8c4b549dc69b9b7ee0d478d5" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "rustversion", "x86", ] +[[package]] +name = "ucs2" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79298e11f316400c57ec268f3c2c29ac3c4d4777687955cd3d4f3a35ce7eba" +dependencies = [ + "bit_field", +] + +[[package]] +name = "uguid" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8352f8c05e47892e7eaf13b34abd76a7f4aeaf817b716e88789381927f199c" +dependencies = [ + "bytemuck", +] + [[package]] name = "uluru" version = "3.1.0" @@ -2464,15 +2598,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-width" @@ -2504,7 +2638,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6a39747311dabb3d37807037ed1c3c38d39f99198d091b5b79ecd5c8d82f799" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "enumn", "log", "zerocopy 0.7.35", @@ -2533,7 +2667,7 @@ checksum = "65c67ce935f3b4329e473ecaff7bab444fcdc3d1d19f8bae61fabfa90b84f93e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -2559,9 +2693,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr", ] @@ -2597,7 +2731,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7841fa0098ceb15c567d93d3fae292c49e10a7662b4936d5f6a9728594555ba" dependencies = [ "bit_field", - "bitflags 2.10.0", + "bitflags 2.11.0", "const_fn", "rustversion", "volatile 0.4.6", @@ -2646,11 +2780,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ - "zerocopy-derive 0.8.31", + "zerocopy-derive 0.8.48", ] [[package]] @@ -2661,16 +2795,16 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] diff --git a/Cargo.toml b/Cargo.toml index 4ca38d0a..f79323a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ axnet = { path = "arceos/modules/axnet" } axruntime = { path = "arceos/modules/axruntime" } axsync = { path = "arceos/modules/axsync" } axtask = { path = "arceos/modules/axtask" } +axdma = { path = "arceos/modules/axdma" } axbacktrace = "0.1" axerrno = "0.2" @@ -109,8 +110,7 @@ smp = ["axfeat/smp", "axplat-riscv64-visionfive2?/smp"] vf2 = ["dep:axplat-riscv64-visionfive2", "axfeat/driver-sdmmc"] -#sg2002 = ["dep:axplat-riscv64-sg2002", "starry-api/sg2002", "axfeat/plat-sg2002"] -sg2002 = ["dep:axplat-riscv64-sg2002", "axfeat/plat-sg2002"] +sg2002 = ["dep:axplat-riscv64-sg2002", "starry-api/sg2002", "axfeat/plat-sg2002"] [dependencies] axdriver.workspace = true @@ -141,7 +141,7 @@ optional = true [dependencies.axplat-riscv64-sg2002] version = "0.1" git = "https://github.com/elliott10/axplat-riscv64-sg2002.git" -rev = "92a95ef8" +rev = "bf8a42d8" features = ["fp-simd", "irq", "rtc"] optional = true @@ -160,7 +160,7 @@ axdriver_virtio = { git = "https://github.com/elliott10/axdriver_crates.git", re axdriver_vsock = { git = "https://github.com/elliott10/axdriver_crates.git", rev = "4d73e06a" } [patch."https://github.com/arceos-org/axcpu.git"] -axcpu = { git = "https://github.com/elliott10/axcpu.git", rev = "47b2dbcb" } +axcpu = { git = "https://github.com/elliott10/axcpu.git", rev = "628f1c99" } [patch."https://github.com/arceos-org/page_table_multiarch.git"] page_table_multiarch = { git = "https://github.com/arceos-org//page_table_multiarch.git", rev = "53a08f4e" } diff --git a/api/src/vfs/dev/mod.rs b/api/src/vfs/dev/mod.rs index 6eb2f4a9..3911f3ba 100644 --- a/api/src/vfs/dev/mod.rs +++ b/api/src/vfs/dev/mod.rs @@ -14,6 +14,9 @@ pub mod tty; #[cfg(feature = "sg2002")] pub mod ion; +#[cfg(feature = "sg2002")] +pub mod tpu; + use alloc::{format, sync::Arc}; use core::any::Any; @@ -237,6 +240,16 @@ fn builder(fs: Arc) -> DirMaker { #[cfg(feature = "sg2002")] { + root.add( + "cvi-tpu0", + Device::new( + fs.clone(), + NodeType::CharacterDevice, + DeviceId::new(240, 0), + Arc::new(unsafe { tpu::TpuDevice::new() }), + ), + ); + // Ion device let ion_device = Arc::new(ion::IonDevice::new()); ION_DEVICE.call_once(|| ion_device.clone()); diff --git a/api/src/vfs/dev/tpu/device.rs b/api/src/vfs/dev/tpu/device.rs new file mode 100644 index 00000000..e60c5713 --- /dev/null +++ b/api/src/vfs/dev/tpu/device.rs @@ -0,0 +1,591 @@ +//! TPU 设备抽象 +//! +//! 提供高层 API 供操作系统调用 + +use alloc::{collections::VecDeque, sync::Arc}; +use core::{ + cell::Cell, + sync::atomic::{AtomicU32, Ordering}, +}; + +use axsync::Mutex; + +// use log::{debug, error, info, warn}; +use super::{ + TDMA_PHYS_BASE, TIU_PHYS_BASE, error::TpuError, platform::TpuRuntimeState, tdma::TdmaRegs, + tiu::TiuRegs, types::*, +}; +use crate::{ + file::{get_file_like, ion::IonBufferFile}, + vfs::{ + DeviceOps, + dev::ion::{IonBufferManager, IonHandle, global_ion_buffer_manager}, + }, +}; + +/// TPU 设备状态 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TpuState { + /// 未初始化 + Uninitialized, + /// 空闲 + Idle, + /// 运行中 + Running, + /// 已挂起 + Suspended, +} + +/// TPU 任务提交路径 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TpuSubmitPath { + /// 普通描述符模式 + DesNormal = 0, +} + +/// TPU 任务节点 +#[derive(Debug)] +pub struct TpuTaskNode { + /// 进程 ID + pub pid: u32, + /// 序列号 + pub seq_no: u32, + /// DMA buffer 文件描述符 + pub dmabuf_fd: i32, + /// DMA buffer 虚拟地址 + pub dmabuf_vaddr: usize, + /// DMA buffer 物理地址 + pub dmabuf_paddr: u64, + /// 提交路径 + pub tpu_path: TpuSubmitPath, + /// 执行结果 + pub ret: i32, +} + +/// TPU 内核工作状态 +pub struct TpuKernelWork { + /// 任务队列 + pub task_list: VecDeque, + /// 完成队列 + pub done_list: VecDeque, +} + +impl Default for TpuKernelWork { + fn default() -> Self { + Self { + task_list: VecDeque::new(), + done_list: VecDeque::new(), + } + } +} + +/// TPU 设备内部状态 +struct TpuDeviceInner { + /// TDMA 寄存器 + tdma: TdmaRegs, + /// TIU 寄存器 + tiu: TiuRegs, + /// 设备状态 + state: TpuState, + /// 运行时状态 + runtime: TpuRuntimeState, + /// 任务工作队列 + kernel_work: TpuKernelWork, +} + +/// TPU 设备 +pub struct TpuDevice { + /// 内部状态 (使用 Mutex 保护) + inner: Mutex, + /// 序列号计数器 + seq_counter: AtomicU32, + /// Ion buffer 管理器引用 + ion_manager: Option>, +} + +impl TpuDevice { + /// 创建未初始化的 TPU 设备 + /// + /// 使用默认物理地址,需要提供虚拟地址偏移 + /// + /// # Safety + /// 调用者必须确保偏移计算后的虚拟地址有效 + pub unsafe fn new() -> Self { + let virt_offset = 0xffff_ffc0_0000_0000u64 as isize; + let tdma_vaddr = (TDMA_PHYS_BASE as isize + virt_offset) as *mut u8; + let tiu_vaddr = (TIU_PHYS_BASE as isize + virt_offset) as *mut u8; + + Self { + inner: Mutex::new(TpuDeviceInner { + tdma: unsafe { TdmaRegs::new(tdma_vaddr) }, + tiu: unsafe { TiuRegs::new(tiu_vaddr) }, + state: TpuState::Uninitialized, + runtime: TpuRuntimeState::default(), + kernel_work: TpuKernelWork::default(), + }), + seq_counter: AtomicU32::new(0), + ion_manager: Some(global_ion_buffer_manager()), + } + } + + /// 使用指定的虚拟地址和 Ion 管理器创建 TPU 设备 + /// + /// # Safety + /// 调用者必须确保虚拟地址有效 + pub unsafe fn with_ion_manager( + tdma_vaddr: *mut u8, + tiu_vaddr: *mut u8, + ion_manager: Arc, + ) -> Self { + Self { + inner: Mutex::new(TpuDeviceInner { + tdma: unsafe { TdmaRegs::new(tdma_vaddr) }, + tiu: unsafe { TiuRegs::new(tiu_vaddr) }, + state: TpuState::Uninitialized, + runtime: TpuRuntimeState::default(), + kernel_work: TpuKernelWork::default(), + }), + seq_counter: AtomicU32::new(0), + ion_manager: Some(ion_manager), + } + } + + /// 使用指定的虚拟地址创建 TPU 设备 + /// + /// # Safety + /// 调用者必须确保虚拟地址有效 + pub unsafe fn from_vaddr(tdma_vaddr: *mut u8, tiu_vaddr: *mut u8) -> Self { + Self { + inner: Mutex::new(TpuDeviceInner { + tdma: unsafe { TdmaRegs::new(tdma_vaddr) }, + tiu: unsafe { TiuRegs::new(tiu_vaddr) }, + state: TpuState::Uninitialized, + runtime: TpuRuntimeState::default(), + kernel_work: TpuKernelWork::default(), + }), + seq_counter: AtomicU32::new(0), + ion_manager: Some(global_ion_buffer_manager()), + } + } + + /// 设置 Ion buffer 管理器 + pub fn set_ion_manager(&mut self, manager: Arc) { + self.ion_manager = Some(manager); + } + + /// 初始化 TPU 设备 (probe) + pub fn init(&self) -> Result<(), TpuError> { + let mut inner = self.inner.lock(); + + // 重置命令 ID + super::platform::resync_cmd_id(&inner.tdma, &inner.tiu); + + inner.state = TpuState::Idle; + inner.runtime = TpuRuntimeState::default(); + + info!("TPU device initialized"); + Ok(()) + } + + /// 获取设备状态 + pub fn state(&self) -> TpuState { + self.inner.lock().state + } + + /// 检查设备是否就绪 + pub fn is_ready(&self) -> bool { + self.inner.lock().state == TpuState::Idle + } + + /// 处理 TDMA 中断 + /// + /// 应该在你的 OS 中断处理程序中调用此函数 + /// + /// 返回是否有错误发生 + pub fn handle_irq(&self) -> bool { + let mut inner = self.inner.lock(); + // 先获取需要的引用,避免同时借用 + let tdma = &inner.tdma as *const TdmaRegs; + let tiu = &inner.tiu as *const TiuRegs; + let runtime = &mut inner.runtime; + unsafe { super::platform::handle_tdma_irq(&*tdma, &*tiu, runtime) } + } + + /// 获取下一个序列号 + fn next_seq_no(&self) -> u32 { + self.seq_counter.fetch_add(1, Ordering::SeqCst) + } + + /// 提交 DMA buffer 任务 + fn submit_dmabuf(&self, arg: usize) -> Result { + // 从用户空间读取参数 + let submit_arg = unsafe { &*(arg as *const CviSubmitDmaArg) }; + + debug!( + "[TPU] submit dmabuf: fd={}, seq_no={}", + submit_arg.fd, submit_arg.seq_no + ); + + // 从文件描述符获取 IonBufferFile + let fd = submit_arg.fd as i32; + let file = get_file_like(fd).map_err(|_| { + error!("[TPU] Failed to get file for fd={}", fd); + TpuError::InvalidDmabuf + })?; + + // 尝试转换为 IonBufferFile (使用 downcast_arc) + let ion_file: Arc = file.downcast_arc::().map_err(|_| { + error!("[TPU] fd={} is not an IonBufferFile", fd); + TpuError::InvalidDmabuf + })?; + + // 获取缓冲区信息 + let buffer_info = ion_file.info(); + debug!( + "[TPU] dmabuf info: handle={}, size={}, paddr=0x{:x}", + buffer_info.handle, buffer_info.size, buffer_info.phys_addr + ); + + // 从 Ion 管理器获取完整的 buffer 信息 + let ion_manager = self.ion_manager.as_ref().ok_or(TpuError::NotInitialized)?; + let handle = IonHandle(buffer_info.handle); + let buffer = ion_manager + .get_buffer(handle) + .map_err(|_| TpuError::InvalidDmabuf)?; + + let dmabuf_vaddr = buffer.dma_info.cpu_addr.as_ptr() as usize; + let dmabuf_paddr = buffer.dma_info.bus_addr.as_u64(); + + debug!( + "[TPU] Buffer: vaddr=0x{:x}, paddr=0x{:x}", + dmabuf_vaddr, dmabuf_paddr + ); + + // 创建任务节点 + let task = TpuTaskNode { + pid: 0, // 当前没有进程 ID 概念,可以后续扩展 + seq_no: submit_arg.seq_no, + dmabuf_fd: submit_arg.fd, + dmabuf_vaddr, + dmabuf_paddr, + tpu_path: TpuSubmitPath::DesNormal, + ret: 0, + }; + + // 添加到任务队列 + let mut inner = self.inner.lock(); + inner.kernel_work.task_list.push_back(task); + + // 直接执行任务 (简化版本,不使用工作线程) + self.process_task_locked(&mut inner)?; + + Ok(0) + } + + /// 处理任务 (内部函数,需要持有锁) + fn process_task_locked(&self, inner: &mut TpuDeviceInner) -> Result<(), TpuError> { + while let Some(mut task) = inner.kernel_work.task_list.pop_front() { + // 初始化 TPU + super::platform::resync_cmd_id(&inner.tdma, &inner.tiu); + inner.runtime.irq_received = false; + + // 执行 DMA buffer + let result = + self.run_dmabuf_internal(inner, task.dmabuf_vaddr as *const u8, task.dmabuf_paddr); + + task.ret = match result { + Ok(_) => 0, + Err(e) => { + error!("TPU run dmabuf failed: {:?}", e); + -1 + } + }; + + // 移动到完成队列 + inner.kernel_work.done_list.push_back(task); + } + + Ok(()) + } + + /// 内部执行 DMA buffer + fn run_dmabuf_internal( + &self, + inner: &mut TpuDeviceInner, + dmabuf_vaddr: *const u8, + dmabuf_paddr: u64, + ) -> Result<(), TpuError> { + if inner.state != TpuState::Idle && inner.state != TpuState::Uninitialized { + return Err(TpuError::NotInitialized); + } + + inner.state = TpuState::Running; + + // 简化版超时检查 (使用 Cell 实现内部可变性) + let timeout_counter = Cell::new(0u64); + let timeout_limit = 1_000_000_000u64; // 大约 10 秒 + + let wait_irq = || -> Result<(), TpuError> { + // 轮询等待中断 + // 简化实现:直接返回 Ok,由 poll_cmdbuf_done 处理超时 + let mut counter = timeout_counter.get(); + while counter < timeout_limit { + counter += 1; + timeout_counter.set(counter); + core::hint::spin_loop(); + // 简化:假设执行一定迭代后完成 + if counter > 10000 { + break; + } + } + if counter >= timeout_limit { + return Err(TpuError::Timeout); + } + Ok(()) + }; + + let timeout_checker = || -> bool { timeout_counter.get() > timeout_limit }; + + // 使用指针避免同时借用 + let tdma = &inner.tdma as *const TdmaRegs; + let tiu = &inner.tiu as *const TiuRegs; + let runtime = &mut inner.runtime; + + let result = unsafe { + super::platform::run_dmabuf( + &*tdma, + &*tiu, + dmabuf_vaddr, + dmabuf_paddr, + runtime, + wait_irq, + timeout_checker, + ) + }; + + inner.state = TpuState::Idle; + result + } + + /// 等待 DMA buffer 完成 + fn wait_dmabuf(&self, arg: usize) -> Result { + let wait_arg = unsafe { &mut *(arg as *mut CviWaitDmaArg) }; + + debug!("TPU wait dmabuf: seq_no={}", wait_arg.seq_no); + + let mut inner = self.inner.lock(); + + // 在完成队列中查找 + let mut found_idx = None; + for (idx, task) in inner.kernel_work.done_list.iter().enumerate() { + if task.seq_no == wait_arg.seq_no { + found_idx = Some(idx); + break; + } + } + + if let Some(idx) = found_idx { + let task = inner.kernel_work.done_list.remove(idx).unwrap(); + wait_arg.ret = task.ret; + debug!( + "TPU wait dmabuf completed: seq_no={}, ret={}", + wait_arg.seq_no, task.ret + ); + Ok(0) + } else { + warn!("TPU wait dmabuf: seq_no {} not found", wait_arg.seq_no); + wait_arg.ret = -1; + Err(TpuError::NotInitialized) + } + } + + /// 刷新 DMA buffer 缓存 (通过物理地址) + fn cache_flush(&self, arg: usize) -> Result { + let flush_arg = unsafe { &*(arg as *const CviCacheOpArg) }; + + debug!( + "TPU cache flush: paddr=0x{:x}, size={}", + flush_arg.paddr, flush_arg.size + ); + + // 在 RISC-V 上执行 cache flush + #[cfg(target_arch = "riscv64")] + { + // 使用 fence 指令确保内存一致性 + unsafe { + core::arch::asm!("fence iorw, iorw"); + } + } + + Ok(0) + } + + /// 无效化 DMA buffer 缓存 (通过物理地址) + fn cache_invalidate(&self, arg: usize) -> Result { + let invalidate_arg = unsafe { &*(arg as *const CviCacheOpArg) }; + + debug!( + "TPU cache invalidate: paddr=0x{:x}, size={}", + invalidate_arg.paddr, invalidate_arg.size + ); + + // 在 RISC-V 上执行 cache invalidate + #[cfg(target_arch = "riscv64")] + { + unsafe { + core::arch::asm!("fence iorw, iorw"); + } + } + + Ok(0) + } + + /// 刷新 DMA buffer 缓存 (通过 fd) + /// todo: implement actual cache operations + fn dmabuf_flush_fd(&self, arg: usize) -> Result { + let fd = arg as i32; + debug!("TPU dmabuf flush fd: {}", fd); + + // 从 Ion 获取 buffer 并刷新 + if let Some(ref ion_manager) = self.ion_manager { + let handle = IonHandle(fd as u32); + if let Ok(buffer) = ion_manager.get_buffer(handle) { + let paddr = buffer.dma_info.bus_addr.as_u64(); + let size = buffer.size; + + #[cfg(target_arch = "riscv64")] + unsafe { + core::arch::asm!("fence iorw, iorw"); + } + + debug!("Flushed buffer: paddr=0x{:x}, size={}", paddr, size); + } + } + + Ok(0) + } + + /// 无效化 DMA buffer 缓存 (通过 fd) + /// todo: implement actual cache operations + fn dmabuf_invld_fd(&self, arg: usize) -> Result { + let fd = arg as i32; + debug!("TPU dmabuf invalidate fd: {}", fd); + + // 从 Ion 获取 buffer 并无效化 + if let Some(ref ion_manager) = self.ion_manager { + let handle = IonHandle(fd as u32); + if let Ok(_buffer) = ion_manager.get_buffer(handle) { + #[cfg(target_arch = "riscv64")] + unsafe { + core::arch::asm!("fence iorw, iorw"); + } + } + } + + Ok(0) + } + + /// 挂起 TPU + pub fn suspend(&self) -> Result<(), TpuError> { + let mut inner = self.inner.lock(); + + if inner.state == TpuState::Suspended { + return Ok(()); + } + + // 使用指针避免同时借用 + let tdma = &inner.tdma as *const TdmaRegs; + let tiu = &inner.tiu as *const TiuRegs; + let reg_backup = &mut inner.runtime.reg_backup; + unsafe { + super::platform::backup_registers(&*tdma, &*tiu, reg_backup); + } + inner.state = TpuState::Suspended; + + info!("TPU suspended"); + Ok(()) + } + + /// 恢复 TPU + pub fn resume(&self) -> Result<(), TpuError> { + let mut inner = self.inner.lock(); + + if inner.state != TpuState::Suspended { + return Err(TpuError::NotInitialized); + } + + // 使用指针避免同时借用 + let tdma = &inner.tdma as *const TdmaRegs; + let tiu = &inner.tiu as *const TiuRegs; + let reg_backup = &inner.runtime.reg_backup; + unsafe { + super::platform::restore_registers(&*tdma, &*tiu, reg_backup); + } + inner.state = TpuState::Idle; + + info!("TPU resumed"); + Ok(()) + } + + /// 重置 TPU + pub fn reset(&self) { + let mut inner = self.inner.lock(); + + super::platform::resync_cmd_id(&inner.tdma, &inner.tiu); + inner.runtime = TpuRuntimeState::default(); + inner.state = TpuState::Idle; + + info!("TPU reset"); + } +} + +// 实现 Send 和 Sync +unsafe impl Send for TpuDevice {} +unsafe impl Sync for TpuDevice {} + +impl DeviceOps for TpuDevice { + fn read_at(&self, _buf: &mut [u8], _offset: u64) -> axfs_ng_vfs::VfsResult { + Ok(0) + } + + fn write_at(&self, _buf: &[u8], _offset: u64) -> axfs_ng_vfs::VfsResult { + Ok(0) + } + + fn ioctl(&self, cmd: u32, arg: usize) -> axfs_ng_vfs::VfsResult { + debug!("TPU ioctl: cmd=0x{:x}, arg=0x{:x}", cmd, arg); + + let result = match cmd { + CVITPU_SUBMIT_DMABUF => self.submit_dmabuf(arg), + CVITPU_DMABUF_FLUSH_FD => self.dmabuf_flush_fd(arg), + CVITPU_DMABUF_INVLD_FD => self.dmabuf_invld_fd(arg), + CVITPU_DMABUF_FLUSH => self.cache_flush(arg), + CVITPU_DMABUF_INVLD => self.cache_invalidate(arg), + CVITPU_WAIT_DMABUF => self.wait_dmabuf(arg), + CVITPU_PIO_MODE => { + warn!("TPU PIO mode not implemented"); + Ok(0) + } + CVITPU_LOAD_TEE | CVITPU_SUBMIT_TEE | CVITPU_UNLOAD_TEE => { + warn!("TPU TEE operations not supported"); + Err(TpuError::NotInitialized) + } + _ => { + warn!("Unknown TPU ioctl command: 0x{:x}", cmd); + Err(TpuError::NotInitialized) + } + }; + + match result { + Ok(v) => Ok(v), + Err(e) => { + error!("TPU ioctl error: {:?}", e); + Err(axerrno::AxError::Unsupported) + } + } + } + + fn as_any(&self) -> &dyn core::any::Any { + self + } +} diff --git a/api/src/vfs/dev/tpu/error.rs b/api/src/vfs/dev/tpu/error.rs new file mode 100644 index 00000000..a9a3ab17 --- /dev/null +++ b/api/src/vfs/dev/tpu/error.rs @@ -0,0 +1,41 @@ +//! TPU 错误类型定义 + +/// TPU 操作错误类型 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TpuError { + /// 超时错误 + Timeout, + /// 无效的 DMA buffer + InvalidDmabuf, + /// TDMA 错误 + TdmaError(u32), + /// TIU 错误 + TiuError(u32), + /// 设备未初始化 + NotInitialized, + /// 设备正忙 + Busy, + /// 被中断 + Interrupted, + /// PMU buffer 地址未对齐 + PmuBufferNotAligned, + /// DMA buffer 地址未对齐 + DmabufNotAligned, +} + +impl TpuError { + /// 获取错误码 (兼容 Linux errno 风格) + pub fn as_errno(&self) -> i32 { + match self { + TpuError::Timeout => -110, // ETIMEDOUT + TpuError::InvalidDmabuf => -22, // EINVAL + TpuError::TdmaError(_) => -5, // EIO + TpuError::TiuError(_) => -5, // EIO + TpuError::NotInitialized => -19, // ENODEV + TpuError::Busy => -16, // EBUSY + TpuError::Interrupted => -4, // EINTR + TpuError::PmuBufferNotAligned => -22, + TpuError::DmabufNotAligned => -22, + } + } +} diff --git a/api/src/vfs/dev/tpu/mod.rs b/api/src/vfs/dev/tpu/mod.rs new file mode 100644 index 00000000..7dc9555b --- /dev/null +++ b/api/src/vfs/dev/tpu/mod.rs @@ -0,0 +1,29 @@ +//! TPU Driver for SG2002 (Cvitek) +//! +//! This is a no_std Rust implementation of the TPU hardware driver. +//! Ported from the original Linux kernel driver. + +#![allow(dead_code)] + +pub mod device; +pub mod error; +pub mod platform; +pub mod tdma; +pub mod tiu; +pub mod types; + +pub use device::TpuDevice; +pub use error::TpuError; +pub use types::*; + +/// TDMA 物理基地址 +pub const TDMA_PHYS_BASE: usize = 0x0C10_0000; + +/// TIU 物理基地址 +pub const TIU_PHYS_BASE: usize = 0x0C10_1000; + +/// 默认超时时间 (毫秒) +pub const DEFAULT_TIMEOUT_MS: u64 = 60 * 1000; + +/// DMA buffer 魔数 +pub const TPU_DMABUF_HEADER_M: u16 = 0xB5B5; diff --git a/api/src/vfs/dev/tpu/platform.rs b/api/src/vfs/dev/tpu/platform.rs new file mode 100644 index 00000000..c995bd7e --- /dev/null +++ b/api/src/vfs/dev/tpu/platform.rs @@ -0,0 +1,285 @@ +//! TPU 平台操作 +//! +//! 对应原 tpu_platform.c 中的核心功能 + +use super::{ + error::TpuError, + tdma::{TPUPMU_BUFBASE, TPUPMU_BUFSIZE, TPUPMU_CTRL, TdmaRegs}, + tiu::TiuRegs, + types::{CmdIdNode, CpuSyncDesc, DmaHeader, TpuPmuEvent}, +}; + +/// TPU 寄存器备份信息 (用于挂起/恢复) +#[derive(Debug, Clone, Copy, Default)] +pub struct TpuRegBackup { + pub tdma_int_mask: u32, + pub tdma_sync_status: u32, + pub tiu_ctrl_base_address: u32, + + pub tdma_arraybase0_l: u32, + pub tdma_arraybase1_l: u32, + pub tdma_arraybase2_l: u32, + pub tdma_arraybase3_l: u32, + pub tdma_arraybase4_l: u32, + pub tdma_arraybase5_l: u32, + pub tdma_arraybase6_l: u32, + pub tdma_arraybase7_l: u32, + pub tdma_arraybase0_h: u32, + pub tdma_arraybase1_h: u32, + + pub tdma_des_base: u32, + pub tdma_dbg_mode: u32, + pub tdma_dcm_disable: u32, + pub tdma_ctrl: u32, +} + +/// TPU 运行时状态 +#[derive(Debug, Clone, Copy, Default)] +pub struct TpuRuntimeState { + /// 中断已收到标志 + pub irq_received: bool, + /// 备份的寄存器值 + pub reg_backup: TpuRegBackup, +} + +/// 启用 TPU PMU +pub fn pmu_enable(tdma: &TdmaRegs, pmubuf_addr_p: u64, pmubuf_size: u32, event: TpuPmuEvent) { + // 右移 4 位 + let buf_addr = pmubuf_addr_p >> 4; + let buf_size = (pmubuf_size as u64) >> 4; + + // 设置 buffer 起始地址和大小 + tdma.write(TPUPMU_BUFBASE, buf_addr as u32); + tdma.write(TPUPMU_BUFSIZE, buf_size as u32); + + // 设置控制寄存器 + let mut reg_value: u32 = 0; + reg_value |= 0x1; // enable + reg_value |= 0x8; // enable_tpu + reg_value |= 0x10; // enable_tdma + reg_value |= (event as u32) << 5; // event type + reg_value |= 0x3 << 8; // burst length = 16 + reg_value |= 0x1 << 10; // ring buffer mode + reg_value &= !0xFFFF0000; // enable dcm + + tdma.write(TPUPMU_CTRL, reg_value); +} + +/// 禁用 TPU PMU +pub fn pmu_disable(tdma: &TdmaRegs) { + let reg_value = tdma.read(TPUPMU_CTRL); + tdma.write(TPUPMU_CTRL, reg_value & !0x1); +} + +/// 重新同步命令 ID +pub fn resync_cmd_id(tdma: &TdmaRegs, tiu: &TiuRegs) { + tiu.reset_id(); + tdma.reset_sync_id(); +} + +/// 处理 TDMA 中断 +/// +/// 返回是否有错误发生 +pub fn handle_tdma_irq(tdma: &TdmaRegs, tiu: &TiuRegs, state: &mut TpuRuntimeState) -> bool { + let reg_value = tdma.read(super::tdma::TDMA_INT_MASK); + let int_status = (reg_value >> 16) & !super::tdma::TDMA_MASK_INIT; + + let has_error = + int_status != super::tdma::TDMA_INT_EOD && int_status != super::tdma::TDMA_INT_EOPMU; + + // 清除中断 + tdma.clear_interrupt(); + + // 保存状态 + state.reg_backup.tdma_int_mask = tdma.read(super::tdma::TDMA_INT_MASK); + state.reg_backup.tdma_sync_status = tdma.read(super::tdma::TDMA_SYNC_STATUS); + state.reg_backup.tiu_ctrl_base_address = tiu.read_bd_ctrl(0); + + state.irq_received = true; + + has_error +} + +/// 轮询等待命令完成 +pub fn poll_cmdbuf_done( + tiu: &TiuRegs, + id_node: &CmdIdNode, + state: &TpuRuntimeState, + timeout_checker: impl Fn() -> bool, +) -> Result<(), TpuError> { + // 检查 TDMA + if id_node.tdma_cmd_id > 0 { + let tdma_id = state.reg_backup.tdma_sync_status >> 16; + if tdma_id < id_node.tdma_cmd_id { + // return Err(TpuError::TdmaError(tdma_id)); + } + } + + // 轮询 TIU + if id_node.bd_cmd_id > 0 { + loop { + let reg_val = tiu.read_bd_ctrl(0); + let current_id = (reg_val >> 6) & 0xFFFF; + let int_flag = (reg_val & (1 << 1)) != 0; + + if current_id >= id_node.bd_cmd_id && int_flag { + // 清除中断 + tiu.write_bd_ctrl(0, reg_val | (1 << 1)); + break; + } + + // 检查超时 + if timeout_checker() { + return Err(TpuError::Timeout); + } + + // CPU 放松 (让出执行权给其他任务) + core::hint::spin_loop(); + } + } + + Ok(()) +} + +/// 执行 DMA buffer +/// +/// 这是核心执行函数,对应原 platform_run_dmabuf +pub fn run_dmabuf( + tdma: &TdmaRegs, + tiu: &TiuRegs, + dmabuf_vaddr: *const u8, + dmabuf_paddr: u64, + state: &mut TpuRuntimeState, + wait_irq: impl Fn() -> Result<(), TpuError>, + timeout_checker: impl Fn() -> bool, +) -> Result<(), TpuError> { + // 解析 header + let header = unsafe { &*(dmabuf_vaddr as *const DmaHeader) }; + + if !header.is_valid() { + return Err(TpuError::InvalidDmabuf); + } + + // 检查 DMA buffer 对齐 + if (dmabuf_paddr & 0xFFF) != 0 { + return Err(TpuError::DmabufNotAligned); + } + + // 重置状态 + state.irq_received = false; + + // 设置 array base + tdma.set_array_bases(header); + + // 检查是否启用 PMU + let pmu_enabled = header.has_valid_pmu(); + let pmubuf_addr = dmabuf_paddr + header.pmubuf_offset as u64; + + if pmu_enabled { + pmu_enable( + tdma, + pmubuf_addr, + header.pmubuf_size, + TpuPmuEvent::TdmaBandwidth, + ); + } + + // 获取 CPU 描述符指针 + let desc_base = + unsafe { dmabuf_vaddr.add(core::mem::size_of::()) as *const CpuSyncDesc }; + + // 遍历所有 CPU 描述符 + for i in 0..header.cpu_desc_count { + let desc = unsafe { &*desc_base.add(i as usize) }; + + let bd_num = (desc.num_bd & 0xFFFF) as u32; + let tdma_num = (desc.num_gdma & 0xFFFF) as u32; + let bd_offset = desc.offset_bd; + let tdma_offset = desc.offset_gdma; + + // 重置命令 ID + resync_cmd_id(tdma, tiu); + state.irq_received = false; + + let id_node = CmdIdNode { + bd_cmd_id: bd_num, + tdma_cmd_id: tdma_num, + }; + + // 启动 TIU + if bd_num > 0 { + tiu.fire_descriptor(bd_offset as u64, bd_num); + } + + // 启动 TDMA + if tdma_num > 0 { + tdma.fire_descriptor(tdma_offset as u64, tdma_num); + } + + // 等待 TDMA 完成 + if tdma_num > 0 { + wait_irq()?; + } + + // 检查完成状态 + poll_cmdbuf_done(tiu, &id_node, state, &timeout_checker)?; + } + + // 禁用 PMU + if pmu_enabled { + state.irq_received = false; + pmu_disable(tdma); + wait_irq()?; + } + + Ok(()) +} + +/// 备份 TPU 寄存器 (挂起时使用) +pub fn backup_registers(tdma: &TdmaRegs, tiu: &TiuRegs, backup: &mut TpuRegBackup) { + use super::tdma::*; + + backup.tdma_int_mask = tdma.read(TDMA_INT_MASK); + backup.tdma_sync_status = tdma.read(TDMA_SYNC_STATUS); + backup.tiu_ctrl_base_address = tiu.read_bd_ctrl(0); + + backup.tdma_arraybase0_l = tdma.read(TDMA_ARRAYBASE0_L); + backup.tdma_arraybase1_l = tdma.read(TDMA_ARRAYBASE1_L); + backup.tdma_arraybase2_l = tdma.read(TDMA_ARRAYBASE2_L); + backup.tdma_arraybase3_l = tdma.read(TDMA_ARRAYBASE3_L); + backup.tdma_arraybase4_l = tdma.read(TDMA_ARRAYBASE4_L); + backup.tdma_arraybase5_l = tdma.read(TDMA_ARRAYBASE5_L); + backup.tdma_arraybase6_l = tdma.read(TDMA_ARRAYBASE6_L); + backup.tdma_arraybase7_l = tdma.read(TDMA_ARRAYBASE7_L); + backup.tdma_arraybase0_h = tdma.read(TDMA_ARRAYBASE0_H); + backup.tdma_arraybase1_h = tdma.read(TDMA_ARRAYBASE1_H); + + backup.tdma_des_base = tdma.read(TDMA_DES_BASE); + backup.tdma_dbg_mode = tdma.read(TDMA_DEBUG_MODE); + backup.tdma_dcm_disable = tdma.read(TDMA_DCM_DISABLE); + backup.tdma_ctrl = tdma.read(TDMA_CTRL); +} + +/// 恢复 TPU 寄存器 (恢复时使用) +pub fn restore_registers(tdma: &TdmaRegs, tiu: &TiuRegs, backup: &TpuRegBackup) { + use super::tdma::*; + + tdma.write(TDMA_INT_MASK, backup.tdma_int_mask); + tdma.write(TDMA_SYNC_STATUS, backup.tdma_sync_status); + tiu.write_bd_ctrl(0, backup.tiu_ctrl_base_address); + + tdma.write(TDMA_ARRAYBASE0_L, backup.tdma_arraybase0_l); + tdma.write(TDMA_ARRAYBASE1_L, backup.tdma_arraybase1_l); + tdma.write(TDMA_ARRAYBASE2_L, backup.tdma_arraybase2_l); + tdma.write(TDMA_ARRAYBASE3_L, backup.tdma_arraybase3_l); + tdma.write(TDMA_ARRAYBASE4_L, backup.tdma_arraybase4_l); + tdma.write(TDMA_ARRAYBASE5_L, backup.tdma_arraybase5_l); + tdma.write(TDMA_ARRAYBASE6_L, backup.tdma_arraybase6_l); + tdma.write(TDMA_ARRAYBASE7_L, backup.tdma_arraybase7_l); + tdma.write(TDMA_ARRAYBASE0_H, backup.tdma_arraybase0_h); + tdma.write(TDMA_ARRAYBASE1_H, backup.tdma_arraybase1_h); + + tdma.write(TDMA_DES_BASE, backup.tdma_des_base); + tdma.write(TDMA_DEBUG_MODE, backup.tdma_dbg_mode); + tdma.write(TDMA_DCM_DISABLE, backup.tdma_dcm_disable); +} diff --git a/api/src/vfs/dev/tpu/tdma.rs b/api/src/vfs/dev/tpu/tdma.rs new file mode 100644 index 00000000..1a86b7ec --- /dev/null +++ b/api/src/vfs/dev/tpu/tdma.rs @@ -0,0 +1,200 @@ +//! TDMA 寄存器定义和操作 + +use core::ptr::{read_volatile, write_volatile}; + +/// TDMA 描述符寄存器字节数 +pub const TDMA_DESC_REG_BYTES: usize = 0x40; + +/// TDMA 引擎描述符数量 +pub const TDMA_ENGINE_DESCRIPTOR_NUM: usize = TDMA_DESC_REG_BYTES >> 2; + +/// TDMA 基地址寄存器数量 +pub const TDMA_NUM_BASE_REGS: usize = 0x8; + +// ============ TDMA 寄存器偏移 ============ + +/// TDMA 控制寄存器 +pub const TDMA_CTRL: usize = 0x0; +/// TDMA 描述符基地址 +pub const TDMA_DES_BASE: usize = 0x4; +/// TDMA 中断掩码 +pub const TDMA_INT_MASK: usize = 0x8; +/// TDMA 同步状态 +pub const TDMA_SYNC_STATUS: usize = 0xC; +/// TDMA 命令接收寄存器 0-15 +pub const TDMA_CMD_ACCP0: usize = 0x10; +pub const TDMA_CMD_ACCP1: usize = 0x14; +pub const TDMA_CMD_ACCP2: usize = 0x18; +pub const TDMA_CMD_ACCP3: usize = 0x1C; +pub const TDMA_CMD_ACCP4: usize = 0x20; +pub const TDMA_CMD_ACCP5: usize = 0x24; +pub const TDMA_CMD_ACCP6: usize = 0x28; +pub const TDMA_CMD_ACCP7: usize = 0x2C; +pub const TDMA_CMD_ACCP8: usize = 0x30; +pub const TDMA_CMD_ACCP9: usize = 0x34; +pub const TDMA_CMD_ACCP10: usize = 0x38; +pub const TDMA_CMD_ACCP11: usize = 0x3C; +pub const TDMA_CMD_ACCP12: usize = 0x40; +pub const TDMA_CMD_ACCP13: usize = 0x44; +pub const TDMA_CMD_ACCP14: usize = 0x48; +pub const TDMA_CMD_ACCP15: usize = 0x4C; + +/// Array base 寄存器 (低32位) +pub const TDMA_ARRAYBASE0_L: usize = 0x70; +pub const TDMA_ARRAYBASE1_L: usize = 0x74; +pub const TDMA_ARRAYBASE2_L: usize = 0x78; +pub const TDMA_ARRAYBASE3_L: usize = 0x7C; +pub const TDMA_ARRAYBASE4_L: usize = 0x80; +pub const TDMA_ARRAYBASE5_L: usize = 0x84; +pub const TDMA_ARRAYBASE6_L: usize = 0x88; +pub const TDMA_ARRAYBASE7_L: usize = 0x8C; + +/// Array base 寄存器 (高32位) +pub const TDMA_ARRAYBASE0_H: usize = 0x90; +pub const TDMA_ARRAYBASE1_H: usize = 0x94; + +/// TDMA 调试模式 +pub const TDMA_DEBUG_MODE: usize = 0xA0; +/// TDMA DCM 禁用 +pub const TDMA_DCM_DISABLE: usize = 0xA4; +/// TDMA 状态 +pub const TDMA_STATUS: usize = 0xEC; + +// ============ TPU PMU 寄存器偏移 ============ + +/// PMU 控制寄存器 +pub const TPUPMU_CTRL: usize = 0x200; +/// PMU buffer 基地址 +pub const TPUPMU_BUFBASE: usize = 0x20C; +/// PMU buffer 大小 +pub const TPUPMU_BUFSIZE: usize = 0x210; + +// ============ TDMA 控制位 ============ + +/// TDMA 使能位 +pub const TDMA_CTRL_ENABLE_BIT: u32 = 0; +/// TDMA 模式选择位 +pub const TDMA_CTRL_MODESEL_BIT: u32 = 1; +/// TDMA 重置同步 ID 位 +pub const TDMA_CTRL_RESET_SYNCID_BIT: u32 = 2; +/// 强制 1 array 模式 +pub const TDMA_CTRL_FORCE_1ARRAY: u32 = 5; +/// 强制 2 array 模式 +pub const TDMA_CTRL_FORCE_2ARRAY: u32 = 6; +/// Burst 长度位 +pub const TDMA_CTRL_BURSTLEN_BIT: u32 = 8; +/// 64字节对齐使能 +pub const TDMA_CTRL_64BYTE_ALIGN_EN: u32 = 10; +/// Intra 命令关闭 +pub const TDMA_CTRL_INTRA_CMD_OFF: u32 = 13; +/// 描述符数量位 +pub const TDMA_CTRL_DESNUM_BIT: u32 = 16; + +// ============ TDMA 中断相关 ============ + +/// TDMA 中断掩码初始值 (忽略 nchw/stride=0 错误) +pub const TDMA_MASK_INIT: u32 = 0x20; +/// TDMA 描述符结束中断 +pub const TDMA_INT_EOD: u32 = 0x1; +/// TDMA PMU 结束中断 +pub const TDMA_INT_EOPMU: u32 = 0x8000; +/// TDMA 全部空闲状态 +pub const TDMA_ALL_IDLE: u32 = 0x1F; + +/// TDMA 寄存器操作 +pub struct TdmaRegs { + base: *mut u8, +} + +// SAFETY: TDMA 寄存器访问是通过内存映射进行的,可以安全地在线程间共享 +// 寄存器访问本身是原子的,多线程访问需要在更高层进行同步 +unsafe impl Sync for TdmaRegs {} +unsafe impl Send for TdmaRegs {} + +impl TdmaRegs { + /// 创建 TDMA 寄存器操作实例 + /// + /// # Safety + /// 调用者必须确保 base 指向有效的 TDMA 寄存器映射地址 + pub const unsafe fn new(base: *mut u8) -> Self { + Self { base } + } + + /// 读取寄存器 + #[inline] + pub fn read(&self, offset: usize) -> u32 { + unsafe { read_volatile((self.base as usize + offset) as *const u32) } + } + + /// 写入寄存器 + #[inline] + pub fn write(&self, offset: usize, value: u32) { + unsafe { write_volatile((self.base as usize + offset) as *mut u32, value) } + } + + /// 获取基地址 + pub fn base(&self) -> *mut u8 { + self.base + } + + /// 获取中断状态 + pub fn get_int_status(&self) -> u32 { + let reg_value = self.read(TDMA_INT_MASK); + (reg_value >> 16) & !TDMA_MASK_INIT + } + + /// 清除中断 + pub fn clear_interrupt(&self) { + self.write(TDMA_INT_MASK, 0xFFFF0000); + } + + /// 获取同步状态中的 TDMA ID + pub fn get_sync_tdma_id(&self) -> u32 { + self.read(TDMA_SYNC_STATUS) >> 16 + } + + /// 设置 array base 寄存器 + pub fn set_array_bases(&self, header: &super::types::DmaHeader) { + self.write(TDMA_ARRAYBASE0_L, header.arraybase_0_l); + self.write(TDMA_ARRAYBASE1_L, header.arraybase_1_l); + self.write(TDMA_ARRAYBASE2_L, header.arraybase_2_l); + self.write(TDMA_ARRAYBASE3_L, header.arraybase_3_l); + self.write(TDMA_ARRAYBASE4_L, header.arraybase_4_l); + self.write(TDMA_ARRAYBASE5_L, header.arraybase_5_l); + self.write(TDMA_ARRAYBASE6_L, header.arraybase_6_l); + self.write(TDMA_ARRAYBASE7_L, header.arraybase_7_l); + // 假设高位始终为 0 + self.write(TDMA_ARRAYBASE0_H, 0); + self.write(TDMA_ARRAYBASE1_H, 0); + } + + /// 重置同步 ID + pub fn reset_sync_id(&self) { + self.write(TDMA_CTRL, 1 << TDMA_CTRL_RESET_SYNCID_BIT); + self.write(TDMA_CTRL, 0); + // 重置中断状态 + self.write(TDMA_INT_MASK, 0xFFFF0000); + } + + /// 启动 TDMA 描述符执行 + pub fn fire_descriptor(&self, desc_offset: u64, num_tdma: u32) { + // 设置描述符地址 + self.write(TDMA_DES_BASE, desc_offset as u32); + // 确保调试模式禁用 + self.write(TDMA_DEBUG_MODE, 0); + // 启用 DCM + self.write(TDMA_DCM_DISABLE, 0); + // 初始化中断掩码 + self.write(TDMA_INT_MASK, TDMA_MASK_INIT); + + // 启动 TDMA + let ctrl = (1 << TDMA_CTRL_ENABLE_BIT) + | (1 << TDMA_CTRL_MODESEL_BIT) + | (num_tdma << TDMA_CTRL_DESNUM_BIT) + | (0x3 << TDMA_CTRL_BURSTLEN_BIT) + | (1 << TDMA_CTRL_FORCE_1ARRAY) + | (1 << TDMA_CTRL_INTRA_CMD_OFF) + | (1 << TDMA_CTRL_64BYTE_ALIGN_EN); + self.write(TDMA_CTRL, ctrl); + } +} diff --git a/api/src/vfs/dev/tpu/tiu.rs b/api/src/vfs/dev/tpu/tiu.rs new file mode 100644 index 00000000..ccec0fba --- /dev/null +++ b/api/src/vfs/dev/tpu/tiu.rs @@ -0,0 +1,128 @@ +//! TIU (Tensor Instruction Unit) 寄存器定义和操作 + +use core::ptr::{read_volatile, write_volatile}; + +/// BD 引擎命令对齐位 +pub const BDC_ENGINE_CMD_ALIGNED_BIT: u32 = 8; + +/// BD 控制基地址偏移 +pub const BD_CTRL_BASE_ADDR: usize = 0x100; + +// ============ BD 控制位 (基于 BD_CTRL_BASE_ADDR) ============ + +/// TPU 使能位 +pub const BD_TPU_EN: u32 = 0; +/// 描述符地址有效位 +pub const BD_DES_ADDR_VLD: u32 = 30; +/// TIU 中断全局使能位 +pub const BD_INTR_ENABLE: u32 = 31; + +/// TIU 寄存器操作 +pub struct TiuRegs { + base: *mut u8, +} + +// SAFETY: TIU 寄存器访问是通过内存映射进行的,可以安全地在线程间共享 +// 寄存器访问本身是原子的,多线程访问需要在更高层进行同步 +unsafe impl Sync for TiuRegs {} +unsafe impl Send for TiuRegs {} + +impl TiuRegs { + /// 创建 TIU 寄存器操作实例 + /// + /// # Safety + /// 调用者必须确保 base 指向有效的 TIU 寄存器映射地址 + pub const unsafe fn new(base: *mut u8) -> Self { + Self { base } + } + + /// 读取寄存器 + #[inline] + pub fn read(&self, offset: usize) -> u32 { + unsafe { read_volatile((self.base as usize + offset) as *const u32) } + } + + /// 写入寄存器 + #[inline] + pub fn write(&self, offset: usize, value: u32) { + unsafe { write_volatile((self.base as usize + offset) as *mut u32, value) } + } + + /// 获取基地址 + pub fn base(&self) -> *mut u8 { + self.base + } + + /// 读取 BD 控制寄存器 + #[inline] + pub fn read_bd_ctrl(&self, offset: usize) -> u32 { + self.read(BD_CTRL_BASE_ADDR + offset) + } + + /// 写入 BD 控制寄存器 + #[inline] + pub fn write_bd_ctrl(&self, offset: usize, value: u32) { + self.write(BD_CTRL_BASE_ADDR + offset, value) + } + + /// 获取当前 BD 命令 ID + pub fn get_current_bd_id(&self) -> u32 { + (self.read_bd_ctrl(0) >> 6) & 0xFFFF + } + + /// 检查 BD 中断是否触发 + pub fn is_bd_interrupt(&self) -> bool { + (self.read_bd_ctrl(0) & (1 << 1)) != 0 + } + + /// 清除 BD 中断 + pub fn clear_bd_interrupt(&self) { + let reg_val = self.read_bd_ctrl(0); + self.write_bd_ctrl(0, reg_val | (1 << 1)); + } + + /// 重置 TIU ID + pub fn reset_id(&self) { + // 重置 TIU ID + let reg_val = self.read_bd_ctrl(0xC); + self.write_bd_ctrl(0xC, reg_val | 0x1); + self.write_bd_ctrl(0xC, reg_val & !0x1); + + // 禁用 TPU 和描述符模式 + let reg_val = self.read_bd_ctrl(0); + self.write_bd_ctrl(0, reg_val & !((1 << BD_TPU_EN) | (1 << BD_DES_ADDR_VLD))); + + // 重置中断状态 + let reg_val = self.read_bd_ctrl(0); + self.write_bd_ctrl(0, reg_val | (1 << 1)); + } + + /// 设置并启动 TIU 描述符执行 + pub fn fire_descriptor(&self, desc_offset: u64, _num_bd: u32) { + let desc_addr = desc_offset << BDC_ENGINE_CMD_ALIGNED_BIT; + + // 设置描述符地址 + self.write_bd_ctrl(0x4, (desc_addr & 0xFFFFFFFF) as u32); + let reg_val = self.read_bd_ctrl(0x8); + self.write_bd_ctrl( + 0x8, + (reg_val & 0xFFFFFF00) | ((desc_addr >> 32) as u32 & 0xFF), + ); + + // 禁用 TIU pre_exe + let reg_val = self.read_bd_ctrl(0xC); + self.write_bd_ctrl(0xC, reg_val | (1 << 11)); + + // 设置 1 array, lane=8 + let reg_val = self.read_bd_ctrl(0); + let reg_val = reg_val & !0x3FC00000; + self.write_bd_ctrl(0, reg_val | (3 << 22)); + + // 启动 TIU + let reg_val = self.read_bd_ctrl(0); + self.write_bd_ctrl( + 0, + reg_val | (1 << BD_DES_ADDR_VLD) | (1 << BD_INTR_ENABLE) | (1 << BD_TPU_EN), + ); + } +} diff --git a/api/src/vfs/dev/tpu/types.rs b/api/src/vfs/dev/tpu/types.rs new file mode 100644 index 00000000..b8c666ac --- /dev/null +++ b/api/src/vfs/dev/tpu/types.rs @@ -0,0 +1,468 @@ +//! TPU 数据结构定义 + +// ============================================================================ +// IOCTL 命令定义 +// ============================================================================ + +/// IOCTL 基础命令号 +pub const IOCTL_TPU_BASE: u8 = b'p'; + +/// 计算 _IOW 命令码 (写操作) +const fn iow(ty: u8, nr: u8, size: usize) -> u32 { + // _IOW: direction = 1 (write) + (1u32 << 30) | ((size as u32) << 16) | ((ty as u32) << 8) | (nr as u32) +} + +/// 计算 _IOWR 命令码 (读写操作) +const fn iowr(ty: u8, nr: u8, size: usize) -> u32 { + // _IOWR: direction = 3 (read | write) + (3u32 << 30) | ((size as u32) << 16) | ((ty as u32) << 8) | (nr as u32) +} + +/// 提交 DMA buffer 执行 +pub const CVITPU_SUBMIT_DMABUF: u32 = iow(IOCTL_TPU_BASE, 0x01, 8); +/// 刷新 DMA buffer (通过 fd) +pub const CVITPU_DMABUF_FLUSH_FD: u32 = iow(IOCTL_TPU_BASE, 0x02, 8); +/// 无效化 DMA buffer (通过 fd) +pub const CVITPU_DMABUF_INVLD_FD: u32 = iow(IOCTL_TPU_BASE, 0x03, 8); +/// 刷新 DMA buffer (通过物理地址) +pub const CVITPU_DMABUF_FLUSH: u32 = iow(IOCTL_TPU_BASE, 0x04, 8); +/// 无效化 DMA buffer (通过物理地址) +pub const CVITPU_DMABUF_INVLD: u32 = iow(IOCTL_TPU_BASE, 0x05, 8); +/// 等待 DMA buffer 完成 +pub const CVITPU_WAIT_DMABUF: u32 = iowr(IOCTL_TPU_BASE, 0x06, 8); +/// PIO 模式执行 +pub const CVITPU_PIO_MODE: u32 = iow(IOCTL_TPU_BASE, 0x07, 8); +/// 加载 TEE +pub const CVITPU_LOAD_TEE: u32 = iowr(IOCTL_TPU_BASE, 0x08, 8); +/// 提交 TEE +pub const CVITPU_SUBMIT_TEE: u32 = iow(IOCTL_TPU_BASE, 0x09, 8); +/// 卸载 TEE +pub const CVITPU_UNLOAD_TEE: u32 = iow(IOCTL_TPU_BASE, 0x0A, 8); +/// 提交 PIO +pub const CVITPU_SUBMIT_PIO: u32 = iow(IOCTL_TPU_BASE, 0x0B, 8); +/// 等待 PIO +pub const CVITPU_WAIT_PIO: u32 = iowr(IOCTL_TPU_BASE, 0x0C, 8); + +// ============================================================================ +// IOCTL 数据结构 +// ============================================================================ + +/// 缓存操作参数 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct CviCacheOpArg { + /// 物理地址 + pub paddr: u64, + /// 大小 + pub size: u64, + /// DMA 文件描述符 + pub dma_fd: i32, + /// 填充对齐 + pub _padding: i32, +} + +/// 提交 DMA 参数 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct CviSubmitDmaArg { + /// DMA buffer 文件描述符 + pub fd: i32, + /// 序列号 + pub seq_no: u32, +} + +/// 等待 DMA 参数 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct CviWaitDmaArg { + /// 序列号 + pub seq_no: u32, + /// 返回值 + pub ret: i32, +} + +/// PIO 模式参数 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct CviPioMode { + /// 命令缓冲区地址 + pub cmdbuf: u64, + /// 大小 + pub sz: u64, +} + +/// 加载 TEE 参数 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct CviLoadTeeArg { + /// REE 域命令缓冲区地址 + pub cmdbuf_addr_ree: u64, + /// REE 域命令缓冲区长度 + pub cmdbuf_len_ree: u32, + /// 填充 + pub _pad1: u32, + /// REE 域权重地址 + pub weight_addr_ree: u64, + /// REE 域权重长度 + pub weight_len_ree: u32, + /// 填充 + pub _pad2: u32, + /// REE 域神经元地址 + pub neuron_addr_ree: u64, + /// TEE 域 DMA buffer 地址 + pub dmabuf_addr_tee: u64, +} + +/// 提交 TEE 参数 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct CviSubmitTeeArg { + /// TEE DMA buffer 地址 + pub dmabuf_tee_addr: u64, + /// 全局地址 base 2 + pub gaddr_base2: u64, + /// 全局地址 base 3 + pub gaddr_base3: u64, + /// 全局地址 base 4 + pub gaddr_base4: u64, + /// 全局地址 base 5 + pub gaddr_base5: u64, + /// 全局地址 base 6 + pub gaddr_base6: u64, + /// 全局地址 base 7 + pub gaddr_base7: u64, + /// 序列号 + pub seq_no: u32, + /// 填充 + pub _padding: u32, +} + +/// 卸载 TEE 参数 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct CviUnloadTeeArg { + /// 地址 + pub addr: u64, + /// 大小 + pub size: u64, +} + +/// TDMA 复制参数 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct CviTdmaCopyArg { + /// 源物理地址 + pub paddr_src: u64, + /// 目标物理地址 + pub paddr_dst: u64, + /// 高度 + pub h: u32, + /// 宽度 (字节) + pub w_bytes: u32, + /// 源步长 (字节) + pub stride_bytes_src: u32, + /// 目标步长 (字节) + pub stride_bytes_dst: u32, + /// 启用 2D + pub enable_2d: u32, + /// 长度 (字节) + pub leng_bytes: u32, + /// 序列号 + pub seq_no: u32, + /// 填充 + pub _padding: u32, +} + +/// TDMA 等待参数 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct CviTdmaWaitArg { + /// 序列号 + pub seq_no: u32, + /// 返回值 + pub ret: i32, +} + +// ============================================================================ +// DMA buffer 头部结构 +// ============================================================================ + +/// DMA buffer 头部结构 +/// 对应 C 结构体 dma_hdr_t,大小 128 字节 +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct DmaHeader { + /// Magic number (高位) + pub dmabuf_magic_m: u16, + /// Magic number (低位) + pub dmabuf_magic_s: u16, + /// DMA buffer 总大小 + pub dmabuf_size: u32, + /// CPU 描述符数量 + pub cpu_desc_count: u32, + /// BD 描述符数量 + pub bd_desc_count: u32, + /// TDMA 描述符数量 + pub tdma_desc_count: u32, + /// TPU 时钟频率 + pub tpu_clk_rate: u32, + /// PMU buffer 大小 + pub pmubuf_size: u32, + /// PMU buffer 偏移 + pub pmubuf_offset: u32, + /// Array base 0 低32位 + pub arraybase_0_l: u32, + /// Array base 0 高32位 + pub arraybase_0_h: u32, + /// Array base 1 低32位 + pub arraybase_1_l: u32, + /// Array base 1 高32位 + pub arraybase_1_h: u32, + /// Array base 2 低32位 + pub arraybase_2_l: u32, + /// Array base 2 高32位 + pub arraybase_2_h: u32, + /// Array base 3 低32位 + pub arraybase_3_l: u32, + /// Array base 3 高32位 + pub arraybase_3_h: u32, + /// Array base 4 低32位 + pub arraybase_4_l: u32, + /// Array base 4 高32位 + pub arraybase_4_h: u32, + /// Array base 5 低32位 + pub arraybase_5_l: u32, + /// Array base 5 高32位 + pub arraybase_5_h: u32, + /// Array base 6 低32位 + pub arraybase_6_l: u32, + /// Array base 6 高32位 + pub arraybase_6_h: u32, + /// Array base 7 低32位 + pub arraybase_7_l: u32, + /// Array base 7 高32位 + pub arraybase_7_h: u32, + /// 保留字段 + pub reserved: [u32; 8], +} + +impl DmaHeader { + /// 检查魔数是否有效 + pub fn is_valid(&self) -> bool { + self.dmabuf_magic_m == super::TPU_DMABUF_HEADER_M + } + + /// 检查 PMU buffer 是否有效且对齐 + pub fn has_valid_pmu(&self) -> bool { + self.pmubuf_offset != 0 + && self.pmubuf_size != 0 + && (self.pmubuf_offset & 0xF) == 0 + && (self.pmubuf_size & 0xF) == 0 + } +} + +/// CPU 同步描述符 +/// 对应 C 结构体 cvi_cpu_sync_desc_t +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CpuSyncDesc { + /// 操作类型 + pub op_type: u32, + /// BD 命令数量 + pub num_bd: u32, + /// GDMA 命令数量 + pub num_gdma: u32, + /// BD 描述符偏移 + pub offset_bd: u32, + /// GDMA 描述符偏移 + pub offset_gdma: u32, + /// 保留字段 + pub reserved: [u32; 2], + /// 字符串 (用于调试) + pub str_data: [u8; (CPU_ENGINE_DESCRIPTOR_NUM - 7) * 4], +} + +/// CPU 引擎描述符数量 +pub const CPU_ENGINE_DESCRIPTOR_NUM: usize = 56; + +/// 命令 ID 节点 +#[derive(Debug, Clone, Copy, Default)] +pub struct CmdIdNode { + /// BD 命令 ID + pub bd_cmd_id: u32, + /// TDMA 命令 ID + pub tdma_cmd_id: u32, +} + +/// TPU 平台配置 +#[derive(Debug, Clone, Copy)] +pub struct TpuPlatformCfg { + /// TDMA 基地址 (虚拟) + pub tdma_base: *mut u8, + /// TIU 基地址 (虚拟) + pub tiu_base: *mut u8, + /// PMU buffer 物理地址 + pub pmubuf_addr_p: u64, + /// PMU buffer 大小 + pub pmubuf_size: u32, +} + +/// PMU 事件类型 +#[repr(u32)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TpuPmuEvent { + /// Bank 冲突 + BankConflict = 0x0, + /// Stall 计数 + StallCount = 0x1, + /// TDMA 带宽 + TdmaBandwidth = 0x2, + /// TDMA 写选通 + TdmaWriteStrobe = 0x3, +} + +/// TDMA 寄存器描述符 +/// 用于构建 TDMA 命令 +#[repr(C)] +#[derive(Debug, Clone, Copy, Default)] +pub struct TdmaReg { + pub vld: u32, + pub compress_en: u32, + pub eod: u32, + pub intp_en: u32, + pub bar_en: u32, + pub check_bf16_value: u32, + pub trans_dir: u32, + pub rsv00: u32, + pub trans_fmt: u32, + pub transpose_md: u32, + pub rsv01: u32, + pub intra_cmd_paral: u32, + pub outstanding_en: u32, + pub cmd_id: u32, + pub spec_func: u32, + pub dst_fmt: u32, + pub src_fmt: u32, + pub cmprs_fmt: u32, + pub sys_dtype: u32, + pub rsv2_1: u32, + pub int8_sign: u32, + pub compress_zero_guard: u32, + pub int8_rnd_mode: u32, + pub wait_id_tpu: u32, + pub wait_id_other_tdma: u32, + pub wait_id_sdma: u32, + pub const_val: u32, + pub src_base_reg_sel: u32, + pub mv_lut_idx: u32, + pub dst_base_reg_sel: u32, + pub mv_lut_base: u32, + pub rsv4_5: u32, + pub dst_h_stride: u32, + pub dst_c_stride_low: u32, + pub dst_n_stride: u32, + pub src_h_stride: u32, + pub src_c_stride_low: u32, + pub src_n_stride: u32, + pub dst_c: u32, + pub src_c: u32, + pub dst_w: u32, + pub dst_h: u32, + pub src_w: u32, + pub src_h: u32, + pub dst_base_addr_low: u32, + pub src_base_addr_low: u32, + pub src_n: u32, + pub dst_base_addr_high: u32, + pub src_base_addr_high: u32, + pub src_c_stride_high: u32, + pub dst_c_stride_high: u32, + pub compress_bias0: u32, + pub compress_bias1: u32, + pub layer_id: u32, +} + +impl TdmaReg { + /// 创建新的 TDMA 寄存器描述符,使用默认值 + pub fn new() -> Self { + Self { + dst_fmt: 0x1, + src_fmt: 0x1, + dst_h_stride: 0x1, + dst_c_stride_low: 0x1, + dst_n_stride: 0x1, + src_h_stride: 0x1, + src_c_stride_low: 0x1, + src_n_stride: 0x1, + dst_c: 0x1, + src_c: 0x1, + dst_w: 0x1, + dst_h: 0x1, + src_w: 0x1, + src_h: 0x1, + src_n: 0x1, + ..Default::default() + } + } + + /// 将寄存器描述符编码为 16 个 u32 数组 + pub fn emit(&self, out: &mut [u32; 16]) { + out[15] = (self.compress_bias0 & 0xFF) + | ((self.compress_bias1 & 0xFF) << 8) + | ((self.layer_id & 0xFFFF) << 16); + + out[14] = (self.src_c_stride_high & 0xFFFF) | ((self.dst_c_stride_high & 0xFFFF) << 16); + + out[13] = (self.src_n & 0xFFFF) + | ((self.dst_base_addr_high & 0xFF) << 16) + | ((self.src_base_addr_high & 0xFF) << 24); + + out[12] = self.src_base_addr_low; + out[11] = self.dst_base_addr_low; + + out[10] = (self.src_w & 0xFFFF) | ((self.src_h & 0xFFFF) << 16); + out[9] = (self.dst_w & 0xFFFF) | ((self.dst_h & 0xFFFF) << 16); + out[8] = (self.dst_c & 0xFFFF) | ((self.src_c & 0xFFFF) << 16); + + out[7] = self.src_n_stride; + out[6] = (self.src_h_stride & 0xFFFF) | ((self.src_c_stride_low & 0xFFFF) << 16); + out[5] = self.dst_n_stride; + out[4] = (self.dst_h_stride & 0xFFFF) | ((self.dst_c_stride_low & 0xFFFF) << 16); + + out[3] = (self.const_val & 0xFFFF) + | ((self.src_base_reg_sel & 0x7) << 16) + | ((self.mv_lut_idx & 0x1) << 19) + | ((self.dst_base_reg_sel & 0x7) << 20) + | ((self.mv_lut_base & 0x1) << 23) + | ((self.rsv4_5 & 0xFF) << 24); + + out[2] = (self.wait_id_other_tdma & 0xFFFF) | ((self.wait_id_sdma & 0xFFFF) << 16); + + out[1] = (self.spec_func & 0x7) + | ((self.dst_fmt & 0x3) << 3) + | ((self.src_fmt & 0x3) << 5) + | ((self.cmprs_fmt & 0x1) << 7) + | ((self.sys_dtype & 0x1) << 8) + | ((self.rsv2_1 & 0xF) << 9) + | ((self.int8_sign & 0x1) << 13) + | ((self.compress_zero_guard & 0x1) << 14) + | ((self.int8_rnd_mode & 0x1) << 15) + | ((self.wait_id_tpu & 0xFFFF) << 16); + + out[0] = (self.vld & 0x1) + | ((self.compress_en & 0x1) << 1) + | ((self.eod & 0x1) << 2) + | ((self.intp_en & 0x1) << 3) + | ((self.bar_en & 0x1) << 4) + | ((self.check_bf16_value & 0x1) << 5) + | ((self.trans_dir & 0x3) << 6) + | ((self.rsv00 & 0x3) << 8) + | ((self.trans_fmt & 0x1) << 10) + | ((self.transpose_md & 0x3) << 11) + | ((self.rsv01 & 0x1) << 13) + | ((self.intra_cmd_paral & 0x1) << 14) + | ((self.outstanding_en & 0x1) << 15) + | ((self.cmd_id & 0xFFFF) << 16); + } +}