1use aarch64_cpu::registers::ID_AA64PFR0_EL1;
2use aarch64_cpu::registers::{Readable, Writeable};
3use armv9a::regs::{ID_AA64PFR1_SME_EL1, SMCR_EL2, ZCR_EL2};
4use core::arch::asm;
5use lazy_static::lazy_static;
6
7const ZCR_EL2_LEN_WIDTH: u64 = 4;
11const SVE_VQ_ARCH_MAX: u64 = (1 << ZCR_EL2_LEN_WIDTH) - 1;
12const QUARD_WORD: u64 = 128;
13pub const MAX_VQ: u64 = 4;
22
23#[derive(Default, Debug)]
24pub struct SimdConfig {
26 pub sve_en: bool,
28
29 pub sve_vq: u64,
31
32 pub sme_en: bool,
34}
35
36lazy_static! {
37 static ref SIMD_CONFIG: SimdConfig = {
39 let mut sve_en: bool = false;
41 let mut sve_vq: u64 = 0;
42 let mut sme_en: bool = false;
43
44 trace!("Reading simd features");
45 #[cfg(not(any(test, miri, fuzzing)))]
46 if ID_AA64PFR0_EL1.is_set(ID_AA64PFR0_EL1::SVE) {
47 trace!("SVE is set");
48 ZCR_EL2.write(ZCR_EL2::LEN.val(SVE_VQ_ARCH_MAX));
52 let vl_b = unsafe { get_vector_length_bytes() };
54 sve_vq = ((vl_b << 3)/ QUARD_WORD) - 1;
55 if sve_vq > MAX_VQ {
56 sve_vq = MAX_VQ - 1;
57 }
58 sve_en = true;
59 trace!("sve_vq={:?}", sve_vq);
60 }
61
62 #[cfg(not(any(test, miri, fuzzing)))]
64 if ID_AA64PFR1_SME_EL1.is_set(ID_AA64PFR1_SME_EL1::SME) {
65 trace!("SME is set");
66 SMCR_EL2.write(SMCR_EL2::RAZWI.val(SMCR_EL2::RAZWI.mask) + SMCR_EL2::LEN.val(SMCR_EL2::LEN.mask));
68 let raz = SMCR_EL2.read(SMCR_EL2::RAZWI);
69 let len = SMCR_EL2.read(SMCR_EL2::LEN);
70 let sme_svq_arch_max = (raz << 4) + len;
71 trace!("sme_svq_arch_max={:?}", sme_svq_arch_max);
72
73 assert!(sme_svq_arch_max <= SVE_VQ_ARCH_MAX);
74 sme_en = true;
75 }
76
77 SimdConfig {
78 sve_en,
79 sve_vq,
80 sme_en,
81 }
82 };
83}
84
85#[allow(aarch64_softfloat_neon)]
87#[target_feature(enable = "sve")]
88unsafe fn get_vector_length_bytes() -> u64 {
89 let vl_b: u64;
90 unsafe {
91 asm!("rdvl {}, #1", out(reg) vl_b);
92 }
93 vl_b
94}
95
96pub fn validate(en: bool, sve_vl: u64) -> bool {
97 if en && !SIMD_CONFIG.sve_en {
98 return false;
99 }
100 if sve_vl > SIMD_CONFIG.sve_vq {
101 return false;
102 }
103 true
104}
105
106pub fn sve_en() -> bool {
107 SIMD_CONFIG.sve_en
108}
109
110pub fn max_sve_vl() -> u64 {
111 SIMD_CONFIG.sve_vq
112}
113
114pub fn sme_en() -> bool {
115 SIMD_CONFIG.sme_en
116}