rust_analysis

Linux Kernel Rust 代码梳理

分析日期:2026-01-16

分析范围:Linux kernel 中的 Rust 代码


一、整体架构

复制代码
rust/                          # Rust 核心代码
├── kernel/                    # 内核 API 封装(~90个模块)
├── bindings/                  # C 绑定
├── uapi/                      # UAPI 绑定  
├── macros/                    # 过程宏(module!, vtable, fmt! 等)
├── pin-init/                  # 固定初始化(#[pin_data], pin_init!)
├── zerocopy/                  # 零拷贝库
└── ffi.rs                     # FFI 类型定义

samples/rust/                  # 示例代码(~18个)
tools/testing/selftests/rust/  # 自测代码

二、核心模块详解

2.1 kernel crate (rust/kernel/lib.rs)

入口文件,定义了 90+ 个子系统模块:

模块 功能
alloc 内存分配器(Box, Vec, KBox, KVec)
sync 同步原语(Mutex, SpinLock, Arc, CondVar)
device 设备模型(Device<Ctx> 泛型类型状态)
driver 驱动框架(Driver trait, Registration)
module 模块系统(Module, InPlaceModule trait)
error 错误处理(Error, Result, 错误码)
types 类型系统(Opaque, ForeignOwnable, ScopeGuard)
pci/usb/i2c 总线子系统抽象
mm/fs/net 内存/文件系统/网络

2.2 内存分配 (kernel/alloc.rs)

rust 复制代码
// 核心分配器 trait
pub unsafe trait Allocator {
    const MIN_ALIGN: usize;
    fn alloc(layout: Layout, flags: Flags, nid: NumaNode) -> Result<NonNull<[u8]>, AllocError>;
    fn realloc(...) -> Result<NonNull<[u8]>, AllocError>;
    fn free(ptr: NonNull<u8>, layout: Layout);
}

// 分配标志
pub mod flags {
    pub const GFP_KERNEL: Flags = ...;      // 内核上下文
    pub const GFP_ATOMIC: Flags = ...;      // 原子上下文
    pub const __GFP_ZERO: Flags = ...;      // 零初始化
}

// 智能指针
pub use kbox::Box;      // 等同内核 kmalloc
pub use kvec::Vec;      // 动态数组

2.3 同步原语 (kernel/sync.rs)

rust 复制代码
// 通用锁结构
pub struct Lock<T: ?Sized, B: Backend> {
    #[pin] state: Opaque<B::State>,
    #[pin] data: UnsafeCell<T>,
}

// 使用示例
pub use lock::mutex::{new_mutex, Mutex, MutexGuard};
pub use lock::spinlock::{new_spinlock, SpinLock};

// 原子引用计数
pub use arc::Arc;           // 线程安全引用计数
pub use aref::ARef;         // 内核对象引用计数

2.4 设备模型 (kernel/device.rs)

类型状态模式 - 使用泛型参数表示设备上下文:

rust 复制代码
pub struct Device<Ctx: DeviceContext = Normal>(Opaque<bindings::device>, PhantomData<Ctx>);

// 设备上下文层次结构
// CoreInternal → Core → Bound → Normal

impl Device {
    // 安全转换
    pub unsafe fn as_bound(&self) -> &Device<Bound>;
    pub fn name(&self) -> &CStr;
    pub fn fwnode(&self) -> Option<&property::FwNode>;
}

// 设备打印宏
dev_info!(dev, "message: {}\n", value);
dev_err!(dev, "error occurred\n");

2.5 驱动框架 (kernel/driver.rs)

rust 复制代码
// 驱动注册
pub struct Registration<T: RegistrationOps> {
    #[pin] reg: Opaque<T::DriverType>,
}

// 模块驱动宏
module_pci_driver! {
    type: SampleDriver,
    name: "rust_driver_pci",
    license: "GPL v2",
}

2.6 错误处理 (kernel/error.rs)

rust 复制代码
pub struct Error(NonZeroI32);  // 封装内核 errno

pub type Result<T = (), E = Error> = core::result::Result<T, E>;

// 错误码常量
pub mod code {
    pub const EINVAL: Error = ...;
    pub const ENOMEM: Error = ...;
    // 130+ 个标准错误码
}

// C API 转换
pub fn to_result(err: c_int) -> Result;        // 负数 → Err
pub fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T>;  // 错误指针转换

2.7 类型系统 (kernel/types.rs)

rust 复制代码
// 不透明类型 - 封装 C 结构体
pub struct Opaque<T> {
    value: UnsafeCell<MaybeUninit<T>>,
    _pin: PhantomPinned,
}

// 外部所有权传递
pub unsafe trait ForeignOwnable {
    fn into_foreign(self) -> *mut c_void;
    unsafe fn from_foreign(ptr: *mut c_void) -> Self;
}

// 作用域守卫
pub struct ScopeGuard<T, F: FnOnce(T)>;

2.8 过程宏 (macros/lib.rs)

宏 功能
module! 声明内核模块
#[vtable] Vtable 特质
#[export] 导出函数给 C
fmt! 内核格式化
concat_idents! 连接标识符
paste! 粘贴标识符
#[kunit_tests] KUnit 测试

三、总线子系统

3.1 PCI 总线 (kernel/pci.rs)

rust 复制代码
/// PCI 设备 ID
#[repr(transparent)]
pub struct DeviceId(bindings::pci_device_id);

impl DeviceId {
    /// 等价于 C 的 PCI_DEVICE 宏
    pub const fn from_id(vendor: Vendor, device: u32) -> Self;
}

/// PCI 设备
#[repr(transparent)]
pub struct Device<Ctx: device::DeviceContext = device::Normal>(
    Opaque<bindings::pci_device>, PhantomData<Ctx>,
);

/// PCI 驱动 trait
pub trait Driver {
    type IdInfo: 'static;
    type Data<'bound>: Send + 'bound;
    const ID_TABLE: IdTable<Self::IdInfo>;
    
    fn probe<'bound>(
        dev: &'bound Device<device::Core<'_>>,
        id_info: Option<&'bound Self::IdInfo>,
    ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound;
}

3.2 USB 总线 (kernel/usb.rs)

rust 复制代码
/// USB 驱动适配器
pub struct Adapter<T: Driver>(T);

