xref: /netbsd-src/usr.sbin/cpuctl/arch/arm.c (revision 6478b40555af74e0026fe65da2becaaefc2c3b08)
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