Merge branch 'x86/cpu' into x86/core, to resolve conflicts

Conflicts:
	arch/x86/kernel/cpu/bugs.c

Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2025-05-13 10:37:01 +02:00
commit 2fb8414e64
54 changed files with 1721 additions and 1484 deletions

View File

@ -1097,7 +1097,7 @@ R: Carlos Bilbao <carlos.bilbao@kernel.org>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: Documentation/arch/x86/amd_hsmp.rst
F: arch/x86/include/asm/amd_hsmp.h
F: arch/x86/include/asm/amd/hsmp.h
F: arch/x86/include/uapi/asm/amd_hsmp.h
F: drivers/platform/x86/amd/hsmp/
@ -1142,7 +1142,7 @@ M: Mario Limonciello <mario.limonciello@amd.com>
M: Yazen Ghannam <yazen.ghannam@amd.com>
L: linux-kernel@vger.kernel.org
S: Supported
F: arch/x86/include/asm/amd_node.h
F: arch/x86/include/asm/amd/node.h
F: arch/x86/kernel/amd_node.c
AMD PDS CORE DRIVER
@ -26290,7 +26290,7 @@ R: Ahmed S. Darwish <darwi@linutronix.de>
L: x86-cpuid@lists.linux.dev
S: Maintained
W: https://x86-cpuid.org
F: tools/arch/x86/kcpuid/cpuid.csv
F: tools/arch/x86/kcpuid/
X86 ENTRY CODE
M: Andy Lutomirski <luto@kernel.org>

View File

@ -26,7 +26,7 @@ static u32 ibs_caps;
#include <linux/hardirq.h>
#include <asm/nmi.h>
#include <asm/amd-ibs.h>
#include <asm/amd/ibs.h>
/* attr.config2 */
#define IBS_SW_FILTER_MASK 1

View File

@ -1,5 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _ASM_X86_AMD_HSMP_H_
#define _ASM_X86_AMD_HSMP_H_
@ -13,4 +12,5 @@ static inline int hsmp_send_message(struct hsmp_message *msg)
return -ENODEV;
}
#endif
#endif /*_ASM_X86_AMD_HSMP_H_*/

View File

@ -1,4 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_X86_AMD_IBS_H
#define _ASM_X86_AMD_IBS_H
/*
* From PPR Vol 1 for AMD Family 19h Model 01h B1
* 55898 Rev 0.35 - Feb 5, 2021
@ -151,3 +154,5 @@ struct perf_ibs_data {
};
u64 regs[MSR_AMD64_IBS_REG_COUNT_MAX];
};
#endif /* _ASM_X86_AMD_IBS_H */

View File