/// USB 设备 ID
#[repr(transparent)]
pub struct DeviceId(bindings::usb_device_id);

impl DeviceId {
    /// 等价于 C 的 USB_DEVICE 宏
    pub const fn from_id(vendor: u16, product: u16) -> Self;
}

/// USB 接口(类型状态模式)
#[repr(transparent)]
pub struct Interface<Ctx: device::DeviceContext = device::Normal>(
    Opaque<bindings::usb_interface>, PhantomData<Ctx>,
);

/// USB 驱动 trait
pub trait Driver {
    type IdInfo: 'static;
    type Data<'bound>: Send + 'bound;
    const ID_TABLE: IdTable<Self::IdInfo>;
    
    fn probe<'bound>(
        interface: &'bound Interface<device::Core<'_>>,
        id: &DeviceId,
        id_info: Option<&'bound Self::IdInfo>,
    ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound;
    
    fn disconnect<'bound>(
        interface: &'bound Interface<device::Core<'_>>,
        data: Pin<&Self::Data<'bound>>,
    );
}

3.3 I2C 总线 (kernel/i2c.rs)

rust 复制代码
/// I2C 设备 ID
#[repr(transparent)]
pub struct DeviceId(bindings::i2c_device_id);

impl DeviceId {
    pub const fn new(id: &'static CStr) -> Self;
}

/// I2C 客户端设备
#[repr(transparent)]
pub struct I2cClient<Ctx: device::DeviceContext = device::Normal>(
    Opaque<bindings::i2c_client>, PhantomData<Ctx>,
);

/// I2C 驱动 trait
pub trait Driver {
    type IdInfo: 'static;
    type Data<'bound>: Send + 'bound;
    
    const I2C_ID_TABLE: Option<IdTable<Self::IdInfo>> = None;
    const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
    const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None;
    
    fn probe<'bound>(
        dev: &'bound I2cClient<device::Core<'_>>,
        id_info: Option<&'bound Self::IdInfo>,
    ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound;
}

3.4 Platform 总线 (kernel/platform.rs)

rust 复制代码
/// 平台设备
#[repr(transparent)]
pub struct Device<Ctx: device::DeviceContext = device::Normal>(
    Opaque<bindings::platform_device>, PhantomData<Ctx>,
);

impl<Ctx: device::DeviceContext> Device<Ctx> {
    /// 按索引获取资源
    pub fn resource_by_index(&self, index: u32) -> Option<&Resource>;
    
    /// 按索引获取 IRQ
    pub fn irq_by_index(&self, index: u32) -> Result<IrqRequest<'_>>;
}

/// 平台驱动 trait
pub trait Driver {
    type IdInfo: 'static;
    type Data<'bound>: Send + 'bound;
    
    const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
    const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None;
    
    fn probe<'bound>(
        dev: &'bound Device<device::Core<'_>>,
        id_info: Option<&'bound Self::IdInfo>,
    ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound;
}

3.5 总线子系统对比

总线 核心文件 Driver Trait 设备类型 注册宏
PCI kernel/pci.rs pci::Driver pci::Device<Ctx> module_pci_driver!
USB kernel/usb.rs usb::Driver usb::Interface<Ctx> module_usb_driver!
I2C kernel/i2c.rs i2c::Driver i2c::I2cClient<Ctx> module_i2c_driver!
Platform kernel/platform.rs platform::Driver platform::Device<Ctx> module_platform_driver!
MDIO kernel/net/phy.rs phy::Driver phy::Device module_phy_driver!

四、网络子系统

文件位置 :rust/kernel/net/(mod.rs、netlink.rs、phy/)

4.1 核心结构

rust 复制代码
// Netlink 消息包装
pub struct NetlinkSkBuff { skb: NonNull<bindings::sk_buff> }
pub struct GenlMsg { skb: NetlinkSkBuff, hdr: NonNull<c_void> }

// Generic Netlink 族
#[repr(transparent)]
pub struct Family { inner: Opaque<bindings::genl_family> }

// PHY 设备抽象
#[repr(transparent)]
pub struct Device(Opaque<bindings::phy_device>);

// PHY 驱动 vtable
#[repr(transparent)]
pub struct DriverVTable(Opaque<bindings::phy_driver>);

4.2 Driver Trait(PHY 子系统)

rust 复制代码
#[vtable]
pub trait Driver {
    const FLAGS: u32 = 0;
    const NAME: &'static CStr;
    const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_custom_mask(0, 0);
    
    fn soft_reset(_dev: &mut Device) -> Result { build_error!(VTABLE_DEFAULT_ERROR) }
    fn probe(_dev: &mut Device) -> Result { build_error!(VTABLE_DEFAULT_ERROR) }
    fn config_aneg(_dev: &mut Device) -> Result { build_error!(VTABLE_DEFAULT_ERROR) }
    fn read_status(_dev: &mut Device) -> Result<u16> { build_error!(VTABLE_DEFAULT_ERROR) }
}
rust 复制代码
// 定义 Netlink 族
static BINDER_NL_FAMILY: Family = Family::const_new(
    kernel::module::this_module::<crate::LocalModule>(),
    c"binder_family",
    BINDER_FAMILY_VERSION,
    &BINDER_NL_FAMILY_MCGRPS,
);

// 发送多播消息
impl Report {
    pub fn new(size: usize, portid: u32, seq: u32, flags: alloc::Flags) -> Result<Self> {
        let skb = NetlinkSkBuff::new(size, flags)?;
        let skb = skb.genlmsg_put(portid, seq, &BINDER_NL_FAMILY, BINDER_CMD_REPORT)?;
        Ok(Self { skb })
    }
    
    pub fn multicast(self, portid: u32, flags: alloc::Flags) -> Result {
        self.skb.multicast(&BINDER_NL_FAMILY, portid, 0, flags)
    }
}

4.4 网络子系统架构

复制代码
rust/kernel/net/
├── mod.rs          # 网络模块主入口
├── netlink.rs      # Generic Netlink 支持
└── phy/
    ├── mod.rs      # PHY 设备抽象
    └── reg.rs      # PHY 寄存器接口(C22/C45)

五、文件系统

文件位置 :rust/kernel/fs/、rust/kernel/debugfs.rs、rust/kernel/configfs.rs

5.1 核心结构

rust 复制代码
// 文件对象封装
#[repr(transparent)]
pub struct File { inner: Opaque<bindings::file> }

// 非线程安全版本
#[repr(transparent)]
pub struct LocalFile { inner: Opaque<bindings::file> }

// 内核 IO 回调
pub struct Kiocb<'a, T> { inner: NonNull<bindings::kiocb>, _phantom: PhantomData<&'a T> }

