1 /* $NetBSD: arm.c,v 1.1 2013/01/31 23:40:48 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 2013 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas of 3am Software Foundry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 34 #ifndef lint 35 __RCSID("$NetBSD: arm.c,v 1.1 2013/01/31 23:40:48 matt Exp $"); 36 #endif /* not lint */ 37 38 #include <sys/types.h> 39 #include <sys/cpuio.h> 40 #include <sys/sysctl.h> 41 #include <stdio.h> 42 #include <stdbool.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <inttypes.h> 46 #include <err.h> 47 48 #include "../cpuctl.h" 49 50 static const char * const id_isar_fieldnames[][8] = { 51 { 52 "Swap", "Bitcount", "Bitfield", "CmpBranch", 53 "Coproc", "Debug", "Divde", NULL 54 }, { 55 "Endian", "Except", "Except_AR", "Extend", 56 "IfThen", "Immediate", "Interwork", "Jazelle" 57 }, { 58 "LoadStore", "MemHint", "MultAccessInt", "Mult", 59 "MultS", "MultU", "PSR_AR", "Reversal" 60 }, { 61 "Saturate", "SIMD", "SVC", "SynchPrim", 62 "TabBranch", "ThumbCopy", "TrueNOP", "ThumbEE_Extn" 63 }, { 64 "Unpriv", "WithShifts", "Writeback", "SMC", 65 "Barrier", "SynchPrim_frac", "PSR_M", "SWP" 66 } 67 }; 68 69 static const uint8_t id_isar_boolean[] = { 70 0x2f, 0xb7, 0x41, 0xf5, 0xfc 71 }; 72 73 static const char * const id_mmfr_fieldnames[][8] = { 74 { 75 "VMSA-Support", 76 "PMSA-Support", 77 "Outermost-Shareablity", 78 "Shareability-Levels", 79 "TCM-Support", 80 "Auxilary-Registers", 81 "FCSE-Support", 82 "Innermost-Shareability" 83 }, { 84 "L1-Harvard-Cache-VA", 85 "L1-Unified-Cache-VA", 86 "L1-Harvard-Cache-Set/Way", 87 "L1-Unified-Cache-Set/Way", 88 "L1-Harvard-Cache", 89 "L1-Unified-Cache", 90 "L1-Cache-Test-and-Clean", 91 "Branch-Predictor", 92 }, { 93 "L1-Harvard-Foreground-Fetch", 94 "L1-Unified-Background-Fetch", 95 "L1-Harvard-Range", 96 "Harvard-TLB", 97 "Unified-TLB", 98 "Mem-Barrier", 99 "WFI-Stall", 100 "HW-Access", 101 }, { 102 "Cache-Maintenance-MVA", 103 "Cache-Maintenance-Set/Way", 104 "BP-Maintenance", 105 "Maintenance-Broadcast", 106 NULL, 107 "Coherent-Tablewalk", 108 "Cached-Memory-Size", 109 "Supersection-Support", 110 }, 111 }; 112 113 static const uint8_t id_mmfr_present[] = { 114 0x8c, 0x00, 0x00, 0x68 115 }; 116 117 static const char * const id_pfr_fieldnames[][8] = { 118 { 119 "ThumbEE", 120 "Jazelle", 121 "Thumb", 122 "ARM", 123 }, { 124 "Programmer", 125 "Security", 126 "M-profile", 127 "Virtualization", 128 "Generic-Timer", 129 }, 130 }; 131 132 static const char * const id_mvfr_fieldnames[][8] = { 133 { 134 "ASIMD-Registers", 135 "Single-Precision", 136 "Double-Precision", 137 "VFP-Exception-Trapping", 138 "Divide", 139 "Square-Root", 140 "Short-Vectors", 141 "VFP-Rounding-Modes", 142 }, { 143 "Flush-To-Zero", 144 "Default-NaN", 145 "ASIMD-Load/Store", 146 "ASIMD-Integer", 147 "ASIMD-SPFP", 148 "ASIMD-HPFP", 149 "VFP-HPFP", 150 "ASIMD-FMAC", 151 }, 152 }; 153 154 static const uint8_t id_mvfr_present[] = { 155 0x80, 0x03, 156 }; 157 158 static void 159 print_features(const char *cpuname, const char *setname, 160 const int *id_data, size_t id_len, const char * const id_fieldnames[][8], 161 size_t id_nfieldnames, const uint8_t *id_boolean, const uint8_t *id_present) 162 { 163 char buf[81]; 164 size_t len = 0; 165 const char *sep = ""; 166 for (size_t i = 0; i < id_len / sizeof(id_data[0]); i++) { 167 int isar = id_data[i]; 168 for (u_int j = 0; isar != 0 && j < 8; j++, isar >>= 4) { 169 const char *name = NULL; 170 const char *value = ""; 171 char namebuf[12], valuebuf[12], tmpbuf[30]; 172 if ((isar & 0x0f) == 0 173 && (id_present == NULL 174 || (id_present[i] & (1 << j))) == 0) { 175 continue; 176 } 177 if (len == 0) { 178 len = snprintf(buf, sizeof(buf), 179 "%s: %s: ", cpuname, setname); 180 } 181 if (i < id_nfieldnames) { 182 name = id_fieldnames[i][j]; 183 } 184 if (name == NULL) { 185 name = namebuf; 186 snprintf(namebuf, sizeof(namebuf), 187 "%zu[%u]", i, j); 188 } 189 if (id_boolean == NULL 190 || (id_boolean[i] & (1 << j)) == 0 191 || (isar & 0xe) != 0) { 192 value = valuebuf; 193 snprintf(valuebuf, sizeof(valuebuf), 194 "=%u", isar & 0x0f); 195 } 196 size_t tmplen = snprintf(tmpbuf, sizeof(tmpbuf), 197 "%s%s%s", sep, name, value); 198 if (len + tmplen > 78) { 199 printf("%s\n", buf); 200 len = snprintf(buf, sizeof(buf), 201 "%s: %s: %s", cpuname, setname, tmpbuf + 2); 202 } else { 203 len = strlcat(buf, tmpbuf, sizeof(buf)); 204 } 205 sep = ", "; 206 } 207 } 208 if (len > 0) { 209 printf("%s\n", buf); 210 } 211 } 212 213 void 214 identifycpu(int fd, const char *cpuname) 215 { 216 int *id_data; 217 size_t id_isar_len = 0; 218 size_t id_mmfr_len = 0; 219 size_t id_pfr_len = 0; 220 size_t id_mvfr_len = 0; 221 222 if (sysctlbyname("machdep.id_isar", NULL, &id_isar_len, NULL, 0) < 0 223 || sysctlbyname("machdep.id_mmfr", NULL, &id_mmfr_len, NULL, 0) < 0 224 || sysctlbyname("machdep.id_pfr", NULL, &id_pfr_len, NULL, 0) < 0 225 || sysctlbyname("machdep.id_mvfr", NULL, &id_mvfr_len, NULL, 0) < 0) { 226 warn("sysctlbyname"); 227 return; 228 } 229 230 id_data = malloc(id_isar_len); 231 232 sysctlbyname("machdep.id_isar", id_data, &id_isar_len, NULL, 0); 233 print_features(cpuname, "isa features", id_data, id_isar_len, 234 id_isar_fieldnames, __arraycount(id_isar_fieldnames), 235 id_isar_boolean, NULL); 236 237 free(id_data); 238 id_data = malloc(id_mmfr_len); 239 240 sysctlbyname("machdep.id_mmfr", id_data, &id_mmfr_len, NULL, 0); 241 print_features(cpuname, "memory model", id_data, id_mmfr_len, 242 id_mmfr_fieldnames, __arraycount(id_mmfr_fieldnames), 243 NULL /*id_mmfr_boolean*/, id_mmfr_present); 244 245 free(id_data); 246 id_data = malloc(id_pfr_len); 247 248 sysctlbyname("machdep.id_pfr", id_data, &id_pfr_len, NULL, 0); 249 print_features(cpuname, "processor features", id_data, id_pfr_len, 250 id_pfr_fieldnames, __arraycount(id_pfr_fieldnames), 251 NULL /*id_pfr_boolean*/, NULL /*id_pfr_present*/); 252 253 free(id_data); 254 id_data = malloc(id_mvfr_len); 255 256 sysctlbyname("machdep.id_mvfr", id_data, &id_mvfr_len, NULL, 0); 257 print_features(cpuname, "media and VFP features", id_data, id_mvfr_len, 258 id_mvfr_fieldnames, __arraycount(id_mvfr_fieldnames), 259 NULL /*id_mvfr_boolean*/, id_mvfr_present); 260 261 free(id_data); 262 } 263 264 int 265 ucodeupdate_check(int fd, struct cpu_ucode *uc) 266 { 267 268 return 0; 269 } 270