@ -4,7 +4,7 @@
#include <linux/ioport.h>
#include <linux/pci.h>
#include <asm/amd_node.h>
#include <asm/amd/node.h>
struct amd_nb_bus_dev_range {
u8 bus;

View File

@ -476,11 +476,11 @@
#define X86_FEATURE_CLEAR_BHB_LOOP (21*32+ 1) /* Clear branch history at syscall entry using SW loop */
#define X86_FEATURE_BHI_CTRL (21*32+ 2) /* BHI_DIS_S HW control available */
#define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* BHI_DIS_S HW control enabled */
#define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */
#define X86_FEATURE_AMD_FAST_CPPC (21*32 + 5) /* Fast CPPC */
#define X86_FEATURE_AMD_HETEROGENEOUS_CORES (21*32 + 6) /* Heterogeneous Core Topology */
#define X86_FEATURE_AMD_WORKLOAD_CLASS (21*32 + 7) /* Workload Classification */
#define X86_FEATURE_PREFER_YMM (21*32 + 8) /* Avoid ZMM registers due to downclocking */
#define X86_FEATURE_CLEAR_BHB_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */
#define X86_FEATURE_AMD_FAST_CPPC (21*32+ 5) /* Fast CPPC */
#define X86_FEATURE_AMD_HTR_CORES (21*32+ 6) /* Heterogeneous Core Topology */
#define X86_FEATURE_AMD_WORKLOAD_CLASS (21*32+ 7) /* Workload Classification */
#define X86_FEATURE_PREFER_YMM (21*32+ 8) /* Avoid ZMM registers due to downclocking */
/*
* BUG word(s)
@ -519,7 +519,7 @@
#define X86_BUG_ITLB_MULTIHIT X86_BUG(23) /* "itlb_multihit" CPU may incur MCE during certain page attribute changes */
#define X86_BUG_SRBDS X86_BUG(24) /* "srbds" CPU may leak RNG bits if not mitigated */
#define X86_BUG_MMIO_STALE_DATA X86_BUG(25) /* "mmio_stale_data" CPU is affected by Processor MMIO Stale Data vulnerabilities */
#define X86_BUG_MMIO_UNKNOWN X86_BUG(26) /* "mmio_unknown" CPU is too old and its MMIO Stale Data status is unknown */
/* unused, was #define X86_BUG_MMIO_UNKNOWN X86_BUG(26) "mmio_unknown" CPU is too old and its MMIO Stale Data status is unknown */
#define X86_BUG_RETBLEED X86_BUG(27) /* "retbleed" CPU is affected by RETBleed */
#define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* "eibrs_pbrsb" EIBRS is vulnerable to Post Barrier RSB Predictions */
#define X86_BUG_SMT_RSB X86_BUG(29) /* "smt_rsb" CPU is vulnerable to Cross-Thread Return Address Predictions */
@ -527,10 +527,10 @@
#define X86_BUG_TDX_PW_MCE X86_BUG(31) /* "tdx_pw_mce" CPU may incur #MC if non-TD software does partial write to TDX private memory */
/* BUG word 2 */
#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* "srso" AMD SRSO bug */
#define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* "div0" AMD DIV0 speculation bug */
#define X86_BUG_RFDS X86_BUG(1*32 + 2) /* "rfds" CPU is vulnerable to Register File Data Sampling */
#define X86_BUG_BHI X86_BUG(1*32 + 3) /* "bhi" CPU is affected by Branch History Injection */
#define X86_BUG_IBPB_NO_RET X86_BUG(1*32 + 4) /* "ibpb_no_ret" IBPB omits return target predictions */
#define X86_BUG_SPECTRE_V2_USER X86_BUG(1*32 + 5) /* "spectre_v2_user" CPU is affected by Spectre variant 2 attack between user processes */
#define X86_BUG_SRSO X86_BUG( 1*32+ 0) /* "srso" AMD SRSO bug */
#define X86_BUG_DIV0 X86_BUG( 1*32+ 1) /* "div0" AMD DIV0 speculation bug */
#define X86_BUG_RFDS X86_BUG( 1*32+ 2) /* "rfds" CPU is vulnerable to Register File Data Sampling */
#define X86_BUG_BHI X86_BUG( 1*32+ 3) /* "bhi" CPU is affected by Branch History Injection */
#define X86_BUG_IBPB_NO_RET X86_BUG( 1*32+ 4) /* "ibpb_no_ret" IBPB omits return target predictions */
#define X86_BUG_SPECTRE_V2_USER X86_BUG( 1*32+ 5) /* "spectre_v2_user" CPU is affected by Spectre variant 2 attack between user processes */
#endif /* _ASM_X86_CPUFEATURES_H */

View File

@ -4,5 +4,6 @@
#define _ASM_X86_CPUID_H
#include <asm/cpuid/api.h>
#include <asm/cpuid/leaf_0x2_api.h>
#endif /* _ASM_X86_CPUID_H */

View File

@ -36,9 +36,9 @@ static inline void native_cpuid(u32 *eax, u32 *ebx,
}
#define NATIVE_CPUID_REG(reg) \
static inline u32 native_cpuid_##reg(u32 op) \
static inline u32 native_cpuid_##reg(u32 op) \
{ \
u32 eax = op, ebx, ecx = 0, edx; \
u32 eax = op, ebx, ecx = 0, edx; \
\
native_cpuid(&eax, &ebx, &ecx, &edx); \
\
@ -207,4 +207,13 @@ static inline u32 hypervisor_cpuid_base(const char *sig, u32 leaves)
return 0;
}
/*
* CPUID(0x80000006) parsing helpers
*/
static inline bool cpuid_amd_hygon_has_l3_cache(void)
{
return cpuid_edx(0x80000006);
}
#endif /* _ASM_X86_CPUID_API_H */

View File

@ -0,0 +1,73 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_X86_CPUID_LEAF_0x2_API_H
#define _ASM_X86_CPUID_LEAF_0x2_API_H
#include <asm/cpuid/api.h>
#include <asm/cpuid/types.h>
/**
* cpuid_get_leaf_0x2_regs() - Return sanitized leaf 0x2 register output
* @regs: Output parameter
*
* Query CPUID leaf 0x2 and store its output in @regs. Force set any
* invalid 1-byte descriptor returned by the hardware to zero (the NULL
* cache/TLB descriptor) before returning it to the caller.
*
* Use for_each_leaf_0x2_entry() to iterate over the register output in
* parsed form.
*/
static inline void cpuid_get_leaf_0x2_regs(union leaf_0x2_regs *regs)
{
cpuid_leaf(0x2, regs);
/*
* All Intel CPUs must report an iteration count of 1. In case
* of bogus hardware, treat all returned descriptors as NULL.
*/
if (regs->desc[0] != 0x01) {
for (int i = 0; i < 4; i++)
regs->regv[i] = 0;
return;
}
/*
* The most significant bit (MSB) of each register must be clear.
* If a register is invalid, replace its descriptors with NULL.
*/
for (int i = 0; i < 4; i++) {
if (regs->reg[i].invalid)
regs->regv[i] = 0;
}
}
/**
* for_each_leaf_0x2_entry() - Iterator for parsed leaf 0x2 descriptors
* @regs: Leaf 0x2 register output, returned by cpuid_get_leaf_0x2_regs()
* @__ptr: u8 pointer, for macro internal use only
* @entry: Pointer to parsed descriptor information at each iteration
*
* Loop over the 1-byte descriptors in the passed leaf 0x2 output registers
* @regs. Provide the parsed information for each descriptor through @entry.
*
* To handle cache-specific descriptors, switch on @entry->c_type. For TLB
* descriptors, switch on @entry->t_type.
*
* Example usage for cache descriptors::
*
* const struct leaf_0x2_table *entry;
* union leaf_0x2_regs regs;
* u8 *ptr;
*
* cpuid_get_leaf_0x2_regs(&regs);
* for_each_leaf_0x2_entry(regs, ptr, entry) {
* switch (entry->c_type) {
* ...
* }
* }
*/
#define for_each_leaf_0x2_entry(regs, __ptr, entry) \
for (__ptr = &(regs).desc[1]; \
__ptr < &(regs).desc[16] && (entry = &cpuid_0x2_table[*__ptr]); \
__ptr++)
#endif /* _ASM_X86_CPUID_LEAF_0x2_API_H */

View File

@ -2,6 +2,7 @@
#ifndef _ASM_X86_CPUID_TYPES_H
#define _ASM_X86_CPUID_TYPES_H
#include <linux/build_bug.h>
#include <linux/types.h>
/*
@ -29,4 +30,99 @@ enum cpuid_regs_idx {
#define CPUID_LEAF_FREQ 0x16
#define CPUID_LEAF_TILE 0x1d
/*
* Types for CPUID(0x2) parsing
* Check <asm/cpuid/leaf_0x2_api.h>
*/
struct leaf_0x2_reg {
u32 : 31,
invalid : 1;
};
union leaf_0x2_regs {
struct leaf_0x2_reg reg[4];
u32 regv[4];
u8 desc[16];
};
/*
* Leaf 0x2 1-byte descriptors' cache types
* To be used for their mappings at cpuid_0x2_table[]
*
* Start at 1 since type 0 is reserved for HW byte descriptors which are
* not recognized by the kernel; i.e., those without an explicit mapping.
*/
enum _cache_table_type {
CACHE_L1_INST = 1,
CACHE_L1_DATA,
CACHE_L2,
CACHE_L3
/* Adjust __TLB_TABLE_TYPE_BEGIN before adding more types */
} __packed;
#ifndef __CHECKER__
static_assert(sizeof(enum _cache_table_type) == 1);
#endif
/*
* Ensure that leaf 0x2 cache and TLB type values do not intersect,
* since they share the same type field at struct cpuid_0x2_table.
*/
#define __TLB_TABLE_TYPE_BEGIN (CACHE_L3 + 1)
/*
* Leaf 0x2 1-byte descriptors' TLB types
* To be used for their mappings at cpuid_0x2_table[]
*/
enum _tlb_table_type {
TLB_INST_4K = __TLB_TABLE_TYPE_BEGIN,
TLB_INST_4M,
TLB_INST_2M_4M,
TLB_INST_ALL,
TLB_DATA_4K,
TLB_DATA_4M,
TLB_DATA_2M_4M,
TLB_DATA_4K_4M,
TLB_DATA_1G,
TLB_DATA_1G_2M_4M,
TLB_DATA0_4K,
TLB_DATA0_4M,
TLB_DATA0_2M_4M,
STLB_4K,
STLB_4K_2M,
} __packed;
#ifndef __CHECKER__
static_assert(sizeof(enum _tlb_table_type) == 1);
#endif
/*
* Combined parsing table for leaf 0x2 cache and TLB descriptors.
*/
struct leaf_0x2_table {
union {
enum _cache_table_type c_type;
enum _tlb_table_type t_type;
};
union {
short c_size;
short entries;
};
};
extern const struct leaf_0x2_table cpuid_0x2_table[256];
/*
* All of leaf 0x2's one-byte TLB descriptors implies the same number of entries
* for their respective TLB types. TLB descriptor 0x63 is an exception: it
* implies 4 dTLB entries for 1GB pages and 32 dTLB entries for 2MB or 4MB pages.
*
* Encode that descriptor's dTLB entry count for 2MB/4MB pages here, as the entry
* count for dTLB 1GB pages is already encoded at the cpuid_0x2_table[]'s mapping.
*/
#define TLB_0x63_2M_4M_ENTRIES 32
#endif /* _ASM_X86_CPUID_TYPES_H */

View File

@ -327,7 +327,7 @@
.endm
.macro CLEAR_BRANCH_HISTORY_VMEXIT
ALTERNATIVE "", "call clear_bhb_loop", X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT
ALTERNATIVE "", "call clear_bhb_loop", X86_FEATURE_CLEAR_BHB_VMEXIT
.endm
#else
#define CLEAR_BRANCH_HISTORY

View File

@ -272,7 +272,7 @@ int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
}
/* detect if running on heterogeneous design */
if (cpu_feature_enabled(X86_FEATURE_AMD_HETEROGENEOUS_CORES)) {
if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES)) {
switch (core_type) {
case TOPO_CPU_TYPE_UNKNOWN:
pr_warn("Undefined core type found for cpu %d\n", cpu);

View File

@ -39,7 +39,7 @@
#include <asm/gart.h>
#include <asm/set_memory.h>
#include <asm/dma.h>
#include <asm/amd_nb.h>
#include <asm/amd/nb.h>
#include <asm/x86_init.h>
static unsigned long iommu_bus_base; /* GART remapping area (physical) */

View File

@ -13,7 +13,9 @@
#include <linux/export.h>
#include <linux/spinlock.h>
#include <linux/pci_ids.h>
#include <asm/amd_nb.h>
#include <asm/amd/nb.h>
#include <asm/cpuid.h>
static u32 *flush_words;
@ -91,10 +93,7 @@ static int amd_cache_northbridges(void)
if (amd_gart_present())
amd_northbridges.flags |= AMD_NB_GART;
/*
* Check for L3 cache presence.
*/
if (!cpuid_edx(0x80000006))
if (!cpuid_amd_hygon_has_l3_cache())
return 0;
/*

View File

@ -9,7 +9,7 @@
*/
#include <linux/debugfs.h>
#include <asm/amd_node.h>
#include <asm/amd/node.h>
/*
* AMD Nodes are a physical collection of I/O devices within an SoC. There can be one

View File

@ -29,7 +29,7 @@
#include <asm/gart.h>
#include <asm/pci-direct.h>
#include <asm/dma.h>
#include <asm/amd_nb.h>
#include <asm/amd/nb.h>
#include <asm/x86_init.h>
#include <linux/crash_dump.h>

View File

@ -24,7 +24,7 @@ obj-y += rdrand.o
obj-y += match.o
obj-y += bugs.o
obj-y += aperfmperf.o
obj-y += cpuid-deps.o
obj-y += cpuid-deps.o cpuid_0x2_table.o
obj-y += umwait.o
obj-y += capflags.o powerflags.o
@ -38,6 +38,9 @@ obj-y += intel.o tsx.o
obj-$(CONFIG_PM) += intel_epb.o
endif
obj-$(CONFIG_CPU_SUP_AMD) += amd.o
ifeq ($(CONFIG_AMD_NB)$(CONFIG_SYSFS),yy)
obj-y += amd_cache_disable.o
endif
obj-$(CONFIG_CPU_SUP_HYGON) += hygon.o
obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o
obj-$(CONFIG_CPU_SUP_CENTAUR) += centaur.o

View File

@ -0,0 +1,301 @@
// SPDX-License-Identifier: GPL-2.0
/*
* AMD L3 cache_disable_{0,1} sysfs handling
* Documentation/ABI/testing/sysfs-devices-system-cpu
*/
#include <linux/cacheinfo.h>
#include <linux/capability.h>
#include <linux/pci.h>
#include <linux/sysfs.h>
#include <asm/amd/nb.h>
#include "cpu.h"
/*
* L3 cache descriptors
*/
static void amd_calc_l3_indices(struct amd_northbridge *nb)
{
struct amd_l3_cache *l3 = &nb->l3_cache;
unsigned int sc0, sc1, sc2, sc3;
u32 val = 0;
pci_read_config_dword(nb->misc, 0x1C4, &val);
/* calculate subcache sizes */
l3->subcaches[0] = sc0 = !(val & BIT(0));
l3->subcaches[1] = sc1 = !(val & BIT(4));
if (boot_cpu_data.x86 == 0x15) {
l3->subcaches[0] = sc0 += !(val & BIT(1));
l3->subcaches[1] = sc1 += !(val & BIT(5));
}
l3->subcaches[2] = sc2 = !(val & BIT(8)) + !(val & BIT(9));
l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13));
l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
}
/*
* check whether a slot used for disabling an L3 index is occupied.
* @l3: L3 cache descriptor
* @slot: slot number (0..1)
*
* @returns: the disabled index if used or negative value if slot free.
*/
static int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned int slot)
{
unsigned int reg = 0;
pci_read_config_dword(nb->misc, 0x1BC + slot * 4, &reg);
/* check whether this slot is activated already */
if (reg & (3UL << 30))
return reg & 0xfff;
return -1;
}
static ssize_t show_cache_disable(struct cacheinfo *ci, char *buf, unsigned int slot)
{
int index;
struct amd_northbridge *nb = ci->priv;
index = amd_get_l3_disable_slot(nb, slot);
if (index >= 0)
return sysfs_emit(buf, "%d\n", index);
return sysfs_emit(buf, "FREE\n");
}
#define SHOW_CACHE_DISABLE(slot) \
static ssize_t \
cache_disable_##slot##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct cacheinfo *ci = dev_get_drvdata(dev); \
return show_cache_disable(ci, buf, slot); \
}
SHOW_CACHE_DISABLE(0)
SHOW_CACHE_DISABLE(1)
static void amd_l3_disable_index(struct amd_northbridge *nb, int cpu,
unsigned int slot, unsigned long idx)
{
int i;
idx |= BIT(30);
/*
* disable index in all 4 subcaches
*/
for (i = 0; i < 4; i++) {
u32 reg = idx | (i << 20);
if (!nb->l3_cache.subcaches[i])
continue;
pci_write_config_dword(nb->misc, 0x1BC + slot * 4, reg);
/*
* We need to WBINVD on a core on the node containing the L3
* cache which indices we disable therefore a simple wbinvd()
* is not sufficient.
*/
wbinvd_on_cpu(cpu);
reg |= BIT(31);
pci_write_config_dword(nb->misc, 0x1BC + slot * 4, reg);
}
}
/*
* disable a L3 cache index by using a disable-slot
*
* @l3: L3 cache descriptor
* @cpu: A CPU on the node containing the L3 cache
* @slot: slot number (0..1)
* @index: index to disable
*
* @return: 0 on success, error status on failure
*/
static int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu,
unsigned int slot, unsigned long index)
{
int ret = 0;
/* check if @slot is already used or the index is already disabled */
ret = amd_get_l3_disable_slot(nb, slot);
if (ret >= 0)
return -EEXIST;
if (index > nb->l3_cache.indices)
return -EINVAL;
/* check whether the other slot has disabled the same index already */
if (index == amd_get_l3_disable_slot(nb, !slot))
return -EEXIST;
amd_l3_disable_index(nb, cpu, slot, index);
return 0;
}
static ssize_t store_cache_disable(struct cacheinfo *ci, const char *buf,
size_t count, unsigned int slot)
{
struct amd_northbridge *nb = ci->priv;
unsigned long val = 0;
int cpu, err = 0;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
cpu = cpumask_first(&ci->shared_cpu_map);
if (kstrtoul(buf, 10, &val) < 0)
return -EINVAL;
err = amd_set_l3_disable_slot(nb, cpu, slot, val);
if (err) {
if (err == -EEXIST)
pr_warn("L3 slot %d in use/index already disabled!\n",
slot);
return err;
}
return count;
}
#define STORE_CACHE_DISABLE(slot) \
static ssize_t \
cache_disable_##slot##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct cacheinfo *ci = dev_get_drvdata(dev); \
return store_cache_disable(ci, buf, count, slot); \
}
STORE_CACHE_DISABLE(0)
STORE_CACHE_DISABLE(1)
static ssize_t subcaches_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct cacheinfo *ci = dev_get_drvdata(dev);
int cpu = cpumask_first(&ci->shared_cpu_map);
return sysfs_emit(buf, "%x\n", amd_get_subcaches(cpu));
}
static ssize_t subcaches_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct cacheinfo *ci = dev_get_drvdata(dev);
int cpu = cpumask_first(&ci->shared_cpu_map);
unsigned long val;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (kstrtoul(buf, 16, &val) < 0)
return -EINVAL;
if (amd_set_subcaches(cpu, val))
return -EINVAL;
return count;
}
static DEVICE_ATTR_RW(cache_disable_0);
static DEVICE_ATTR_RW(cache_disable_1);
static DEVICE_ATTR_RW(subcaches);
static umode_t cache_private_attrs_is_visible(struct kobject *kobj,
struct attribute *attr, int unused)
{
struct device *dev = kobj_to_dev(kobj);
struct cacheinfo *ci = dev_get_drvdata(dev);
umode_t mode = attr->mode;
if (!ci->priv)
return 0;
if ((attr == &dev_attr_subcaches.attr) &&
amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
return mode;
if ((attr == &dev_attr_cache_disable_0.attr ||
attr == &dev_attr_cache_disable_1.attr) &&
amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
return mode;
return 0;
}
static struct attribute_group cache_private_group = {
.is_visible = cache_private_attrs_is_visible,
};
static void init_amd_l3_attrs(void)
{
static struct attribute **amd_l3_attrs;
int n = 1;
if (amd_l3_attrs) /* already initialized */
return;
if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
n += 2;
if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
n += 1;
amd_l3_attrs = kcalloc(n, sizeof(*amd_l3_attrs), GFP_KERNEL);
if (!amd_l3_attrs)
return;
n = 0;
if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
amd_l3_attrs[n++] = &dev_attr_cache_disable_0.attr;
amd_l3_attrs[n++] = &dev_attr_cache_disable_1.attr;
}
if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
amd_l3_attrs[n++] = &dev_attr_subcaches.attr;
cache_private_group.attrs = amd_l3_attrs;
}
const struct attribute_group *cache_get_priv_group(struct cacheinfo *ci)
{
struct amd_northbridge *nb = ci->priv;
if (ci->level < 3 || !nb)
return NULL;
if (nb && nb->l3_cache.indices)
init_amd_l3_attrs();
return &cache_private_group;
}
struct amd_northbridge *amd_init_l3_cache(int index)
{
struct amd_northbridge *nb;
int node;
/* only for L3, and not in virtualized environments */
if (index < 3)
return NULL;
node = topology_amd_node_id(smp_processor_id());
nb = node_to_amd_nb(node);
if (nb && !nb->l3_cache.indices)
amd_calc_l3_indices(nb);
return nb;
}

View File

@ -551,7 +551,6 @@ static const char * const mmio_strings[] = {
static void __init mmio_select_mitigation(void)
{
if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA) ||
boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN) ||
cpu_mitigations_off()) {
mmio_mitigation = MMIO_MITIGATION_OFF;
return;
@ -1880,13 +1879,13 @@ static void __init bhi_apply_mitigation(void)
if (bhi_mitigation == BHI_MITIGATION_VMEXIT_ONLY) {
pr_info("Spectre BHI mitigation: SW BHB clearing on VM exit only\n");
setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT);
setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_VMEXIT);
return;
}
pr_info("Spectre BHI mitigation: SW BHB clearing on syscall and VM exit\n");
setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_LOOP);
setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT);
setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_VMEXIT);
}
static void __init spectre_v2_select_mitigation(void)
@ -2947,9 +2946,6 @@ static ssize_t tsx_async_abort_show_state(char *buf)
static ssize_t mmio_stale_data_show_state(char *buf)
{
if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
return sysfs_emit(buf, "Unknown: No mitigations\n");
if (mmio_mitigation == MMIO_MITIGATION_OFF)
return sysfs_emit(buf, "%s\n", mmio_strings[mmio_mitigation]);
@ -3025,7 +3021,7 @@ static const char *spectre_bhi_state(void)
!boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE) &&
rrsba_disabled)
return "; BHI: Retpoline";
else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT))
else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_VMEXIT))
return "; BHI: Vulnerable, KVM: SW loop";
return "; BHI: Vulnerable";
@ -3134,7 +3130,6 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
return srbds_show_state(buf);
case X86_BUG_MMIO_STALE_DATA:
case X86_BUG_MMIO_UNKNOWN:
return mmio_stale_data_show_state(buf);
case X86_BUG_RETBLEED:
@ -3203,10 +3198,7 @@ ssize_t cpu_show_srbds(struct device *dev, struct device_attribute *attr, char *
ssize_t cpu_show_mmio_stale_data(struct device *dev, struct device_attribute *attr, char *buf)
{
if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_UNKNOWN);
else
return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_STALE_DATA);
return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_STALE_DATA);
}
ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, char *buf)