// DebugFS 目录/文件条目
pub(crate) struct Entry<'a> { entry: *mut bindings::dentry, _parent: Option<Arc<Entry<'static>>> }

5.2 文件操作特征体系

rust 复制代码
// Writer 特征 - 文本输出
pub trait Writer {
    fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
}

// BinaryWriter 特征 - 二进制输出
pub trait BinaryWriter {
    fn write_to_slice(&self, writer: &mut UserSliceWriter, offset: &mut file::Offset) -> Result<usize>;
}

// Reader 特征 - 文本输入
pub trait Reader {
    fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result;
}

5.3 DebugFS 文件操作实现

rust 复制代码
// 只读文件实现
impl<T: Writer + Sync> ReadFile<T> for T {
    const FILE_OPS: FileOps<T> = {
        let operations = bindings::file_operations {
            read: Some(bindings::seq_read),
            llseek: Some(bindings::seq_lseek),
            release: Some(bindings::single_release),
            open: Some(writer_open::<Self>),
            ..pin_init::zeroed()
        };
        unsafe { FileOps::new(operations, 0o400) }
    };
}

// 读写文件实现
impl<T: Writer + Reader + Sync> ReadWriteFile<T> for T {
    const FILE_OPS: FileOps<T> = {
        let operations = bindings::file_operations {
            open: Some(writer_open::<T>),
            read: Some(bindings::seq_read),
            write: Some(write::<T>),
            llseek: Some(bindings::seq_lseek),
            release: Some(bindings::single_release),
            ..pin_init::zeroed()
        };
        unsafe { FileOps::new(operations, 0o600) }
    };
}

5.4 文件系统示例(DebugFS)

rust 复制代码
#[pin_data]
struct RustDebugFs {
    pdev: ARef<platform::Device>,
    _debugfs: Dir,
    #[pin]
    counter: File<Atomic<usize>>,
    #[pin]
    inner: File<Mutex<Inner>>,
}

impl RustDebugFs {
    fn new<'a, 'b>(pdev: &'a platform::Device<Core<'b>>) -> impl PinInit<Self, Error> + use<'a, 'b> {
        let debugfs = Dir::new(c"sample_debugfs");
        try_pin_init! {
            Self {
                counter <- debugfs.read_write_file(c"counter", Atomic::<usize>::new(0)),
                inner <- debugfs.read_write_file(c"pair", new_mutex!(Inner { x: 3, y: 10 })),
                _debugfs: debugfs,
                pdev: pdev.into(),
            }
        }
    }
}

六、内存管理

文件位置 :rust/kernel/mm.rs、rust/kernel/page.rs、rust/kernel/alloc.rs、rust/kernel/alloc/allocator.rs

6.1 页抽象

rust 复制代码
// 页常量
pub const PAGE_SHIFT: usize = bindings::PAGE_SHIFT as usize;
pub const PAGE_SIZE: usize = bindings::PAGE_SIZE;
pub const PAGE_MASK: usize = !(PAGE_SIZE - 1);

// 拥有页所有权的指针
pub struct Page { page: NonNull<bindings::page> }

// 非拥有借用版本
pub struct BorrowedPage<'a>(ManuallyDrop<Page>, PhantomData<&'a Page>);

impl Page {
    pub fn alloc_page(flags: Flags) -> Result<Self, AllocError> {
        let page = unsafe { bindings::alloc_pages(flags.as_raw(), 0) };
        let page = NonNull::new(page).ok_or(AllocError)?;
        Ok(Self { page })
    }
}

impl Drop for Page {
    fn drop(&mut self) {
        unsafe { bindings::__free_pages(self.page.as_ptr(), 0) };
    }
}

6.2 分配器 Trait

rust 复制代码
pub unsafe trait Allocator {
    const MIN_ALIGN: usize;
    
    fn alloc(layout: Layout, flags: Flags, nid: NumaNode) -> Result<NonNull<[u8]>, AllocError> {
        unsafe { Self::realloc(None, layout, Layout::new::<()>(), flags, nid) }
    }
    
    unsafe fn realloc(...) -> Result<NonNull<[u8]>, AllocError>;
    
    unsafe fn free(ptr: NonNull<u8>, layout: Layout) {
        let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), layout, Flags(0), NumaNode::NO_NODE) };
    }
}

6.3 三种分配器实现

rust 复制代码
// 连续内核分配器
pub struct Kmalloc;

// 虚拟连续内核分配器
pub struct Vmalloc;

// kvmalloc(先试 kmalloc,失败回退到 vmalloc)
pub struct KVmalloc;

unsafe impl Allocator for Kmalloc {
    const MIN_ALIGN: usize = ARCH_KMALLOC_MINALIGN;
    unsafe fn realloc(...) -> Result<NonNull<[u8]>, AllocError> {
        let layout = Kmalloc::aligned_layout(layout);
        unsafe { ReallocFunc::KREALLOC.call(ptr, layout, old_layout, flags, nid) }
    }
}

6.4 虚拟内存区域(VMA)

rust 复制代码
// VMA 包装器
#[repr(transparent)]
pub struct VmaRef { vma: Opaque<bindings::vm_area_struct> }

impl VmaRef {
    pub fn start(&self) -> usize { unsafe { (*self.as_ptr()).__bindgen_anon_1.__bindgen_anon_1.vm_start } }
    pub fn end(&self) -> usize { unsafe { (*self.as_ptr()).__bindgen_anon_1.__bindgen_anon_1.vm_end } }
    pub fn flags(&self) -> vm_flags_t { unsafe { (*self.as_ptr()).__bindgen_anon_2.vm_flags } }
}

// 地址空间包装
pub struct MmWithUser { mm: Mm }

