1 /* $NetBSD: arm.c,v 1.6 2022/08/06 18:26:43 andvar 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.6 2022/08/06 18:26:43 andvar 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-Shareability",
78 "Shareability-Levels",
79 "TCM-Support",
80 "Auxiliary-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
print_features(const char * cpuname,const char * setname,const int * id_data,size_t id_len,const char * const id_fieldnames[][8],size_t id_nfieldnames,const uint8_t * id_boolean,const uint8_t * id_present)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[24], 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 bool
identifycpu_bind(void)214 identifycpu_bind(void)
215 {
216
217 return false;
218 }
219
220 void
identifycpu(int fd,const char * cpuname)221 identifycpu(int fd, const char *cpuname)
222 {
223 int *id_data;
224 size_t id_isar_len = 0;
225 size_t id_mmfr_len = 0;
226 size_t id_pfr_len = 0;
227 size_t id_mvfr_len = 0;
228
229 if (sysctlbyname("machdep.id_isar", NULL, &id_isar_len, NULL, 0) < 0
230 || sysctlbyname("machdep.id_mmfr", NULL, &id_mmfr_len, NULL, 0) < 0
231 || sysctlbyname("machdep.id_pfr", NULL, &id_pfr_len, NULL, 0) < 0
232 || sysctlbyname("machdep.id_mvfr", NULL, &id_mvfr_len, NULL, 0) < 0) {
233 warn("sysctlbyname");
234 return;
235 }
236
237 id_data = malloc(id_isar_len);
238
239 sysctlbyname("machdep.id_isar", id_data, &id_isar_len, NULL, 0);
240 print_features(cpuname, "isa features", id_data, id_isar_len,
241 id_isar_fieldnames, __arraycount(id_isar_fieldnames),
242 id_isar_boolean, NULL);
243
244 free(id_data);
245 id_data = malloc(id_mmfr_len);
246
247 sysctlbyname("machdep.id_mmfr", id_data, &id_mmfr_len, NULL, 0);
248 print_features(cpuname, "memory model", id_data, id_mmfr_len,
249 id_mmfr_fieldnames, __arraycount(id_mmfr_fieldnames),
250 NULL /*id_mmfr_boolean*/, id_mmfr_present);
251
252 free(id_data);
253 id_data = malloc(id_pfr_len);
254
255 sysctlbyname("machdep.id_pfr", id_data, &id_pfr_len, NULL, 0);
256 print_features(cpuname, "processor features", id_data, id_pfr_len,
257 id_pfr_fieldnames, __arraycount(id_pfr_fieldnames),
258 NULL /*id_pfr_boolean*/, NULL /*id_pfr_present*/);
259
260 free(id_data);
261 id_data = malloc(id_mvfr_len);
262
263 sysctlbyname("machdep.id_mvfr", id_data, &id_mvfr_len, NULL, 0);
264 print_features(cpuname, "media and VFP features", id_data, id_mvfr_len,
265 id_mvfr_fieldnames, __arraycount(id_mvfr_fieldnames),
266 NULL /*id_mvfr_boolean*/, id_mvfr_present);
267
268 free(id_data);
269 }
270
271 int
ucodeupdate_check(int fd,struct cpu_ucode * uc)272 ucodeupdate_check(int fd, struct cpu_ucode *uc)
273 {
274
275 return 0;
276 }
277