RISC-V Linux 的向量扩展支持

本文档简要概述了 Linux 为支持用户空间使用 RISC-V 向量扩展而提供的接口。

1. prctl() 接口

添加了两个新的 prctl() 调用,允许程序管理在用户空间使用向量(Vector)的启用状态。这些接口的预期使用准则是为 init 系统提供一种修改其域下运行进程的 V 可用性的方法。不建议在库例程(library routines)中调用这些接口,因为库不应覆盖从父进程配置的策略。此外,用户必须注意这些接口不可移植到非 Linux 或非 RISC-V 环境,因此不建议在可移植代码中使用。要在 ELF 程序中获取 V 的可用性,请读取辅助向量(auxiliary vector)中 ELF_HWCAPCOMPAT_HWCAP_ISA_V 位。

  • prctl(PR_RISCV_V_SET_CONTROL, unsigned long arg)

    设置调用线程的向量启用状态,其中控制参数由两个 2 位启用状态和一个用于继承模式的位组成。调用进程的其他线程不受影响。

    启用状态是一个三态值,每个值在控制参数中占用 2 位空间

    • PR_RISCV_V_VSTATE_CTRL_DEFAULT:在 execve() 时使用系统范围的默认启用状态。系统范围的默认设置可以通过 sysctl 接口进行控制(参见下文的 sysctl 部分)。

    • PR_RISCV_V_VSTATE_CTRL_ON:允许在该线程中运行 Vector。

    • PR_RISCV_V_VSTATE_CTRL_OFF:不允许使用 Vector。在此类条件下执行向量指令将产生陷阱(trap)并导致线程终止。

    arg:控制参数是一个 5 位值,由 3 部分组成,分别由 3 个掩码进行访问。

    3 个掩码 PR_RISCV_V_VSTATE_CTRL_CUR_MASKPR_RISCV_V_VSTATE_CTRL_NEXT_MASKPR_RISCV_V_VSTATE_CTRL_INHERIT 分别代表 bit[1:0]、bit[3:2] 和 bit[4]。bit[1:0] 对应当前线程的启用状态,bit[3:2] 处的设置在下一次 execve() 时生效。bit[4] 定义了 bit[3:2] 中设置的继承模式。

    • PR_RISCV_V_VSTATE_CTRL_CUR_MASK:bit[1:0]:决定调用线程的向量启用状态。一旦启用 Vector,调用线程将无法将其关闭。如果此掩码中的值为 PR_RISCV_V_VSTATE_CTRL_OFF 但当前启用状态并非关闭,则 prctl() 调用将失败并返回 EPERM。在此处设置 PR_RISCV_V_VSTATE_CTRL_DEFAULT 不会产生任何效果,只是恢复原来的启用状态。

    • PR_RISCV_V_VSTATE_CTRL_NEXT_MASK:bit[3:2]:决定调用线程在下一次 execve() 系统调用时的向量启用设置。如果在此掩码中使用 PR_RISCV_V_VSTATE_CTRL_DEFAULT,则启用状态将由 execve() 发生时的系统范围启用状态决定。

    • PR_RISCV_V_VSTATE_CTRL_INHERIT:bit[4]:PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 设置的继承模式。如果设置了此位,则后续的 execve() 不会清除 PR_RISCV_V_VSTATE_CTRL_NEXT_MASKPR_RISCV_V_VSTATE_CTRL_INHERIT 中的设置。即使系统范围的默认值发生更改,此设置依然保持不变。

    返回值
    • 成功时返回 0;

    • EINVAL:不支持 Vector,当前或下一个掩码的启用状态无效;

    • EPERM:如果已为调用线程启用了 Vector,却试图在 PR_RISCV_V_VSTATE_CTRL_CUR_MASK 中关闭 Vector。

    成功时:
    • 对 PR_RISCV_V_VSTATE_CTRL_CUR_MASK 的有效设置将立即生效。PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 中指定的启用状态在下一次 execve() 调用时生效;如果设置了 PR_RISCV_V_VSTATE_CTRL_INHERIT 位,则在所有随后的 execve() 调用中生效。

    • 每次成功的调用都会覆盖调用线程先前的设置。

  • prctl(PR_RISCV_V_GET_CONTROL)

    获取调用线程的相同向量启用状态。下一次 execve() 调用的设置以及继承位会通过按位或(OR)组合在一起。

    请注意,ELF 程序可以通过读取辅助向量中 ELF_HWCAPCOMPAT_HWCAP_ISA_V 位来获取自身 V 的可用性。

    返回值
    • 成功时返回非负值;

    • EINVAL:不支持 Vector。

2. 系统运行时配置(sysctl)

为了减轻信号栈扩展带来的 ABI 影响,向管理员、发行版维护人员和开发人员提供了一种策略机制,以 sysctl 旋钮(knob)的形式控制用户空间进程的默认向量启用状态

  • /proc/sys/abi/riscv_v_default_allow

    向该文件写入文本形式的 0 或 1 可以为新启动的用户空间程序设置系统默认的启用状态。有效值为

    • 0:默认不允许新进程执行向量代码。

    • 1:默认允许新进程执行向量代码。

    读取该文件会返回当前的系统默认启用状态。

    在每次 execve() 调用时,新进程的新启用状态都会被设为系统默认值,除非

    • 为调用进程设置了 PR_RISCV_V_VSTATE_CTRL_INHERIT,且 PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 中的设置不是 PR_RISCV_V_VSTATE_CTRL_DEFAULT。或者,

    • PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 中的设置不是 PR_RISCV_V_VSTATE_CTRL_DEFAULT。

    修改系统默认启用状态不会影响任何未进行 execve() 调用的现有进程或线程的启用状态。

3. 跨系统调用的向量寄存器状态

正如 V 扩展 1.0 版本 [1] 所指出的,向量寄存器会被系统调用破坏(clobbered)。

1: https://github.com/riscv/riscv-v-spec/blob/master/calling-convention.adoc