impl MmWithUser {
    pub fn mmap_read_lock(&self) -> MmapReadGuard<'_> {
        unsafe { bindings::mmap_read_lock(self.as_raw()) };
        MmapReadGuard { mm: self, _nts: NotThreadSafe }
    }
}

6.5 内存管理组件概览

组件 文件 核心类型 功能
页抽象 page.rs Page, BorrowedPage 页分配/释放、映射/解映射
分配器 alloc/allocator.rs Kmalloc, Vmalloc, KVmalloc 内存分配/重分配/释放
VMA mm/virt.rs VmaRef, VmaNew 虚拟内存区域管理
地址空间 mm.rs Mm, MmWithUser 进程地址空间管理
IOMMU iommu/pgtable.rs IoPageTable IOMMU 页表管理

七、进程管理

文件位置 :rust/kernel/task.rs、rust/kernel/cred.rs、rust/kernel/pid_namespace.rs、rust/kernel/workqueue.rs

7.1 任务(Task)抽象

rust 复制代码
// 包装内核的 struct task_struct
#[repr(transparent)]
pub struct Task(pub(crate) Opaque<bindings::task_struct>);

// 表示当前任务
pub struct CurrentTask(Task, NotThreadSafe);

impl Task {
    pub fn pid(&self) -> Pid { unsafe { *ptr::addr_of!((*self.as_ptr()).pid) } }
    pub fn tgid(&self) -> Pid { unsafe { *ptr::addr_of!((*self.as_ptr()).tgid) } }
    pub fn uid(&self) -> Kuid { Kuid::from_raw(unsafe { bindings::task_uid(self.as_ptr()) }) }
    pub fn signal_pending(&self) -> bool { unsafe { bindings::signal_pending(self.as_ptr()) != 0 } }
    pub fn wake_up(&self) { unsafe { bindings::wake_up_process(self.as_ptr()) }; }
}

// 当前任务宏
#[macro_export]
macro_rules! current {
    () => { unsafe { &*$crate::task::Task::current() } };
}

7.2 进程凭证

rust 复制代码
// 包装内核的 struct cred
#[repr(transparent)]
pub struct Credential(Opaque<bindings::cred>);

impl Credential {
    pub fn euid(&self) -> Kuid { Kuid::from_raw(unsafe { (*self.0.get()).euid }) }
    pub fn get_secid(&self) -> u32 {
        let mut secid = 0;
        unsafe { bindings::security_cred_getsecid(self.0.get(), &mut secid) };
        secid
    }
}

7.3 同步原语

rust 复制代码
// 条件变量(等待队列)
#[pin_data]
pub struct CondVar {
    #[pin]
    pub(crate) wait_queue_head: Opaque<bindings::wait_queue_head>,
    #[pin]
    _pin: PhantomPinned,
}

impl CondVar {
    pub fn wait<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) {
        self.wait_internal(TASK_UNINTERRUPTIBLE, guard, MAX_SCHEDULE_TIMEOUT);
    }
    
    pub fn wait_interruptible<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) -> bool {
        self.wait_internal(TASK_INTERRUPTIBLE, guard, MAX_SCHEDULE_TIMEOUT);
        crate::current!().signal_pending()
    }
    
    pub fn notify_one(&self) { self.notify(1); }
    pub fn notify_all(&self) { self.notify(0); }
}

// 完成同步
#[pin_data]
pub struct Completion { #[pin] inner: Opaque<bindings::completion> }

impl Completion {
    pub fn complete_all(&self) { unsafe { bindings::complete_all(self.as_raw()) }; }
    pub fn wait_for_completion(&self) { unsafe { bindings::wait_for_completion(self.as_raw()) }; }
}

7.4 工作队列

rust 复制代码
// 工作队列包装
pub struct Queue(Opaque<bindings::workqueue_struct>);

impl Queue {
    pub fn enqueue<W, const ID: u64>(&self, w: W) -> W::EnqueueOutput
    where
        W: RawWorkItem<ID> + Send + 'static,
    {
        // 入队工作项
    }
    
    pub fn system() -> &'static Queue {
        unsafe { Queue::from_raw(bindings::system_wq) }
    }
}

7.5 进程管理组件概览

组件 文件 核心类型 功能
任务 task.rs Task, CurrentTask 进程/线程抽象
凭证 cred.rs Credential 进程权限管理
PID 命名空间 pid_namespace.rs PidNamespace PID 隔离
工作队列 workqueue.rs Queue 异步任务执行
条件变量 sync/condvar.rs CondVar 等待/通知机制

八、示例代码分析

8.1 最小模块 (samples/rust/rust_minimal.rs)

rust 复制代码
module! {
    type: RustMinimal,
    name: "rust_minimal",
    authors: ["Rust for Linux Contributors"],
    description: "Rust minimal sample",
    license: "GPL",
    params: {
        test_parameter: i64 { default: 1, description: "..." },
    },
}

struct RustMinimal {
    numbers: KVec<i32>,
}

impl kernel::Module for RustMinimal {
    fn init(_module: &'static ThisModule) -> Result<Self> {
        let mut numbers = KVec::new();
        numbers.push(72, GFP_KERNEL)?;
        numbers.push(108, GFP_KERNEL)?;
        numbers.push(200, GFP_KERNEL)?;
        Ok(Self { numbers })
    }
}

impl Drop for RustMinimal {
    fn drop(&mut self) {
        pr_info!("My numbers are {:?}\n", self.numbers);
    }
}

8.2 PCI 驱动示例 (samples/rust/rust_driver_pci.rs)

rust 复制代码
impl pci::Driver for SampleDriver {
    type IdInfo = TestIndex;
    type Data<'bound> = SampleDriverData<'bound>;

    fn probe<'bound>(
        pdev: &'bound pci::Device<Core<'_>>,
        info: Option<&'bound Self::IdInfo>,
    ) -> impl PinInit<Self::Data<'bound>, Error> {
        pdev.enable_device_mem()?;
        pdev.set_master();
        let bar = pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_driver_pci")?;
        Ok(SampleDriverData { pdev, bar, index: *info.unwrap() })
    }
}

8.3 USB 驱动示例 (samples/rust/rust_driver_usb.rs)

rust 复制代码
struct SampleDriver {
    _intf: ARef<usb::Interface>,
}

