blob: 5cc35fd3025fac659979b2f1c52b427393f8b876 [file] [log] [blame]
//! Run-time feature detection for s390x on Linux.
use super::auxvec;
use crate::detect::{Feature, bit, cache};
/// Try to read the features from the auxiliary vector
pub(crate) fn detect_features() -> cache::Initializer {
if let Ok(auxv) = auxvec::auxv() {
let hwcap: AtHwcap = auxv.into();
return hwcap.cache();
}
cache::Initializer::default()
}
/// These values are part of the platform-specific [asm/elf.h][kernel], and are a selection of the
/// fields found in the [Facility Indications].
///
/// [Facility Indications]: https://www.ibm.com/support/pages/sites/default/files/2021-05/SA22-7871-10.pdf#page=63
/// [kernel]: https://github.com/torvalds/linux/blob/b62cef9a5c673f1b8083159f5dc03c1c5daced2f/arch/s390/include/asm/elf.h#L129
#[derive(Debug, Default, PartialEq)]
struct AtHwcap {
esan3: bool,
zarch: bool,
stfle: bool,
msa: bool,
ldisp: bool,
eimm: bool,
dfp: bool,
hpage: bool,
etf3eh: bool,
high_gprs: bool,
te: bool,
vxrs: bool,
vxrs_bcd: bool,
vxrs_ext: bool,
gs: bool,
vxrs_ext2: bool,
vxrs_pde: bool,
sort: bool,
dflt: bool,
vxrs_pde2: bool,
nnpa: bool,
pci_mio: bool,
sie: bool,
}
impl From<auxvec::AuxVec> for AtHwcap {
/// Reads AtHwcap from the auxiliary vector.
fn from(auxv: auxvec::AuxVec) -> Self {
AtHwcap {
esan3: bit::test(auxv.hwcap, 0),
zarch: bit::test(auxv.hwcap, 1),
stfle: bit::test(auxv.hwcap, 2),
msa: bit::test(auxv.hwcap, 3),
ldisp: bit::test(auxv.hwcap, 4),
eimm: bit::test(auxv.hwcap, 5),
dfp: bit::test(auxv.hwcap, 6),
hpage: bit::test(auxv.hwcap, 7),
etf3eh: bit::test(auxv.hwcap, 8),
high_gprs: bit::test(auxv.hwcap, 9),
te: bit::test(auxv.hwcap, 10),
vxrs: bit::test(auxv.hwcap, 11),
vxrs_bcd: bit::test(auxv.hwcap, 12),
vxrs_ext: bit::test(auxv.hwcap, 13),
gs: bit::test(auxv.hwcap, 14),
vxrs_ext2: bit::test(auxv.hwcap, 15),
vxrs_pde: bit::test(auxv.hwcap, 16),
sort: bit::test(auxv.hwcap, 17),
dflt: bit::test(auxv.hwcap, 18),
vxrs_pde2: bit::test(auxv.hwcap, 19),
nnpa: bit::test(auxv.hwcap, 20),
pci_mio: bit::test(auxv.hwcap, 21),
sie: bit::test(auxv.hwcap, 22),
}
}
}
impl AtHwcap {
/// Initializes the cache from the feature bits.
fn cache(self) -> cache::Initializer {
let mut value = cache::Initializer::default();
{
let mut enable_feature = |f, enable| {
if enable {
value.set(f as u32);
}
};
// vector and related
// bit 129 of the extended facility list
enable_feature(Feature::vector, self.vxrs);
// bit 135 of the extended facility list
enable_feature(Feature::vector_enhancements_1, self.vxrs_ext);
// bit 148 of the extended facility list
enable_feature(Feature::vector_enhancements_2, self.vxrs_ext2);
// bit 134 of the extended facility list
enable_feature(Feature::vector_packed_decimal, self.vxrs_bcd);
// bit 152 of the extended facility list
enable_feature(Feature::vector_packed_decimal_enhancement, self.vxrs_pde);
// bit 192 of the extended facility list
enable_feature(Feature::vector_packed_decimal_enhancement_2, self.vxrs_pde2);
// bit 165 of the extended facility list
enable_feature(Feature::nnp_assist, self.nnpa);
// others
// bit 45 of the extended facility list
enable_feature(Feature::high_word, self.high_gprs);
// bit 73 of the extended facility list
enable_feature(Feature::transactional_execution, self.te);
// bit 133 of the extended facility list
enable_feature(Feature::guarded_storage, self.gs);
// bit 150 of the extended facility list
enable_feature(Feature::enhanced_sort, self.sort);
// bit 151 of the extended facility list
enable_feature(Feature::deflate_conversion, self.dflt);
}
value
}
}