diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c --- a/sys/arm64/arm64/identcpu.c +++ b/sys/arm64/arm64/identcpu.c @@ -1741,16 +1741,7 @@ bool get_kernel_reg(u_int reg, uint64_t *val) { - int i; - - for (i = 0; i < nitems(user_regs); i++) { - if (user_regs[i].reg == reg) { - *val = CPU_DESC_FIELD(kern_cpu_desc, i); - return (true); - } - } - - return (false); + return (cpu_desc_get(&kern_cpu_desc, reg, val)); } /* @@ -1788,7 +1779,7 @@ } static uint64_t -update_lower_register(uint64_t val, uint64_t new_val, u_int shift, +update_lower_register_field(uint64_t val, uint64_t new_val, u_int shift, int width, bool sign) { uint64_t mask; @@ -1808,6 +1799,17 @@ return (val); } +static uint64_t +update_lower_register(struct mrs_field *fields, uint64_t val, uint64_t new_val) +{ + for (int i = 0; fields[i].type != 0; i++) { + val = update_lower_register_field(val, new_val, + fields[i].shift, 4, fields[i].sign); + } + + return (val); +} + void update_special_regs(u_int cpu) { @@ -1847,13 +1849,13 @@ fields[j].shift; break; case MRS_LOWER: - user_reg = update_lower_register(user_reg, + user_reg = update_lower_register_field(user_reg, value, fields[j].shift, 4, fields[j].sign); break; default: panic("Invalid field type: %d", fields[j].type); } - kern_reg = update_lower_register(kern_reg, value, + kern_reg = update_lower_register_field(kern_reg, value, fields[j].shift, 4, fields[j].sign); } @@ -1878,6 +1880,66 @@ M_ZERO | M_WAITOK); } +struct cpu_desc * +cpu_desc_alloc(int flags) +{ + struct cpu_desc *desc; + + /* Only CPU_DESC_MIN is implemented */ + MPASS(flags == CPU_DESC_MIN); + + desc = malloc(sizeof(*desc), M_IDENTCPU, M_WAITOK | M_ZERO); + + desc->id_aa64pfr0 = ID_AA64PFR0_AdvSIMD_NONE | ID_AA64PFR0_FP_NONE | + ID_AA64PFR0_EL1_64 | ID_AA64PFR0_EL0_64; + desc->id_aa64dfr0 = ID_AA64DFR0_DebugVer_8; + + return (desc); +} + +bool +cpu_desc_update(struct cpu_desc *desc, u_int reg, uint64_t val, + bool use_existing) +{ + int regid; + bool found; + + found = false; + for (regid = 0; regid < nitems(user_regs); regid++) { + if (user_regs[regid].reg == reg) { + found = true; + break; + } + } + if (!found) + return (false); + + /* Keep the existing value */ + if (use_existing) + val = update_lower_register(user_regs[regid].fields, val, + CPU_DESC_FIELD(*desc, regid)); + + /* Use the kernel value */ + val = update_lower_register(user_regs[regid].fields, val, + CPU_DESC_FIELD(kern_cpu_desc, regid)); + + CPU_DESC_FIELD(*desc, regid) = val; + return (true); +} + +bool +cpu_desc_get(struct cpu_desc *desc, u_int reg, uint64_t *val) +{ + for (int i = 0; i < nitems(user_regs); i++) { + if (user_regs[i].reg == reg) { + *val = CPU_DESC_FIELD(*desc, i); + return (true); + } + } + + return (false); +} + /* HWCAP */ bool __read_frequently lse_supported = false; diff --git a/sys/arm64/include/cpu.h b/sys/arm64/include/cpu.h --- a/sys/arm64/include/cpu.h +++ b/sys/arm64/include/cpu.h @@ -183,6 +183,8 @@ #define CPU_MATCH_ERRATA_CAVIUM_THUNDERX_1_1 0 #endif +struct cpu_desc; + extern char btext[]; extern char etext[]; @@ -216,6 +218,12 @@ void cpu_desc_init(void); +#define CPU_DESC_MIN (1<<0) /* Minimise the ID registers until */ + /* they are set with cpu_desc_set */ +struct cpu_desc *cpu_desc_alloc(int); +bool cpu_desc_update(struct cpu_desc *, u_int, uint64_t, bool); +bool cpu_desc_get(struct cpu_desc *, u_int, uint64_t *); + #define CPU_AFFINITY(cpu) __cpu_affinity[(cpu)] #define CPU_CURRENT_SOCKET \ (CPU_AFF2(CPU_AFFINITY(PCPU_GET(cpuid))))