kernel::usb_device_table!(
    USB_TABLE,
    <SampleDriver as usb::Driver>::IdInfo,
    [(usb::DeviceId::from_id(0x1234, 0x5678), ()),]
);

impl usb::Driver for SampleDriver {
    type IdInfo = ();
    type Data<'bound> = Self;
    const ID_TABLE: usb::IdTable<Self::IdInfo> = &USB_TABLE;

    fn probe<'bound>(
        intf: &'bound usb::Interface<Core<'_>>,
        _id: &usb::DeviceId,
        _info: Option<&'bound Self::IdInfo>,
    ) -> impl PinInit<Self, Error> + 'bound {
        let dev: &device::Device<Core<'_>> = intf.as_ref();
        dev_info!(dev, "Rust USB driver sample probed\n");
        Ok(Self { _intf: intf.into() })
    }

    fn disconnect<'bound>(intf: &'bound usb::Interface<Core<'_>>, _data: Pin<&Self>) {
        let dev: &device::Device<Core<'_>> = intf.as_ref();
        dev_info!(dev, "Rust USB driver sample disconnected\n");
    }
}

kernel::module_usb_driver! {
    type: SampleDriver,
    name: "rust_driver_usb",
    authors: ["Daniel Almeida"],
    description: "Rust USB driver sample",
    license: "GPL v2",
}

关键要点:

  1. 使用 usb_device_table! 宏声明设备 ID 表
  2. 实现 usb::Driver trait 的 probe 和 disconnect 方法
  3. 通过 intf.into() 获取接口的引用计数 (ARef)
  4. 使用 module_usb_driver! 宏声明模块

九、关键设计模式详解

9.1 类型状态模式 (Type-level State Machine)

9.1.1 核心思想

类型状态模式使用 Rust 的泛型参数来编码设备的上下文状态,在编译期保证 API 的正确使用。

rust 复制代码
// rust/kernel/device.rs:167
pub struct Device<Ctx: DeviceContext = Normal>(
    Opaque<bindings::device>, 
    PhantomData<Ctx>
);
9.1.2 上下文层次结构
复制代码
┌─────────────────┐
│  CoreInternal   │ ──► Core (总线内部回调)
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│     Core        │ ──► Bound (驱动 probe 回调)
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│     Bound       │ ──► Normal (已绑定驱动的设备)
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│    Normal       │ (默认:普通设备)
└─────────────────┘

关键实现 (rust/kernel/device.rs:628-701):

rust 复制代码
// 实现 Deref 层次结构,自动转换上下文类型
macro_rules! impl_device_context_deref {
    (unsafe { $device:ident }) => {
        // CoreInternal → Core
        ::kernel::__impl_device_context_deref!(unsafe {
            $device,
            <'a> $crate::device::CoreInternal<'a> => $crate::device::Core<'a>
        });
        // Core → Bound
        ::kernel::__impl_device_context_deref!(unsafe {
            $device,
            <'a> $crate::device::Core<'a> => $crate::device::Bound
        });
        // Bound → Normal
        ::kernel::__impl_device_context_deref!(unsafe {
            $device,
            $crate::device::Bound => $crate::device::Normal
        });
    };
}
9.1.3 上下文类型定义
rust 复制代码
// rust/kernel/device.rs:498-554

/// Normal: 默认上下文,无额外约束
pub struct Normal;

/// Core<'a>: 总线回调中的设备,生命周期绑定到回调作用域
pub struct Core<'a>(PhantomData<fn(&'a ()) -> &'a ()>);

/// CoreInternal<'a>: 内部总线抽象使用
pub struct CoreInternal<'a>(PhantomData<fn(&'a ()) -> &'a ()>);

/// Bound: 设备已绑定到驱动,保证驱动私有数据存在
pub struct Bound;

/// BoundInternal: 内部使用的绑定上下文
pub struct BoundInternal;
9.1.4 实际应用示例
rust 复制代码
// PCI 驱动 probe 回调:接收 Device<Core<'_>>,只能在此作用域使用
fn probe<'bound>(
    dev: &'bound pci::Device<device::Core<'_>>,  // 只能在此作用域使用
    id_info: Option<&'bound Self::IdInfo>,
) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
    // 可以调用 Core 上下文的方法
    dev.enable_device_mem()?;
    dev.set_master();
    
    // 通过 Deref 自动转换为 Bound/Normal
    let normal_dev: &device::Device<device::Normal> = dev.as_ref();
}

类型状态的好处:

  1. 编译期保证 :某些 API 只能在特定上下文中调用(如 drvdata_borrow 需要 InternalBoundContext)
  2. 生命周期安全 :Core<'a> 确保设备引用不会逃逸回调作用域
  3. 零运行时开销:泛型在编译期擦除,无额外成本

9.2 RAII 模式 (Resource Acquisition Is Initialization)

9.2.1 核心思想

RAII 通过 Drop trait 确保资源在离开作用域时自动释放,避免资源泄漏。

9.2.2 锁守卫实现(rust/kernel/sync/lock.rs:299-305)
rust 复制代码
/// 锁守卫:离开作用域时自动解锁
pub struct Guard<'a, T: ?Sized, B: Backend> {
    pub(crate) lock: &'a Lock<T, B>,
    pub(crate) state: B::GuardState,
    _not_send: NotThreadSafe,  // !Send
}

impl<'a, T: ?Sized, B: Backend> Drop for Guard<'_, T, B> {
    #[inline]
    fn drop(&mut self) {
        // SAFETY: 调用者拥有锁,可以安全解锁
        unsafe { B::unlock(self.lock.state.get(), &self.state) };
    }
}

使用方式:

rust 复制代码
let mutex: Mutex<i32> = new_mutex!(42);
{
    let guard = mutex.lock();  // 获取锁
    *guard += 1;               // 访问数据(通过 Deref)
    // guard 离开作用域时自动解锁
}
9.2.3 作用域守卫(rust/kernel/types.rs:229-276)
rust 复制代码
/// 运行清理函数当被 drop 时
pub struct ScopeGuard<T, F: FnOnce(T)>(Option<(T, F)>);

impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
    fn drop(&mut self) {
        // 执行清理函数
        if let Some((data, cleanup)) = self.0.take() {
            cleanup(data)
        }
    }
}

