1*6478b405Sandvar /* $NetBSD: arm.c,v 1.6 2022/08/06 18:26:43 andvar Exp $ */
29ac4c420Smatt
39ac4c420Smatt /*-
49ac4c420Smatt * Copyright (c) 2013 The NetBSD Foundation, Inc.
59ac4c420Smatt * All rights reserved.
69ac4c420Smatt *
79ac4c420Smatt * This code is derived from software contributed to The NetBSD Foundation
89ac4c420Smatt * by Matt Thomas of 3am Software Foundry.
99ac4c420Smatt *
109ac4c420Smatt * Redistribution and use in source and binary forms, with or without
119ac4c420Smatt * modification, are permitted provided that the following conditions
129ac4c420Smatt * are met:
139ac4c420Smatt * 1. Redistributions of source code must retain the above copyright
149ac4c420Smatt * notice, this list of conditions and the following disclaimer.
159ac4c420Smatt * 2. Redistributions in binary form must reproduce the above copyright
169ac4c420Smatt * notice, this list of conditions and the following disclaimer in the
179ac4c420Smatt * documentation and/or other materials provided with the distribution.
189ac4c420Smatt *
199ac4c420Smatt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
209ac4c420Smatt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
219ac4c420Smatt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
229ac4c420Smatt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
239ac4c420Smatt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
249ac4c420Smatt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
259ac4c420Smatt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
269ac4c420Smatt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279ac4c420Smatt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
289ac4c420Smatt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
299ac4c420Smatt * POSSIBILITY OF SUCH DAMAGE.
309ac4c420Smatt */
319ac4c420Smatt
329ac4c420Smatt #include <sys/cdefs.h>
339ac4c420Smatt
349ac4c420Smatt #ifndef lint
35*6478b405Sandvar __RCSID("$NetBSD: arm.c,v 1.6 2022/08/06 18:26:43 andvar Exp $");
369ac4c420Smatt #endif /* not lint */
379ac4c420Smatt
389ac4c420Smatt #include <sys/types.h>
399ac4c420Smatt #include <sys/cpuio.h>
409ac4c420Smatt #include <sys/sysctl.h>
419ac4c420Smatt #include <stdio.h>
429ac4c420Smatt #include <stdbool.h>
439ac4c420Smatt #include <stdlib.h>
449ac4c420Smatt #include <string.h>
459ac4c420Smatt #include <inttypes.h>
469ac4c420Smatt #include <err.h>
479ac4c420Smatt
489ac4c420Smatt #include "../cpuctl.h"
499ac4c420Smatt
509ac4c420Smatt static const char * const id_isar_fieldnames[][8] = {
519ac4c420Smatt {
529ac4c420Smatt "Swap", "Bitcount", "Bitfield", "CmpBranch",
539ac4c420Smatt "Coproc", "Debug", "Divde", NULL
549ac4c420Smatt }, {
559ac4c420Smatt "Endian", "Except", "Except_AR", "Extend",
569ac4c420Smatt "IfThen", "Immediate", "Interwork", "Jazelle"
579ac4c420Smatt }, {
589ac4c420Smatt "LoadStore", "MemHint", "MultAccessInt", "Mult",
599ac4c420Smatt "MultS", "MultU", "PSR_AR", "Reversal"
609ac4c420Smatt }, {
619ac4c420Smatt "Saturate", "SIMD", "SVC", "SynchPrim",
629ac4c420Smatt "TabBranch", "ThumbCopy", "TrueNOP", "ThumbEE_Extn"
639ac4c420Smatt }, {
649ac4c420Smatt "Unpriv", "WithShifts", "Writeback", "SMC",
659ac4c420Smatt "Barrier", "SynchPrim_frac", "PSR_M", "SWP"
669ac4c420Smatt }
679ac4c420Smatt };
689ac4c420Smatt
699ac4c420Smatt static const uint8_t id_isar_boolean[] = {
709ac4c420Smatt 0x2f, 0xb7, 0x41, 0xf5, 0xfc
719ac4c420Smatt };
729ac4c420Smatt
739ac4c420Smatt static const char * const id_mmfr_fieldnames[][8] = {
749ac4c420Smatt {
759ac4c420Smatt "VMSA-Support",
769ac4c420Smatt "PMSA-Support",
77*6478b405Sandvar "Outermost-Shareability",
789ac4c420Smatt "Shareability-Levels",
799ac4c420Smatt "TCM-Support",
805e4e6222Smsaitoh "Auxiliary-Registers",
819ac4c420Smatt "FCSE-Support",
829ac4c420Smatt "Innermost-Shareability"
839ac4c420Smatt }, {
849ac4c420Smatt "L1-Harvard-Cache-VA",
859ac4c420Smatt "L1-Unified-Cache-VA",
869ac4c420Smatt "L1-Harvard-Cache-Set/Way",
879ac4c420Smatt "L1-Unified-Cache-Set/Way",
889ac4c420Smatt "L1-Harvard-Cache",
899ac4c420Smatt "L1-Unified-Cache",
909ac4c420Smatt "L1-Cache-Test-and-Clean",
919ac4c420Smatt "Branch-Predictor",
929ac4c420Smatt }, {
939ac4c420Smatt "L1-Harvard-Foreground-Fetch",
949ac4c420Smatt "L1-Unified-Background-Fetch",
959ac4c420Smatt "L1-Harvard-Range",
969ac4c420Smatt "Harvard-TLB",
979ac4c420Smatt "Unified-TLB",
989ac4c420Smatt "Mem-Barrier",
999ac4c420Smatt "WFI-Stall",
1009ac4c420Smatt "HW-Access",
1019ac4c420Smatt }, {
1029ac4c420Smatt "Cache-Maintenance-MVA",
1039ac4c420Smatt "Cache-Maintenance-Set/Way",
1049ac4c420Smatt "BP-Maintenance",
1059ac4c420Smatt "Maintenance-Broadcast",
1069ac4c420Smatt NULL,
1079ac4c420Smatt "Coherent-Tablewalk",
1089ac4c420Smatt "Cached-Memory-Size",
1099ac4c420Smatt "Supersection-Support",
1109ac4c420Smatt },
1119ac4c420Smatt };
1129ac4c420Smatt
1139ac4c420Smatt static const uint8_t id_mmfr_present[] = {
1149ac4c420Smatt 0x8c, 0x00, 0x00, 0x68
1159ac4c420Smatt };
1169ac4c420Smatt
1179ac4c420Smatt static const char * const id_pfr_fieldnames[][8] = {
1189ac4c420Smatt {
1199ac4c420Smatt "ThumbEE",
1209ac4c420Smatt "Jazelle",
1219ac4c420Smatt "Thumb",
1229ac4c420Smatt "ARM",
1239ac4c420Smatt }, {
1249ac4c420Smatt "Programmer",
1259ac4c420Smatt "Security",
1269ac4c420Smatt "M-profile",
1279ac4c420Smatt "Virtualization",
1289ac4c420Smatt "Generic-Timer",
1299ac4c420Smatt },
1309ac4c420Smatt };
1319ac4c420Smatt
1329ac4c420Smatt static const char * const id_mvfr_fieldnames[][8] = {
1339ac4c420Smatt {
1349ac4c420Smatt "ASIMD-Registers",
1359ac4c420Smatt "Single-Precision",
1369ac4c420Smatt "Double-Precision",
1379ac4c420Smatt "VFP-Exception-Trapping",
1389ac4c420Smatt "Divide",
1399ac4c420Smatt "Square-Root",
1409ac4c420Smatt "Short-Vectors",
1419ac4c420Smatt "VFP-Rounding-Modes",
1429ac4c420Smatt }, {
1439ac4c420Smatt "Flush-To-Zero",
1449ac4c420Smatt "Default-NaN",
1459ac4c420Smatt "ASIMD-Load/Store",
1469ac4c420Smatt "ASIMD-Integer",
1479ac4c420Smatt "ASIMD-SPFP",
1489ac4c420Smatt "ASIMD-HPFP",
1499ac4c420Smatt "VFP-HPFP",
1509ac4c420Smatt "ASIMD-FMAC",
1519ac4c420Smatt },
1529ac4c420Smatt };
1539ac4c420Smatt
1549ac4c420Smatt static const uint8_t id_mvfr_present[] = {
1559ac4c420Smatt 0x80, 0x03,
1569ac4c420Smatt };
1579ac4c420Smatt
1589ac4c420Smatt 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)1599ac4c420Smatt print_features(const char *cpuname, const char *setname,
1609ac4c420Smatt const int *id_data, size_t id_len, const char * const id_fieldnames[][8],
1619ac4c420Smatt size_t id_nfieldnames, const uint8_t *id_boolean, const uint8_t *id_present)
1629ac4c420Smatt {
1639ac4c420Smatt char buf[81];
1649ac4c420Smatt size_t len = 0;
1659ac4c420Smatt const char *sep = "";
1669ac4c420Smatt for (size_t i = 0; i < id_len / sizeof(id_data[0]); i++) {
1679ac4c420Smatt int isar = id_data[i];
1689ac4c420Smatt for (u_int j = 0; isar != 0 && j < 8; j++, isar >>= 4) {
1699ac4c420Smatt const char *name = NULL;
1709ac4c420Smatt const char *value = "";
17137649e40Smrg char namebuf[24], valuebuf[12], tmpbuf[30];
1729ac4c420Smatt if ((isar & 0x0f) == 0
1739ac4c420Smatt && (id_present == NULL
1749ac4c420Smatt || (id_present[i] & (1 << j))) == 0) {
1759ac4c420Smatt continue;
1769ac4c420Smatt }
1779ac4c420Smatt if (len == 0) {
1789ac4c420Smatt len = snprintf(buf, sizeof(buf),
1799ac4c420Smatt "%s: %s: ", cpuname, setname);
1809ac4c420Smatt }
1819ac4c420Smatt if (i < id_nfieldnames) {
1829ac4c420Smatt name = id_fieldnames[i][j];
1839ac4c420Smatt }
1849ac4c420Smatt if (name == NULL) {
1859ac4c420Smatt name = namebuf;
1869ac4c420Smatt snprintf(namebuf, sizeof(namebuf),
1879ac4c420Smatt "%zu[%u]", i, j);
1889ac4c420Smatt }
1899ac4c420Smatt if (id_boolean == NULL
1909ac4c420Smatt || (id_boolean[i] & (1 << j)) == 0
1919ac4c420Smatt || (isar & 0xe) != 0) {
1929ac4c420Smatt value = valuebuf;
1939ac4c420Smatt snprintf(valuebuf, sizeof(valuebuf),
1949ac4c420Smatt "=%u", isar & 0x0f);
1959ac4c420Smatt }
1969ac4c420Smatt size_t tmplen = snprintf(tmpbuf, sizeof(tmpbuf),
1979ac4c420Smatt "%s%s%s", sep, name, value);
1989ac4c420Smatt if (len + tmplen > 78) {
1999ac4c420Smatt printf("%s\n", buf);
2009ac4c420Smatt len = snprintf(buf, sizeof(buf),
2019ac4c420Smatt "%s: %s: %s", cpuname, setname, tmpbuf + 2);
2029ac4c420Smatt } else {
2039ac4c420Smatt len = strlcat(buf, tmpbuf, sizeof(buf));
2049ac4c420Smatt }
2059ac4c420Smatt sep = ", ";
2069ac4c420Smatt }
2079ac4c420Smatt }
2089ac4c420Smatt if (len > 0) {
2099ac4c420Smatt printf("%s\n", buf);
2109ac4c420Smatt }
2119ac4c420Smatt }
2129ac4c420Smatt
2138ea87328Smrg bool
identifycpu_bind(void)2148ea87328Smrg identifycpu_bind(void)
2158ea87328Smrg {
2168ea87328Smrg
2178ea87328Smrg return false;
2188ea87328Smrg }
2198ea87328Smrg
2209ac4c420Smatt void
identifycpu(int fd,const char * cpuname)2219ac4c420Smatt identifycpu(int fd, const char *cpuname)
2229ac4c420Smatt {
2239ac4c420Smatt int *id_data;
2249ac4c420Smatt size_t id_isar_len = 0;
2259ac4c420Smatt size_t id_mmfr_len = 0;
2269ac4c420Smatt size_t id_pfr_len = 0;
2279ac4c420Smatt size_t id_mvfr_len = 0;
2289ac4c420Smatt
2299ac4c420Smatt if (sysctlbyname("machdep.id_isar", NULL, &id_isar_len, NULL, 0) < 0
2309ac4c420Smatt || sysctlbyname("machdep.id_mmfr", NULL, &id_mmfr_len, NULL, 0) < 0
2319ac4c420Smatt || sysctlbyname("machdep.id_pfr", NULL, &id_pfr_len, NULL, 0) < 0
2329ac4c420Smatt || sysctlbyname("machdep.id_mvfr", NULL, &id_mvfr_len, NULL, 0) < 0) {
2339ac4c420Smatt warn("sysctlbyname");
2349ac4c420Smatt return;
2359ac4c420Smatt }
2369ac4c420Smatt
2379ac4c420Smatt id_data = malloc(id_isar_len);
2389ac4c420Smatt
2399ac4c420Smatt sysctlbyname("machdep.id_isar", id_data, &id_isar_len, NULL, 0);
2409ac4c420Smatt print_features(cpuname, "isa features", id_data, id_isar_len,
2419ac4c420Smatt id_isar_fieldnames, __arraycount(id_isar_fieldnames),
2429ac4c420Smatt id_isar_boolean, NULL);
2439ac4c420Smatt
2449ac4c420Smatt free(id_data);
2459ac4c420Smatt id_data = malloc(id_mmfr_len);
2469ac4c420Smatt
2479ac4c420Smatt sysctlbyname("machdep.id_mmfr", id_data, &id_mmfr_len, NULL, 0);
2489ac4c420Smatt print_features(cpuname, "memory model", id_data, id_mmfr_len,
2499ac4c420Smatt id_mmfr_fieldnames, __arraycount(id_mmfr_fieldnames),
2509ac4c420Smatt NULL /*id_mmfr_boolean*/, id_mmfr_present);
2519ac4c420Smatt
2529ac4c420Smatt free(id_data);
2539ac4c420Smatt id_data = malloc(id_pfr_len);
2549ac4c420Smatt
2559ac4c420Smatt sysctlbyname("machdep.id_pfr", id_data, &id_pfr_len, NULL, 0);
2569ac4c420Smatt print_features(cpuname, "processor features", id_data, id_pfr_len,
2579ac4c420Smatt id_pfr_fieldnames, __arraycount(id_pfr_fieldnames),
2589ac4c420Smatt NULL /*id_pfr_boolean*/, NULL /*id_pfr_present*/);
2599ac4c420Smatt
2609ac4c420Smatt free(id_data);
2619ac4c420Smatt id_data = malloc(id_mvfr_len);
2629ac4c420Smatt
2639ac4c420Smatt sysctlbyname("machdep.id_mvfr", id_data, &id_mvfr_len, NULL, 0);
2649ac4c420Smatt print_features(cpuname, "media and VFP features", id_data, id_mvfr_len,
2659ac4c420Smatt id_mvfr_fieldnames, __arraycount(id_mvfr_fieldnames),
2669ac4c420Smatt NULL /*id_mvfr_boolean*/, id_mvfr_present);
2679ac4c420Smatt
2689ac4c420Smatt free(id_data);
2699ac4c420Smatt }
2709ac4c420Smatt
2719ac4c420Smatt int
ucodeupdate_check(int fd,struct cpu_ucode * uc)2729ac4c420Smatt ucodeupdate_check(int fd, struct cpu_ucode *uc)
2739ac4c420Smatt {
2749ac4c420Smatt
2759ac4c420Smatt return 0;
2769ac4c420Smatt }
277