Skip to main content

libarch/riscv64/
feature.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! RISC-V feature set.
6//!
7//! This mirrors `arch::RiscvFeature` / `arch::RiscvFeatures` in
8//! `<lib/arch/riscv64/feature.h>`.  Only the enumerator *order* is shared
9//! between the two: the C++ container's layout is private, and Rust obtains its
10//! contents through accessors rather than by mirroring it.
11
12/// An enumeration of RISC-V features.
13///
14/// This is not intended to be exhaustive, but rather to include the features
15/// that the kernel currently depends on.
16///
17/// The discriminants must match `arch::RiscvFeature` in
18/// `<lib/arch/riscv64/feature.h>`, which is where they are checked.
19#[repr(u32)]
20#[derive(Copy, Clone, Debug, Eq, PartialEq)]
21pub enum RiscvFeature {
22    /// Extension for supervisor based timer.
23    Sstc = 0,
24    /// SuperVisor extension for Page-Based Memory Types.
25    Svpbmt = 1,
26    /// The standard V extension for vector support.
27    Vector = 2,
28    /// Cache-Block Management Operations.
29    Zicbom = 3,
30    /// Cache-Block Zero Operations.
31    Zicboz = 4,
32    /// Counter CSRs are accessible.
33    Zicntr = 5,
34}
35
36impl RiscvFeature {
37    /// Every feature, in discriminant order.
38    pub const ALL: [RiscvFeature; 6] = [
39        RiscvFeature::Sstc,
40        RiscvFeature::Svpbmt,
41        RiscvFeature::Vector,
42        RiscvFeature::Zicbom,
43        RiscvFeature::Zicboz,
44        RiscvFeature::Zicntr,
45    ];
46}
47
48/// A simple container abstraction around the set of RISC-V features.
49#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
50pub struct RiscvFeatures {
51    bits: u64,
52    cbom_size: u16,
53    cboz_size: u16,
54}
55
56impl RiscvFeatures {
57    /// Constructs a feature set from a raw bitmask, in which bit `n` records
58    /// support for the feature whose discriminant is `n`.
59    pub const fn from_bits(bits: u64) -> Self {
60        Self { bits, cbom_size: 0, cboz_size: 0 }
61    }
62
63    /// The raw bitmask, in which bit `n` records support for the feature whose
64    /// discriminant is `n`.
65    pub const fn bits(&self) -> u64 {
66        self.bits
67    }
68
69    /// Whether a given feature is supported.
70    pub const fn supports(&self, feature: RiscvFeature) -> bool {
71        (self.bits & (1 << (feature as u32))) != 0
72    }
73
74    /// Sets support for a given feature.
75    pub fn set(&mut self, feature: RiscvFeature, supported: bool) -> &mut Self {
76        if supported {
77            self.bits |= 1 << (feature as u32);
78        } else {
79            self.bits &= !(1 << (feature as u32));
80        }
81        self
82    }
83
84    /// The cache block size for Cache-Block Management Operations, in bytes.
85    pub const fn cbom_size(&self) -> u16 {
86        self.cbom_size
87    }
88
89    /// The cache block size for Cache-Block Zero Operations, in bytes.
90    pub const fn cboz_size(&self) -> u16 {
91        self.cboz_size
92    }
93
94    /// Sets the Cache-Block Management Operations block size.
95    pub fn set_cbom_size(&mut self, size: u16) -> &mut Self {
96        self.cbom_size = size;
97        self
98    }
99
100    /// Sets the Cache-Block Zero Operations block size.
101    pub fn set_cboz_size(&mut self, size: u16) -> &mut Self {
102        self.cboz_size = size;
103        self
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    #[test]
112    fn features() {
113        let mut features = RiscvFeatures::default();
114        assert!(!features.supports(RiscvFeature::Vector));
115
116        features.set(RiscvFeature::Vector, true).set(RiscvFeature::Zicbom, true);
117        assert!(features.supports(RiscvFeature::Vector));
118        assert!(features.supports(RiscvFeature::Zicbom));
119        assert!(!features.supports(RiscvFeature::Zicboz));
120
121        features.set(RiscvFeature::Vector, false);
122        assert!(!features.supports(RiscvFeature::Vector));
123        assert!(features.supports(RiscvFeature::Zicbom));
124    }
125
126    #[test]
127    fn bits_round_trip() {
128        let mut features = RiscvFeatures::default();
129        for feature in RiscvFeature::ALL {
130            features.set(feature, true);
131        }
132        assert_eq!(features.bits(), 0b11_1111);
133        assert_eq!(RiscvFeatures::from_bits(features.bits()), RiscvFeatures::from_bits(0b11_1111));
134    }
135}