#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: procfs_machdep.c,v 1.6 2024/02/07 04:20:26 msaitoh Exp $");
#include <sys/param.h>
#include <sys/cpu.h>
#include <sys/systm.h>
#include <miscfs/procfs/procfs.h>
#include <aarch64/armreg.h>
#include <aarch64/cpufunc.h>
#define FORWARD_BUF(_len) \
do { \
total += _len; \
if (_len < left) { \
buf += _len; \
left -= _len; \
} else { \
buf += left; \
left = 0; \
} \
} while (0 )
#define OUTPUT_BUF(fmt, args...) \
do { \
size_t l = snprintf(buf, left, fmt, ## args); \
FORWARD_BUF(l); \
} while (0)
static int
procfs_cpuinfo_features(struct cpu_info *ci, char *buf, int buflen)
{
uint64_t isar0, isar1, mmfr2, pfr0, pfr1;
size_t left, total;
isar0 = ci->ci_id.ac_aa64isar0;
isar1 = ci->ci_id.ac_aa64isar1;
mmfr2 = ci->ci_id.ac_aa64mmfr2;
pfr0 = ci->ci_id.ac_aa64pfr0;
pfr1 = ci->ci_id.ac_aa64pfr1;
left = buflen;
total = 0;
OUTPUT_BUF("Features\t:");
#define SO_EQ(reg, mask, val) (__SHIFTOUT((reg), (mask)) == (val))
if (SO_EQ(pfr0, ID_AA64PFR0_EL1_FP, ID_AA64PFR0_EL1_FP_IMPL))
OUTPUT_BUF(" fp");
if (SO_EQ(pfr0, ID_AA64PFR0_EL1_ADVSIMD, ID_AA64PFR0_EL1_ADV_SIMD_IMPL))
OUTPUT_BUF(" asimd");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_AES, ID_AA64ISAR0_EL1_AES_AES))
OUTPUT_BUF(" aes");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_AES, ID_AA64ISAR0_EL1_AES_PMUL))
OUTPUT_BUF(" pmull");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_SHA1,
ID_AA64ISAR0_EL1_SHA1_SHA1CPMHSU))
OUTPUT_BUF(" sha1");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_SHA2,
ID_AA64ISAR0_EL1_SHA2_SHA256HSU))
OUTPUT_BUF(" sha2");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_CRC32, ID_AA64ISAR0_EL1_CRC32_CRC32X))
OUTPUT_BUF(" crc32");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_ATOMIC, ID_AA64ISAR0_EL1_ATOMIC_SWP))
OUTPUT_BUF(" atomics");
if (SO_EQ(pfr0, ID_AA64PFR0_EL1_FP, ID_AA64PFR0_EL1_FP_HP))
OUTPUT_BUF(" fphp");
if (SO_EQ(pfr0, ID_AA64PFR0_EL1_ADVSIMD, ID_AA64PFR0_EL1_ADV_SIMD_HP))
OUTPUT_BUF(" asimdhp");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_RDM, ID_AA64ISAR0_EL1_RDM_SQRDML))
OUTPUT_BUF(" asimdrdm");
if (SO_EQ(isar1, ID_AA64ISAR1_EL1_JSCVT,
ID_AA64ISAR1_EL1_JSCVT_SUPPORTED))
OUTPUT_BUF(" jscvt");
if (SO_EQ(isar1, ID_AA64ISAR1_EL1_FCMA,
ID_AA64ISAR1_EL1_FCMA_SUPPORTED))
OUTPUT_BUF(" fcma");
if (SO_EQ(isar1, ID_AA64ISAR1_EL1_LRCPC, ID_AA64ISAR1_EL1_LRCPC_PR))
OUTPUT_BUF(" lrcpc");
if (SO_EQ(isar1, ID_AA64ISAR1_EL1_DPB, ID_AA64ISAR1_EL1_DPB_CVAP))
OUTPUT_BUF(" dcpop");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_SHA3, ID_AA64ISAR0_EL1_SHA3_EOR3))
OUTPUT_BUF(" sha3");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_SM3, ID_AA64ISAR0_EL1_SM3_SM3))
OUTPUT_BUF(" sm3");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_SM4, ID_AA64ISAR0_EL1_SM4_SM4))
OUTPUT_BUF(" sm4");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_DP, ID_AA64ISAR0_EL1_DP_UDOT))
OUTPUT_BUF(" asimddp");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_SHA2,
ID_AA64ISAR0_EL1_SHA2_SHA512HSU))
OUTPUT_BUF(" sha512");
if (SO_EQ(pfr0, ID_AA64PFR0_EL1_SVE, ID_AA64PFR0_EL1_SVE_IMPL))
OUTPUT_BUF(" sve");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_FHM, ID_AA64ISAR0_EL1_FHM_FMLAL))
OUTPUT_BUF(" asimdfhm");
if (SO_EQ(pfr0, ID_AA64PFR0_EL1_DIT, ID_AA64PFR0_EL1_DIT_IMPL))
OUTPUT_BUF(" dit");
if (SO_EQ(mmfr2, ID_AA64MMFR2_EL1_AT, ID_AA64MMFR2_EL1_AT_16BIT))
OUTPUT_BUF(" uscat");
if (SO_EQ(isar1, ID_AA64ISAR1_EL1_LRCPC, ID_AA64ISAR1_EL1_LRCPC_PR_UR))
OUTPUT_BUF(" ilrcpc");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_TS, ID_AA64ISAR0_EL1_TS_CFINV))
OUTPUT_BUF(" flagm");
if (SO_EQ(pfr1, ID_AA64PFR1_EL1_SSBS, ID_AA64PFR1_EL1_SSBS_MSR_MRS))
OUTPUT_BUF(" ssbs");
if (SO_EQ(isar1, ID_AA64ISAR1_EL1_SB, ID_AA64ISAR1_EL1_SB_SUPPORTED))
OUTPUT_BUF(" sb");
#ifdef ARMV83_PAC
if (aarch64_pac_enabled)
OUTPUT_BUF(" paca pacg");
#endif
if (SO_EQ(isar1, ID_AA64ISAR1_EL1_DPB, ID_AA64ISAR1_EL1_DPB_CVAP_CVADP))
OUTPUT_BUF(" dcpodp");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_TS, ID_AA64ISAR0_EL1_TS_AXFLAG))
OUTPUT_BUF(" flagm2");
if (SO_EQ(isar1, ID_AA64ISAR1_EL1_FRINTTS,
ID_AA64ISAR1_EL1_FRINTTS_SUPPORTED))
OUTPUT_BUF(" frint");
if (SO_EQ(isar1, ID_AA64ISAR1_EL1_I8MM,
ID_AA64ISAR1_EL1_I8MM_SUPPORTED))
OUTPUT_BUF(" i8mm");
if (SO_EQ(isar1, ID_AA64ISAR1_EL1_BF16, ID_AA64ISAR1_EL1_BF16_BFDOT))
OUTPUT_BUF(" bf16");
if (SO_EQ(isar1, ID_AA64ISAR1_EL1_DGH, ID_AA64ISAR1_EL1_DGH_SUPPORTED))
OUTPUT_BUF(" dgh");
if (SO_EQ(isar0, ID_AA64ISAR0_EL1_RNDR, ID_AA64ISAR0_EL1_RNDR_RNDRRS))
OUTPUT_BUF(" rng");
#ifdef ARMV85_BTI
if (aarch64_bti_enabled)
OUTPUT_BUF(" bti");
#endif
OUTPUT_BUF("\n");
#undef SO_EQ
return total;
}
int
procfs_getcpuinfstr(char *buf, size_t *lenp)
{
struct cpu_info *ci;
CPU_INFO_ITERATOR cii;
size_t left, len, total;
int ret = 0;
left = *lenp;
total = 0;
for (CPU_INFO_FOREACH(cii, ci)) {
OUTPUT_BUF("processor\t: %d\n", cii);
len = procfs_cpuinfo_features(ci, buf, left);
FORWARD_BUF(len);
OUTPUT_BUF("CPU implementer\t: 0x%02lx\n",
__SHIFTOUT(ci->ci_id.ac_midr, CPU_ID_IMPLEMENTOR_MASK));
OUTPUT_BUF("CPU architecture: 8\n");
OUTPUT_BUF("CPU variant\t: 0x%lx\n",
__SHIFTOUT(ci->ci_id.ac_midr, CPU_ID_VARIANT_MASK));
OUTPUT_BUF("CPU part\t: 0x%03lx\n",
__SHIFTOUT(ci->ci_id.ac_midr, CPU_ID_PARTNO_MASK));
OUTPUT_BUF("CPU revision\t: %lu\n",
__SHIFTOUT(ci->ci_id.ac_midr, CPU_ID_REVISION_MASK));
OUTPUT_BUF("\n");
}
if (total >= *lenp)
ret = -1;
*lenp = total + 1;
return ret;
}