// 使用示例:自动释放资源
fn example() {
    let _log = ScopeGuard::new(|| pr_info!("函数退出\n"));
    // 无论正常返回还是提前返回,清理函数都会执行
    if condition { return; }
    // ...
}
9.2.4 驱动注册(rust/kernel/driver.rs:250-257)
rust 复制代码
/// 驱动注册:drop 时自动注销
#[pin_data(PinnedDrop)]
pub struct Registration<T: RegistrationOps> {
    #[pin]
    reg: Opaque<T::DriverType>,
}

#[pinned_drop]
impl<T: RegistrationOps> PinnedDrop for Registration<T> {
    fn drop(self: Pin<&mut Self>) {
        // SAFETY: self 存在意味着之前已成功注册
        unsafe { T::unregister(&self.reg) };
    }
}
9.2.5 页释放(rust/kernel/page.rs:533-537)
rust 复制代码
impl Drop for Page {
    fn drop(&mut self) {
        // 自动释放页
        unsafe { bindings::__free_pages(self.page.as_ptr(), 0) };
    }
}

RAII 的好处:

  1. 异常安全 :即使 panic,Drop 也会执行
  2. 无泄漏:所有路径都保证释放
  3. 可组合:守卫可以返回、嵌套、传递

9.3 Vtable 模式 (Virtual Table)

9.3.1 核心思想

使用 #[vtable] 宏将 Rust trait 映射到 C 的函数指针表(vtable),实现面向对象风格的回调。

9.3.2 宏实现(rust/macros/vtable.rs:24-72)
rust 复制代码
/// 处理 trait 定义:添加 HAS_* 常量和 OwnerModule 类型
fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
    let mut gen_items = Vec::new();

    // 添加 USE_VTABLE_ATTR 标记
    gen_items.push(parse_quote! {
        const USE_VTABLE_ATTR: ();
    });

    // 添加 OwnerModule 关联类型(如果不存在)
    if !item.items.iter().any(|i| matches!(i, TraitItem::Type(t) if t.ident == "OwnerModule")) {
        gen_items.push(parse_quote! {
            type OwnerModule: ::kernel::ModuleMetadata;
        });
    }

    // 为每个方法生成 HAS_* 常量
    for item in &item.items {
        if let TraitItem::Fn(fn_item) = item {
            let name = &fn_item.sig.ident;
            let gen_const_name = Ident::new(
                &format!("HAS_{}", name.to_string().to_uppercase()),
                name.span(),
            );
            gen_items.push(parse_quote! {
                #[doc = "Indicates if the method is overridden"]
                const #gen_const_name: bool = false;  // 默认未重写
            });
        }
    }
    
    item.items.extend(gen_items);
    Ok(item)
}
9.3.3 使用示例

定义 vtable trait:

rust 复制代码
#[vtable]
pub trait Operations: Send + Sync + Sized {
    fn foo(&self) -> Result<()> {
        build_error!(VTABLE_DEFAULT_ERROR)  // 默认实现永远不会被调用
    }

    fn bar(&self) -> Result<()> {
        build_error!(VTABLE_DEFAULT_ERROR)
    }
}

实现 vtable trait:

rust 复制代码
#[vtable]
impl Operations for Foo {
    fn foo(&self) -> Result<()> {
        // 实现 foo
    }
    // bar 使用默认实现(HAS_BAR = false)
}

// 宏自动生成:
// const HAS_FOO: bool = true;   // 已重写
// const HAS_BAR: bool = false;  // 未重写
// type OwnerModule = LocalModule;  // 自动插入
9.3.4 实际应用:PHY 驱动(rust/kernel/net/phy/mod.rs)
rust 复制代码
#[vtable]
pub trait Driver {
    const FLAGS: u32 = 0;
    const NAME: &'static CStr;
    
    fn soft_reset(_dev: &mut Device) -> Result { 
        build_error!(VTABLE_DEFAULT_ERROR) 
    }
    fn probe(_dev: &mut Device) -> Result { 
        build_error!(VTABLE_DEFAULT_ERROR) 
    }
    fn config_aneg(_dev: &mut Device) -> Result { 
        build_error!(VTABLE_DEFAULT_ERROR) 
    }
}

C 侧调用流程:

复制代码
C 函数指针 ──► Rust 桩函数 ──► 检查 HAS_* 常量 ──► 调用实现的方法
                                      │
                                      ▼
                              如果 false,跳过调用

Vtable 的好处:

  1. 可选方法 :使用 NULL 指针表示未重写的方法
  2. 类型安全:Rust 编译器检查签名
  3. 自动生成:宏自动生成 HAS_* 常量和 OwnerModule

9.4 Opaque 模式 (Opaque Types)

9.4.1 核心思想

Opaque<T> 封装不透明的 C 类型,允许 Rust 安全地持有可能未初始化的 C 结构体。

9.4.2 实现(rust/kernel/types.rs:331-419)
rust 复制代码
#[repr(transparent)]
pub struct Opaque<T> {
    value: UnsafeCell<MaybeUninit<T>>,  // 允许未初始化内存
    _pin: PhantomPinned,                // !Unpin,保证固定
}

关键特性:

  1. 允许未初始化 :使用 MaybeUninit<T> 允许任意位模式
  2. 可变性灵活 :&Opaque<T> 允许可变访问(绕过 Rust 常规规则)
  3. 不强制唯一性 :多个 &mut Opaque<T> 可指向同一值
  4. 线程不安全 :默认 !Sync,需要外部同步
9.4.3 核心方法
rust 复制代码
impl<T> Opaque<T> {
    /// 创建已初始化的值
    pub const fn new(value: T) -> Self {
        Self {
            value: UnsafeCell::new(MaybeUninit::new(value)),
            _pin: PhantomPinned,
        }
    }

    /// 创建未初始化的值
    pub const fn uninit() -> Self {
        Self {
            value: UnsafeCell::new(MaybeUninit::uninit()),
            _pin: PhantomPinned,
        }
    }

    /// 创建零初始化的值
    pub const fn zeroed() -> Self { ... }

