mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
76bdc7266a
This adds 'Innovative Computing Labs' as an external author to update-copyright.py, to cover the copyright notice in gprofng/common/opteron_pcbe.c, and uses that plus another external author 'Oracle and' to update gprofng copyright dates. I'm not going to commit 'Oracle and' as an accepted author, but that covers the string "Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved." found in gprofng/testsuite/gprofng.display/jsynprog files.
204 lines
6.3 KiB
C
204 lines
6.3 KiB
C
/* Copyright (C) 2021-2023 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#if defined(__i386__) || defined(__x86_64)
|
|
#include <cpuid.h> /* GCC-provided */
|
|
#elif defined(__aarch64__)
|
|
#define ATTRIBUTE_UNUSED __attribute__((unused))
|
|
|
|
static inline uint_t __attribute_const__
|
|
__get_cpuid (unsigned int op ATTRIBUTE_UNUSED, unsigned int *eax,
|
|
unsigned int *ebx ATTRIBUTE_UNUSED,
|
|
unsigned int *ecx ATTRIBUTE_UNUSED, unsigned int *edx ATTRIBUTE_UNUSED)
|
|
{
|
|
// CPUID bit assignments:
|
|
// [31:24] IMPLEMENTER (0x50 - ARM_CPU_IMP_APM)
|
|
// [23:20] VARIANT indicates processor revision (0x2 = Revision 2)
|
|
// [19:16] Constant (Reads as 0xF)
|
|
// [15:04] PARTNO indicates part number (0xC23 = Cortex-M3)
|
|
// [03:00] REVISION indicates patch release (0x0 = Patch 0)
|
|
// unsigned long v = 0;
|
|
// __asm volatile ("MRS %[result], MPIDR_EL1" : [result] "=r" (v));
|
|
// Tprintf(DBG_LT0, "cpuid.c:%d read_cpuid_id() MPIDR_EL1=0x%016lx\n", __LINE__, v);
|
|
uint_t res = 0;
|
|
__asm volatile ("MRS %[result], MIDR_EL1" : [result] "=r" (*eax));
|
|
Tprintf (DBG_LT0, "cpuid.c:%d read_cpuid_id() MIDR_EL1=0x%016x\n", __LINE__, *eax);
|
|
return res;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Various routines to handle identification
|
|
* and classification of x86 processors.
|
|
*/
|
|
|
|
#define IS_GLOBAL /* externally visible */
|
|
#define X86_VENDOR_Intel 0
|
|
#define X86_VENDORSTR_Intel "GenuineIntel"
|
|
#define X86_VENDOR_IntelClone 1
|
|
#define X86_VENDOR_AMD 2
|
|
#define X86_VENDORSTR_AMD "AuthenticAMD"
|
|
|
|
#define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
|
|
#define CPI_FAMILY_XTD(reg) BITX(reg, 27, 20)
|
|
#define CPI_MODEL_XTD(reg) BITX(reg, 19, 16)
|
|
#define CPI_TYPE(reg) BITX(reg, 13, 12)
|
|
#define CPI_FAMILY(reg) BITX(reg, 11, 8)
|
|
#define CPI_STEP(reg) BITX(reg, 3, 0)
|
|
#define CPI_MODEL(reg) BITX(reg, 7, 4)
|
|
#define IS_EXTENDED_MODEL_INTEL(model) ((model) == 0x6 || (model) >= 0xf)
|
|
|
|
|
|
typedef struct
|
|
{
|
|
unsigned int eax;
|
|
unsigned int ebx;
|
|
unsigned int ecx;
|
|
unsigned int edx;
|
|
} cpuid_regs_t;
|
|
|
|
typedef struct
|
|
{
|
|
unsigned int cpi_model;
|
|
unsigned int cpi_family;
|
|
unsigned int cpi_vendor; /* enum of cpi_vendorstr */
|
|
unsigned int cpi_maxeax; /* fn 0: %eax */
|
|
char cpi_vendorstr[13]; /* fn 0: %ebx:%ecx:%edx */
|
|
} cpuid_info_t;
|
|
|
|
|
|
#if defined(__i386__) || defined(__x86_64)
|
|
static uint_t
|
|
cpuid_vendorstr_to_vendorcode (char *vendorstr)
|
|
{
|
|
if (strcmp (vendorstr, X86_VENDORSTR_Intel) == 0)
|
|
return X86_VENDOR_Intel;
|
|
else if (strcmp (vendorstr, X86_VENDORSTR_AMD) == 0)
|
|
return X86_VENDOR_AMD;
|
|
else
|
|
return X86_VENDOR_IntelClone;
|
|
}
|
|
|
|
static int
|
|
my_cpuid (unsigned int op, cpuid_regs_t *regs)
|
|
{
|
|
regs->eax = regs->ebx = regs->ecx = regs->edx = 0;
|
|
int ret = __get_cpuid (op, ®s->eax, ®s->ebx, ®s->ecx, ®s->edx);
|
|
TprintfT (DBG_LT1, "my_cpuid: __get_cpuid(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) returns %d\n",
|
|
op, regs->eax, regs->ebx, regs->ecx, regs->edx, ret);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static cpuid_info_t *
|
|
get_cpuid_info ()
|
|
{
|
|
static int cpuid_inited = 0;
|
|
static cpuid_info_t cpuid_info;
|
|
cpuid_info_t *cpi = &cpuid_info;
|
|
if (cpuid_inited)
|
|
return cpi;
|
|
cpuid_inited = 1;
|
|
|
|
#if defined(__aarch64__)
|
|
// CPUID bit assignments:
|
|
// [31:24] IMPLEMENTER (0x50 - ARM_CPU_IMP_APM)
|
|
// [23:20] VARIANT indicates processor revision (0x2 = Revision 2)
|
|
// [19:16] Constant (Reads as 0xF)
|
|
// [15:04] PARTNO indicates part number (0xC23 = Cortex-M3)
|
|
// [03:00] REVISION indicates patch release (0x0 = Patch 0)
|
|
uint_t reg = 0;
|
|
__asm volatile ("MRS %[result], MIDR_EL1" : [result] "=r" (reg));
|
|
cpi->cpi_vendor = reg >> 24;
|
|
cpi->cpi_model = (reg >> 4) & 0xfff;
|
|
switch (cpi->cpi_vendor)
|
|
{
|
|
case ARM_CPU_IMP_APM:
|
|
case ARM_CPU_IMP_ARM:
|
|
case ARM_CPU_IMP_CAVIUM:
|
|
case ARM_CPU_IMP_BRCM:
|
|
case ARM_CPU_IMP_QCOM:
|
|
strncpy (cpi->cpi_vendorstr, AARCH64_VENDORSTR_ARM, sizeof (cpi->cpi_vendorstr));
|
|
break;
|
|
default:
|
|
strncpy (cpi->cpi_vendorstr, "UNKNOWN ARM", sizeof (cpi->cpi_vendorstr));
|
|
break;
|
|
}
|
|
Tprintf (DBG_LT0, "cpuid.c:%d read_cpuid_id() MIDR_EL1==0x%016x cpi_vendor=%d cpi_model=%d\n",
|
|
__LINE__, (unsigned int) reg, cpi->cpi_vendor, cpi->cpi_model);
|
|
|
|
#elif defined(__i386__) || defined(__x86_64)
|
|
cpuid_regs_t regs;
|
|
my_cpuid (0, ®s);
|
|
cpi->cpi_maxeax = regs.eax;
|
|
((uint32_t *) cpi->cpi_vendorstr)[0] = regs.ebx;
|
|
((uint32_t *) cpi->cpi_vendorstr)[1] = regs.edx;
|
|
((uint32_t *) cpi->cpi_vendorstr)[2] = regs.ecx;
|
|
cpi->cpi_vendorstr[12] = 0;
|
|
cpi->cpi_vendor = cpuid_vendorstr_to_vendorcode (cpi->cpi_vendorstr);
|
|
|
|
my_cpuid (1, ®s);
|
|
cpi->cpi_model = CPI_MODEL (regs.eax);
|
|
cpi->cpi_family = CPI_FAMILY (regs.eax);
|
|
if (cpi->cpi_family == 0xf)
|
|
cpi->cpi_family += CPI_FAMILY_XTD (regs.eax);
|
|
|
|
/*
|
|
* Beware: AMD uses "extended model" iff base *FAMILY* == 0xf.
|
|
* Intel, and presumably everyone else, uses model == 0xf, as
|
|
* one would expect (max value means possible overflow). Sigh.
|
|
*/
|
|
switch (cpi->cpi_vendor)
|
|
{
|
|
case X86_VENDOR_Intel:
|
|
if (IS_EXTENDED_MODEL_INTEL (cpi->cpi_family))
|
|
cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
|
|
break;
|
|
case X86_VENDOR_AMD:
|
|
if (CPI_FAMILY (cpi->cpi_family) == 0xf)
|
|
cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
|
|
break;
|
|
default:
|
|
if (cpi->cpi_model == 0xf)
|
|
cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
|
|
break;
|
|
}
|
|
#endif
|
|
return cpi;
|
|
}
|
|
|
|
static inline uint_t
|
|
cpuid_getvendor ()
|
|
{
|
|
return get_cpuid_info ()->cpi_vendor;
|
|
}
|
|
|
|
static inline uint_t
|
|
cpuid_getfamily ()
|
|
{
|
|
return get_cpuid_info ()->cpi_family;
|
|
}
|
|
|
|
static inline uint_t
|
|
cpuid_getmodel ()
|
|
{
|
|
return get_cpuid_info ()->cpi_model;
|
|
}
|