[RFC] std_detect: RISC-V platform guide documentation by a4lg · Pull Request #1779 · rust-lang/stdarch (original) (raw)
To help users make a decision for feature checking on a RISC-V system:
- Whether to use this runtime detection macro (or prefer to use static feature enablement with
-Ctarget-featurecompiler option) and - Determine the platform and versions to support,
This commit adds a RISC-V platform guide with minimum supported platform versions.
Related
Screenshot
Because I could not make a single HTML version of the resulting documentation, I will paste a screenshot (slightly modified for readability) here.
Image (as of PR v7): screenshot-is_riscv_feature_detected.png
Image (old; PR v6): screenshot-is_riscv_feature_detected.png
Image (old; PR v5): screenshot-is_riscv_feature_detected.png
Image (old; PR v3): screenshot-is_riscv_feature_detected.png
Image (old; PR v2): screenshot-is_riscv_feature_detected.png
Image (old; PR v1): screenshot-is_riscv_feature_detected.png
Background / Problem
Absence of Architectural Runtime Feature Detection on RISC-V
Unlike x86 architectures with an unprivileged CPUID instruction and Arm/AArch64 architectures with a series of system registers (available to the operating system level (EL1) but some operating systems chose to expose them to the user mode (EL0) through instruction emulation), RISC-V does not provide any fine-grained feature detection facility itself.
The only standard RISC-V architectural thing provided is the misa CSR but it is only available to the firmware level (M-mode, even higher than the S-mode which the operating system normally runs on, and the firmware normally does not provide the contents of the misa CSR to lower modes). Even if this CSR is accessible, it's very coarse (only provides existence of single-letter extensions).
Per-Platform Runtime Feature Detection Mess
As a result, runtime feature detection on RISC-V entirely depends on the platform-specific facility which heavily depends on the platform and its version per feature.
For instance, the main source of the runtime feature detection on Linux is the Devicetree (optionally, command line arguments and boot time benchmark) and the kernel exports a subset (while making some conversions like Ssnpm → Supm, note that the Supm extension is not supported by the standard Rust feature handling system for being too OS-dependent) through the auxiliary vector and the riscv_hwprobe system call.
However, this filtering is performed on the kernel which means only features supported by the kernel (I mean, features in the read-only, highly version-specific allow list in the kernel) are exposed to the user mode. Note that, even some unsupported extensions may work without explicit kernel support as long as the hardware supports the extension (and extension does not need any help by the kernel).
This is a mess and the author considers just providing the list of features supported by the macro is insufficient for users who actually want to use runtime feature detection.
Existence of a Supported but Not Useful Feature: "zkr" (and "zk")
The problem is not just the platform and the version. For instance, there is an example of "zkr" (the Zkr extension) which is...
- Supported by this macro,
- Likely to be supported by many future application-class hardware
- But unlikely to return
trueby a result of true runtime feature detection.
This is due to the fact that the seed CSR provided by this extension is normally inaccessible from the user mode.
For instance, OpenSBI ― a reference RISC-V firmware implementation ― changes the mseccfg CSR so that the seed CSR is accessible from the S-mode (OS) but not from the U-mode (user) by default. Worse than that, this behavior is not even configurable from the OS.
It also affects the Zk extension "zk" (fully-featured scalar cryptography) which contains the Zkr extension.
Proposal
This commit makes the large portion of the supported feature list table-based to show platform support (with minimum supported versions) per feature and a few footnotes.
Even the value in a column is "No", there are various cases (some can be helpful on certain circumstances (even if runtime detection is not directly supported) and others need alternative solution by avoiding checks using the given feature). Footnotes are mainly written to help making a decision on such cases.
Tables are basically sorted (purely) alphabetically to make finding an extension easier but this change makes relations between extensions less obvious. The author still prefers this format because the user will find an extension to use with the ISA manual (which describes relations between extensions anyway).
It also adds some notes as a RISC-V platform guide.
Note: About Reverse Implication (Extension Groups)
It intentionally omits the description of the reverse implication related to extension groups (such like implication of B from its members: Zba, Zbb and Zbs extensions) because it currently does not synchronize well with the -Ctarget-feature compiler option (due to missing reverse implication checks using cfg and due to constraints of the current Rust's feature handling).
Instead, it only describes forward implications (like D implying F) due to the fact that it relatively synchronizes well between Rust and stdarch for this kind of feature handling (not fully synchronized though).
Still, an extension group is (implicitly) considered "supported" once the platform/version supports runtime detection of all members in it.
Supported versions shown in the table is the lowest of:
- The first version (or just "Yes" when the version is the first one with upstream RISC-V support (Linux: 4.16))
supporting runtime detection of the extension group
(e.g. "Yes" on the A extension) or - The first version supporting runtime detection of all members in it
(e.g. "6.5" on the B extension).
Request for Comments
Although this PR can be a regular PR right now, I first request comments because the change is very significant.
Is this Guide to be Here?
Because this kind of change is large and the resulting documentation is far more verbose than the rest (runtime feature detection macro on other architectures), I'm not sure whether this kind of the guide is suitable here.
Even if this kind of the guide is helpful for users, it may not be the right place.
What do you think?
Are Version Numbers Required in the Extension Table?
The author prefers to include version numbers (also due to the fact that there are large gaps of runtime feature detection on the Linux kernel version 6.4 and later) but if that's too much, the author considers just showing Yes/No (with footnotes) will be still helpful for users (far better than nothing).
History
Version 1 (2025-04-17)
The initial proposal.
Version 2 (2025-04-17)
Slightly modified to pass "Check Style" CI.
Version 3 (2025-04-17)
- Clarification: Fill all platform support columns per feature without assuming empty column as the default "No"
(instead, place "No" without slacking off) - Fix: "minimum kernel version" → "minimum supported version"
In this context, the platform is not limited to Linux and more generic terms should have been used.
PR version 3 fixed this by using "supported", filling with a more meaningful context. - Clarification: the Zicntr extension is (currently) not just "No"
Runtime detection of this extension will be available on the Linux kernel version 6.15 (as of rc2).
Because we cannot say something like Linux kernel will, PR version 3 fills just why this extension is not supported.
I guess the reason would be to avoid mostly dummy implementation of this extension (but not sure). - Consistency: Use words "Linux kernel version X.XX"
"Performance Hints" section used "Linux version X.XX" and this version fixes that. - Minor tidying for a footnote about the Zkr extension.
Version 4 (2025-04-17)
- Clarification (in the commit message):
An extension group is considered "supported" once all members support runtime detection.
For instance, Linux does not directly provide runtime detection of the B extension but all of its members (Zba, Zbb and Zbs) is supported on the Linux kernel version 6.5. Supported versions shown is the lowest of:- The first version (or just "Yes" when the version is the first one with upstream RISC-V support (Linux: 4.16)) supporting runtime detection of the extension group (e.g. "Yes" on the A extension) or
- The first version supporting runtime detection of all members in it (e.g. "6.5" on the B extension).
- Minor adjustment to a header (too minor so the screenshot is not updated, at least for now).
Version 5 (2025-04-18)
See diff (for the file relevant to this PR)
- Rebase
- Minor Bug Fix:
"zicntr"(the Zicntr extension) was not alphabetically sorted.
This is caused because it was originally ported from a branch including Linux kernel version 6.15 changes and manually modified to the current state (version 6.14).
Version 6 (2025-04-19)
See diff (including ones caused by rebase)
- Rebase
- Clarification: Existence of counter extensions is not availability of counters!!!
The new footnote to the Zicntr extension is as follows:
Even if this extension is available, it does not necessarily mean that all performance counters are accessible.
For instance, Linux kernel version 6.6 or later prohibits accesses to performance counters other thantime(wall-clock) by default.
Also beware that, even if the performance counters likecycleandinstretare accessible, their value can be unreliable (e.g. returning constant value) under certain circumstances.
This seems not very meaningful in this PR alone but it's very generic and will get practically useful beginning with the Linux kernel version 6.15 (with runtime detection of the Zicntr and Zihpm extensions).
Unless explicitly configured, the only accessible and reliable performance counter on Linux is time (wall-clock). Other performance counters are blocked by default in the Linux kernel version 6.6 or later.
If the Linux kernel is version 6.5 or before, access to cycle and instret are not blocked. However, it returns the constant value (unless explicitly configured) when OpenSBI is the BIOS and the mcountinhibit CSR is available (QEMU: when zicntr=true is specified for the CPU option from minimal configuration).
perf Linux utility for instance, configures performance counters through the PMU driver (indirectly making SBI (firmware) calls) to measure performance.
Version 7 (2025-04-20)
- Grammar fixes and adjustments.