mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
x86: mce: Provide extended physical CPU info.
Provide extended physial CPU info for the sake of dom0 MCE handling. This information includes <cpu,core,thread> info for all logical CPUs, cpuid information from all of them, and initial MSR values for a few MSRs that are important to MCE handling. Signed-off-by: Frank van der Linden <Frank.Vanderlinden@Sun.COM>
This commit is contained in:
1 parent
ab620f29ef
commit
e16fc5ba59
6 files changed
+194
-22
No files matched your search
@@ -99,6 +99,8 @@ void k8_machine_check(struct cpu_user_regs *regs, long error_code)
|
||||
|
||||
mc_data = x86_mcinfo_getptr();
|
||||
cpu_nr = smp_processor_id();
|
||||
BUG_ON(cpu_nr != vcpu->processor);
|
||||
|
||||
curdom = vcpu->domain;
|
||||
|
||||
memset(&mc_global, 0, sizeof(mc_global));
|
||||
@@ -106,14 +108,12 @@ void k8_machine_check(struct cpu_user_regs *regs, long error_code)
|
||||
mc_global.common.size = sizeof(mc_global);
|
||||
|
||||
mc_global.mc_domid = curdom->domain_id; /* impacted domain */
|
||||
mc_global.mc_coreid = vcpu->processor; /* impacted physical cpu */
|
||||
BUG_ON(cpu_nr != vcpu->processor);
|
||||
mc_global.mc_core_threadid = 0;
|
||||
|
||||
x86_mc_get_cpu_info(cpu_nr, &mc_global.mc_socketid,
|
||||
&mc_global.mc_coreid, &mc_global.mc_core_threadid,
|
||||
&mc_global.mc_apicid, NULL, NULL, NULL);
|
||||
|
||||
mc_global.mc_vcpuid = vcpu->vcpu_id; /* impacted vcpu */
|
||||
#if 0 /* TODO: on which socket is this physical core?
|
||||
It's not clear to me how to figure this out. */
|
||||
mc_global.mc_socketid = ???;
|
||||
#endif
|
||||
mc_global.mc_flags |= MC_FLAG_UNCORRECTABLE;
|
||||
rdmsrl(MSR_IA32_MCG_STATUS, mc_global.mc_gstatus);
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ void mce_amd_checkregs(void *info)
|
||||
mc_data = NULL;
|
||||
|
||||
cpu_nr = smp_processor_id();
|
||||
BUG_ON(cpu_nr != vcpu->processor);
|
||||
event_enabled = guest_enabled_event(dom0->vcpu[0], VIRQ_MCA);
|
||||
error_found = 0;
|
||||
|
||||
@@ -103,14 +104,12 @@ void mce_amd_checkregs(void *info)
|
||||
mc_global.common.size = sizeof(mc_global);
|
||||
|
||||
mc_global.mc_domid = vcpu->domain->domain_id; /* impacted domain */
|
||||
mc_global.mc_coreid = vcpu->processor; /* impacted physical cpu */
|
||||
BUG_ON(cpu_nr != vcpu->processor);
|
||||
mc_global.mc_core_threadid = 0;
|
||||
mc_global.mc_vcpuid = vcpu->vcpu_id; /* impacted vcpu */
|
||||
#if 0 /* TODO: on which socket is this physical core?
|
||||
It's not clear to me how to figure this out. */
|
||||
mc_global.mc_socketid = ???;
|
||||
#endif
|
||||
|
||||
x86_mc_get_cpu_info(cpu_nr, &mc_global.mc_socketid,
|
||||
&mc_global.mc_coreid, &mc_global.mc_core_threadid,
|
||||
&mc_global.mc_apicid, NULL, NULL, NULL);
|
||||
|
||||
mc_global.mc_flags |= MC_FLAG_CORRECTABLE;
|
||||
rdmsrl(MSR_IA32_MCG_STATUS, mc_global.mc_gstatus);
|
||||
|
||||
|
||||
@@ -443,6 +443,96 @@ next:
|
||||
|
||||
|
||||
|
||||
static void do_mc_get_cpu_info(void *v)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
int cindex, cpn;
|
||||
struct cpuinfo_x86 *c;
|
||||
xen_mc_logical_cpu_t *log_cpus, *xcp;
|
||||
uint32_t junk, ebx;
|
||||
|
||||
log_cpus = v;
|
||||
c = &cpu_data[cpu];
|
||||
cindex = 0;
|
||||
cpn = cpu - 1;
|
||||
|
||||
/*
|
||||
* Deal with sparse masks, condensed into a contig array.
|
||||
*/
|
||||
while (cpn >= 0) {
|
||||
if (cpu_isset(cpn, cpu_online_map))
|
||||
cindex++;
|
||||
cpn--;
|
||||
}
|
||||
|
||||
xcp = &log_cpus[cindex];
|
||||
c = &cpu_data[cpu];
|
||||
xcp->mc_cpunr = cpu;
|
||||
x86_mc_get_cpu_info(cpu, &xcp->mc_chipid,
|
||||
&xcp->mc_coreid, &xcp->mc_threadid,
|
||||
&xcp->mc_apicid, &xcp->mc_ncores,
|
||||
&xcp->mc_ncores_active, &xcp->mc_nthreads);
|
||||
xcp->mc_cpuid_level = c->cpuid_level;
|
||||
xcp->mc_family = c->x86;
|
||||
xcp->mc_vendor = c->x86_vendor;
|
||||
xcp->mc_model = c->x86_model;
|
||||
xcp->mc_step = c->x86_mask;
|
||||
xcp->mc_cache_size = c->x86_cache_size;
|
||||
xcp->mc_cache_alignment = c->x86_cache_alignment;
|
||||
memcpy(xcp->mc_vendorid, c->x86_vendor_id, sizeof xcp->mc_vendorid);
|
||||
memcpy(xcp->mc_brandid, c->x86_model_id, sizeof xcp->mc_brandid);
|
||||
memcpy(xcp->mc_cpu_caps, c->x86_capability, sizeof xcp->mc_cpu_caps);
|
||||
|
||||
/*
|
||||
* This part needs to run on the CPU itself.
|
||||
*/
|
||||
xcp->mc_nmsrvals = __MC_NMSRS;
|
||||
xcp->mc_msrvalues[0].reg = MSR_IA32_MCG_CAP;
|
||||
rdmsrl(MSR_IA32_MCG_CAP, xcp->mc_msrvalues[0].value);
|
||||
|
||||
if (c->cpuid_level >= 1) {
|
||||
cpuid(1, &junk, &ebx, &junk, &junk);
|
||||
xcp->mc_clusterid = (ebx >> 24) & 0xff;
|
||||
} else
|
||||
xcp->mc_clusterid = hard_smp_processor_id();
|
||||
}
|
||||
|
||||
|
||||
void x86_mc_get_cpu_info(unsigned cpu, uint32_t *chipid, uint16_t *coreid,
|
||||
uint16_t *threadid, uint32_t *apicid,
|
||||
unsigned *ncores, unsigned *ncores_active,
|
||||
unsigned *nthreads)
|
||||
{
|
||||
struct cpuinfo_x86 *c;
|
||||
|
||||
*apicid = cpu_physical_id(cpu);
|
||||
c = &cpu_data[cpu];
|
||||
if (c->apicid == BAD_APICID) {
|
||||
*chipid = cpu;
|
||||
*coreid = 0;
|
||||
*threadid = 0;
|
||||
if (ncores != NULL)
|
||||
*ncores = 1;
|
||||
if (ncores_active != NULL)
|
||||
*ncores_active = 1;
|
||||
if (nthreads != NULL)
|
||||
*nthreads = 1;
|
||||
} else {
|
||||
*chipid = phys_proc_id[cpu];
|
||||
if (c->x86_max_cores > 1)
|
||||
*coreid = cpu_core_id[cpu];
|
||||
else
|
||||
*coreid = 0;
|
||||
*threadid = c->apicid & ((1 << (c->x86_num_siblings - 1)) - 1);
|
||||
if (ncores != NULL)
|
||||
*ncores = c->x86_max_cores;
|
||||
if (ncores_active != NULL)
|
||||
*ncores_active = c->booted_cores;
|
||||
if (nthreads != NULL)
|
||||
*nthreads = c->x86_num_siblings;
|
||||
}
|
||||
}
|
||||
|
||||
/* Machine Check Architecture Hypercall */
|
||||
long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u_xen_mc)
|
||||
{
|
||||
@@ -452,6 +542,7 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u_xen_mc)
|
||||
struct domain *domU;
|
||||
struct xen_mc_fetch *mc_fetch;
|
||||
struct xen_mc_notifydomain *mc_notifydomain;
|
||||
struct xen_mc_physcpuinfo *mc_physcpuinfo;
|
||||
struct mc_info *mi;
|
||||
uint32_t flags;
|
||||
uint32_t fetch_idx;
|
||||
@@ -460,6 +551,8 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u_xen_mc)
|
||||
* a DomU to fetch mc data while Dom0 notifies another DomU. */
|
||||
static DEFINE_SPINLOCK(mc_lock);
|
||||
static DEFINE_SPINLOCK(mc_notify_lock);
|
||||
int nlcpu;
|
||||
xen_mc_logical_cpu_t *log_cpus = NULL;
|
||||
|
||||
if ( copy_from_guest(op, u_xen_mc, 1) )
|
||||
return -EFAULT;
|
||||
@@ -580,6 +673,43 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u_xen_mc)
|
||||
|
||||
spin_unlock(&mc_notify_lock);
|
||||
break;
|
||||
|
||||
case XEN_MC_physcpuinfo:
|
||||
if ( !IS_PRIV(v->domain) )
|
||||
return -EPERM;
|
||||
|
||||
mc_physcpuinfo = &op->u.mc_physcpuinfo;
|
||||
nlcpu = num_online_cpus();
|
||||
|
||||
if (!guest_handle_is_null(mc_physcpuinfo->info)) {
|
||||
if (mc_physcpuinfo->ncpus <= 0)
|
||||
return -EINVAL;
|
||||
nlcpu = min(nlcpu, (int)mc_physcpuinfo->ncpus);
|
||||
log_cpus = xmalloc_array(xen_mc_logical_cpu_t, nlcpu);
|
||||
if (log_cpus == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (on_each_cpu(do_mc_get_cpu_info, log_cpus,
|
||||
1, 1) != 0) {
|
||||
xfree(log_cpus);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
mc_physcpuinfo->ncpus = nlcpu;
|
||||
|
||||
if (copy_to_guest(u_xen_mc, op, 1)) {
|
||||
if (log_cpus != NULL)
|
||||
xfree(log_cpus);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!guest_handle_is_null(mc_physcpuinfo->info)) {
|
||||
if (copy_to_guest(mc_physcpuinfo->info,
|
||||
log_cpus, nlcpu))
|
||||
ret = -EFAULT;
|
||||
xfree(log_cpus);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -34,4 +34,5 @@ void x86_mcinfo_clear(struct mc_info *mi);
|
||||
int x86_mcinfo_add(struct mc_info *mi, void *mcinfo);
|
||||
void x86_mcinfo_dump(struct mc_info *mi);
|
||||
void mc_panic(char *s);
|
||||
|
||||
void x86_mc_get_cpu_info(unsigned, uint32_t *, uint16_t *, uint16_t *,
|
||||
uint32_t *, uint32_t *, uint32_t *, uint32_t *);
|
||||
@@ -182,11 +182,9 @@ static struct mc_info *machine_check_poll(int calltype)
|
||||
mcg.mc_flags = MC_FLAG_POLLED;
|
||||
else if (calltype == MC_FLAG_CMCI)
|
||||
mcg.mc_flags = MC_FLAG_CMCI;
|
||||
mcg.mc_socketid = phys_proc_id[cpu];
|
||||
mcg.mc_coreid = cpu_core_id[cpu];
|
||||
mcg.mc_apicid = cpu_physical_id(cpu);
|
||||
mcg.mc_core_threadid =
|
||||
mcg.mc_apicid & ( 1 << (cpu_data[cpu].x86_num_siblings - 1));
|
||||
x86_mc_get_cpu_info(
|
||||
cpu, &mcg.mc_socketid, &mcg.mc_coreid,
|
||||
&mcg.mc_core_threadid, &mcg.mc_apicid, NULL, NULL, NULL);
|
||||
rdmsrl(MSR_IA32_MCG_STATUS, mcg.mc_gstatus);
|
||||
|
||||
for ( i = 0; i < nr_mce_banks; i++ ) {
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
/* Hypercall */
|
||||
#define __HYPERVISOR_mca __HYPERVISOR_arch_0
|
||||
|
||||
#define XEN_MCA_INTERFACE_VERSION 0x03000001
|
||||
#define XEN_MCA_INTERFACE_VERSION 0x03000002
|
||||
|
||||
/* IN: Dom0 calls hypercall from MC event handler. */
|
||||
#define XEN_MC_CORRECTABLE 0x0
|
||||
@@ -118,7 +118,7 @@ struct mcinfo_global {
|
||||
uint16_t mc_domid;
|
||||
uint32_t mc_socketid; /* physical socket of the physical core */
|
||||
uint16_t mc_coreid; /* physical impacted core */
|
||||
uint8_t mc_apicid;
|
||||
uint32_t mc_apicid;
|
||||
uint16_t mc_core_threadid; /* core thread of physical core */
|
||||
uint16_t mc_vcpuid; /* virtual cpu scheduled for mc_domid */
|
||||
uint64_t mc_gstatus; /* global status */
|
||||
@@ -175,6 +175,41 @@ struct mc_info {
|
||||
};
|
||||
typedef struct mc_info mc_info_t;
|
||||
|
||||
#define __MC_MSR_ARRAYSIZE 8
|
||||
#define __MC_NMSRS 1
|
||||
#define MC_NCAPS 7 /* 7 CPU feature flag words */
|
||||
#define MC_CAPS_STD_EDX 0 /* cpuid level 0x00000001 (%edx) */
|
||||
#define MC_CAPS_AMD_EDX 1 /* cpuid level 0x80000001 (%edx) */
|
||||
#define MC_CAPS_TM 2 /* cpuid level 0x80860001 (TransMeta) */
|
||||
#define MC_CAPS_LINUX 3 /* Linux-defined */
|
||||
#define MC_CAPS_STD_ECX 4 /* cpuid level 0x00000001 (%ecx) */
|
||||
#define MC_CAPS_VIA 5 /* cpuid level 0xc0000001 */
|
||||
#define MC_CAPS_AMD_ECX 6 /* cpuid level 0x80000001 (%ecx) */
|
||||
|
||||
typedef struct mcinfo_logical_cpu {
|
||||
uint32_t mc_cpunr;
|
||||
uint32_t mc_chipid;
|
||||
uint16_t mc_coreid;
|
||||
uint16_t mc_threadid;
|
||||
uint32_t mc_apicid;
|
||||
uint32_t mc_clusterid;
|
||||
uint32_t mc_ncores;
|
||||
uint32_t mc_ncores_active;
|
||||
uint32_t mc_nthreads;
|
||||
int32_t mc_cpuid_level;
|
||||
uint32_t mc_family;
|
||||
uint32_t mc_vendor;
|
||||
uint32_t mc_model;
|
||||
uint32_t mc_step;
|
||||
char mc_vendorid[16];
|
||||
char mc_brandid[64];
|
||||
uint32_t mc_cpu_caps[MC_NCAPS];
|
||||
uint32_t mc_cache_size;
|
||||
uint32_t mc_cache_alignment;
|
||||
int32_t mc_nmsrvals;
|
||||
struct mcinfo_msr mc_msrvalues[__MC_MSR_ARRAYSIZE];
|
||||
} xen_mc_logical_cpu_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_mc_logical_cpu_t);
|
||||
|
||||
|
||||
/*
|
||||
@@ -272,6 +307,14 @@ struct xen_mc_notifydomain {
|
||||
typedef struct xen_mc_notifydomain xen_mc_notifydomain_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_mc_notifydomain_t);
|
||||
|
||||
#define XEN_MC_physcpuinfo 3
|
||||
struct xen_mc_physcpuinfo {
|
||||
/* IN/OUT */
|
||||
uint32_t ncpus;
|
||||
uint32_t pad0;
|
||||
/* OUT */
|
||||
XEN_GUEST_HANDLE(xen_mc_logical_cpu_t) info;
|
||||
};
|
||||
|
||||
struct xen_mc {
|
||||
uint32_t cmd;
|
||||
@@ -279,6 +322,7 @@ struct xen_mc {
|
||||
union {
|
||||
struct xen_mc_fetch mc_fetch;
|
||||
struct xen_mc_notifydomain mc_notifydomain;
|
||||
struct xen_mc_physcpuinfo mc_physcpuinfo;
|
||||
uint8_t pad[MCINFO_HYPERCALLSIZE];
|
||||
} u;
|
||||
};
|
||||
|
||||