arm64: Implement HWCAP

Add HWCAP support for arm64.
defines are the same as in Linux and a userland program can use
elf_aux_info to get the data.
We only save the common denominator for all cores in case the
big and little cluster have different support (this is known to
exists even if we don't support those SoCs in FreeBSD)

Differential Revision:	https://reviews.freebsd.org/D17137
This commit is contained in:
Emmanuel Vadot 2019-07-20 14:29:11 +00:00
parent b24594e544
commit d5fdfa2c8a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=350166
4 changed files with 134 additions and 5 deletions

View File

@ -55,6 +55,8 @@ __FBSDID("$FreeBSD$");
#include "linker_if.h"
u_long elf_hwcap;
static struct sysentvec elf64_freebsd_sysvec = {
.sv_size = SYS_MAXSYSCALL,
.sv_table = sysent,
@ -88,6 +90,7 @@ static struct sysentvec elf64_freebsd_sysvec = {
.sv_schedtail = NULL,
.sv_thread_detach = NULL,
.sv_trap = NULL,
.sv_hwcap = &elf_hwcap,
};
INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);

View File

@ -44,8 +44,11 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/undefined.h>
#include <machine/elf.h>
static int ident_lock;
static void print_cpu_features(u_int cpu);
static u_long parse_cpu_features_hwcap(u_int cpu);
char machine[] = "arm64";
@ -412,10 +415,14 @@ update_user_regs(u_int cpu)
}
}
/* HWCAP */
extern u_long elf_hwcap;
static void
identify_cpu_sysinit(void *dummy __unused)
{
int cpu;
u_long hwcap;
/* Create a user visible cpu description with safe values */
memset(&user_cpu_desc, 0, sizeof(user_cpu_desc));
@ -427,6 +434,11 @@ identify_cpu_sysinit(void *dummy __unused)
CPU_FOREACH(cpu) {
print_cpu_features(cpu);
hwcap = parse_cpu_features_hwcap(cpu);
if (elf_hwcap == 0)
elf_hwcap = hwcap;
else
elf_hwcap &= hwcap;
update_user_regs(cpu);
}
@ -434,7 +446,95 @@ identify_cpu_sysinit(void *dummy __unused)
}
SYSINIT(idenrity_cpu, SI_SUB_SMP, SI_ORDER_ANY, identify_cpu_sysinit, NULL);
void
static u_long
parse_cpu_features_hwcap(u_int cpu)
{
u_long hwcap = 0;
if (ID_AA64ISAR0_DP(cpu_desc[cpu].id_aa64isar0) == ID_AA64ISAR0_DP_IMPL)
hwcap |= HWCAP_ASIMDDP;
if (ID_AA64ISAR0_SM4(cpu_desc[cpu].id_aa64isar0) == ID_AA64ISAR0_SM4_IMPL)
hwcap |= HWCAP_SM4;
if (ID_AA64ISAR0_SM3(cpu_desc[cpu].id_aa64isar0) == ID_AA64ISAR0_SM3_IMPL)
hwcap |= HWCAP_SM3;
if (ID_AA64ISAR0_RDM(cpu_desc[cpu].id_aa64isar0) == ID_AA64ISAR0_RDM_IMPL)
hwcap |= HWCAP_ASIMDRDM;
if (ID_AA64ISAR0_Atomic(cpu_desc[cpu].id_aa64isar0) == ID_AA64ISAR0_Atomic_IMPL)
hwcap |= HWCAP_ATOMICS;
if (ID_AA64ISAR0_CRC32(cpu_desc[cpu].id_aa64isar0) == ID_AA64ISAR0_CRC32_BASE)
hwcap |= HWCAP_CRC32;
switch (ID_AA64ISAR0_SHA2(cpu_desc[cpu].id_aa64isar0)) {
case ID_AA64ISAR0_SHA2_BASE:
hwcap |= HWCAP_SHA2;
break;
case ID_AA64ISAR0_SHA2_512:
hwcap |= HWCAP_SHA2 | HWCAP_SHA512;
break;
default:
break;
}
if (ID_AA64ISAR0_SHA1(cpu_desc[cpu].id_aa64isar0))
hwcap |= HWCAP_SHA1;
switch (ID_AA64ISAR0_AES(cpu_desc[cpu].id_aa64isar0)) {
case ID_AA64ISAR0_AES_BASE:
hwcap |= HWCAP_AES;
break;
case ID_AA64ISAR0_AES_PMULL:
hwcap |= HWCAP_PMULL | HWCAP_AES;
break;
default:
break;
}
if (ID_AA64ISAR1_LRCPC(cpu_desc[cpu].id_aa64isar1) == ID_AA64ISAR1_LRCPC_IMPL)
hwcap |= HWCAP_LRCPC;
if (ID_AA64ISAR1_FCMA(cpu_desc[cpu].id_aa64isar1) == ID_AA64ISAR1_FCMA_IMPL)
hwcap |= HWCAP_FCMA;
if (ID_AA64ISAR1_JSCVT(cpu_desc[cpu].id_aa64isar1) == ID_AA64ISAR1_JSCVT_IMPL)
hwcap |= HWCAP_JSCVT;
if (ID_AA64ISAR1_DPB(cpu_desc[cpu].id_aa64isar1) == ID_AA64ISAR1_DPB_IMPL)
hwcap |= HWCAP_DCPOP;
if (ID_AA64PFR0_SVE(cpu_desc[cpu].id_aa64pfr0) == ID_AA64PFR0_SVE_IMPL)
hwcap |= HWCAP_SVE;
switch (ID_AA64PFR0_AdvSIMD(cpu_desc[cpu].id_aa64pfr0)) {
case ID_AA64PFR0_AdvSIMD_IMPL:
hwcap |= HWCAP_ASIMD;
break;
case ID_AA64PFR0_AdvSIMD_HP:
hwcap |= HWCAP_ASIMD | HWCAP_ASIMDDP;
break;
default:
break;
}
switch (ID_AA64PFR0_FP(cpu_desc[cpu].id_aa64pfr0)) {
case ID_AA64PFR0_FP_IMPL:
hwcap |= HWCAP_FP;
break;
case ID_AA64PFR0_FP_HP:
hwcap |= HWCAP_FP | HWCAP_FPHP;
break;
default:
break;
}
return (hwcap);
}
static void
print_cpu_features(u_int cpu)
{
struct sbuf *sb;
@ -488,9 +588,6 @@ print_cpu_features(u_int cpu)
"hardware bugs that may cause the incorrect operation of "
"atomic operations.\n");
if (cpu != 0 && cpu_print_regs == 0)
return;
#define SEP_STR ((printed++) == 0) ? "" : ","
/* AArch64 Instruction Set Attribute Register 0 */