File diff suppressed because it is too large Load Diff

View File

@ -1006,17 +1006,18 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
c->x86_capability[CPUID_D_1_EAX] = eax;
}
/* AMD-defined flags: level 0x80000001 */
/*
* Check if extended CPUID leaves are implemented: Max extended
* CPUID leaf must be in the 0x80000001-0x8000ffff range.
*/
eax = cpuid_eax(0x80000000);
c->extended_cpuid_level = eax;
c->extended_cpuid_level = ((eax & 0xffff0000) == 0x80000000) ? eax : 0;
if ((eax & 0xffff0000) == 0x80000000) {
if (eax >= 0x80000001) {
cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
if (c->extended_cpuid_level >= 0x80000001) {
cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
c->x86_capability[CPUID_8000_0001_ECX] = ecx;
c->x86_capability[CPUID_8000_0001_EDX] = edx;
}
c->x86_capability[CPUID_8000_0001_ECX] = ecx;
c->x86_capability[CPUID_8000_0001_EDX] = edx;
}
if (c->extended_cpuid_level >= 0x80000007) {
@ -1403,15 +1404,10 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
* Affected CPU list is generally enough to enumerate the vulnerability,
* but for virtualization case check for ARCH_CAP MSR bits also, VMM may
* not want the guest to enumerate the bug.
*
* Set X86_BUG_MMIO_UNKNOWN for CPUs that are neither in the blacklist,
* nor in the whitelist and also don't enumerate MSR ARCH_CAP MMIO bits.
*/
if (!arch_cap_mmio_immune(x86_arch_cap_msr)) {
if (cpu_matches(cpu_vuln_blacklist, MMIO))
setup_force_cpu_bug(X86_BUG_MMIO_STALE_DATA);
else if (!cpu_matches(cpu_vuln_whitelist, NO_MMIO))
setup_force_cpu_bug(X86_BUG_MMIO_UNKNOWN);
}
if (!cpu_has(c, X86_FEATURE_BTC_NO)) {

View File

@ -75,6 +75,15 @@ extern void check_null_seg_clears_base(struct cpuinfo_x86 *c);
void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, u16 die_id);
void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *c);
#if defined(CONFIG_AMD_NB) && defined(CONFIG_SYSFS)
struct amd_northbridge *amd_init_l3_cache(int index);
#else
static inline struct amd_northbridge *amd_init_l3_cache(int index)
{
return NULL;
}
#endif
unsigned int aperfmperf_get_khz(int cpu);
void cpu_select_mitigations(void);

View File

@ -82,8 +82,12 @@ static const struct cpuid_dep cpuid_deps[] = {
{ X86_FEATURE_XFD, X86_FEATURE_XSAVES },
{ X86_FEATURE_XFD, X86_FEATURE_XGETBV1 },
{ X86_FEATURE_AMX_TILE, X86_FEATURE_XFD },
{ X86_FEATURE_AMX_FP16, X86_FEATURE_AMX_TILE },
{ X86_FEATURE_AMX_BF16, X86_FEATURE_AMX_TILE },
{ X86_FEATURE_AMX_INT8, X86_FEATURE_AMX_TILE },
{ X86_FEATURE_SHSTK, X86_FEATURE_XSAVES },
{ X86_FEATURE_FRED, X86_FEATURE_LKGS },
{ X86_FEATURE_SPEC_CTRL_SSBD, X86_FEATURE_SPEC_CTRL },
{}
};

View File

@ -0,0 +1,128 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/sizes.h>
#include <asm/cpuid/types.h>
#include "cpu.h"
#define CACHE_ENTRY(_desc, _type, _size) \
[_desc] = { \
.c_type = (_type), \
.c_size = (_size) / SZ_1K, \
}
#define TLB_ENTRY(_desc, _type, _entries) \
[_desc] = { \
.t_type = (_type), \
.entries = (_entries), \
}
const struct leaf_0x2_table cpuid_0x2_table[256] = {
CACHE_ENTRY(0x06, CACHE_L1_INST, SZ_8K ), /* 4-way set assoc, 32 byte line size */
CACHE_ENTRY(0x08, CACHE_L1_INST, SZ_16K ), /* 4-way set assoc, 32 byte line size */
CACHE_ENTRY(0x09, CACHE_L1_INST, SZ_32K ), /* 4-way set assoc, 64 byte line size */
CACHE_ENTRY(0x0a, CACHE_L1_DATA, SZ_8K ), /* 2 way set assoc, 32 byte line size */
CACHE_ENTRY(0x0c, CACHE_L1_DATA, SZ_16K ), /* 4-way set assoc, 32 byte line size */
CACHE_ENTRY(0x0d, CACHE_L1_DATA, SZ_16K ), /* 4-way set assoc, 64 byte line size */
CACHE_ENTRY(0x0e, CACHE_L1_DATA, SZ_24K ), /* 6-way set assoc, 64 byte line size */
CACHE_ENTRY(0x21, CACHE_L2, SZ_256K ), /* 8-way set assoc, 64 byte line size */
CACHE_ENTRY(0x22, CACHE_L3, SZ_512K ), /* 4-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x23, CACHE_L3, SZ_1M ), /* 8-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x25, CACHE_L3, SZ_2M ), /* 8-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x29, CACHE_L3, SZ_4M ), /* 8-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x2c, CACHE_L1_DATA, SZ_32K ), /* 8-way set assoc, 64 byte line size */
CACHE_ENTRY(0x30, CACHE_L1_INST, SZ_32K ), /* 8-way set assoc, 64 byte line size */
CACHE_ENTRY(0x39, CACHE_L2, SZ_128K ), /* 4-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x3a, CACHE_L2, SZ_192K ), /* 6-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x3b, CACHE_L2, SZ_128K ), /* 2-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x3c, CACHE_L2, SZ_256K ), /* 4-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x3d, CACHE_L2, SZ_384K ), /* 6-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x3e, CACHE_L2, SZ_512K ), /* 4-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x3f, CACHE_L2, SZ_256K ), /* 2-way set assoc, 64 byte line size */
CACHE_ENTRY(0x41, CACHE_L2, SZ_128K ), /* 4-way set assoc, 32 byte line size */
CACHE_ENTRY(0x42, CACHE_L2, SZ_256K ), /* 4-way set assoc, 32 byte line size */
CACHE_ENTRY(0x43, CACHE_L2, SZ_512K ), /* 4-way set assoc, 32 byte line size */
CACHE_ENTRY(0x44, CACHE_L2, SZ_1M ), /* 4-way set assoc, 32 byte line size */
CACHE_ENTRY(0x45, CACHE_L2, SZ_2M ), /* 4-way set assoc, 32 byte line size */
CACHE_ENTRY(0x46, CACHE_L3, SZ_4M ), /* 4-way set assoc, 64 byte line size */
CACHE_ENTRY(0x47, CACHE_L3, SZ_8M ), /* 8-way set assoc, 64 byte line size */
CACHE_ENTRY(0x48, CACHE_L2, SZ_3M ), /* 12-way set assoc, 64 byte line size */
CACHE_ENTRY(0x49, CACHE_L3, SZ_4M ), /* 16-way set assoc, 64 byte line size */
CACHE_ENTRY(0x4a, CACHE_L3, SZ_6M ), /* 12-way set assoc, 64 byte line size */
CACHE_ENTRY(0x4b, CACHE_L3, SZ_8M ), /* 16-way set assoc, 64 byte line size */
CACHE_ENTRY(0x4c, CACHE_L3, SZ_12M ), /* 12-way set assoc, 64 byte line size */
CACHE_ENTRY(0x4d, CACHE_L3, SZ_16M ), /* 16-way set assoc, 64 byte line size */
CACHE_ENTRY(0x4e, CACHE_L2, SZ_6M ), /* 24-way set assoc, 64 byte line size */
CACHE_ENTRY(0x60, CACHE_L1_DATA, SZ_16K ), /* 8-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x66, CACHE_L1_DATA, SZ_8K ), /* 4-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x67, CACHE_L1_DATA, SZ_16K ), /* 4-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x68, CACHE_L1_DATA, SZ_32K ), /* 4-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x78, CACHE_L2, SZ_1M ), /* 4-way set assoc, 64 byte line size */
CACHE_ENTRY(0x79, CACHE_L2, SZ_128K ), /* 8-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x7a, CACHE_L2, SZ_256K ), /* 8-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x7b, CACHE_L2, SZ_512K ), /* 8-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x7c, CACHE_L2, SZ_1M ), /* 8-way set assoc, sectored cache, 64 byte line size */
CACHE_ENTRY(0x7d, CACHE_L2, SZ_2M ), /* 8-way set assoc, 64 byte line size */
CACHE_ENTRY(0x7f, CACHE_L2, SZ_512K ), /* 2-way set assoc, 64 byte line size */
CACHE_ENTRY(0x80, CACHE_L2, SZ_512K ), /* 8-way set assoc, 64 byte line size */
CACHE_ENTRY(0x82, CACHE_L2, SZ_256K ), /* 8-way set assoc, 32 byte line size */
CACHE_ENTRY(0x83, CACHE_L2, SZ_512K ), /* 8-way set assoc, 32 byte line size */
CACHE_ENTRY(0x84, CACHE_L2, SZ_1M ), /* 8-way set assoc, 32 byte line size */
CACHE_ENTRY(0x85, CACHE_L2, SZ_2M ), /* 8-way set assoc, 32 byte line size */
CACHE_ENTRY(0x86, CACHE_L2, SZ_512K ), /* 4-way set assoc, 64 byte line size */
CACHE_ENTRY(0x87, CACHE_L2, SZ_1M ), /* 8-way set assoc, 64 byte line size */
CACHE_ENTRY(0xd0, CACHE_L3, SZ_512K ), /* 4-way set assoc, 64 byte line size */
CACHE_ENTRY(0xd1, CACHE_L3, SZ_1M ), /* 4-way set assoc, 64 byte line size */
CACHE_ENTRY(0xd2, CACHE_L3, SZ_2M ), /* 4-way set assoc, 64 byte line size */
CACHE_ENTRY(0xd6, CACHE_L3, SZ_1M ), /* 8-way set assoc, 64 byte line size */
CACHE_ENTRY(0xd7, CACHE_L3, SZ_2M ), /* 8-way set assoc, 64 byte line size */
CACHE_ENTRY(0xd8, CACHE_L3, SZ_4M ), /* 12-way set assoc, 64 byte line size */
CACHE_ENTRY(0xdc, CACHE_L3, SZ_2M ), /* 12-way set assoc, 64 byte line size */
CACHE_ENTRY(0xdd, CACHE_L3, SZ_4M ), /* 12-way set assoc, 64 byte line size */
CACHE_ENTRY(0xde, CACHE_L3, SZ_8M ), /* 12-way set assoc, 64 byte line size */
CACHE_ENTRY(0xe2, CACHE_L3, SZ_2M ), /* 16-way set assoc, 64 byte line size */
CACHE_ENTRY(0xe3, CACHE_L3, SZ_4M ), /* 16-way set assoc, 64 byte line size */
CACHE_ENTRY(0xe4, CACHE_L3, SZ_8M ), /* 16-way set assoc, 64 byte line size */
CACHE_ENTRY(0xea, CACHE_L3, SZ_12M ), /* 24-way set assoc, 64 byte line size */
CACHE_ENTRY(0xeb, CACHE_L3, SZ_18M ), /* 24-way set assoc, 64 byte line size */
CACHE_ENTRY(0xec, CACHE_L3, SZ_24M ), /* 24-way set assoc, 64 byte line size */
TLB_ENTRY( 0x01, TLB_INST_4K, 32 ), /* TLB_INST 4 KByte pages, 4-way set associative */
TLB_ENTRY( 0x02, TLB_INST_4M, 2 ), /* TLB_INST 4 MByte pages, full associative */
TLB_ENTRY( 0x03, TLB_DATA_4K, 64 ), /* TLB_DATA 4 KByte pages, 4-way set associative */
TLB_ENTRY( 0x04, TLB_DATA_4M, 8 ), /* TLB_DATA 4 MByte pages, 4-way set associative */
TLB_ENTRY( 0x05, TLB_DATA_4M, 32 ), /* TLB_DATA 4 MByte pages, 4-way set associative */
TLB_ENTRY( 0x0b, TLB_INST_4M, 4 ), /* TLB_INST 4 MByte pages, 4-way set associative */
TLB_ENTRY( 0x4f, TLB_INST_4K, 32 ), /* TLB_INST 4 KByte pages */
TLB_ENTRY( 0x50, TLB_INST_ALL, 64 ), /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
TLB_ENTRY( 0x51, TLB_INST_ALL, 128 ), /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
TLB_ENTRY( 0x52, TLB_INST_ALL, 256 ), /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
TLB_ENTRY( 0x55, TLB_INST_2M_4M, 7 ), /* TLB_INST 2-MByte or 4-MByte pages, fully associative */
TLB_ENTRY( 0x56, TLB_DATA0_4M, 16 ), /* TLB_DATA0 4 MByte pages, 4-way set associative */
TLB_ENTRY( 0x57, TLB_DATA0_4K, 16 ), /* TLB_DATA0 4 KByte pages, 4-way associative */
TLB_ENTRY( 0x59, TLB_DATA0_4K, 16 ), /* TLB_DATA0 4 KByte pages, fully associative */
TLB_ENTRY( 0x5a, TLB_DATA0_2M_4M, 32 ), /* TLB_DATA0 2-MByte or 4 MByte pages, 4-way set associative */
TLB_ENTRY( 0x5b, TLB_DATA_4K_4M, 64 ), /* TLB_DATA 4 KByte and 4 MByte pages */
TLB_ENTRY( 0x5c, TLB_DATA_4K_4M, 128 ), /* TLB_DATA 4 KByte and 4 MByte pages */
TLB_ENTRY( 0x5d, TLB_DATA_4K_4M, 256 ), /* TLB_DATA 4 KByte and 4 MByte pages */
TLB_ENTRY( 0x61, TLB_INST_4K, 48 ), /* TLB_INST 4 KByte pages, full associative */
TLB_ENTRY( 0x63, TLB_DATA_1G_2M_4M, 4 ), /* TLB_DATA 1 GByte pages, 4-way set associative
* (plus 32 entries TLB_DATA 2 MByte or 4 MByte pages, not encoded here) */
TLB_ENTRY( 0x6b, TLB_DATA_4K, 256 ), /* TLB_DATA 4 KByte pages, 8-way associative */
TLB_ENTRY( 0x6c, TLB_DATA_2M_4M, 128 ), /* TLB_DATA 2 MByte or 4 MByte pages, 8-way associative */
TLB_ENTRY( 0x6d, TLB_DATA_1G, 16 ), /* TLB_DATA 1 GByte pages, fully associative */
TLB_ENTRY( 0x76, TLB_INST_2M_4M, 8 ), /* TLB_INST 2-MByte or 4-MByte pages, fully associative */
TLB_ENTRY( 0xb0, TLB_INST_4K, 128 ), /* TLB_INST 4 KByte pages, 4-way set associative */
TLB_ENTRY( 0xb1, TLB_INST_2M_4M, 4 ), /* TLB_INST 2M pages, 4-way, 8 entries or 4M pages, 4-way entries */
TLB_ENTRY( 0xb2, TLB_INST_4K, 64 ), /* TLB_INST 4KByte pages, 4-way set associative */
TLB_ENTRY( 0xb3, TLB_DATA_4K, 128 ), /* TLB_DATA 4 KByte pages, 4-way set associative */
TLB_ENTRY( 0xb4, TLB_DATA_4K, 256 ), /* TLB_DATA 4 KByte pages, 4-way associative */
TLB_ENTRY( 0xb5, TLB_INST_4K, 64 ), /* TLB_INST 4 KByte pages, 8-way set associative */
TLB_ENTRY( 0xb6, TLB_INST_4K, 128 ), /* TLB_INST 4 KByte pages, 8-way set associative */
TLB_ENTRY( 0xba, TLB_DATA_4K, 64 ), /* TLB_DATA 4 KByte pages, 4-way associative */
TLB_ENTRY( 0xc0, TLB_DATA_4K_4M, 8 ), /* TLB_DATA 4 KByte and 4 MByte pages, 4-way associative */
TLB_ENTRY( 0xc1, STLB_4K_2M, 1024 ), /* STLB 4 KByte and 2 MByte pages, 8-way associative */
TLB_ENTRY( 0xc2, TLB_DATA_2M_4M, 16 ), /* TLB_DATA 2 MByte/4MByte pages, 4-way associative */
TLB_ENTRY( 0xca, STLB_4K, 512 ), /* STLB 4 KByte pages, 4-way associative */
};

View File

@ -6,6 +6,7 @@
#include <linux/minmax.h>
#include <linux/smp.h>
#include <linux/string.h>
#include <linux/types.h>
#ifdef CONFIG_X86_64
#include <linux/topology.h>
@ -15,6 +16,7 @@
#include <asm/cpu_device_id.h>
#include <asm/cpufeature.h>
#include <asm/cpu.h>
#include <asm/cpuid.h>
#include <asm/hwcap2.h>
#include <asm/intel-family.h>
#include <asm/microcode.h>
@ -646,103 +648,11 @@ static unsigned int intel_size_cache(struct cpuinfo_x86 *c, unsigned int size)
}
#endif
#define TLB_INST_4K 0x01
#define TLB_INST_4M 0x02
#define TLB_INST_2M_4M 0x03
#define TLB_INST_ALL 0x05
#define TLB_INST_1G 0x06
#define TLB_DATA_4K 0x11
#define TLB_DATA_4M 0x12
#define TLB_DATA_2M_4M 0x13
#define TLB_DATA_4K_4M 0x14
#define TLB_DATA_1G 0x16
#define TLB_DATA_1G_2M_4M 0x17
#define TLB_DATA0_4K 0x21
#define TLB_DATA0_4M 0x22
#define TLB_DATA0_2M_4M 0x23
#define STLB_4K 0x41
#define STLB_4K_2M 0x42
/*
* All of leaf 0x2's one-byte TLB descriptors implies the same number of
* entries for their respective TLB types. The 0x63 descriptor is an
* exception: it implies 4 dTLB entries for 1GB pages 32 dTLB entries
* for 2MB or 4MB pages. Encode descriptor 0x63 dTLB entry count for
* 2MB/4MB pages here, as its count for dTLB 1GB pages is already at the
* intel_tlb_table[] mapping.
*/
#define TLB_0x63_2M_4M_ENTRIES 32
struct _tlb_table {
unsigned char descriptor;
char tlb_type;
unsigned int entries;
};
static const struct _tlb_table intel_tlb_table[] = {
{ 0x01, TLB_INST_4K, 32}, /* TLB_INST 4 KByte pages, 4-way set associative */
{ 0x02, TLB_INST_4M, 2}, /* TLB_INST 4 MByte pages, full associative */
{ 0x03, TLB_DATA_4K, 64}, /* TLB_DATA 4 KByte pages, 4-way set associative */
{ 0x04, TLB_DATA_4M, 8}, /* TLB_DATA 4 MByte pages, 4-way set associative */
{ 0x05, TLB_DATA_4M, 32}, /* TLB_DATA 4 MByte pages, 4-way set associative */
{ 0x0b, TLB_INST_4M, 4}, /* TLB_INST 4 MByte pages, 4-way set associative */
{ 0x4f, TLB_INST_4K, 32}, /* TLB_INST 4 KByte pages */
{ 0x50, TLB_INST_ALL, 64}, /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
{ 0x51, TLB_INST_ALL, 128}, /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
{ 0x52, TLB_INST_ALL, 256}, /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
{ 0x55, TLB_INST_2M_4M, 7}, /* TLB_INST 2-MByte or 4-MByte pages, fully associative */
{ 0x56, TLB_DATA0_4M, 16}, /* TLB_DATA0 4 MByte pages, 4-way set associative */
{ 0x57, TLB_DATA0_4K, 16}, /* TLB_DATA0 4 KByte pages, 4-way associative */
{ 0x59, TLB_DATA0_4K, 16}, /* TLB_DATA0 4 KByte pages, fully associative */
{ 0x5a, TLB_DATA0_2M_4M, 32}, /* TLB_DATA0 2-MByte or 4 MByte pages, 4-way set associative */
{ 0x5b, TLB_DATA_4K_4M, 64}, /* TLB_DATA 4 KByte and 4 MByte pages */
{ 0x5c, TLB_DATA_4K_4M, 128}, /* TLB_DATA 4 KByte and 4 MByte pages */
{ 0x5d, TLB_DATA_4K_4M, 256}, /* TLB_DATA 4 KByte and 4 MByte pages */
{ 0x61, TLB_INST_4K, 48}, /* TLB_INST 4 KByte pages, full associative */
{ 0x63, TLB_DATA_1G_2M_4M, 4}, /* TLB_DATA 1 GByte pages, 4-way set associative
* (plus 32 entries TLB_DATA 2 MByte or 4 MByte pages, not encoded here) */
{ 0x6b, TLB_DATA_4K, 256}, /* TLB_DATA 4 KByte pages, 8-way associative */
{ 0x6c, TLB_DATA_2M_4M, 128}, /* TLB_DATA 2 MByte or 4 MByte pages, 8-way associative */
{ 0x6d, TLB_DATA_1G, 16}, /* TLB_DATA 1 GByte pages, fully associative */
{ 0x76, TLB_INST_2M_4M, 8}, /* TLB_INST 2-MByte or 4-MByte pages, fully associative */
{ 0xb0, TLB_INST_4K, 128}, /* TLB_INST 4 KByte pages, 4-way set associative */
{ 0xb1, TLB_INST_2M_4M, 4}, /* TLB_INST 2M pages, 4-way, 8 entries or 4M pages, 4-way entries */
{ 0xb2, TLB_INST_4K, 64}, /* TLB_INST 4KByte pages, 4-way set associative */
{ 0xb3, TLB_DATA_4K, 128}, /* TLB_DATA 4 KByte pages, 4-way set associative */
{ 0xb4, TLB_DATA_4K, 256}, /* TLB_DATA 4 KByte pages, 4-way associative */
{ 0xb5, TLB_INST_4K, 64}, /* TLB_INST 4 KByte pages, 8-way set associative */
{ 0xb6, TLB_INST_4K, 128}, /* TLB_INST 4 KByte pages, 8-way set associative */
{ 0xba, TLB_DATA_4K, 64}, /* TLB_DATA 4 KByte pages, 4-way associative */
{ 0xc0, TLB_DATA_4K_4M, 8}, /* TLB_DATA 4 KByte and 4 MByte pages, 4-way associative */
{ 0xc1, STLB_4K_2M, 1024}, /* STLB 4 KByte and 2 MByte pages, 8-way associative */
{ 0xc2, TLB_DATA_2M_4M, 16}, /* TLB_DATA 2 MByte/4MByte pages, 4-way associative */
{ 0xca, STLB_4K, 512}, /* STLB 4 KByte pages, 4-way associative */
{ 0x00, 0, 0 }
};
static void intel_tlb_lookup(const unsigned char desc)
static void intel_tlb_lookup(const struct leaf_0x2_table *entry)
{
unsigned int entries;
unsigned char k;
short entries = entry->entries;
if (desc == 0)
return;
/* look up this descriptor in the table */
for (k = 0; intel_tlb_table[k].descriptor != desc &&
intel_tlb_table[k].descriptor != 0; k++)
;
if (intel_tlb_table[k].tlb_type == 0)
return;
entries = intel_tlb_table[k].entries;
switch (intel_tlb_table[k].tlb_type) {
switch (entry->t_type) {
case STLB_4K:
tlb_lli_4k = max(tlb_lli_4k, entries);
tlb_lld_4k = max(tlb_lld_4k, entries);
@ -799,28 +709,16 @@ static void intel_tlb_lookup(const unsigned char desc)
static void intel_detect_tlb(struct cpuinfo_x86 *c)
{
int i, j, n;
unsigned int regs[4];
unsigned char *desc = (unsigned char *)regs;
const struct leaf_0x2_table *entry;
union leaf_0x2_regs regs;
u8 *ptr;
if (c->cpuid_level < 2)
return;
/* Number of times to iterate */
n = cpuid_eax(2) & 0xFF;
for (i = 0 ; i < n ; i++) {
cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
/* If bit 31 is set, this is an unknown format */
for (j = 0 ; j < 4 ; j++)
if (regs[j] & (1 << 31))
regs[j] = 0;
/* Byte 0 is level count, not a descriptor */
for (j = 1 ; j < 16 ; j++)
intel_tlb_lookup(desc[j]);
}
cpuid_get_leaf_0x2_regs(&regs);
for_each_leaf_0x2_entry(regs, ptr, entry)
intel_tlb_lookup(entry);
}
static const struct cpu_dev intel_cpu_dev = {

View File

@ -24,7 +24,7 @@
#include <linux/pci.h>
#include <linux/uaccess.h>
#include <asm/amd_nb.h>
#include <asm/amd/nb.h>
#include <asm/apic.h>
#include <asm/irq_vectors.h>
#include <asm/mce.h>

View File

@ -53,7 +53,7 @@ static const struct cpuid_bit cpuid_bits[] = {
{ X86_FEATURE_PERFMON_V2, CPUID_EAX, 0, 0x80000022, 0 },
{ X86_FEATURE_AMD_LBR_V2, CPUID_EAX, 1, 0x80000022, 0 },
{ X86_FEATURE_AMD_LBR_PMC_FREEZE, CPUID_EAX, 2, 0x80000022, 0 },
{ X86_FEATURE_AMD_HETEROGENEOUS_CORES, CPUID_EAX, 30, 0x80000026, 0 },
{ X86_FEATURE_AMD_HTR_CORES, CPUID_EAX, 30, 0x80000026, 0 },
{ 0, 0, 0, 0, 0 }
};

View File

@ -182,7 +182,7 @@ static void parse_topology_amd(struct topo_scan *tscan)
if (cpu_feature_enabled(X86_FEATURE_TOPOEXT))
has_topoext = cpu_parse_topology_ext(tscan);
if (cpu_feature_enabled(X86_FEATURE_AMD_HETEROGENEOUS_CORES))
if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES))
tscan->c->topo.cpu_type = cpuid_ebx(0x80000026);
if (!has_topoext && !parse_8000_0008(tscan))

View File

@ -25,7 +25,7 @@
#include <asm/numa.h>
#include <asm/mpspec.h>
#include <asm/apic.h>
#include <asm/amd_nb.h>
#include <asm/amd/nb.h>
static unsigned char __initdata nodeids[8];

View File

@ -18,7 +18,7 @@
#include <asm/e820/api.h>
#include <asm/proto.h>
#include <asm/dma.h>
#include <asm/amd_nb.h>
#include <asm/amd/nb.h>
#include "numa_internal.h"

View File

@ -5,7 +5,7 @@
#include <linux/cpu.h>
#include <linux/range.h>
#include <asm/amd_nb.h>
#include <asm/amd/nb.h>
#include <asm/pci_x86.h>
#include <asm/pci-direct.h>

View File

@ -9,7 +9,7 @@
#include <linux/pci.h>
#include <linux/suspend.h>
#include <linux/vgaarb.h>
#include <asm/amd_node.h>
#include <asm/amd/node.h>
#include <asm/hpet.h>
#include <asm/pci_x86.h>

View File

@ -16,7 +16,7 @@
#include <linux/mmzone.h>
#include <asm/page.h> /* PAGE_SIZE */
#include <asm/e820/api.h>
#include <asm/amd_nb.h>
#include <asm/amd/nb.h>
#include <asm/gart.h>
#include "agp.h"

View File

@ -2,8 +2,8 @@
#include <linux/ras.h>
#include <linux/string_choices.h>
#include "amd64_edac.h"
#include <asm/amd_nb.h>
#include <asm/amd_node.h>
#include <asm/amd/nb.h>
#include <asm/amd/node.h>
static struct edac_pci_ctl_info *pci_ctl;

View File

@ -20,7 +20,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <asm/amd_node.h>
#include <asm/amd/node.h>
#include <asm/processor.h>
MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");

View File

@ -9,7 +9,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/amd_hsmp.h>
#include <asm/amd/hsmp.h>
#include <linux/acpi.h>
#include <linux/device.h>
@ -23,7 +23,7 @@
#include <uapi/asm-generic/errno-base.h>
#include <asm/amd_node.h>
#include <asm/amd/node.h>
#include "hsmp.h"

View File

@ -7,7 +7,7 @@
* This file provides a device implementation for HSMP interface
*/
#include <asm/amd_hsmp.h>
#include <asm/amd/hsmp.h>
#include <linux/acpi.h>
#include <linux/delay.h>

View File

@ -9,7 +9,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/amd_hsmp.h>
#include <asm/amd/hsmp.h>
#include <linux/build_bug.h>
#include <linux/device.h>
@ -18,7 +18,7 @@
#include <linux/platform_device.h>
#include <linux/sysfs.h>
#include <asm/amd_node.h>
#include <asm/amd/node.h>
#include "hsmp.h"

View File

@ -11,7 +11,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/amd_nb.h>
#include <asm/amd/nb.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>

View File

@ -28,7 +28,7 @@
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <asm/amd_node.h>
#include <asm/amd/node.h>
#include "pmc.h"

View File

@ -14,7 +14,7 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <asm/amd_node.h>
#include <asm/amd/node.h>
#include "pmf.h"
/* PMF-SMU communication registers */

View File

@ -290,7 +290,7 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
#ifdef CONFIG_AMD_NB
#include <asm/amd_nb.h>
#include <asm/amd/nb.h>
static void quirk_amd_mmconfig_area(struct pnp_dev *dev)
{

View File

@ -17,8 +17,8 @@
#include <linux/bitops.h>
#include <linux/ras.h>
#include <asm/amd_nb.h>
#include <asm/amd_node.h>
#include <asm/amd/nb.h>
#include <asm/amd/node.h>
#include "reg_fields.h"

View File

@ -22,7 +22,7 @@
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <asm/amd_node.h>
#include <asm/amd/node.h>
#include "amd.h"
#include "../mach-config.h"

View File

@ -21,7 +21,7 @@
#include <linux/pm_runtime.h>
#include <linux/pci.h>
#include <asm/amd_node.h>
#include <asm/amd/node.h>
#include "amd.h"
#include "acp-mach.h"

View File

@ -23,7 +23,7 @@
#include "amd.h"
#include "acp-mach.h"
#include <asm/amd_node.h>
#include <asm/amd/node.h>
#define DRV_NAME "acp_asoc_acp70"

View File

@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <asm/amd_node.h>
#include <asm/amd/node.h>
#include "../ops.h"
#include "acp.h"

View File

@ -4,7 +4,7 @@
* 55898 Rev 0.35 - Feb 5, 2021
*/
#include "msr-index.h"
#include "../msr-index.h"
/* IBS_OP_DATA2 DataSrc */
#define IBS_DATA_SRC_LOC_CACHE 2

View File

@ -476,11 +476,11 @@
#define X86_FEATURE_CLEAR_BHB_LOOP (21*32+ 1) /* Clear branch history at syscall entry using SW loop */
#define X86_FEATURE_BHI_CTRL (21*32+ 2) /* BHI_DIS_S HW control available */
#define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* BHI_DIS_S HW control enabled */
#define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */
#define X86_FEATURE_AMD_FAST_CPPC (21*32 + 5) /* Fast CPPC */
#define X86_FEATURE_AMD_HETEROGENEOUS_CORES (21*32 + 6) /* Heterogeneous Core Topology */
#define X86_FEATURE_AMD_WORKLOAD_CLASS (21*32 + 7) /* Workload Classification */
#define X86_FEATURE_PREFER_YMM (21*32 + 8) /* Avoid ZMM registers due to downclocking */
#define X86_FEATURE_CLEAR_BHB_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */
#define X86_FEATURE_AMD_FAST_CPPC (21*32+ 5) /* Fast CPPC */
#define X86_FEATURE_AMD_HTR_CORES (21*32+ 6) /* Heterogeneous Core Topology */
#define X86_FEATURE_AMD_WORKLOAD_CLASS (21*32+ 7) /* Workload Classification */
#define X86_FEATURE_PREFER_YMM (21*32+ 8) /* Avoid ZMM registers due to downclocking */
/*
* BUG word(s)
@ -519,7 +519,7 @@
#define X86_BUG_ITLB_MULTIHIT X86_BUG(23) /* "itlb_multihit" CPU may incur MCE during certain page attribute changes */
#define X86_BUG_SRBDS X86_BUG(24) /* "srbds" CPU may leak RNG bits if not mitigated */
#define X86_BUG_MMIO_STALE_DATA X86_BUG(25) /* "mmio_stale_data" CPU is affected by Processor MMIO Stale Data vulnerabilities */
#define X86_BUG_MMIO_UNKNOWN X86_BUG(26) /* "mmio_unknown" CPU is too old and its MMIO Stale Data status is unknown */
/* unused, was #define X86_BUG_MMIO_UNKNOWN X86_BUG(26) "mmio_unknown" CPU is too old and its MMIO Stale Data status is unknown */
#define X86_BUG_RETBLEED X86_BUG(27) /* "retbleed" CPU is affected by RETBleed */
#define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* "eibrs_pbrsb" EIBRS is vulnerable to Post Barrier RSB Predictions */
#define X86_BUG_SMT_RSB X86_BUG(29) /* "smt_rsb" CPU is vulnerable to Cross-Thread Return Address Predictions */
@ -527,10 +527,10 @@
#define X86_BUG_TDX_PW_MCE X86_BUG(31) /* "tdx_pw_mce" CPU may incur #MC if non-TD software does partial write to TDX private memory */
/* BUG word 2 */
#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* "srso" AMD SRSO bug */
#define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* "div0" AMD DIV0 speculation bug */
#define X86_BUG_RFDS X86_BUG(1*32 + 2) /* "rfds" CPU is vulnerable to Register File Data Sampling */
#define X86_BUG_BHI X86_BUG(1*32 + 3) /* "bhi" CPU is affected by Branch History Injection */
#define X86_BUG_IBPB_NO_RET X86_BUG(1*32 + 4) /* "ibpb_no_ret" IBPB omits return target predictions */
#define X86_BUG_SPECTRE_V2_USER X86_BUG(1*32 + 5) /* "spectre_v2_user" CPU is affected by Spectre variant 2 attack between user processes */
#define X86_BUG_SRSO X86_BUG( 1*32+ 0) /* "srso" AMD SRSO bug */
#define X86_BUG_DIV0 X86_BUG( 1*32+ 1) /* "div0" AMD DIV0 speculation bug */
#define X86_BUG_RFDS X86_BUG( 1*32+ 2) /* "rfds" CPU is vulnerable to Register File Data Sampling */
#define X86_BUG_BHI X86_BUG( 1*32+ 3) /* "bhi" CPU is affected by Branch History Injection */
#define X86_BUG_IBPB_NO_RET X86_BUG( 1*32+ 4) /* "ibpb_no_ret" IBPB omits return target predictions */
#define X86_BUG_SPECTRE_V2_USER X86_BUG( 1*32+ 5) /* "spectre_v2_user" CPU is affected by Spectre variant 2 attack between user processes */
#endif /* _ASM_X86_CPUFEATURES_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,17 @@
// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#include <stdio.h>
#include <cpuid.h>
#include <err.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define __noreturn __attribute__((__noreturn__))
typedef unsigned int u32;
typedef unsigned long long u64;
@ -49,7 +52,7 @@ static const char * const reg_names[] = {
struct subleaf {
u32 index;
u32 sub;
u32 eax, ebx, ecx, edx;
u32 output[NR_REGS];
struct reg_desc info[NR_REGS];
};
@ -63,21 +66,64 @@ struct cpuid_func {
int nr;
};
enum range_index {
RANGE_STD = 0, /* Standard */
RANGE_EXT = 0x80000000, /* Extended */
RANGE_TSM = 0x80860000, /* Transmeta */
RANGE_CTR = 0xc0000000, /* Centaur/Zhaoxin */
};
#define CPUID_INDEX_MASK 0xffff0000
#define CPUID_FUNCTION_MASK (~CPUID_INDEX_MASK)
struct cpuid_range {
/* array of main leafs */
struct cpuid_func *funcs;
/* number of valid leafs */
int nr;
bool is_ext;
enum range_index index;
};
/*
* basic: basic functions range: [0... ]
* ext: extended functions range: [0x80000000... ]
*/
struct cpuid_range *leafs_basic, *leafs_ext;
static struct cpuid_range ranges[] = {
{ .index = RANGE_STD, },
{ .index = RANGE_EXT, },
{ .index = RANGE_TSM, },
{ .index = RANGE_CTR, },
};
static char *range_to_str(struct cpuid_range *range)
{
switch (range->index) {
case RANGE_STD: return "Standard";
case RANGE_EXT: return "Extended";
case RANGE_TSM: return "Transmeta";
case RANGE_CTR: return "Centaur";
default: return NULL;
}
}
#define __for_each_cpuid_range(range, __condition) \
for (unsigned int i = 0; \
i < ARRAY_SIZE(ranges) && ((range) = &ranges[i]) && (__condition); \
i++)
#define for_each_valid_cpuid_range(range) __for_each_cpuid_range(range, (range)->nr != 0)
#define for_each_cpuid_range(range) __for_each_cpuid_range(range, true)
struct cpuid_range *index_to_cpuid_range(u32 index)
{
u32 func_idx = index & CPUID_FUNCTION_MASK;
u32 range_idx = index & CPUID_INDEX_MASK;
struct cpuid_range *range;
for_each_valid_cpuid_range(range) {
if (range->index == range_idx && (u32)range->nr > func_idx)
return range;
}
return NULL;
}
static bool is_amd;
static bool show_details;
static bool show_raw;
static bool show_flags_only = true;
@ -85,16 +131,16 @@ static u32 user_index = 0xFFFFFFFF;
static u32 user_sub = 0xFFFFFFFF;
static int flines;
static inline void cpuid(u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
{
/* ecx is often an input as well as an output. */
asm volatile("cpuid"
: "=a" (*eax),
"=b" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "0" (*eax), "2" (*ecx));
}
/*
* Force using <cpuid.h> __cpuid_count() instead of __cpuid(). The
* latter leaves ECX uninitialized, which can break CPUID queries.
*/
#define cpuid(leaf, a, b, c, d) \
__cpuid_count(leaf, 0, a, b, c, d)
#define cpuid_count(leaf, subleaf, a, b, c, d) \
__cpuid_count(leaf, subleaf, a, b, c, d)
static inline bool has_subleafs(u32 f)
{
@ -117,11 +163,11 @@ static void leaf_print_raw(struct subleaf *leaf)
if (leaf->sub == 0)
printf("0x%08x: subleafs:\n", leaf->index);
printf(" %2d: EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n",
leaf->sub, leaf->eax, leaf->ebx, leaf->ecx, leaf->edx);
printf(" %2d: EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n", leaf->sub,
leaf->output[0], leaf->output[1], leaf->output[2], leaf->output[3]);
} else {
printf("0x%08x: EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n",
leaf->index, leaf->eax, leaf->ebx, leaf->ecx, leaf->edx);
printf("0x%08x: EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n", leaf->index,
leaf->output[0], leaf->output[1], leaf->output[2], leaf->output[3]);
}
}
@ -140,19 +186,19 @@ static bool cpuid_store(struct cpuid_range *range, u32 f, int subleaf,
* Cut off vendor-prefix from CPUID function as we're using it as an
* index into ->funcs.
*/
func = &range->funcs[f & 0xffff];
func = &range->funcs[f & CPUID_FUNCTION_MASK];
if (!func->leafs) {
func->leafs = malloc(sizeof(struct subleaf));
if (!func->leafs)
perror("malloc func leaf");
err(EXIT_FAILURE, NULL);
func->nr = 1;
} else {
s = func->nr;
func->leafs = realloc(func->leafs, (s + 1) * sizeof(*leaf));
if (!func->leafs)
perror("realloc f->leafs");
err(EXIT_FAILURE, NULL);
func->nr++;
}
@ -161,84 +207,73 @@ static bool cpuid_store(struct cpuid_range *range, u32 f, int subleaf,
leaf->index = f;
leaf->sub = subleaf;
leaf->eax = a;
leaf->ebx = b;
leaf->ecx = c;
leaf->edx = d;
leaf->output[R_EAX] = a;
leaf->output[R_EBX] = b;
leaf->output[R_ECX] = c;
leaf->output[R_EDX] = d;
return false;
}
static void raw_dump_range(struct cpuid_range *range)
{
u32 f;
int i;
printf("%s Leafs :\n", range->is_ext ? "Extended" : "Basic");
printf("%s Leafs :\n", range_to_str(range));
printf("================\n");
for (f = 0; (int)f < range->nr; f++) {
for (u32 f = 0; (int)f < range->nr; f++) {
struct cpuid_func *func = &range->funcs[f];
u32 index = f;
if (range->is_ext)
index += 0x80000000;
/* Skip leaf without valid items */
if (!func->nr)
continue;
/* First item is the main leaf, followed by all subleafs */
for (i = 0; i < func->nr; i++)
for (int i = 0; i < func->nr; i++)
leaf_print_raw(&func->leafs[i]);
}
}
#define MAX_SUBLEAF_NUM 64
struct cpuid_range *setup_cpuid_range(u32 input_eax)
#define MAX_RANGE_INDEX_OFFSET 0xff
void setup_cpuid_range(struct cpuid_range *range)
{
u32 max_func, idx_func, subleaf, max_subleaf;
u32 eax, ebx, ecx, edx, f = input_eax;
struct cpuid_range *range;
bool allzero;
u32 max_func, range_funcs_sz;
u32 eax, ebx, ecx, edx;
eax = input_eax;
ebx = ecx = edx = 0;
cpuid(range->index, max_func, ebx, ecx, edx);
cpuid(&eax, &ebx, &ecx, &edx);
max_func = eax;
idx_func = (max_func & 0xffff) + 1;
/*
* If the CPUID range's maximum function value is garbage, then it
* is not recognized by this CPU. Set the range's number of valid
* leaves to zero so that for_each_valid_cpu_range() can ignore it.
*/
if (max_func < range->index || max_func > (range->index + MAX_RANGE_INDEX_OFFSET)) {
range->nr = 0;
return;
}
range = malloc(sizeof(struct cpuid_range));
if (!range)
perror("malloc range");
range->nr = (max_func & CPUID_FUNCTION_MASK) + 1;
range_funcs_sz = range->nr * sizeof(struct cpuid_func);
if (input_eax & 0x80000000)
range->is_ext = true;
else
range->is_ext = false;
range->funcs = malloc(sizeof(struct cpuid_func) * idx_func);
range->funcs = malloc(range_funcs_sz);
if (!range->funcs)
perror("malloc range->funcs");
err(EXIT_FAILURE, NULL);
range->nr = idx_func;
memset(range->funcs, 0, sizeof(struct cpuid_func) * idx_func);
memset(range->funcs, 0, range_funcs_sz);
for (; f <= max_func; f++) {
eax = f;
subleaf = ecx = 0;
for (u32 f = range->index; f <= max_func; f++) {
u32 max_subleaf = MAX_SUBLEAF_NUM;
bool allzero;
cpuid(&eax, &ebx, &ecx, &edx);
allzero = cpuid_store(range, f, subleaf, eax, ebx, ecx, edx);
cpuid(f, eax, ebx, ecx, edx);
allzero = cpuid_store(range, f, 0, eax, ebx, ecx, edx);
if (allzero)
continue;
if (!has_subleafs(f))
continue;
max_subleaf = MAX_SUBLEAF_NUM;
/*
* Some can provide the exact number of subleafs,
* others have to be tried (0xf)
@ -256,20 +291,15 @@ struct cpuid_range *setup_cpuid_range(u32 input_eax)
if (f == 0x80000026)
max_subleaf = 5;
for (subleaf = 1; subleaf < max_subleaf; subleaf++) {
eax = f;
ecx = subleaf;
for (u32 subleaf = 1; subleaf < max_subleaf; subleaf++) {
cpuid_count(f, subleaf, eax, ebx, ecx, edx);
cpuid(&eax, &ebx, &ecx, &edx);
allzero = cpuid_store(range, f, subleaf,
eax, ebx, ecx, edx);
allzero = cpuid_store(range, f, subleaf, eax, ebx, ecx, edx);
if (allzero)
continue;
}
}
return range;
}
/*
@ -280,15 +310,13 @@ struct cpuid_range *setup_cpuid_range(u32 input_eax)
* 0, 0, EAX, 31:0, max_basic_leafs, Max input value for supported subleafs
* 1, 0, ECX, 0, sse3, Streaming SIMD Extensions 3(SSE3)
*/
static int parse_line(char *line)
static void parse_line(char *line)
{
char *str;
int i;
struct cpuid_range *range;
struct cpuid_func *func;
struct subleaf *leaf;
u32 index;
u32 sub;
char buffer[512];
char *buf;
/*
@ -310,12 +338,12 @@ static int parse_line(char *line)
/* Skip comments and NULL line */
if (line[0] == '#' || line[0] == '\n')
return 0;
return;
strncpy(buffer, line, 511);
buffer[511] = 0;
str = buffer;
for (i = 0; i < 5; i++) {
for (int i = 0; i < 5; i++) {
tokens[i] = strtok(str, ",");
if (!tokens[i])
goto err_exit;
@ -328,21 +356,19 @@ static int parse_line(char *line)
/* index/main-leaf */
index = strtoull(tokens[0], NULL, 0);
if (index & 0x80000000)
range = leafs_ext;
else
range = leafs_basic;
index &= 0x7FFFFFFF;
/* Skip line parsing for non-existing indexes */
if ((int)index >= range->nr)
return -1;
/*
* Skip line parsing if the index is not covered by known-valid
* CPUID ranges on this CPU.
*/
range = index_to_cpuid_range(index);
if (!range)
return;
/* Skip line parsing if the index CPUID output is all zero */
index &= CPUID_FUNCTION_MASK;
func = &range->funcs[index];
/* Return if the index has no valid item on this platform */
if (!func->nr)
return 0;
return;
/* subleaf */
buf = tokens[1];
@ -355,11 +381,11 @@ static int parse_line(char *line)
subleaf_start = strtoul(start, NULL, 0);
subleaf_end = min(subleaf_end, (u32)(func->nr - 1));
if (subleaf_start > subleaf_end)
return 0;
return;
} else {
subleaf_start = subleaf_end;
if (subleaf_start > (u32)(func->nr - 1))
return 0;
return;
}
/* register */
@ -382,7 +408,7 @@ static int parse_line(char *line)
bit_end = strtoul(end, NULL, 0);
bit_start = (start) ? strtoul(start, NULL, 0) : bit_end;
for (sub = subleaf_start; sub <= subleaf_end; sub++) {
for (u32 sub = subleaf_start; sub <= subleaf_end; sub++) {
leaf = &func->leafs[sub];
reg = &leaf->info[reg_index];
bdesc = &reg->descs[reg->nr++];
@ -392,12 +418,11 @@ static int parse_line(char *line)
strcpy(bdesc->simp, strtok(tokens[4], " \t"));
strcpy(bdesc->detail, tokens[5]);
}
return 0;
return;
err_exit:
printf("Warning: wrong line format:\n");
printf("\tline[%d]: %s\n", flines, line);
return -1;
warnx("Wrong line format:\n"
"\tline[%d]: %s", flines, line);
}
/* Parse csv file, and construct the array of all leafs and subleafs */
@ -418,10 +443,8 @@ static void parse_text(void)
file = fopen("./cpuid.csv", "r");
}
if (!file) {
printf("Fail to open '%s'\n", filename);
return;
}
if (!file)
err(EXIT_FAILURE, "%s", filename);
while (1) {
ret = getline(&line, &len, file);
@ -436,21 +459,13 @@ static void parse_text(void)
fclose(file);
}
/* Decode every eax/ebx/ecx/edx */
static void decode_bits(u32 value, struct reg_desc *rdesc, enum cpuid_reg reg)
static void show_reg(const struct reg_desc *rdesc, u32 value)
{
struct bits_desc *bdesc;
int start, end, i;
const struct bits_desc *bdesc;
int start, end;
u32 mask;
if (!rdesc->nr) {
if (show_details)
printf("\t %s: 0x%08x\n", reg_names[reg], value);
return;
}
for (i = 0; i < rdesc->nr; i++) {
for (int i = 0; i < rdesc->nr; i++) {
bdesc = &rdesc->descs[i];
start = bdesc->start;
@ -480,23 +495,21 @@ static void decode_bits(u32 value, struct reg_desc *rdesc, enum cpuid_reg reg)
}
}
static void show_reg_header(bool has_entries, u32 leaf, u32 subleaf, const char *reg_name)
{
if (show_details && has_entries)
printf("CPUID_0x%x_%s[0x%x]:\n", leaf, reg_name, subleaf);
}
static void show_leaf(struct subleaf *leaf)
{
if (!leaf)
return;
if (show_raw) {
if (show_raw)
leaf_print_raw(leaf);
} else {
if (show_details)
printf("CPUID_0x%x_ECX[0x%x]:\n",
leaf->index, leaf->sub);
}
decode_bits(leaf->eax, &leaf->info[R_EAX], R_EAX);
decode_bits(leaf->ebx, &leaf->info[R_EBX], R_EBX);
decode_bits(leaf->ecx, &leaf->info[R_ECX], R_ECX);
decode_bits(leaf->edx, &leaf->info[R_EDX], R_EDX);
for (int i = R_EAX; i < NR_REGS; i++) {
show_reg_header((leaf->info[i].nr > 0), leaf->index, leaf->sub, reg_names[i]);
show_reg(&leaf->info[i], leaf->output[i]);
}
if (!show_raw && show_details)
printf("\n");
@ -504,46 +517,37 @@ static void show_leaf(struct subleaf *leaf)
static void show_func(struct cpuid_func *func)
{
int i;
if (!func)
return;
for (i = 0; i < func->nr; i++)
for (int i = 0; i < func->nr; i++)
show_leaf(&func->leafs[i]);
}
static void show_range(struct cpuid_range *range)
{
int i;
for (i = 0; i < range->nr; i++)
for (int i = 0; i < range->nr; i++)
show_func(&range->funcs[i]);
}
static inline struct cpuid_func *index_to_func(u32 index)
{
u32 func_idx = index & CPUID_FUNCTION_MASK;
struct cpuid_range *range;
u32 func_idx;
range = (index & 0x80000000) ? leafs_ext : leafs_basic;
func_idx = index & 0xffff;
if ((func_idx + 1) > (u32)range->nr) {
printf("ERR: invalid input index (0x%x)\n", index);
range = index_to_cpuid_range(index);
if (!range)
return NULL;
}
return &range->funcs[func_idx];
}
static void show_info(void)
{
struct cpuid_range *range;
struct cpuid_func *func;
if (show_raw) {
/* Show all of the raw output of 'cpuid' instr */
raw_dump_range(leafs_basic);
raw_dump_range(leafs_ext);
for_each_valid_cpuid_range(range)
raw_dump_range(range);
return;
}
@ -551,18 +555,19 @@ static void show_info(void)
/* Only show specific leaf/subleaf info */
func = index_to_func(user_index);
if (!func)
return;
errx(EXIT_FAILURE, "Invalid input leaf (0x%x)", user_index);
/* Dump the raw data also */
show_raw = true;
if (user_sub != 0xFFFFFFFF) {
if (user_sub + 1 <= (u32)func->nr) {
show_leaf(&func->leafs[user_sub]);
return;
if (user_sub + 1 > (u32)func->nr) {
errx(EXIT_FAILURE, "Leaf 0x%x has no valid subleaf = 0x%x",
user_index, user_sub);
}
printf("ERR: invalid input subleaf (0x%x)\n", user_sub);
show_leaf(&func->leafs[user_sub]);
return;
}
show_func(func);
@ -570,38 +575,21 @@ static void show_info(void)
}
printf("CPU features:\n=============\n\n");
show_range(leafs_basic);
show_range(leafs_ext);
for_each_valid_cpuid_range(range)
show_range(range);
}
static void setup_platform_cpuid(void)
static void __noreturn usage(int exit_code)
{
u32 eax, ebx, ecx, edx;
/* Check vendor */
eax = ebx = ecx = edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
/* "htuA" */
if (ebx == 0x68747541)
is_amd = true;
/* Setup leafs for the basic and extended range */
leafs_basic = setup_cpuid_range(0x0);
leafs_ext = setup_cpuid_range(0x80000000);
}
static void usage(void)
{
printf("kcpuid [-abdfhr] [-l leaf] [-s subleaf]\n"
"\t-a|--all Show both bit flags and complex bit fields info\n"
"\t-b|--bitflags Show boolean flags only\n"
"\t-d|--detail Show details of the flag/fields (default)\n"
"\t-f|--flags Specify the cpuid csv file\n"
"\t-h|--help Show usage info\n"
"\t-l|--leaf=index Specify the leaf you want to check\n"
"\t-r|--raw Show raw cpuid data\n"
"\t-s|--subleaf=sub Specify the subleaf you want to check\n"
errx(exit_code, "kcpuid [-abdfhr] [-l leaf] [-s subleaf]\n"
"\t-a|--all Show both bit flags and complex bit fields info\n"
"\t-b|--bitflags Show boolean flags only\n"
"\t-d|--detail Show details of the flag/fields (default)\n"
"\t-f|--flags Specify the CPUID CSV file\n"
"\t-h|--help Show usage info\n"
"\t-l|--leaf=index Specify the leaf you want to check\n"
"\t-r|--raw Show raw CPUID data\n"
"\t-s|--subleaf=sub Specify the subleaf you want to check"
);
}
@ -617,7 +605,7 @@ static struct option opts[] = {
{ NULL, 0, NULL, 0 }
};
static int parse_options(int argc, char *argv[])
static void parse_options(int argc, char *argv[])
{
int c;
@ -637,9 +625,7 @@ static int parse_options(int argc, char *argv[])
user_csv = optarg;
break;
case 'h':
usage();
exit(1);
break;
usage(EXIT_SUCCESS);
case 'l':
/* main leaf */
user_index = strtoul(optarg, NULL, 0);
@ -652,11 +638,8 @@ static int parse_options(int argc, char *argv[])
user_sub = strtoul(optarg, NULL, 0);
break;
default:
printf("%s: Invalid option '%c'\n", argv[0], optopt);
return -1;
}
return 0;
usage(EXIT_FAILURE);
}
}
/*
@ -669,11 +652,13 @@ static int parse_options(int argc, char *argv[])
*/
int main(int argc, char *argv[])
{
if (parse_options(argc, argv))
return -1;
struct cpuid_range *range;
parse_options(argc, argv);
/* Setup the cpuid leafs of current platform */
setup_platform_cpuid();
for_each_cpuid_range(range)
setup_cpuid_range(range);
/* Read and parse the 'cpuid.csv' */
parse_text();

View File

@ -186,7 +186,7 @@ done
# diff with extra ignore lines
check arch/x86/lib/memcpy_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" -I"^SYM_FUNC_START\(_LOCAL\)*(memcpy_\(erms\|orig\))" -I"^#include <linux/cfi_types.h>"'
check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" -I"^SYM_FUNC_START\(_LOCAL\)*(memset_\(erms\|orig\))"'
check arch/x86/include/asm/amd-ibs.h '-I "^#include [<\"]\(asm/\)*msr-index.h"'
check arch/x86/include/asm/amd/ibs.h '-I "^#include [<\"]\(asm/\)*msr-index.h"'
check arch/arm64/include/asm/cputype.h '-I "^#include [<\"]\(asm/\)*sysreg.h"'
check include/linux/unaligned.h '-I "^#include <linux/unaligned/packed_struct.h>" -I "^#include <asm/byteorder.h>" -I "^#pragma GCC diagnostic"'
check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman-common\(-tools\)*.h>"'

View File

@ -9,7 +9,7 @@
#include <inttypes.h>
#include <linux/string.h>
#include "../../arch/x86/include/asm/amd-ibs.h"
#include "../../arch/x86/include/asm/amd/ibs.h"
#include "debug.h"
#include "session.h"