在 RISC-V 体系结构(包括 IOMMU 规范、Linux 内核驱动以及 OpenSBI 固件)中,WPRI 和 WARL 是用来描述寄存器中某些字段读写行为属性的关键规范术语。它们直接影响软硬件协同设计时"怎么写寄存器、怎么探测硬件能力"。
一、核心定义与硬件语义
-
WPRI(Writes Preserve Values, Reads Ignore)------"保留位,写保持,读忽略"
这类字段在当前规范中为保留(Reserved),供未来扩展使用。
-
软件写策略 :当软件写入该寄存器其他有效字段时,必须保持(Preserve)这些 WPRI 位原有的值,不能随意改写。
-
软件读策略 :读取时应当**忽略(Ignore)** 这些位的值。为兼容未来扩展,硬件实现若不提供这些字段,通常会将其硬连线为 0。
-
IOMMU 场景举例 :IOMMU 寄存器中的
reserved区间(如capabilities或fctrl的高位保留段)通常标记为 WPRI。
-
-
WARL(Write Any values, Reads Legal values)------"可写任意值,读回合法值"
这类字段只在部分编码下有定义行为,但硬件必须保证稳定性。
-
写入 :软件允许写入任意值(不触发异常)。
-
读回 :硬件一定返回一个合法的、受支持的编码值。硬件会根据自身实现能力,将"非法写入值"静默转换成某个支持的合法值。
-
核心用途 :软件常利用 WARL 的"写-读回"特性来探测硬件的实际支持能力(比如尝试写一个最大值,再读回看硬件实际接受了多少)。
-
二、Linux 内核 riscv_iommu 驱动中的实战处理
在 RISC-V IOMMU 驱动(如 drivers/iommu/riscv-iommu.c及相关队列初始化补丁)中,对 WPRI / WARL 的处理非常典型:
1. 对待 WPRI:读-改-写(RMW)时保持原值
驱动在更新一个混合了有效字段和 WPRI 保留字段的 IOMMU 寄存器时,不会直接覆盖写整个寄存器,而是遵循"保留原值"的原则。不过在实际队列/控制寄存器配置中,由于 WPRI 区域一般默认硬连线为 0,驱动的写法通常是:
-
只构造并写入有明确定义的有效字段 (如
PPN、mode、LOG2SZ等)。 -
不对 WPRI 保留位做任何主动设置,等价于保持 0 / 原值,符合规范。
2. 利用 WARL 做硬件能力探测与配置(经典实战)
IOMMU 的队列基址寄存器(如 cqb的 LOG2SZ字段、ddtp的 iommu_mode)往往被定义为 WARL。内核驱动利用这一点来动态适配不同 IOMMU 硬件的实现差异:
// 伪代码逻辑,对应内核补丁中的 riscv_iommu_queue_alloc 等实现
// 1. 向 WARL 字段写入一个期望的最大值(如最大队列长度编码)
riscv_iommu_writeq(iommu, queue->qbr, RISCV_IOMMU_QUEUE_LOGSZ_MAX);
// 2. 立刻读回,硬件会静默将"超出能力的值"裁剪为它实际支持的合法值
qb = riscv_iommu_readq(iommu, queue->qbr);
// 3. 解析硬件实际接受的配置(能力探测)
hw_max_logsz = FIELD_GET(RISCV_IOMMU_QUEUE_LOGSZ_FIELD, qb);
// 4. 根据实际支持值,再正式配置并最终写入确认
final_logsz = min(driver_want_logsz, hw_max_logsz);
qb_final = phys_to_ppn(buf) | FIELD_PREP(RISCV_IOMMU_QUEUE_LOGSZ_FIELD, final_logsz);
riscv_iommu_writeq(iommu, queue->qbr, qb_final);
// 5. 可选:再次读回校验,确保硬件真正接受了配置
rb = riscv_iommu_readq(iommu, queue->qbr);
通过这种方式,驱动无需硬编码各种 IOMMU 实现的能力,而是依靠 WARL 语义自适应。
三、OpenSBI 中的寄存器/CSR 处理视角
OpenSBI 运行在 Machine Mode,如果它要模拟或转发处理某些 IOMMU 相关的 CSR / MMIO 寄存器访问(或在 SSE / RAS 等扩展中处理 miselect/mireg等 WARL 类 CSR),逻辑一般遵循:
-
WPRI 字段 :在模拟寄存器写操作时,OpenSBI 的代码会在"读-改-写"逻辑中,屏蔽(Mask)掉 WPRI 保留位的写入值,保留这些位原有的硬件/影子值,不允软件通过 ECALL 随意变更保留区域。
-
WARL 字段:
-
当内核通过 SBI 调用或直接访问(若 delegated)尝试写入 WARL 字段时,OpenSBI 内部会做合法性裁剪 (比如通过一个
switch或范围判断),将软件写的"任意值"收敛为当前平台实际支持的合法值并存下来。 -
当软件读取时,直接返回这个已裁剪过的合法值。
-
典型场景 :
miselect(用于索引 SBI 扩展的辅助 CSR)本身往往是 WARL 语义------写未实现的索引值时,OpenSBI 保持原合法索引不变,后续对mireg的访问仍基于上次合法值进行。
-
总结来说,WPRI 约束软件"别乱改保留位",而 WARL 给了软件"写任意、读合法"的探测自由度。Linux 驱动主要利用 WARL 做硬件能力自适应配置,写寄存器时自然避开 WPRI 位;OpenSBI 则在底层模拟/处理这些访问时,负责落实"保留原值"和"静默裁剪为合法值"的硬件语义。