Changeset View
Changeset View
Standalone View
Standalone View
sys/arm64/arm64/identcpu.c
Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
#include <machine/cpufunc.h> | #include <machine/cpufunc.h> | ||||
#include <machine/elf.h> | #include <machine/elf.h> | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#include <machine/undefined.h> | #include <machine/undefined.h> | ||||
static void print_cpu_features(u_int cpu); | static void print_cpu_features(u_int cpu); | ||||
static u_long parse_cpu_features_hwcap(void); | static u_long parse_cpu_features_hwcap(void); | ||||
static u_long parse_cpu_features_hwcap2(void); | static u_long parse_cpu_features_hwcap2(void); | ||||
#ifdef COMPAT_FREEBSD32 | |||||
static u_long parse_cpu_features_hwcap32(void); | |||||
static u_long parse_cpu_features_hwcap32_2(void); | |||||
#endif | |||||
char machine[] = "arm64"; | char machine[] = "arm64"; | ||||
#ifdef SCTL_MASK32 | #ifdef SCTL_MASK32 | ||||
extern int adaptive_machine_arch; | extern int adaptive_machine_arch; | ||||
#endif | #endif | ||||
static SYSCTL_NODE(_machdep, OID_AUTO, cache, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, | static SYSCTL_NODE(_machdep, OID_AUTO, cache, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | struct cpu_desc { | ||||
uint64_t id_aa64isar0; | uint64_t id_aa64isar0; | ||||
uint64_t id_aa64isar1; | uint64_t id_aa64isar1; | ||||
uint64_t id_aa64mmfr0; | uint64_t id_aa64mmfr0; | ||||
uint64_t id_aa64mmfr1; | uint64_t id_aa64mmfr1; | ||||
uint64_t id_aa64mmfr2; | uint64_t id_aa64mmfr2; | ||||
uint64_t id_aa64pfr0; | uint64_t id_aa64pfr0; | ||||
uint64_t id_aa64pfr1; | uint64_t id_aa64pfr1; | ||||
uint64_t ctr; | uint64_t ctr; | ||||
#ifdef COMPAT_FREEBSD32 | |||||
uint64_t id_isar5; | |||||
uint64_t id_pfr0; | |||||
uint64_t mvfr0; | |||||
uint64_t mvfr1; | |||||
#endif | |||||
}; | }; | ||||
static struct cpu_desc cpu_desc[MAXCPU]; | static struct cpu_desc cpu_desc[MAXCPU]; | ||||
static struct cpu_desc kern_cpu_desc; | static struct cpu_desc kern_cpu_desc; | ||||
static struct cpu_desc user_cpu_desc; | static struct cpu_desc user_cpu_desc; | ||||
static u_int cpu_print_regs; | static u_int cpu_print_regs; | ||||
#define PRINT_ID_AA64_AFR0 0x00000001 | #define PRINT_ID_AA64_AFR0 0x00000001 | ||||
#define PRINT_ID_AA64_AFR1 0x00000002 | #define PRINT_ID_AA64_AFR1 0x00000002 | ||||
▲ Show 20 Lines • Show All 870 Lines • ▼ Show 20 Lines | static struct mrs_user_reg user_regs[] = { | ||||
.Op2 = 0, | .Op2 = 0, | ||||
.offset = __offsetof(struct cpu_desc, id_aa64pfr0), | .offset = __offsetof(struct cpu_desc, id_aa64pfr0), | ||||
.fields = id_aa64pfr0_fields, | .fields = id_aa64pfr0_fields, | ||||
}, | }, | ||||
{ /* id_aa64pfr0_el1 */ | { /* id_aa64pfr0_el1 */ | ||||
.reg = ID_AA64PFR1_EL1, | .reg = ID_AA64PFR1_EL1, | ||||
.CRm = 4, | .CRm = 4, | ||||
.Op2 = 1, | .Op2 = 1, | ||||
.offset = __offsetof(struct cpu_desc, id_aa64pfr1), | .offset = __offsetof(struct cpu_desc, id_aa64pfr1), | ||||
.fields = id_aa64pfr1_fields, | .fields = id_aa64pfr1_fields, | ||||
andrew: I would swap these so we print when `SEVL` is implemented, otherwise we print something when no… | |||||
}, | }, | ||||
{ /* id_aa64dfr0_el1 */ | { /* id_aa64dfr0_el1 */ | ||||
.reg = ID_AA64DFR0_EL1, | .reg = ID_AA64DFR0_EL1, | ||||
.CRm = 5, | .CRm = 5, | ||||
.Op2 = 0, | .Op2 = 0, | ||||
.offset = __offsetof(struct cpu_desc, id_aa64dfr0), | .offset = __offsetof(struct cpu_desc, id_aa64dfr0), | ||||
.fields = id_aa64dfr0_fields, | .fields = id_aa64dfr0_fields, | ||||
}, | }, | ||||
▲ Show 20 Lines • Show All 233 Lines • ▼ Show 20 Lines | CPU_FOREACH(cpu) { | ||||
if (CTR_IDC_VAL(cpu_desc[cpu].ctr) == 0) | if (CTR_IDC_VAL(cpu_desc[cpu].ctr) == 0) | ||||
idc = false; | idc = false; | ||||
} | } | ||||
/* Exposed to userspace as AT_HWCAP and AT_HWCAP2 */ | /* Exposed to userspace as AT_HWCAP and AT_HWCAP2 */ | ||||
elf_hwcap = parse_cpu_features_hwcap(); | elf_hwcap = parse_cpu_features_hwcap(); | ||||
elf_hwcap2 = parse_cpu_features_hwcap2(); | elf_hwcap2 = parse_cpu_features_hwcap2(); | ||||
#ifdef COMPAT_FREEBSD32 | |||||
/* 32-bit ARM versions of AT_HWCAP/HWCAP2 */ | |||||
elf32_hwcap = parse_cpu_features_hwcap32(); | |||||
elf32_hwcap2 = parse_cpu_features_hwcap32_2(); | |||||
#endif | |||||
if (dic && idc) { | if (dic && idc) { | ||||
arm64_icache_sync_range = &arm64_dic_idc_icache_sync_range; | arm64_icache_sync_range = &arm64_dic_idc_icache_sync_range; | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("Enabling DIC & IDC ICache sync\n"); | printf("Enabling DIC & IDC ICache sync\n"); | ||||
} | } | ||||
if ((elf_hwcap & HWCAP_ATOMICS) != 0) { | if ((elf_hwcap & HWCAP_ATOMICS) != 0) { | ||||
lse_supported = true; | lse_supported = true; | ||||
▲ Show 20 Lines • Show All 194 Lines • ▼ Show 20 Lines | parse_cpu_features_hwcap2(void) | ||||
if (ID_AA64PFR1_BT_VAL(user_cpu_desc.id_aa64pfr1) == | if (ID_AA64PFR1_BT_VAL(user_cpu_desc.id_aa64pfr1) == | ||||
ID_AA64PFR1_BT_IMPL) | ID_AA64PFR1_BT_IMPL) | ||||
hwcap2 |= HWCAP2_BTI; | hwcap2 |= HWCAP2_BTI; | ||||
return (hwcap2); | return (hwcap2); | ||||
} | } | ||||
#ifdef COMPAT_FREEBSD32 | |||||
static u_long | |||||
parse_cpu_features_hwcap32(void) | |||||
{ | |||||
u_long hwcap = HWCAP32_DEFAULT; | |||||
if (MVFR0_EL1_FPDP_VAL(cpu_desc[0].mvfr0) >= | |||||
Not Done Inline ActionsThese registers could be different in a big.LITTLE system so we need a consistent view of them in user_cpu_desc and to use that here. andrew: These registers could be different in a big.LITTLE system so we need a consistent view of them… | |||||
Done Inline ActionsI'll fix that. Will there ever be a big.LITTLE case where some PEs don't support EL0-32 ? grehan: I'll fix that.
Will there ever be a big.LITTLE case where some PEs don't support EL0-32 ? | |||||
Not Done Inline ActionsI don't know of any current SoCs, however (based on what I've been told) there's a strong possibility in future SoCs. andrew: I don't know of any current SoCs, however (based on what I've been told) there's a strong… | |||||
MVFR0_EL1_FPDP_VFP_v2) { | |||||
hwcap |= HWCAP32_VFP; | |||||
if (MVFR0_EL1_FPDP_VAL(cpu_desc[0].mvfr0) == | |||||
MVFR0_EL1_FPDP_VFP_v3_v4) { | |||||
hwcap |= HWCAP32_VFPv3; | |||||
if (MVFR1_EL1_SIMDFMAC_VAL(cpu_desc[0].mvfr1) == | |||||
MVFR1_EL1_SIMDFMAC_IMPL) | |||||
hwcap |= HWCAP32_VFPv4; | |||||
} | |||||
} | |||||
if ((MVFR1_EL1_SIMDLS_VAL(cpu_desc[0].mvfr1) == | |||||
Done Inline Actionsstate3 field of ID_PFR0_EL1 register is fixed to 0 by ARMv8 ARM, so this test is unnecessary mmel: state3 field of ID_PFR0_EL1 register is fixed to 0 by ARMv8 ARM, so this test is unnecessary | |||||
MVFR1_EL1_SIMDLS_IMPL) && | |||||
(MVFR1_EL1_SIMDInt_VAL(cpu_desc[0].mvfr1) == | |||||
MVFR1_EL1_SIMDInt_IMPL) && | |||||
(MVFR1_EL1_SIMDSP_VAL(cpu_desc[0].mvfr1) == | |||||
MVFR1_EL1_SIMDSP_IMPL)) | |||||
hwcap |= HWCAP32_NEON; | |||||
return (hwcap); | |||||
} | |||||
static u_long | |||||
parse_cpu_features_hwcap32_2(void) | |||||
{ | |||||
u_long hwcap2 = 0; | |||||
if (ID_ISAR5_EL1_AES_VAL(cpu_desc[0].id_isar5) >= | |||||
ID_ISAR5_EL1_AES_BASE) | |||||
hwcap2 |= HWCAP32_2_AES; | |||||
if (ID_ISAR5_EL1_AES_VAL(cpu_desc[0].id_isar5) == | |||||
ID_ISAR5_EL1_AES_VMULL) | |||||
hwcap2 |= HWCAP32_2_PMULL; | |||||
if (ID_ISAR5_EL1_SHA1_VAL(cpu_desc[0].id_isar5) == | |||||
ID_ISAR5_EL1_SHA1_IMPL) | |||||
hwcap2 |= HWCAP32_2_SHA1; | |||||
if (ID_ISAR5_EL1_SHA2_VAL(cpu_desc[0].id_isar5) == | |||||
ID_ISAR5_EL1_SHA2_IMPL) | |||||
hwcap2 |= HWCAP32_2_SHA2; | |||||
if (ID_ISAR5_EL1_CRC32_VAL(cpu_desc[0].id_isar5) == | |||||
ID_ISAR5_EL1_CRC32_IMPL) | |||||
hwcap2 |= HWCAP32_2_CRC32; | |||||
return (hwcap2); | |||||
} | |||||
#endif /* COMPAT_FREEBSD32 */ | |||||
static void | static void | ||||
print_ctr_fields(struct sbuf *sb, uint64_t reg, void *arg) | print_ctr_fields(struct sbuf *sb, uint64_t reg, void *arg) | ||||
{ | { | ||||
sbuf_printf(sb, "%u byte D-cacheline,", CTR_DLINE_SIZE(reg)); | sbuf_printf(sb, "%u byte D-cacheline,", CTR_DLINE_SIZE(reg)); | ||||
sbuf_printf(sb, "%u byte I-cacheline,", CTR_ILINE_SIZE(reg)); | sbuf_printf(sb, "%u byte I-cacheline,", CTR_ILINE_SIZE(reg)); | ||||
reg &= ~(CTR_DLINE_MASK | CTR_ILINE_MASK); | reg &= ~(CTR_DLINE_MASK | CTR_ILINE_MASK); | ||||
▲ Show 20 Lines • Show All 296 Lines • ▼ Show 20 Lines | identify_cpu(u_int cpu) | ||||
cpu_desc[cpu].id_aa64dfr1 = READ_SPECIALREG(id_aa64dfr1_el1); | cpu_desc[cpu].id_aa64dfr1 = READ_SPECIALREG(id_aa64dfr1_el1); | ||||
cpu_desc[cpu].id_aa64isar0 = READ_SPECIALREG(id_aa64isar0_el1); | cpu_desc[cpu].id_aa64isar0 = READ_SPECIALREG(id_aa64isar0_el1); | ||||
cpu_desc[cpu].id_aa64isar1 = READ_SPECIALREG(id_aa64isar1_el1); | cpu_desc[cpu].id_aa64isar1 = READ_SPECIALREG(id_aa64isar1_el1); | ||||
cpu_desc[cpu].id_aa64mmfr0 = READ_SPECIALREG(id_aa64mmfr0_el1); | cpu_desc[cpu].id_aa64mmfr0 = READ_SPECIALREG(id_aa64mmfr0_el1); | ||||
cpu_desc[cpu].id_aa64mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1); | cpu_desc[cpu].id_aa64mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1); | ||||
cpu_desc[cpu].id_aa64mmfr2 = READ_SPECIALREG(id_aa64mmfr2_el1); | cpu_desc[cpu].id_aa64mmfr2 = READ_SPECIALREG(id_aa64mmfr2_el1); | ||||
cpu_desc[cpu].id_aa64pfr0 = READ_SPECIALREG(id_aa64pfr0_el1); | cpu_desc[cpu].id_aa64pfr0 = READ_SPECIALREG(id_aa64pfr0_el1); | ||||
cpu_desc[cpu].id_aa64pfr1 = READ_SPECIALREG(id_aa64pfr1_el1); | cpu_desc[cpu].id_aa64pfr1 = READ_SPECIALREG(id_aa64pfr1_el1); | ||||
#ifdef COMPAT_FREEBSD32 | |||||
cpu_desc[cpu].id_isar5 = READ_SPECIALREG(id_isar5_el1); | |||||
cpu_desc[cpu].id_pfr0 = READ_SPECIALREG(id_pfr0_el1); | |||||
cpu_desc[cpu].mvfr0 = READ_SPECIALREG(mvfr0_el1); | |||||
cpu_desc[cpu].mvfr1 = READ_SPECIALREG(mvfr1_el1); | |||||
Not Done Inline ActionsWe should only read these if EL0 supports AArch32. The docs say direct access is unknown if no exception levels support AArch32, however I'm unsure if that means the values are unknown, or the hw could raise an exception. andrew: We should only read these if EL0 supports AArch32. The docs say direct access is unknown if no… | |||||
#endif | |||||
} | } | ||||
static void | static void | ||||
check_cpu_regs(u_int cpu) | check_cpu_regs(u_int cpu) | ||||
{ | { | ||||
switch (cpu_aff_levels) { | switch (cpu_aff_levels) { | ||||
case 0: | case 0: | ||||
▲ Show 20 Lines • Show All 57 Lines • Show Last 20 Lines |
I would swap these so we print when SEVL is implemented, otherwise we print something when no 32-bit support is present.