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