Print this page
cpuid for ARMv7
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright (c) 2014 Joyent, Inc.  All rights reserved.

  14  */
  15 
  16 #include <sys/cpuid_impl.h>
  17 #include <sys/param.h>
  18 #include <sys/bootconf.h>
  19 #include <vm/vm_dep.h>
  20 #include <sys/armv7_bsmf.h>
  21 
  22 /*
  23  * Handle classification and identification of ARM processors.
  24  *
  25  * Currently we do a single pass which reads in information and asserts that the
  26  * basic information which we receive here matches what we'd expect and are able
  27  * to do everything that we need with this ARM CPU.
  28  *
  29  * TODO We'll eventually do another pass to make sure that we properly determine
  30  * the feature set to expose to userland.
  31  */
  32 
  33 static arm_cpuid_t cpuid_data0;
  34 
  35 static void
  36 cpuid_parse_stage(uint32_t line, uint32_t mask, uint32_t shift, int *out)
  37 {
  38         *out = (line & mask) >> shift;
  39 }
  40 
  41 static void
  42 cpuid_fill_main(arm_cpuid_t *cpd)
  43 {
  44         cpd->ac_pfr[0] = arm_cpuid_pfr0();
  45         cpd->ac_pfr[1] = arm_cpuid_pfr1();
  46         cpd->ac_dfr = arm_cpuid_dfr0();
  47         cpd->ac_mmfr[0] = arm_cpuid_mmfr0();
  48         cpd->ac_mmfr[1] = arm_cpuid_mmfr1();
  49         cpd->ac_mmfr[2] = arm_cpuid_mmfr2();
  50         cpd->ac_mmfr[3] = arm_cpuid_mmfr3();
  51         cpd->ac_isar[0] = arm_cpuid_isar0();
  52         cpd->ac_isar[1] = arm_cpuid_isar1();
  53         cpd->ac_isar[2] = arm_cpuid_isar2();
  54         cpd->ac_isar[3] = arm_cpuid_isar3();
  55         cpd->ac_isar[4] = arm_cpuid_isar4();
  56         cpd->ac_isar[5] = arm_cpuid_isar5();
  57 }
  58 
  59 static void
  60 cpuid_fill_fpu(arm_cpuid_t *cpd)
  61 {
  62         cpd->ac_mvfr[0] = arm_cpuid_mvfr0();
  63         cpd->ac_mvfr[1] = arm_cpuid_mvfr1();
  64 }
  65 
  66 #define CACHE_LEN_MASK          0x003
  67 #define CACHE_M_BIT             0x004
  68 #define CACHE_ASSOC_MASK        0x038
  69 #define CACHE_ASSOC_SHIFT       3
  70 #define CACHE_SIZE_MASK         0x3c0
  71 #define CACHE_SIZE_SHIFT        6
  72 #define CACHE_COLOR_BIT         0x800
  73 #define CACHE_MASK              0xfff
  74 #define CACHE_DCACHE_SHIFT      12
  75 #define CACHE_SEPARATE          0x1000000





















  76 
  77 /*
  78  * On ARMv6 the value of the cache size and the cache associativity depends on
  79  * the value of the M bit, which modifies the value that's in the actual index.
  80  */
  81 static uint32_t armv6_cpuid_cache_sizes[2][9] = {
  82         { 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x100000,
  83                 0x20000 },
  84         { 0x300, 0x600, 0xc00, 0x1800, 0x3000, 0x6000, 0xc000, 0x18000,
  85                 0x30000 }
  86 };
  87 
  88 static int8_t armv6_cpuid_cache_assoc[2][9] = {
  89         { 1, 2, 4, 8, 16, 32, 64, 128 },
  90         { -1, 3, 6, 12, 24, 48, 96, 192 }
  91 };
  92 
  93 static uint8_t armv6_cpuid_cache_linesz[] = {
  94         8,
  95         16,
  96         32,
  97         64
  98 };
  99 
 100 static void
 101 cpuid_fill_onecache(arm_cpuid_cache_t *accp, uint32_t val)
 102 {
 103         int mbit, index, assoc;
 104 
 105         mbit = (val & CACHE_M_BIT) != 0 ? 1 : 0;
 106         index = (val & CACHE_ASSOC_MASK) >> CACHE_ASSOC_SHIFT;
 107         assoc = armv6_cpuid_cache_assoc[mbit][index];
 108         if (assoc == -1) {
 109                 accp->acc_exists = B_FALSE;
 110                 return;
 111         }
 112         ASSERT(assoc > 0);
 113         accp->acc_assoc = assoc;
 114         accp->acc_rcolor = (val & CACHE_COLOR_BIT) == 0 ?
 115             B_FALSE : B_TRUE;
 116         index = val & CACHE_LEN_MASK;
 117         accp->acc_linesz = armv6_cpuid_cache_linesz[index];
 118         index = (val & CACHE_SIZE_MASK) >> CACHE_SIZE_SHIFT;
 119         accp->acc_size = armv6_cpuid_cache_sizes[mbit][index];
 120         accp->acc_exists = B_TRUE;
 121 }
 122 
 123 static void
 124 cpuid_fill_caches(arm_cpuid_t *cpd)
 125 {
 126         uint32_t val, icache, dcache;













































 127 
 128         val = arm_cpuid_ctr();
 129         icache = val & CACHE_MASK;
 130         cpuid_fill_onecache(&cpd->ac_icache, icache);
 131         dcache = (val >> CACHE_DCACHE_SHIFT) & CACHE_MASK;
 132         cpuid_fill_onecache(&cpd->ac_dcache, dcache);
 133 
 134         if (val & CACHE_SEPARATE) {
 135                 cpd->ac_unifiedl1 = B_FALSE;
 136         } else {
 137                 cpd->ac_unifiedl1 = B_TRUE;
 138         }
 139 
 140         armv7_bsmdep_l2cacheinfo();
 141         armv6_cachesz = cpd->ac_dcache.acc_size;
 142         armv6_cache_assoc = cpd->ac_dcache.acc_assoc;


 143 }
 144 
 145 
 146 /*
 147  * There isn't a specific way to indicate that we're on ARMv6k. Instead what we
 148  * need to do is go through and check for a few features that we know we're
 149  * going to need.
 150  *
 151  * TODO This will have to be revisited with ARMv7 support
 152  */
 153 static void
 154 cpuid_verify(void)
 155 {
 156         arm_cpuid_mem_vmsa_t vmsa;
 157         arm_cpuid_mem_barrier_t barrier;
 158         int sync, syncf;
 159 
 160         arm_cpuid_t *cpd = &cpuid_data0;
 161 
 162         /* v6 vmsa */
 163         cpuid_parse_stage(cpd->ac_mmfr[0], ARM_CPUID_MMFR0_STATE0_MASK,
 164             ARM_CPUID_MMFR0_STATE0_SHIFT, (int *)&vmsa);
 165         /* TODO We might be able to support v6, but bcm2835+qvpb are this */
 166         if (vmsa != ARM_CPUID_MEM_VMSA_V7) {
 167                 bop_printf(NULL, "invalid vmsa setting, found 0x%x\n", vmsa);
 168                 bop_panic("unsupported cpu");
 169         }
 170 
 171         /* check for ISB, DSB, etc. in cp15 */
 172         cpuid_parse_stage(cpd->ac_mmfr[2], ARM_CPUID_MMFR2_STATE5_MASK,
 173             ARM_CPUID_MMFR2_STATE5_SHIFT, (int *)&barrier);
 174         if (barrier != ARM_CPUID_MEM_BARRIER_CP15 &&
 175             barrier != ARM_CPUID_MEM_BARRIER_INSTR) {
 176                 bop_printf(NULL, "missing support for CP15 memory barriers\n");
 177                 bop_panic("unsupported CPU");
 178         }
 179 
 180         /* synch prims */
 181         cpuid_parse_stage(cpd->ac_isar[4], ARM_CPUID_ISAR3_STATE3_SHIFT,
 182             ARM_CPUID_ISAR4_STATE5_SHIFT, (int *)&sync);
 183         cpuid_parse_stage(cpd->ac_isar[4], ARM_CPUID_ISAR4_STATE3_SHIFT,
 184             ARM_CPUID_ISAR4_STATE5_SHIFT, (int *)&syncf);
 185         if (sync != 0x2 && syncf != 0x0) {
 186                 bop_printf(NULL, "unsupported synch primitives: sync,frac: "
 187                     "%x,%x\n", sync, syncf);
 188                 bop_panic("unsupported CPU");
 189         }
 190 
 191         if (cpd->ac_icache.acc_exists == B_FALSE) {
 192                 bop_printf(NULL, "icache not defined to exist\n");
 193                 bop_panic("unsupported CPU");
 194         }
 195 
 196         if (cpd->ac_dcache.acc_exists == B_FALSE) {
 197                 bop_printf(NULL, "dcache not defined to exist\n");
 198                 bop_panic("unsupported CPU");
 199         }
 200 }
 201 
 202 static void
 203 cpuid_valid_ident(uint32_t ident)
 204 {
 205         arm_cpuid_ident_arch_t arch;
 206 
 207         /*
 208          * We don't support stock ARMv6 or older.
 209          */
 210         arch = (ident & ARM_CPUID_IDENT_ARCH_MASK) >>
 211             ARM_CPUID_IDENT_ARCH_SHIFT;
 212         if (arch != ARM_CPUID_IDENT_ARCH_CPUID) {
 213                 bop_printf(NULL, "encountered unsupported CPU arch: 0x%x",
 214                     arch);
 215                 bop_panic("unsupported CPU");
 216         }
 217 }
 218 
 219 static void
 220 cpuid_valid_fpident(uint32_t ident)
 221 {
 222         arm_cpuid_vfp_arch_t vfp;
 223 
 224         cpuid_parse_stage(ident, ARM_CPUID_VFP_ARCH_MASK,
 225             ARM_CPUID_VFP_ARCH_SHIFT, (int *)&vfp);
 226         if (vfp != ARM_CPUID_VFP_ARCH_V2) {
 227                 bop_printf(NULL, "unsupported vfp version: %x\n", vfp);
 228                 bop_panic("unsupported CPU");
 229         }
 230 
 231         if ((ident & ARM_CPUID_VFP_SW_MASK) != 0) {
 232                 bop_printf(NULL, "encountered software-only vfp\n");
 233                 bop_panic("unsuppored CPU");
 234         }
 235 }
 236 void
 237 cpuid_setup(void)
 238 {
 239         arm_cpuid_t *cpd = &cpuid_data0;
 240 
 241         cpd->ac_ident = arm_cpuid_idreg();
 242         cpuid_valid_ident(cpd->ac_ident);
 243         cpuid_fill_main(cpd);
 244 
 245         cpd->ac_fpident = arm_cpuid_vfpidreg();
 246         cpuid_valid_fpident(cpd->ac_fpident);
 247         cpuid_fill_fpu(cpd);

 248         cpuid_fill_caches(cpd);
 249 
 250         cpuid_verify();
 251 }
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright (c) 2014 Joyent, Inc.  All rights reserved.
  14  * Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  15  */
  16 
  17 #include <sys/cpuid_impl.h>
  18 #include <sys/param.h>
  19 #include <sys/bootconf.h>
  20 #include <vm/vm_dep.h>
  21 #include <sys/armv7_bsmf.h>
  22 
  23 /*
  24  * Handle classification and identification of ARM processors.
  25  *
  26  * Currently we do a single pass which reads in information and asserts that the
  27  * basic information which we receive here matches what we'd expect and are able
  28  * to do everything that we need with this ARM CPU.
  29  *
  30  * TODO We'll eventually do another pass to make sure that we properly determine
  31  * the feature set to expose to userland.
  32  */
  33 
  34 static arm_cpuid_t cpuid_data0;
  35 
  36 static uint32_t
  37 extract(uint32_t line, uint32_t mask, uint32_t shift)
  38 {
  39         return ((line & mask) >> shift);
  40 }
  41 
  42 static void
  43 cpuid_fill_main(arm_cpuid_t *cpd)
  44 {
  45         cpd->ac_pfr[0] = arm_cpuid_pfr0();
  46         cpd->ac_pfr[1] = arm_cpuid_pfr1();
  47         cpd->ac_dfr = arm_cpuid_dfr0();
  48         cpd->ac_mmfr[0] = arm_cpuid_mmfr0();
  49         cpd->ac_mmfr[1] = arm_cpuid_mmfr1();
  50         cpd->ac_mmfr[2] = arm_cpuid_mmfr2();
  51         cpd->ac_mmfr[3] = arm_cpuid_mmfr3();
  52         cpd->ac_isar[0] = arm_cpuid_isar0();
  53         cpd->ac_isar[1] = arm_cpuid_isar1();
  54         cpd->ac_isar[2] = arm_cpuid_isar2();
  55         cpd->ac_isar[3] = arm_cpuid_isar3();
  56         cpd->ac_isar[4] = arm_cpuid_isar4();
  57         cpd->ac_isar[5] = arm_cpuid_isar5();
  58 }
  59 
  60 static void
  61 cpuid_fill_fpu(arm_cpuid_t *cpd)
  62 {
  63         cpd->ac_mvfr[0] = arm_cpuid_mvfr0();
  64         cpd->ac_mvfr[1] = arm_cpuid_mvfr1();
  65 }
  66 
  67 #define CCSIDR_WT               0x80000000
  68 #define CCSIDR_WB               0x40000000
  69 #define CCSIDR_RA               0x20000000
  70 #define CCSIDR_WA               0x10000000
  71 #define CCSIDR_NUMSETS_MASK     0x0fffe000
  72 #define CCSIDR_NUMSETS_SHIFT    13
  73 #define CCSIDR_ASSOC_MASK       0x00001ff8
  74 #define CCSIDR_ASSOC_SHIFT      3
  75 #define CCSIDR_LINESIZE_MASK    0x00000007
  76 #define CCSIDR_LINESIZE_SHIFT   0
  77 
  78 static void
  79 cpuid_fill_onecache(arm_cpuid_t *cpd, int level, boolean_t icache)
  80 {
  81         arm_cpuid_cache_t *cache = &cpd->ac_caches[icache][level];
  82         uint32_t ccsidr;
  83 
  84         ccsidr = arm_cpuid_ccsidr(level, icache);
  85         cpd->ac_ccsidr[icache][level] = ccsidr;
  86 
  87         cache->acc_exists = B_TRUE;
  88         cache->acc_wt = (ccsidr & CCSIDR_WT) == CCSIDR_WT;
  89         cache->acc_wb = (ccsidr & CCSIDR_WB) == CCSIDR_WB;
  90         cache->acc_ra = (ccsidr & CCSIDR_RA) == CCSIDR_RA;
  91         cache->acc_wa = (ccsidr & CCSIDR_WA) == CCSIDR_WA;
  92         cache->acc_sets = extract(ccsidr, CCSIDR_NUMSETS_MASK,
  93             CCSIDR_NUMSETS_SHIFT) + 1;
  94         cache->acc_assoc = extract(ccsidr, CCSIDR_ASSOC_MASK,
  95             CCSIDR_ASSOC_SHIFT) + 1;
  96         cache->acc_linesz = sizeof (uint32_t) << (extract(ccsidr,
  97             CCSIDR_LINESIZE_MASK, CCSIDR_LINESIZE_SHIFT) + 2);
  98 
  99 /*
 100  * XXX?
 101 #warning "set acc_size?"
 102  */








































 103 }
 104 
 105 static void
 106 cpuid_fill_caches(arm_cpuid_t *cpd)
 107 {
 108         uint32_t erg, cwg;
 109         uint32_t l1ip;
 110         uint32_t ctr;
 111         uint32_t clidr;
 112         int level;
 113 
 114         clidr = arm_cpuid_clidr();
 115         cpd->ac_clidr = clidr;
 116 
 117         /* default all caches to not existing, and not unified */
 118         for (level = 0; level < 7; level++) {
 119                 cpd->ac_caches[B_TRUE][level].acc_exists = B_FALSE;
 120                 cpd->ac_caches[B_FALSE][level].acc_exists = B_FALSE;
 121                 cpd->ac_caches[B_TRUE][level].acc_unified = B_FALSE;
 122                 cpd->ac_caches[B_FALSE][level].acc_unified = B_FALSE;
 123         }
 124 
 125         /* retrieve cache info for each level */
 126         for (level = 0; level < 7; level++) {
 127                 arm_cpuid_cache_t *icache = &cpd->ac_caches[B_TRUE][level];
 128                 arm_cpuid_cache_t *dcache = &cpd->ac_caches[B_FALSE][level];
 129                 uint32_t ctype = (cpd->ac_clidr >> (3 * level)) & 0x7;
 130 
 131                 /* stop looking we find the first non-existent level */
 132                 if (!ctype)
 133                         break;
 134 
 135                 switch (ctype) {
 136                 case 1:
 137                         cpuid_fill_onecache(cpd, level, B_TRUE);
 138                         break;
 139                 case 2:
 140                         cpuid_fill_onecache(cpd, level, B_FALSE);
 141                         break;
 142                 case 3:
 143                         cpuid_fill_onecache(cpd, level, B_TRUE);
 144                         cpuid_fill_onecache(cpd, level, B_FALSE);
 145                         break;
 146                 case 4:
 147                         cpuid_fill_onecache(cpd, level, B_FALSE);
 148                         dcache->acc_unified = B_TRUE;
 149                         break;
 150                 default:
 151                         bop_panic("unsupported cache type");
 152                 }
 153         }
 154 
 155         /*
 156          * We require L1-I/D & L2-D.  Unified caches are OK as well.
 157          */
 158         if (!cpd->ac_caches[B_TRUE][0].acc_exists &&
 159             (!cpd->ac_caches[B_FALSE][0].acc_exists ||
 160             !cpd->ac_caches[B_FALSE][0].acc_unified))
 161                 bop_panic("no L1 instructian cache detected");
 162 
 163         if (!cpd->ac_caches[B_FALSE][1].acc_exists)
 164                 bop_panic("no L2 data cache detected");
 165 
 166         /*
 167          * set globals with cache size info
 168          */
 169         l2cache_sz = cpd->ac_caches[B_FALSE][1].acc_size;
 170         l2cache_linesz = cpd->ac_caches[B_FALSE][1].acc_linesz;
 171         l2cache_assoc = cpd->ac_caches[B_FALSE][1].acc_assoc;
 172 }
 173 
 174 
 175 /*
 176  * We need to do is go through and check for a few features that we know
 177  * we're going to need.



 178  */
 179 static void
 180 cpuid_verify(void)
 181 {
 182         arm_cpuid_mem_vmsa_t vmsa;
 183         arm_cpuid_mem_barrier_t barrier;
 184         int sync, syncf;
 185 
 186         arm_cpuid_t *cpd = &cpuid_data0;
 187 
 188         /* v7 vmsa */
 189         vmsa = extract(cpd->ac_mmfr[0], ARM_CPUID_MMFR0_STATE0_MASK,
 190             ARM_CPUID_MMFR0_STATE0_SHIFT);

 191         if (vmsa != ARM_CPUID_MEM_VMSA_V7) {
 192                 bop_printf(NULL, "invalid vmsa setting, found 0x%x\n", vmsa);
 193                 bop_panic("unsupported cpu");
 194         }
 195 
 196         /* check for ISB, DSB, etc. in cp15 */
 197         barrier = extract(cpd->ac_mmfr[2], ARM_CPUID_MMFR2_STATE5_MASK,
 198             ARM_CPUID_MMFR2_STATE5_SHIFT);
 199         if (barrier != ARM_CPUID_MEM_BARRIER_INSTR) {
 200                 bop_printf(NULL, "missing support for memory barrier "
 201                     "instructions\n");
 202                 bop_panic("unsupported CPU");
 203         }
 204 
 205         /* synch prims */
 206         sync = extract(cpd->ac_isar[3], ARM_CPUID_ISAR3_STATE3_SHIFT,
 207             ARM_CPUID_ISAR3_STATE3_SHIFT);
 208         syncf = extract(cpd->ac_isar[4], ARM_CPUID_ISAR4_STATE5_SHIFT,
 209             ARM_CPUID_ISAR4_STATE5_SHIFT);
 210         if (sync != 0x2 && syncf != 0x0) {
 211                 bop_printf(NULL, "unsupported synch primitives: sync,frac: "
 212                     "%x,%x\n", sync, syncf);
 213                 bop_panic("unsupported CPU");
 214         }










 215 }
 216 
 217 static void
 218 cpuid_valid_ident(uint32_t ident)
 219 {
 220         arm_cpuid_ident_arch_t arch;
 221 
 222         /*
 223          * We don't support anything older than ARMv7.
 224          */
 225         arch = (ident & ARM_CPUID_IDENT_ARCH_MASK) >>
 226             ARM_CPUID_IDENT_ARCH_SHIFT;
 227         if (arch != ARM_CPUID_IDENT_ARCH_CPUID) {
 228                 bop_printf(NULL, "encountered unsupported CPU arch: 0x%x",
 229                     arch);
 230                 bop_panic("unsupported CPU");
 231         }
 232 }
 233 
 234 static void
 235 cpuid_valid_fpident(uint32_t ident)
 236 {
 237         arm_cpuid_vfp_arch_t vfp;
 238 
 239         vfp = extract(ident, ARM_CPUID_VFP_ARCH_MASK, ARM_CPUID_VFP_ARCH_SHIFT);
 240         // XXX: _V3_V2BASE? _V3_NOBASE? _V3_V3BASE?
 241         if (vfp != ARM_CPUID_VFP_ARCH_V2) {
 242                 bop_printf(NULL, "unsupported vfp version: %x\n", vfp);
 243                 bop_panic("unsupported CPU");
 244         }
 245 
 246         if ((ident & ARM_CPUID_VFP_SW_MASK) != 0) {
 247                 bop_printf(NULL, "encountered software-only vfp\n");
 248                 bop_panic("unsuppored CPU");
 249         }
 250 }
 251 void
 252 cpuid_setup(void)
 253 {
 254         arm_cpuid_t *cpd = &cpuid_data0;
 255 
 256         cpd->ac_ident = arm_cpuid_midr();
 257         cpuid_valid_ident(cpd->ac_ident);
 258         cpuid_fill_main(cpd);
 259 
 260         cpd->ac_fpident = arm_cpuid_vfpidreg();
 261         cpuid_valid_fpident(cpd->ac_fpident);
 262         cpuid_fill_fpu(cpd);
 263 
 264         cpuid_fill_caches(cpd);
 265 
 266         cpuid_verify();
 267 }