1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
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)
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 #define ATTRIBUTE_UNUSED __attribute__((unused))
26 static inline uint_t __attribute_const__
27 __get_cpuid (unsigned int op ATTRIBUTE_UNUSED
, unsigned int *eax
,
28 unsigned int *ebx ATTRIBUTE_UNUSED
,
29 unsigned int *ecx ATTRIBUTE_UNUSED
, unsigned int *edx ATTRIBUTE_UNUSED
)
31 // CPUID bit assignments:
32 // [31:24] IMPLEMENTER (0x50 - ARM_CPU_IMP_APM)
33 // [23:20] VARIANT indicates processor revision (0x2 = Revision 2)
34 // [19:16] Constant (Reads as 0xF)
35 // [15:04] PARTNO indicates part number (0xC23 = Cortex-M3)
36 // [03:00] REVISION indicates patch release (0x0 = Patch 0)
37 // unsigned long v = 0;
38 // __asm volatile ("MRS %[result], MPIDR_EL1" : [result] "=r" (v));
39 // Tprintf(DBG_LT0, "cpuid.c:%d read_cpuid_id() MPIDR_EL1=0x%016lx\n", __LINE__, v);
41 __asm
volatile ("MRS %[result], MIDR_EL1" : [result
] "=r" (*eax
));
42 Tprintf (DBG_LT0
, "cpuid.c:%d read_cpuid_id() MIDR_EL1=0x%016x\n", __LINE__
, *eax
);
45 #elif defined(__riscv)
47 #include <sys/syscall.h>
49 #include <asm/hwprobe.h>
53 * Various routines to handle identification
54 * and classification of x86 processors.
57 #define IS_GLOBAL /* externally visible */
58 #define X86_VENDOR_Intel 0
59 #define X86_VENDORSTR_Intel "GenuineIntel"
60 #define X86_VENDOR_IntelClone 1
61 #define X86_VENDOR_AMD 2
62 #define X86_VENDORSTR_AMD "AuthenticAMD"
64 #define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
65 #define CPI_FAMILY_XTD(reg) BITX(reg, 27, 20)
66 #define CPI_MODEL_XTD(reg) BITX(reg, 19, 16)
67 #define CPI_TYPE(reg) BITX(reg, 13, 12)
68 #define CPI_FAMILY(reg) BITX(reg, 11, 8)
69 #define CPI_STEP(reg) BITX(reg, 3, 0)
70 #define CPI_MODEL(reg) BITX(reg, 7, 4)
71 #define IS_EXTENDED_MODEL_INTEL(model) ((model) == 0x6 || (model) >= 0xf)
84 unsigned int cpi_model
;
85 unsigned int cpi_family
;
86 unsigned int cpi_vendor
; /* enum of cpi_vendorstr */
87 unsigned int cpi_maxeax
; /* fn 0: %eax */
88 char cpi_vendorstr
[13]; /* fn 0: %ebx:%ecx:%edx */
92 #if defined(__i386__) || defined(__x86_64)
94 cpuid_vendorstr_to_vendorcode (char *vendorstr
)
96 if (strcmp (vendorstr
, X86_VENDORSTR_Intel
) == 0)
97 return X86_VENDOR_Intel
;
98 else if (strcmp (vendorstr
, X86_VENDORSTR_AMD
) == 0)
99 return X86_VENDOR_AMD
;
101 return X86_VENDOR_IntelClone
;
105 my_cpuid (unsigned int op
, cpuid_regs_t
*regs
)
107 regs
->eax
= regs
->ebx
= regs
->ecx
= regs
->edx
= 0;
108 int ret
= __get_cpuid (op
, ®s
->eax
, ®s
->ebx
, ®s
->ecx
, ®s
->edx
);
109 TprintfT (DBG_LT1
, "my_cpuid: __get_cpuid(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) returns %d\n",
110 op
, regs
->eax
, regs
->ebx
, regs
->ecx
, regs
->edx
, ret
);
115 static cpuid_info_t
*
118 static int cpuid_inited
= 0;
119 static cpuid_info_t cpuid_info
;
120 cpuid_info_t
*cpi
= &cpuid_info
;
125 #if defined(__aarch64__)
126 // CPUID bit assignments:
127 // [31:24] IMPLEMENTER (0x50 - ARM_CPU_IMP_APM)
128 // [23:20] VARIANT indicates processor revision (0x2 = Revision 2)
129 // [19:16] Constant (Reads as 0xF)
130 // [15:04] PARTNO indicates part number (0xC23 = Cortex-M3)
131 // [03:00] REVISION indicates patch release (0x0 = Patch 0)
133 __asm
volatile ("MRS %[result], MIDR_EL1" : [result
] "=r" (reg
));
134 cpi
->cpi_vendor
= reg
>> 24;
135 cpi
->cpi_model
= (reg
>> 4) & 0xfff;
136 switch (cpi
->cpi_vendor
)
138 case ARM_CPU_IMP_APM
:
139 case ARM_CPU_IMP_ARM
:
140 case ARM_CPU_IMP_CAVIUM
:
141 case ARM_CPU_IMP_BRCM
:
142 case ARM_CPU_IMP_QCOM
:
143 strncpy (cpi
->cpi_vendorstr
, AARCH64_VENDORSTR_ARM
, sizeof (cpi
->cpi_vendorstr
));
146 strncpy (cpi
->cpi_vendorstr
, "UNKNOWN ARM", sizeof (cpi
->cpi_vendorstr
));
149 Tprintf (DBG_LT0
, "cpuid.c:%d read_cpuid_id() MIDR_EL1==0x%016x cpi_vendor=%d cpi_model=%d\n",
150 __LINE__
, (unsigned int) reg
, cpi
->cpi_vendor
, cpi
->cpi_model
);
152 #elif defined(__i386__) || defined(__x86_64)
155 cpi
->cpi_maxeax
= regs
.eax
;
156 ((uint32_t *) cpi
->cpi_vendorstr
)[0] = regs
.ebx
;
157 ((uint32_t *) cpi
->cpi_vendorstr
)[1] = regs
.edx
;
158 ((uint32_t *) cpi
->cpi_vendorstr
)[2] = regs
.ecx
;
159 cpi
->cpi_vendorstr
[12] = 0;
160 cpi
->cpi_vendor
= cpuid_vendorstr_to_vendorcode (cpi
->cpi_vendorstr
);
163 cpi
->cpi_model
= CPI_MODEL (regs
.eax
);
164 cpi
->cpi_family
= CPI_FAMILY (regs
.eax
);
165 if (cpi
->cpi_family
== 0xf)
166 cpi
->cpi_family
+= CPI_FAMILY_XTD (regs
.eax
);
169 * Beware: AMD uses "extended model" iff base *FAMILY* == 0xf.
170 * Intel, and presumably everyone else, uses model == 0xf, as
171 * one would expect (max value means possible overflow). Sigh.
173 switch (cpi
->cpi_vendor
)
175 case X86_VENDOR_Intel
:
176 if (IS_EXTENDED_MODEL_INTEL (cpi
->cpi_family
))
177 cpi
->cpi_model
+= CPI_MODEL_XTD (regs
.eax
) << 4;
180 if (CPI_FAMILY (cpi
->cpi_family
) == 0xf)
181 cpi
->cpi_model
+= CPI_MODEL_XTD (regs
.eax
) << 4;
184 if (cpi
->cpi_model
== 0xf)
185 cpi
->cpi_model
+= CPI_MODEL_XTD (regs
.eax
) << 4;
188 #elif defined(__riscv)
189 #ifndef __riscv_hwprobe
194 struct riscv_hwprobe res
;
195 res
.key
= RISCV_HWPROBE_KEY_MVENDORID
;
197 int __riscv_hwprobe (struct riscv_hwprobe
*pairs
, \
198 long pair_count
, long cpu_count
, \
199 unsigned long *cpus
, unsigned long flags
) \
201 return syscall(__NR_riscv_hwprobe
, pairs
, pair_count
, cpu_count
, cpus
, flags
);
204 CPU_SET(0, &cpu_set
);
205 long ret
= __riscv_hwprobe(&res
, 1, 1, &cpu_set
, 0);
206 cpi
->cpi_vendor
= res
.value
;
217 return get_cpuid_info ()->cpi_vendor
;
223 return get_cpuid_info ()->cpi_family
;
229 return get_cpuid_info ()->cpi_model
;