Print this page
cpuid for ARMv7

*** 9,18 **** --- 9,19 ---- * http://www.illumos.org/license/CDDL. */ /* * Copyright (c) 2014 Joyent, Inc. All rights reserved. + * Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> */ #include <sys/cpuid_impl.h> #include <sys/param.h> #include <sys/bootconf.h>
*** 30,43 **** * the feature set to expose to userland. */ static arm_cpuid_t cpuid_data0; ! static void ! cpuid_parse_stage(uint32_t line, uint32_t mask, uint32_t shift, int *out) { ! *out = (line & mask) >> shift; } static void cpuid_fill_main(arm_cpuid_t *cpd) { --- 31,44 ---- * the feature set to expose to userland. */ static arm_cpuid_t cpuid_data0; ! static uint32_t ! extract(uint32_t line, uint32_t mask, uint32_t shift) { ! return ((line & mask) >> shift); } static void cpuid_fill_main(arm_cpuid_t *cpd) {
*** 61,213 **** { cpd->ac_mvfr[0] = arm_cpuid_mvfr0(); cpd->ac_mvfr[1] = arm_cpuid_mvfr1(); } ! #define CACHE_LEN_MASK 0x003 ! #define CACHE_M_BIT 0x004 ! #define CACHE_ASSOC_MASK 0x038 ! #define CACHE_ASSOC_SHIFT 3 ! #define CACHE_SIZE_MASK 0x3c0 ! #define CACHE_SIZE_SHIFT 6 ! #define CACHE_COLOR_BIT 0x800 ! #define CACHE_MASK 0xfff ! #define CACHE_DCACHE_SHIFT 12 ! #define CACHE_SEPARATE 0x1000000 /* ! * On ARMv6 the value of the cache size and the cache associativity depends on ! * the value of the M bit, which modifies the value that's in the actual index. */ - static uint32_t armv6_cpuid_cache_sizes[2][9] = { - { 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x100000, - 0x20000 }, - { 0x300, 0x600, 0xc00, 0x1800, 0x3000, 0x6000, 0xc000, 0x18000, - 0x30000 } - }; - - static int8_t armv6_cpuid_cache_assoc[2][9] = { - { 1, 2, 4, 8, 16, 32, 64, 128 }, - { -1, 3, 6, 12, 24, 48, 96, 192 } - }; - - static uint8_t armv6_cpuid_cache_linesz[] = { - 8, - 16, - 32, - 64 - }; - - static void - cpuid_fill_onecache(arm_cpuid_cache_t *accp, uint32_t val) - { - int mbit, index, assoc; - - mbit = (val & CACHE_M_BIT) != 0 ? 1 : 0; - index = (val & CACHE_ASSOC_MASK) >> CACHE_ASSOC_SHIFT; - assoc = armv6_cpuid_cache_assoc[mbit][index]; - if (assoc == -1) { - accp->acc_exists = B_FALSE; - return; - } - ASSERT(assoc > 0); - accp->acc_assoc = assoc; - accp->acc_rcolor = (val & CACHE_COLOR_BIT) == 0 ? - B_FALSE : B_TRUE; - index = val & CACHE_LEN_MASK; - accp->acc_linesz = armv6_cpuid_cache_linesz[index]; - index = (val & CACHE_SIZE_MASK) >> CACHE_SIZE_SHIFT; - accp->acc_size = armv6_cpuid_cache_sizes[mbit][index]; - accp->acc_exists = B_TRUE; } static void cpuid_fill_caches(arm_cpuid_t *cpd) { ! uint32_t val, icache, dcache; ! val = arm_cpuid_ctr(); ! icache = val & CACHE_MASK; ! cpuid_fill_onecache(&cpd->ac_icache, icache); ! dcache = (val >> CACHE_DCACHE_SHIFT) & CACHE_MASK; ! cpuid_fill_onecache(&cpd->ac_dcache, dcache); ! ! if (val & CACHE_SEPARATE) { ! cpd->ac_unifiedl1 = B_FALSE; ! } else { ! cpd->ac_unifiedl1 = B_TRUE; ! } ! ! armv7_bsmdep_l2cacheinfo(); ! armv6_cachesz = cpd->ac_dcache.acc_size; ! armv6_cache_assoc = cpd->ac_dcache.acc_assoc; } /* ! * There isn't a specific way to indicate that we're on ARMv6k. Instead what we ! * need to do is go through and check for a few features that we know we're ! * going to need. ! * ! * TODO This will have to be revisited with ARMv7 support */ static void cpuid_verify(void) { arm_cpuid_mem_vmsa_t vmsa; arm_cpuid_mem_barrier_t barrier; int sync, syncf; arm_cpuid_t *cpd = &cpuid_data0; ! /* v6 vmsa */ ! cpuid_parse_stage(cpd->ac_mmfr[0], ARM_CPUID_MMFR0_STATE0_MASK, ! ARM_CPUID_MMFR0_STATE0_SHIFT, (int *)&vmsa); ! /* TODO We might be able to support v6, but bcm2835+qvpb are this */ if (vmsa != ARM_CPUID_MEM_VMSA_V7) { bop_printf(NULL, "invalid vmsa setting, found 0x%x\n", vmsa); bop_panic("unsupported cpu"); } /* check for ISB, DSB, etc. in cp15 */ ! cpuid_parse_stage(cpd->ac_mmfr[2], ARM_CPUID_MMFR2_STATE5_MASK, ! ARM_CPUID_MMFR2_STATE5_SHIFT, (int *)&barrier); ! if (barrier != ARM_CPUID_MEM_BARRIER_CP15 && ! barrier != ARM_CPUID_MEM_BARRIER_INSTR) { ! bop_printf(NULL, "missing support for CP15 memory barriers\n"); bop_panic("unsupported CPU"); } /* synch prims */ ! cpuid_parse_stage(cpd->ac_isar[4], ARM_CPUID_ISAR3_STATE3_SHIFT, ! ARM_CPUID_ISAR4_STATE5_SHIFT, (int *)&sync); ! cpuid_parse_stage(cpd->ac_isar[4], ARM_CPUID_ISAR4_STATE3_SHIFT, ! ARM_CPUID_ISAR4_STATE5_SHIFT, (int *)&syncf); if (sync != 0x2 && syncf != 0x0) { bop_printf(NULL, "unsupported synch primitives: sync,frac: " "%x,%x\n", sync, syncf); bop_panic("unsupported CPU"); } - - if (cpd->ac_icache.acc_exists == B_FALSE) { - bop_printf(NULL, "icache not defined to exist\n"); - bop_panic("unsupported CPU"); - } - - if (cpd->ac_dcache.acc_exists == B_FALSE) { - bop_printf(NULL, "dcache not defined to exist\n"); - bop_panic("unsupported CPU"); - } } static void cpuid_valid_ident(uint32_t ident) { arm_cpuid_ident_arch_t arch; /* ! * We don't support stock ARMv6 or older. */ arch = (ident & ARM_CPUID_IDENT_ARCH_MASK) >> ARM_CPUID_IDENT_ARCH_SHIFT; if (arch != ARM_CPUID_IDENT_ARCH_CPUID) { bop_printf(NULL, "encountered unsupported CPU arch: 0x%x", --- 62,228 ---- { cpd->ac_mvfr[0] = arm_cpuid_mvfr0(); cpd->ac_mvfr[1] = arm_cpuid_mvfr1(); } ! #define CCSIDR_WT 0x80000000 ! #define CCSIDR_WB 0x40000000 ! #define CCSIDR_RA 0x20000000 ! #define CCSIDR_WA 0x10000000 ! #define CCSIDR_NUMSETS_MASK 0x0fffe000 ! #define CCSIDR_NUMSETS_SHIFT 13 ! #define CCSIDR_ASSOC_MASK 0x00001ff8 ! #define CCSIDR_ASSOC_SHIFT 3 ! #define CCSIDR_LINESIZE_MASK 0x00000007 ! #define CCSIDR_LINESIZE_SHIFT 0 ! ! static void ! cpuid_fill_onecache(arm_cpuid_t *cpd, int level, boolean_t icache) ! { ! arm_cpuid_cache_t *cache = &cpd->ac_caches[icache][level]; ! uint32_t ccsidr; ! ! ccsidr = arm_cpuid_ccsidr(level, icache); ! cpd->ac_ccsidr[icache][level] = ccsidr; ! ! cache->acc_exists = B_TRUE; ! cache->acc_wt = (ccsidr & CCSIDR_WT) == CCSIDR_WT; ! cache->acc_wb = (ccsidr & CCSIDR_WB) == CCSIDR_WB; ! cache->acc_ra = (ccsidr & CCSIDR_RA) == CCSIDR_RA; ! cache->acc_wa = (ccsidr & CCSIDR_WA) == CCSIDR_WA; ! cache->acc_sets = extract(ccsidr, CCSIDR_NUMSETS_MASK, ! CCSIDR_NUMSETS_SHIFT) + 1; ! cache->acc_assoc = extract(ccsidr, CCSIDR_ASSOC_MASK, ! CCSIDR_ASSOC_SHIFT) + 1; ! cache->acc_linesz = sizeof (uint32_t) << (extract(ccsidr, ! CCSIDR_LINESIZE_MASK, CCSIDR_LINESIZE_SHIFT) + 2); /* ! * XXX? ! #warning "set acc_size?" */ } static void cpuid_fill_caches(arm_cpuid_t *cpd) { ! uint32_t erg, cwg; ! uint32_t l1ip; ! uint32_t ctr; ! uint32_t clidr; ! int level; ! ! clidr = arm_cpuid_clidr(); ! cpd->ac_clidr = clidr; ! ! /* default all caches to not existing, and not unified */ ! for (level = 0; level < 7; level++) { ! cpd->ac_caches[B_TRUE][level].acc_exists = B_FALSE; ! cpd->ac_caches[B_FALSE][level].acc_exists = B_FALSE; ! cpd->ac_caches[B_TRUE][level].acc_unified = B_FALSE; ! cpd->ac_caches[B_FALSE][level].acc_unified = B_FALSE; ! } ! ! /* retrieve cache info for each level */ ! for (level = 0; level < 7; level++) { ! arm_cpuid_cache_t *icache = &cpd->ac_caches[B_TRUE][level]; ! arm_cpuid_cache_t *dcache = &cpd->ac_caches[B_FALSE][level]; ! uint32_t ctype = (cpd->ac_clidr >> (3 * level)) & 0x7; ! ! /* stop looking we find the first non-existent level */ ! if (!ctype) ! break; ! ! switch (ctype) { ! case 1: ! cpuid_fill_onecache(cpd, level, B_TRUE); ! break; ! case 2: ! cpuid_fill_onecache(cpd, level, B_FALSE); ! break; ! case 3: ! cpuid_fill_onecache(cpd, level, B_TRUE); ! cpuid_fill_onecache(cpd, level, B_FALSE); ! break; ! case 4: ! cpuid_fill_onecache(cpd, level, B_FALSE); ! dcache->acc_unified = B_TRUE; ! break; ! default: ! bop_panic("unsupported cache type"); ! } ! } ! ! /* ! * We require L1-I/D & L2-D. Unified caches are OK as well. ! */ ! if (!cpd->ac_caches[B_TRUE][0].acc_exists && ! (!cpd->ac_caches[B_FALSE][0].acc_exists || ! !cpd->ac_caches[B_FALSE][0].acc_unified)) ! bop_panic("no L1 instructian cache detected"); ! ! if (!cpd->ac_caches[B_FALSE][1].acc_exists) ! bop_panic("no L2 data cache detected"); ! /* ! * set globals with cache size info ! */ ! l2cache_sz = cpd->ac_caches[B_FALSE][1].acc_size; ! l2cache_linesz = cpd->ac_caches[B_FALSE][1].acc_linesz; ! l2cache_assoc = cpd->ac_caches[B_FALSE][1].acc_assoc; } /* ! * We need to do is go through and check for a few features that we know ! * we're going to need. */ static void cpuid_verify(void) { arm_cpuid_mem_vmsa_t vmsa; arm_cpuid_mem_barrier_t barrier; int sync, syncf; arm_cpuid_t *cpd = &cpuid_data0; ! /* v7 vmsa */ ! vmsa = extract(cpd->ac_mmfr[0], ARM_CPUID_MMFR0_STATE0_MASK, ! ARM_CPUID_MMFR0_STATE0_SHIFT); if (vmsa != ARM_CPUID_MEM_VMSA_V7) { bop_printf(NULL, "invalid vmsa setting, found 0x%x\n", vmsa); bop_panic("unsupported cpu"); } /* check for ISB, DSB, etc. in cp15 */ ! barrier = extract(cpd->ac_mmfr[2], ARM_CPUID_MMFR2_STATE5_MASK, ! ARM_CPUID_MMFR2_STATE5_SHIFT); ! if (barrier != ARM_CPUID_MEM_BARRIER_INSTR) { ! bop_printf(NULL, "missing support for memory barrier " ! "instructions\n"); bop_panic("unsupported CPU"); } /* synch prims */ ! sync = extract(cpd->ac_isar[3], ARM_CPUID_ISAR3_STATE3_SHIFT, ! ARM_CPUID_ISAR3_STATE3_SHIFT); ! syncf = extract(cpd->ac_isar[4], ARM_CPUID_ISAR4_STATE5_SHIFT, ! ARM_CPUID_ISAR4_STATE5_SHIFT); if (sync != 0x2 && syncf != 0x0) { bop_printf(NULL, "unsupported synch primitives: sync,frac: " "%x,%x\n", sync, syncf); bop_panic("unsupported CPU"); } } static void cpuid_valid_ident(uint32_t ident) { arm_cpuid_ident_arch_t arch; /* ! * We don't support anything older than ARMv7. */ arch = (ident & ARM_CPUID_IDENT_ARCH_MASK) >> ARM_CPUID_IDENT_ARCH_SHIFT; if (arch != ARM_CPUID_IDENT_ARCH_CPUID) { bop_printf(NULL, "encountered unsupported CPU arch: 0x%x",
*** 219,230 **** static void cpuid_valid_fpident(uint32_t ident) { arm_cpuid_vfp_arch_t vfp; ! cpuid_parse_stage(ident, ARM_CPUID_VFP_ARCH_MASK, ! ARM_CPUID_VFP_ARCH_SHIFT, (int *)&vfp); if (vfp != ARM_CPUID_VFP_ARCH_V2) { bop_printf(NULL, "unsupported vfp version: %x\n", vfp); bop_panic("unsupported CPU"); } --- 234,245 ---- static void cpuid_valid_fpident(uint32_t ident) { arm_cpuid_vfp_arch_t vfp; ! vfp = extract(ident, ARM_CPUID_VFP_ARCH_MASK, ARM_CPUID_VFP_ARCH_SHIFT); ! // XXX: _V3_V2BASE? _V3_NOBASE? _V3_V3BASE? if (vfp != ARM_CPUID_VFP_ARCH_V2) { bop_printf(NULL, "unsupported vfp version: %x\n", vfp); bop_panic("unsupported CPU"); }
*** 236,251 **** void cpuid_setup(void) { arm_cpuid_t *cpd = &cpuid_data0; ! cpd->ac_ident = arm_cpuid_idreg(); cpuid_valid_ident(cpd->ac_ident); cpuid_fill_main(cpd); cpd->ac_fpident = arm_cpuid_vfpidreg(); cpuid_valid_fpident(cpd->ac_fpident); cpuid_fill_fpu(cpd); cpuid_fill_caches(cpd); cpuid_verify(); } --- 251,267 ---- void cpuid_setup(void) { arm_cpuid_t *cpd = &cpuid_data0; ! cpd->ac_ident = arm_cpuid_midr(); cpuid_valid_ident(cpd->ac_ident); cpuid_fill_main(cpd); cpd->ac_fpident = arm_cpuid_vfpidreg(); cpuid_valid_fpident(cpd->ac_fpident); cpuid_fill_fpu(cpd); + cpuid_fill_caches(cpd); cpuid_verify(); }