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