Skip to content

[RFC] std_detect: RISC-V platform guide documentation #1779

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

a4lg
Copy link
Contributor

@a4lg a4lg commented Apr 17, 2025

To help users make a decision for feature checking on a RISC-V system:

  1. Whether to use this runtime detection macro (or prefer to use static feature enablement with -Ctarget-feature compiler option) and
  2. 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 SsnpmSupm, 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...

  1. Supported by this macro,
  2. Likely to be supported by many future application-class hardware
  3. But unlikely to return true by 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)

See diff

Slightly modified to pass "Check Style" CI.

Version 3 (2025-04-17)

See diff

  • 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)

See diff

  • 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 than time (wall-clock) by default.
Also beware that, even if the performance counters like cycle and instret are 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)

See diff

  • Grammar fixes and adjustments.

@rustbot
Copy link
Collaborator

rustbot commented Apr 17, 2025

r? @Amanieu

rustbot has assigned @Amanieu.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@a4lg a4lg force-pushed the riscv-arch-platform-guide branch from 16c85d4 to 5c86678 Compare April 17, 2025 01:34
@sayantn
Copy link
Contributor

sayantn commented Apr 17, 2025

Maybe a bad question, but what do the gaps in the Linux column mean? Has Linux not added support for them yet?

@a4lg
Copy link
Contributor Author

a4lg commented Apr 17, 2025

@sayantn

I meant:

  • A system call riscv_hwprobe which is new in the kernel version 6.4
    (for Linux kernel between 4.16 and 6.3, this crate entirely depends on the auxiliary vector).
  • Multiple batches of runtime feature addition in the riscv_hwprobe system call
    (e.g. version 6.8 adds support for 37 extensions).

@sayantn
Copy link
Contributor

sayantn commented Apr 17, 2025

No, I meant like

    /// | `"zfinx"`       | Zfinx       |                    |
    /// | `"zhinx"`       | Zhinx       |                    |
    /// | `"zhinxmin"`    | Zhinxmin    |                    |

In the doc comment for is_riscv_feature_detected, what do the empty values for the third column mean?

@a4lg
Copy link
Contributor Author

a4lg commented Apr 17, 2025

@sayantn Ah, sorry. Just unsupported extensions are filled with empty value and I meant "No" as the default value (without anything to note about) but... seems misleading.

@sayantn
Copy link
Contributor

sayantn commented Apr 17, 2025

Just to be clear, the kernel doesn't support it yet, right? Are there any extensions which the kernel supports, but std_detect doesn't implement it?

@a4lg
Copy link
Contributor Author

a4lg commented Apr 17, 2025

Just to be clear, the kernel doesn't support it yet, right?

Yes.

Are there any extensions which the kernel supports, but std_detect doesn't implement it?

As of the Linux kernel 6.14 (the latest release), the only extension not supported by std_detect but supported by the riscv_hwprobe system call is the Supm extension.
But the position of this extension is very special and has a good reason not supporting it.

This extension (a part of the pointer masking specification) denotes that existence of some facility to change the behavior of pointer masking (enabling it makes some upper pointer bits reserved for custom purposes and ignored on hardware access). However, it provides existence of some facility and nothing architectural (no instructions, no CSRs...).

For instance, it just denotes the existence of prctl-based pointer masking control in Linux and that's too OS-dependent. That's why I am requested by a reviewer not to support it in Rust (as in rust-lang/rust#139440).

@sayantn
Copy link
Contributor

sayantn commented Apr 17, 2025

Ok thanks for the info. I was trying to see which target features are available in our CI runs in #1776

@a4lg a4lg force-pushed the riscv-arch-platform-guide branch 5 times, most recently from 464d7a3 to b4b2e26 Compare April 20, 2025 03:50
Since there's no architectural feature detection on RISC-V (unlike `CPUID`
on x86 architectures and some system registers on Arm/AArch64), runtime
feature detection entirely depends on the platform-specific facility.

As a result, availability of each feature heavily depends on the platform
and its version.

To help users make a decision for feature checking on a RISC-V system, this
commit adds a platform guide with minimum supported platform versions.

Note:

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 considered "supported" once the
platform/version supports runtime detection of all members in it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants