RISC-V Linux 的向量扩展支持

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

1. prctl() 接口

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

  • prctl(PR_RISCV_V_SET_CONTROL, unsigned long arg)

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

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

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

    • PR_RISCV_V_VSTATE_CTRL_ON:允许线程运行向量。

    • PR_RISCV_V_VSTATE_CTRL_OFF:不允许使用向量。在这种条件下执行向量指令将陷入并导致线程终止。

    arg:control 参数是一个 5 位值,由 3 部分组成,分别通过 3 个掩码访问。

    这 3 个掩码 PR_RISCV_V_VSTATE_CTRL_CUR_MASK、PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 和 PR_RISCV_V_VSTATE_CTRL_INHERIT 分别表示位 [1:0]、位 [3:2] 和位 [4]。位 [1:0] 表示当前线程的启用状态,位 [3:2] 的设置在下一次 execve() 时生效。位 [4] 定义位 [3:2] 中设置的继承模式。

    • PR_RISCV_V_VSTATE_CTRL_CUR_MASK:位 [1:0]:表示调用线程的向量启用状态。一旦启用,调用线程就无法关闭向量。如果此掩码中的值为 PR_RISCV_V_VSTATE_CTRL_OFF,但当前启用状态不为 off,则 prctl() 调用将失败并显示 EPERM。在此处设置 PR_RISCV_V_VSTATE_CTRL_DEFAULT 不起作用,只是将原始启用状态设置回去。

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

    • PR_RISCV_V_VSTATE_CTRL_INHERIT:位 [4]:PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 中设置的继承模式。如果设置了该位,则以下 execve() 不会清除 PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 和 PR_RISCV_V_VSTATE_CTRL_INHERIT 中的设置。此设置在系统范围默认值的更改中保持不变。

    返回值
    • 成功时为 0;

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

    • EPERM:如果调用线程启用了向量,则在 PR_RISCV_V_VSTATE_CTRL_CUR_MASK 中关闭向量。

    成功时
    • 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() 调用的设置和继承位都进行或运算。

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

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

    • EINVAL:不支持向量。

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] 的 1.0 版本所示,向量寄存器会被系统调用破坏。

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