View File

@ -160,7 +160,6 @@ void cpu_reset(void) __dead2;
void fork_trampoline(void);
void identify_cpu(void);
void install_cpu_errata(void);
void print_cpu_features(u_int);
void swi_vm(void *v);
#define CPU_AFFINITY(cpu) __cpu_affinity[(cpu)]

View File

@ -87,4 +87,34 @@ __ElfType(Auxinfo);
#define ET_DYN_LOAD_ADDR 0x100000
#endif
/* HWCAP */
#define HWCAP_FP 0x00000001
#define HWCAP_ASIMD 0x00000002
#define HWCAP_EVTSTRM 0x00000004
#define HWCAP_AES 0x00000008
#define HWCAP_PMULL 0x00000010
#define HWCAP_SHA1 0x00000020
#define HWCAP_SHA2 0x00000040
#define HWCAP_CRC32 0x00000080
#define HWCAP_ATOMICS 0x00000100
#define HWCAP_FPHP 0x00000200
#define HWCAP_CPUID 0x00000400
#define HWCAP_ASIMDRDM 0x00000800
#define HWCAP_JSCVT 0x00001000
#define HWCAP_FCMA 0x00002000
#define HWCAP_LRCPC 0x00004000
#define HWCAP_DCPOP 0x00008000
#define HWCAP_SHA3 0x00010000
#define HWCAP_SM3 0x00020000
#define HWCAP_SM4 0x00040000
#define HWCAP_ASIMDDP 0x00080000
#define HWCAP_SHA512 0x00100000
#define HWCAP_SVE 0x00200000
#define HWCAP_ASIMDFHM 0x00400000
#define HWCAP_DIT 0x00800000
#define HWCAP_USCAT 0x01000000
#define HWCAP_ILRCPC 0x02000000
#define HWCAP_FLAGM 0x04000000
#endif /* !_MACHINE_ELF_H_ */