    /// FFI 初始化:安全地写入未初始化内存
    pub fn ffi_init(init_func: impl FnOnce(*mut T)) -> impl PinInit<Self> {
        unsafe {
            pin_init::pin_init_from_closure::<_, ::core::convert::Infallible>(move |slot| {
                init_func(Self::cast_into(slot));
                Ok(())
            })
        }
    }

    /// 获取原始指针(unsafe 访问)
    pub const fn get(&self) -> *mut T {
        UnsafeCell::get(&self.value).cast::<T>()
    }
}
9.4.4 实际应用

设备结构体:

rust 复制代码
// rust/kernel/device.rs:167
pub struct Device<Ctx: DeviceContext = Normal>(
    Opaque<bindings::device>,  // 封装 C struct device
    PhantomData<Ctx>,
);

// rust/kernel/pci.rs:340
pub struct Device<Ctx: device::DeviceContext = device::Normal>(
    Opaque<bindings::pci_dev>,  // 封装 C struct pci_dev
    PhantomData<Ctx>,
);

锁状态:

rust 复制代码
// rust/kernel/sync/lock.rs:106
pub struct Lock<T: ?Sized, B: Backend> {
    #[pin]
    state: Opaque<B::State>,  // 封装锁的底层状态(如 mutex、spinlock)
    #[pin]
    _pin: PhantomPinned,
    #[pin]
    data: UnsafeCell<T>,
}

使用模式:

rust 复制代码
impl Device {
    fn read_field(&self) -> u32 {
        // SAFETY: 保证 self 有效且字段已初始化
        unsafe { (*self.0.get()).some_field }
    }
}

Opaque 的好处:

  1. 零成本抽象:无额外运行时开销
  2. 安全封装:访问需要 unsafe,明确责任边界
  3. 固定初始化 :与 pin_init! 宏配合安全初始化
  4. 灵活可变性:绕过 Rust 常规规则以适应 C 代码

9.5 四种模式的关系图

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                      类型状态模式                                │
│                   Device<Ctx> 泛型约束                           │
│                     ▼                                           │
├─────────────────────────────────────────────────────────────────┤
│    ┌─────────────┐      ┌─────────────┐                         │
│    │  Opaque<T>  │◄──── │  RAII Guard │                         │
│    │  封装 C 类型 │      │  自动释放   │                         │
│    └──────┬──────┘      └──────┬──────┘                         │
│           │                    │                                │
│           ▼                    ▼                                │
│    ┌─────────────────────────────────────┐                      │
│    │           Vtable 模式                │                      │
│    │    #[vtable] trait → C 回调         │                      │
│    └─────────────────────────────────────┘                      │
└─────────────────────────────────────────────────────────────────┘

协同工作示例:
1. 设备使用 Opaque 封装 C struct device
2. 设备使用泛型参数表示类型状态(Device<Ctx>)
3. 驱动注册使用 RAII 自动注销
4. 驱动 trait 使用 vtable 映射到 C 回调

十、构建系统

Makefile 配置

makefile 复制代码
obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o
obj-$(CONFIG_RUST) += kernel.o bindings.o
obj-$(CONFIG_RUST) += macros.o pin_init.o zerocopy.o

Kconfig 配置

kconfig 复制代码
config SAMPLE_RUST_MINIMAL
    tristate "Minimal"
    depends on RUST

十一、文件路径索引

文件 说明
rust/kernel/lib.rs kernel crate 入口(312行)
rust/kernel/alloc.rs 内存分配(273行)
rust/kernel/module.rs 模块系统(80行)
rust/kernel/error.rs 错误处理(663行)
rust/kernel/types.rs 类型系统(453行)
rust/kernel/device.rs 设备模型(952行)
rust/kernel/driver.rs 驱动框架(326行)
rust/kernel/sync.rs 同步原语(171行)
rust/kernel/sync/lock.rs 通用锁(324行)
rust/macros/lib.rs 过程宏(539行)
rust/kernel/usb.rs USB 子系统(485行)
rust/kernel/i2c.rs I2C 总线(596行)
rust/kernel/platform.rs Platform 总线
rust/kernel/of.rs 设备树抽象
rust/kernel/acpi.rs ACPI 抽象
rust/kernel/device_id.rs 设备 ID 匹配
rust/kernel/net/mod.rs 网络模块入口
rust/kernel/net/netlink.rs Netlink 封装
rust/kernel/net/phy/mod.rs PHY 设备抽象
rust/kernel/net/phy/reg.rs PHY 寄存器接口
rust/kernel/fs/file.rs 文件对象封装
rust/kernel/debugfs.rs DebugFS 抽象
rust/kernel/configfs.rs ConfigFS 抽象
rust/kernel/mm.rs 内存管理
rust/kernel/page.rs 页抽象
rust/kernel/task.rs 任务抽象
rust/kernel/cred.rs 进程凭证
rust/kernel/workqueue.rs 工作队列
samples/rust/rust_minimal.rs 最小示例(56行)
samples/rust/rust_driver_pci.rs PCI 驱动示例(194行)
samples/rust/rust_driver_usb.rs USB 驱动示例(54行)
samples/rust/rust_driver_i2c.rs I2C 驱动示例
samples/rust/rust_driver_platform.rs Platform 驱动示例
samples/rust/rust_debugfs.rs DebugFS 示例
samples/rust/rust_configfs.rs ConfigFS 示例

十二、学习计划与方法

12.1 学习路径图

复制代码
阶段一:基础准备(2-3周)
├── 1. Rust 语言基础
│   ├── 所有权与生命周期
│   ├── Trait 系统
│   ├── 泛型与关联类型
│   └── 宏系统(声明宏、过程宏)
│
├── 2. Linux 内核基础
│   ├── 内核模块开发
│   ├── 设备模型(device、driver、bus)
│   ├── 内存管理(kmalloc、vmalloc、页分配)
│   └── 同步原语(spinlock、mutex、RCU)
│
└── 3. 工具链准备
    ├── rustc、rustup、cargo
    ├── bindgen(C 绑定生成)
    └── 内核构建系统(Kconfig、Makefile)

