[gdb] Fix tsan warning: signal handler spoils errno
[binutils-gdb.git] / gprofng / common / cpuid.c
blobb4caef54f578f01fcdfc83b32c4237f82e1eccf6
1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
2 Contributed by Oracle.
4 This file is part of GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
21 #if defined(__i386__) || defined(__x86_64)
22 #include <cpuid.h> /* GCC-provided */
23 #elif defined(__aarch64__)
24 #if !defined(ATTRIBUTE_UNUSED)
25 #define ATTRIBUTE_UNUSED __attribute__((unused))
26 #endif
28 static inline uint_t __attribute_const__
29 __get_cpuid (unsigned int op ATTRIBUTE_UNUSED, unsigned int *eax,
30 unsigned int *ebx ATTRIBUTE_UNUSED,
31 unsigned int *ecx ATTRIBUTE_UNUSED, unsigned int *edx ATTRIBUTE_UNUSED)
33 // CPUID bit assignments:
34 // [31:24] IMPLEMENTER (0x50 - ARM_CPU_IMP_APM)
35 // [23:20] VARIANT indicates processor revision (0x2 = Revision 2)
36 // [19:16] Constant (Reads as 0xF)
37 // [15:04] PARTNO indicates part number (0xC23 = Cortex-M3)
38 // [03:00] REVISION indicates patch release (0x0 = Patch 0)
39 // unsigned long v = 0;
40 // __asm volatile ("MRS %[result], MPIDR_EL1" : [result] "=r" (v));
41 // Tprintf(DBG_LT0, "cpuid.c:%d read_cpuid_id() MPIDR_EL1=0x%016lx\n", __LINE__, v);
42 uint_t res = 0;
43 __asm volatile ("MRS %[result], MIDR_EL1" : [result] "=r" (*eax));
44 Tprintf (DBG_LT0, "cpuid.c:%d read_cpuid_id() MIDR_EL1=0x%016x\n", __LINE__, *eax);
45 return res;
47 #elif defined(__riscv)
48 #include <sched.h>
49 #include <sys/syscall.h>
50 #include <unistd.h>
51 #include <asm/hwprobe.h>
52 #endif
55 * Various routines to handle identification
56 * and classification of x86 processors.
59 #define IS_GLOBAL /* externally visible */
60 #define X86_VENDOR_Intel 0
61 #define X86_VENDORSTR_Intel "GenuineIntel"
62 #define X86_VENDOR_IntelClone 1
63 #define X86_VENDOR_AMD 2
64 #define X86_VENDORSTR_AMD "AuthenticAMD"
66 #define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
67 #define CPI_FAMILY_XTD(reg) BITX(reg, 27, 20)
68 #define CPI_MODEL_XTD(reg) BITX(reg, 19, 16)
69 #define CPI_TYPE(reg) BITX(reg, 13, 12)
70 #define CPI_FAMILY(reg) BITX(reg, 11, 8)
71 #define CPI_STEP(reg) BITX(reg, 3, 0)
72 #define CPI_MODEL(reg) BITX(reg, 7, 4)
73 #define IS_EXTENDED_MODEL_INTEL(model) ((model) == 0x6 || (model) >= 0xf)
76 typedef struct
78 unsigned int eax;
79 unsigned int ebx;
80 unsigned int ecx;
81 unsigned int edx;
82 } cpuid_regs_t;
84 typedef struct
86 unsigned int cpi_model;
87 unsigned int cpi_family;
88 unsigned int cpi_vendor; /* enum of cpi_vendorstr */
89 unsigned int cpi_maxeax; /* fn 0: %eax */
90 char cpi_vendorstr[13]; /* fn 0: %ebx:%ecx:%edx */
91 } cpuid_info_t;
94 #if defined(__i386__) || defined(__x86_64)
95 static uint_t
96 cpuid_vendorstr_to_vendorcode (char *vendorstr)
98 if (strcmp (vendorstr, X86_VENDORSTR_Intel) == 0)
99 return X86_VENDOR_Intel;
100 else if (strcmp (vendorstr, X86_VENDORSTR_AMD) == 0)
101 return X86_VENDOR_AMD;
102 else
103 return X86_VENDOR_IntelClone;
106 static int
107 my_cpuid (unsigned int op, cpuid_regs_t *regs)
109 regs->eax = regs->ebx = regs->ecx = regs->edx = 0;
110 int ret = __get_cpuid (op, &regs->eax, &regs->ebx, &regs->ecx, &regs->edx);
111 TprintfT (DBG_LT1, "my_cpuid: __get_cpuid(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) returns %d\n",
112 op, regs->eax, regs->ebx, regs->ecx, regs->edx, ret);
113 return ret;
115 #endif
117 static cpuid_info_t *
118 get_cpuid_info ()
120 static int cpuid_inited = 0;
121 static cpuid_info_t cpuid_info;
122 cpuid_info_t *cpi = &cpuid_info;
123 if (cpuid_inited)
124 return cpi;
125 cpuid_inited = 1;
127 #if defined(__aarch64__)
128 // CPUID bit assignments:
129 // [31:24] IMPLEMENTER (0x50 - ARM_CPU_IMP_APM)
130 // [23:20] VARIANT indicates processor revision (0x2 = Revision 2)
131 // [19:16] Constant (Reads as 0xF)
132 // [15:04] PARTNO indicates part number (0xC23 = Cortex-M3)
133 // [03:00] REVISION indicates patch release (0x0 = Patch 0)
134 uint_t reg = 0;
135 __asm volatile ("MRS %[result], MIDR_EL1" : [result] "=r" (reg));
136 cpi->cpi_vendor = reg >> 24;
137 cpi->cpi_model = (reg >> 4) & 0xfff;
138 switch (cpi->cpi_vendor)
140 case ARM_CPU_IMP_APM:
141 case ARM_CPU_IMP_ARM:
142 case ARM_CPU_IMP_CAVIUM:
143 case ARM_CPU_IMP_BRCM:
144 case ARM_CPU_IMP_QCOM:
145 strncpy (cpi->cpi_vendorstr, AARCH64_VENDORSTR_ARM, sizeof (cpi->cpi_vendorstr));
146 break;
147 default:
148 strncpy (cpi->cpi_vendorstr, "UNKNOWN ARM", sizeof (cpi->cpi_vendorstr));
149 break;
151 Tprintf (DBG_LT0, "cpuid.c:%d read_cpuid_id() MIDR_EL1==0x%016x cpi_vendor=%d cpi_model=%d\n",
152 __LINE__, (unsigned int) reg, cpi->cpi_vendor, cpi->cpi_model);
154 #elif defined(__i386__) || defined(__x86_64)
155 cpuid_regs_t regs;
156 my_cpuid (0, &regs);
157 cpi->cpi_maxeax = regs.eax;
158 ((uint32_t *) cpi->cpi_vendorstr)[0] = regs.ebx;
159 ((uint32_t *) cpi->cpi_vendorstr)[1] = regs.edx;
160 ((uint32_t *) cpi->cpi_vendorstr)[2] = regs.ecx;
161 cpi->cpi_vendorstr[12] = 0;
162 cpi->cpi_vendor = cpuid_vendorstr_to_vendorcode (cpi->cpi_vendorstr);
164 my_cpuid (1, &regs);
165 cpi->cpi_model = CPI_MODEL (regs.eax);
166 cpi->cpi_family = CPI_FAMILY (regs.eax);
167 if (cpi->cpi_family == 0xf)
168 cpi->cpi_family += CPI_FAMILY_XTD (regs.eax);
171 * Beware: AMD uses "extended model" iff base *FAMILY* == 0xf.
172 * Intel, and presumably everyone else, uses model == 0xf, as
173 * one would expect (max value means possible overflow). Sigh.
175 switch (cpi->cpi_vendor)
177 case X86_VENDOR_Intel:
178 if (IS_EXTENDED_MODEL_INTEL (cpi->cpi_family))
179 cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
180 break;
181 case X86_VENDOR_AMD:
182 if (CPI_FAMILY (cpi->cpi_family) == 0xf)
183 cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
184 break;
185 default:
186 if (cpi->cpi_model == 0xf)
187 cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
188 break;
190 #elif defined(__riscv)
191 #ifndef __riscv_hwprobe
192 cpi->cpi_vendor = 0;
193 cpi->cpi_family = 0;
194 cpi->cpi_model = 0;
195 #else
196 struct riscv_hwprobe res;
197 res.key = RISCV_HWPROBE_KEY_MVENDORID;
198 cpu_set_t cpu_set;
199 int __riscv_hwprobe (struct riscv_hwprobe *pairs, \
200 long pair_count, long cpu_count, \
201 unsigned long *cpus, unsigned long flags) \
203 return syscall(__NR_riscv_hwprobe, pairs, pair_count, cpu_count, cpus, flags);
205 CPU_ZERO(&cpu_set);
206 CPU_SET(0, &cpu_set);
207 long ret = __riscv_hwprobe(&res, 1, 1, &cpu_set, 0);
208 cpi->cpi_vendor = res.value;
209 cpi->cpi_family = 0;
210 cpi->cpi_model = 0;
211 #endif
212 #endif
213 return cpi;
216 static inline uint_t
217 cpuid_getvendor ()
219 return get_cpuid_info ()->cpi_vendor;
222 static inline uint_t
223 cpuid_getfamily ()
225 return get_cpuid_info ()->cpi_family;
228 static inline uint_t
229 cpuid_getmodel ()
231 return get_cpuid_info ()->cpi_model;