阶段二:核心框架(2-3周)
├── 1. Rust 内核核心库
│   ├── kernel/lib.rs - 模块入口
│   ├── kernel/alloc.rs - 内存分配
│   ├── kernel/sync.rs - 同步原语
│   ├── kernel/types.rs - 类型系统
│   └── kernel/error.rs - 错误处理
│
├── 2. 设备模型
│   ├── kernel/device.rs - 设备抽象
│   ├── kernel/driver.rs - 驱动框架
│   └── kernel/device_id.rs - 设备 ID 匹配
│
└── 3. 宏系统
    ├── macros/lib.rs - 过程宏
    └── pin-init/ - 固定初始化

阶段三:子系统实践(4-6周)
├── 1. 字符设备
│   ├── kernel/miscdevice.rs
│   └── samples/rust/rust_misc_device.rs
│
├── 2. 总线驱动
│   ├── PCI 驱动(samples/rust/rust_driver_pci.rs)
│   ├── USB 驱动(samples/rust/rust_driver_usb.rs)
│   ├── I2C 驱动(samples/rust/rust_driver_i2c.rs)
│   └── Platform 驱动(samples/rust/rust_driver_platform.rs)
│
├── 3. 文件系统
│   ├── debugfs(samples/rust/rust_debugfs.rs)
│   └── configfs(samples/rust/rust_configfs.rs)
│
└── 4. 网络
    └── net/phy/ - PHY 设备驱动

阶段四:高级主题(持续)
├── 1. 安全保证
│   ├── unsafe 代码审计
│   ├── 内存安全模式
│   └── 并发安全验证
│
├── 2. 性能优化
│   ├── 零成本抽象
│   ├── 内联优化
│   └── 基准测试
│
└── 3. 贡献社区
    ├── 阅读邮件列表
    ├── 提交补丁
    └── 参与代码审查

12.2 推荐学习资源

资源 类型 说明
Rust 官方文档 文档 Rust 语言基础
Linux Kernel Rust 文档 文档 内核 Rust 官方文档
kernel/README.rst 文档 内核 Rust 快速入门
Rust for Linux 仓库 代码 上游开发仓库
LWN.net Rust 文章 文章 内核 Rust 进展报道
Linux Kernel Mailing List 邮件列表 社区讨论

12.3 学习方法要点

1. 代码阅读顺序:

复制代码
rust/kernel/lib.rs → 了解模块结构
    ↓
rust/kernel/alloc.rs → 理解内存分配
    ↓
rust/kernel/sync.rs → 理解同步原语
    ↓
rust/kernel/device.rs → 理解设备模型
    ↓
rust/kernel/driver.rs → 理解驱动框架
    ↓
samples/rust/*.rs → 学习示例代码

2. 关键设计模式:

  • 类型状态模式 :使用泛型参数表示设备上下文(Device<Ctx>)
  • RAII 模式 :通过 Drop trait 自动释放资源
  • Vtable 模式 :使用 #[vtable] 宏实现 trait 到 C 回调的映射
  • Opaque 模式 :使用 Opaque<T> 封装不透明 C 类型

3. 调试技巧:

rust 复制代码
// 使用 pr_info!/pr_debug! 输出
pr_info!("value: {}\n", value);

// 使用 dev_info!/dev_dbg! 输出设备信息
dev_info!(dev, "message: {}\n", value);

// 使用断言
build_assert!(condition, "error message");

4. 常见陷阱:

  • 不要忘记 #[pin] 属性用于固定字段
  • 注意 unsafe 块的安全不变式
  • 正确处理引用计数(AlwaysRefCounted)
  • 注意 Pinned 初始化(PinInit trait)

12.4 学习检查清单

  • 理解 Rust 所有权系统
  • 理解内核模块生命周期
  • 掌握内存分配(GFP_KERNEL vs GFP_ATOMIC)
  • 掌握同步原语(Mutex、SpinLock、CondVar)
  • 理解设备上下文类型状态
  • 能够编写简单的字符设备驱动
  • 能够编写平台驱动
  • 理解设备 ID 匹配机制
  • 掌握 #[vtable] 宏使用
  • 理解固定初始化(pin_init!)
  • 能够阅读和调试 Rust 内核代码
  • 了解如何向社区贡献代码

十三、总结

Linux kernel 中的 Rust 代码结构清晰,主要包含:

  1. 核心库 :kernel、bindings、uapi、ffi 等提供内核 API
  2. 工具库 :pin-init、zerocopy、macros 等提供基础设施
  3. 示例代码 :samples/rust/ 包含各种驱动示例
  4. 构建系统:完整的 Makefile、Kconfig 和脚本支持

Rust 在 Linux kernel 中的使用正在积极发展,提供了安全、高效的内核编程体验。


附录:实践项目建议

初级项目(1-2周)

  1. 修改 samples/rust/rust_minimal.rs 添加新功能
  2. 编写一个简单的 miscdevice 驱动
  3. 创建 debugfs 接口展示内核信息

中级项目(2-4周)

  1. 编写一个完整的平台驱动
  2. 实现一个 I2C 设备驱动
  3. 为现有 C 驱动添加 Rust 封装

高级项目(1-3月)

  1. 实现新的总线子系统 Rust 抽象
  2. 为网络子系统添加 Rust 支持
  3. 重构内核同步原语的 Rust 接口
相关推荐
暴力求解2 小时前
C++ ---继承(二)
开发语言·c++·算法
陈飞EXCEL2 小时前
北京杰飞 IT 旗下妙码生花少儿Python编程上线两大学习系统
开发语言·python·学习
代龙涛3 小时前
WordPress Query 查询机制详解(WP_Query)
开发语言·后端·php·wordpress
程序员cxuan3 小时前
不是,为啥这个模型突然就爆火了??
人工智能·后端·程序员
知守观3 小时前
技术考古:iBATIS 2.3.4 时代的持久层,是如何用 Map 玩转 307 个存储过程的?
java·后端·mybatis
程序员cxuan3 小时前
国产 GPU 能不能打,重点在软件栈
人工智能·后端·程序员
znsoft3 小时前
MaClaw(码卡龙)技术拆解:一个 Go + React 的可自进化智能体平台
开发语言·react.js·golang
the局外人3 小时前
Python 中使用 SSE 实现大模型流式输出
后端·python·llm
苍何3 小时前
用 WorkBuddy + LibTV 做 AI 视频,干活有点猛啊!(附教程)
后端