xen: arm: implement cpuinfo

Use to:

 - Only context switch ThumbEE state if the processor implements it. In
   particular the ARMv8 FastModels do not.
 - Detect the generic timer, and therefore call identify_cpu before
   init_xen_time.

Also improve the boot time messages a bit.

I haven't added decoding for all of the CPUID words, it seems like overkill
for the moment.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Acked-by: Tim Deegan <tim@xen.org>
Cc: stefano.stabellini@citrix.com
This commit is contained in:
Ian Campbell committed 2013-02-22 12:14:56 +00:00
1 parent 75c3b4097c
commit 7269eeae75
10 files changed
+367 -47

No files matched your search

+1
View File
@@ -3,6 +3,7 @@ subdir-$(arm64) += arm64
subdir-y += platforms
obj-y += early_printk.o
obj-y += cpu.o
obj-y += domain.o
obj-y += domctl.o
obj-y += sysctl.o
+69
View File
@@ -0,0 +1,69 @@
/*
* 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 2 of the License, 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.
*/
#include <xen/config.h>
#include <xen/init.h>
#include <xen/lib.h>
#include <xen/sched.h>
#include <asm/processor.h>
void __cpuinit identify_cpu(struct cpuinfo_arm *c)
{
c->midr.bits = READ_SYSREG32(MIDR_EL1);
c->mpidr.bits = READ_SYSREG(MPIDR_EL1);
#ifdef CONFIG_ARM_64
c->pfr64.bits[0] = READ_SYSREG64(ID_AA64PFR0_EL1);
c->pfr64.bits[1] = READ_SYSREG64(ID_AA64PFR1_EL1);
c->dbg64.bits[0] = READ_SYSREG64(ID_AA64DFR0_EL1);
c->dbg64.bits[1] = READ_SYSREG64(ID_AA64DFR1_EL1);
c->aux64.bits[0] = READ_SYSREG64(ID_AA64AFR0_EL1);
c->aux64.bits[1] = READ_SYSREG64(ID_AA64AFR1_EL1);
c->mm64.bits[0] = READ_SYSREG64(ID_AA64MMFR0_EL1);
c->mm64.bits[1] = READ_SYSREG64(ID_AA64MMFR1_EL1);
c->isa64.bits[0] = READ_SYSREG64(ID_AA64ISAR0_EL1);
c->isa64.bits[1] = READ_SYSREG64(ID_AA64ISAR1_EL1);
#endif
c->pfr32.bits[0] = READ_SYSREG32(ID_PFR0_EL1);
c->pfr32.bits[1] = READ_SYSREG32(ID_PFR1_EL1);
c->dbg32.bits[0] = READ_SYSREG32(ID_DFR0_EL1);
c->aux32.bits[0] = READ_SYSREG32(ID_AFR0_EL1);
c->mm32.bits[0] = READ_SYSREG32(ID_MMFR0_EL1);
c->mm32.bits[1] = READ_SYSREG32(ID_MMFR1_EL1);
c->mm32.bits[2] = READ_SYSREG32(ID_MMFR2_EL1);
c->mm32.bits[3] = READ_SYSREG32(ID_MMFR3_EL1);
c->isa32.bits[0] = READ_SYSREG32(ID_ISAR0_EL1);
c->isa32.bits[1] = READ_SYSREG32(ID_ISAR1_EL1);
c->isa32.bits[2] = READ_SYSREG32(ID_ISAR2_EL1);
c->isa32.bits[3] = READ_SYSREG32(ID_ISAR3_EL1);
c->isa32.bits[4] = READ_SYSREG32(ID_ISAR4_EL1);
c->isa32.bits[5] = READ_SYSREG32(ID_ISAR5_EL1);
}
/*
* Local variables:
* mode: C
* c-set-style: "BSD"
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/
+31 -8
View File
@@ -1,3 +1,14 @@
/*
* 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 2 of the License, 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.
*/
#include <xen/config.h>
#include <xen/init.h>
#include <xen/lib.h>
@@ -13,6 +24,7 @@
#include <asm/regs.h>
#include <asm/p2m.h>
#include <asm/irq.h>
#include <asm/cpufeature.h>
#include <asm/gic.h>
#include "vtimer.h"
@@ -58,11 +70,13 @@ static void ctxt_switch_from(struct vcpu *p)
/* Arch timer */
virt_timer_save(p);
#if defined(CONFIG_ARM_32)
/* XXX only save these if ThumbEE e.g. ID_PFR0.THUMB_EE_SUPPORT */
p->arch.teecr = READ_CP32(TEECR);
p->arch.teehbr = READ_CP32(TEEHBR);
if ( is_pv32_domain(p->domain) && cpu_has_thumbee )
{
p->arch.teecr = READ_SYSREG32(TEECR32_EL1);
p->arch.teehbr = READ_SYSREG32(TEEHBR32_EL1);
}
#ifdef CONFIG_ARM_32
p->arch.joscr = READ_CP32(JOSCR);
p->arch.jmcr = READ_CP32(JMCR);
#endif
@@ -121,6 +135,9 @@ static void ctxt_switch_to(struct vcpu *n)
p2m_load_VTTBR(n->domain);
isb();
WRITE_SYSREG32(n->domain->arch.vpidr, VPIDR_EL2);
WRITE_SYSREG(n->domain->arch.vmpidr, VMPIDR_EL2);
/* VGIC */
gic_restore_state(n);
@@ -169,11 +186,13 @@ static void ctxt_switch_to(struct vcpu *n)
WRITE_SYSREG(n->arch.tpidrro_el0, TPIDRRO_EL0);
WRITE_SYSREG(n->arch.tpidr_el1, TPIDR_EL1);
#if defined(CONFIG_ARM_32)
/* XXX only restore these if ThumbEE e.g. ID_PFR0.THUMB_EE_SUPPORT */
WRITE_CP32(n->arch.teecr, TEECR);
WRITE_CP32(n->arch.teehbr, TEEHBR);
if ( is_pv32_domain(n->domain) && cpu_has_thumbee )
{
WRITE_SYSREG32(n->arch.teecr, TEECR32_EL1);
WRITE_SYSREG32(n->arch.teehbr, TEEHBR32_EL1);
}
#ifdef CONFIG_ARM_32
WRITE_CP32(n->arch.joscr, JOSCR);
WRITE_CP32(n->arch.jmcr, JMCR);
#endif
@@ -447,6 +466,10 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags)
if ( (d->shared_info = alloc_xenheap_pages(0, 0)) == NULL )
goto fail;
/* Default the virtual ID to match the physical */
d->arch.vpidr = boot_cpu_data.midr.bits;
d->arch.vmpidr = boot_cpu_data.mpidr.bits;
clear_page(d->shared_info);
share_xen_page_with_guest(
virt_to_page(d->shared_info), d, XENSHARE_writable);
+81 -26
View File
@@ -40,6 +40,9 @@
#include <asm/vfp.h>
#include <asm/early_printk.h>
#include <asm/gic.h>
#include <asm/cpufeature.h>
struct cpuinfo_arm __read_mostly boot_cpu_data;
static __used void init_done(void)
{
@@ -54,41 +57,93 @@ static void __init init_idle_domain(void)
/* TODO: setup_idle_pagetable(); */
}
static const char * __initdata processor_implementers[] = {
['A'] = "ARM Limited",
['D'] = "Digital Equipment Corp",
['M'] = "Motorola, Freescale Semiconductor Inc.",
['Q'] = "Qualcomm Inc.",
['V'] = "Marvell Semiconductor Inc.",
['i'] = "Intel Corporation",
};
static void __init processor_id(void)
{
const char *implementer = "Unknown";
struct cpuinfo_arm *c = &boot_cpu_data;
/* Setup the virtual ID to match the physical */
WRITE_SYSREG32(READ_SYSREG32(MIDR_EL1), VPIDR_EL2);
WRITE_SYSREG(READ_SYSREG(MPIDR_EL1), VMPIDR_EL2);
identify_cpu(c);
current_cpu_data = *c;
if ( c->midr.implementer < ARRAY_SIZE(processor_implementers) &&
processor_implementers[c->midr.implementer] )
implementer = processor_implementers[c->midr.implementer];
if ( c->midr.architecture != 0xf )
printk("Huh, cpu architecture %x, expected 0xf (defined by cpuid)\n",
c->midr.architecture);
printk("Processor: \"%s\", variant: 0x%x, part 0x%03x, rev 0x%x\n",
implementer, c->midr.variant, c->midr.part_number, c->midr.revision);
#if defined(CONFIG_ARM_64)
printk("64-bit Processor Features: %016"PRIx64" %016"PRIx64"\n",
READ_SYSREG64(ID_AA64PFR0_EL1), READ_SYSREG64(ID_AA64PFR1_EL1));
printk("64-bit Debug Features: %016"PRIx64" %016"PRIx64"\n",
READ_SYSREG64(ID_AA64DFR0_EL1), READ_SYSREG64(ID_AA64DFR1_EL1));
printk("64-bit Auxiliary Features: %016"PRIx64" %016"PRIx64"\n",
READ_SYSREG64(ID_AA64AFR0_EL1), READ_SYSREG64(ID_AA64AFR1_EL1));
printk("64-bit Memory Model Features: %016"PRIx64" %016"PRIx64"\n",
READ_SYSREG64(ID_AA64MMFR0_EL1), READ_SYSREG64(ID_AA64MMFR1_EL1));
printk("64-bit ISA Features: %016"PRIx64" %016"PRIx64"\n",
READ_SYSREG64(ID_AA64ISAR0_EL1), READ_SYSREG64(ID_AA64ISAR1_EL1));
printk("64-bit Execution:\n");
printk(" Processor Features: %016"PRIx64" %016"PRIx64"\n",
boot_cpu_data.pfr64.bits[0], boot_cpu_data.pfr64.bits[1]);
printk(" Exception Levels: EL3:%s EL2:%s EL1:%s EL0:%s\n",
cpu_has_el3_32 ? "64+32" : cpu_has_el3_64 ? "64" : "No",
cpu_has_el2_32 ? "64+32" : cpu_has_el2_64 ? "64" : "No",
cpu_has_el1_32 ? "64+32" : cpu_has_el1_64 ? "64" : "No",
cpu_has_el0_32 ? "64+32" : cpu_has_el0_64 ? "64" : "No");
printk(" Extensions:%s%s\n",
cpu_has_fp ? " FloatingPoint" : "",
cpu_has_simd ? " AdvancedSIMD" : "");
printk(" Debug Features: %016"PRIx64" %016"PRIx64"\n",
boot_cpu_data.dbg64.bits[0], boot_cpu_data.dbg64.bits[1]);
printk(" Auxiliary Features: %016"PRIx64" %016"PRIx64"\n",
boot_cpu_data.aux64.bits[0], boot_cpu_data.aux64.bits[1]);
printk(" Memory Model Features: %016"PRIx64" %016"PRIx64"\n",
boot_cpu_data.mm64.bits[0], boot_cpu_data.mm64.bits[1]);
printk(" ISA Features: %016"PRIx64" %016"PRIx64"\n",
boot_cpu_data.isa64.bits[0], boot_cpu_data.isa64.bits[1]);
#endif
/*
* On AArch64 these refer to the capabilities when running in
* AArch32 mode.
*/
printk("32-bit Processor Features: %08x %08x\n",
READ_SYSREG32(ID_PFR0_EL1), READ_SYSREG32(ID_PFR1_EL1));
printk("32-bit Debug Features: %08x\n", READ_SYSREG32(ID_DFR0_EL1));
printk("32-bit Auxiliary Features: %08x\n", READ_SYSREG32(ID_AFR0_EL1));
printk("32-bit Memory Model Features: %08x %08x %08x %08x\n",
READ_SYSREG32(ID_MMFR0_EL1), READ_SYSREG32(ID_MMFR1_EL1),
READ_SYSREG32(ID_MMFR2_EL1), READ_SYSREG32(ID_MMFR3_EL1));
printk("32-bit ISA Features: %08x %08x %08x %08x %08x %08x\n",
READ_SYSREG32(ID_ISAR0_EL1), READ_SYSREG32(ID_ISAR1_EL1),
READ_SYSREG32(ID_ISAR2_EL1), READ_SYSREG32(ID_ISAR3_EL1),
READ_SYSREG32(ID_ISAR4_EL1), READ_SYSREG32(ID_ISAR5_EL1));
if ( cpu_has_aarch32 )
{
printk("32-bit Execution:\n");
printk(" Processor Features: %08"PRIx32":%08"PRIx32"\n",
boot_cpu_data.pfr32.bits[0], boot_cpu_data.pfr32.bits[1]);
printk(" Instruction Sets:%s%s%s%s%s\n",
cpu_has_aarch32 ? " AArch32" : "",
cpu_has_thumb ? " Thumb" : "",
cpu_has_thumb2 ? " Thumb-2" : "",
cpu_has_thumbee ? " ThumbEE" : "",
cpu_has_jazelle ? " Jazelle" : "");
printk(" Extensions:%s%s\n",
cpu_has_gentimer ? " GenericTimer" : "",
cpu_has_security ? " Security" : "");
printk(" Debug Features: %08"PRIx32"\n",
boot_cpu_data.dbg32.bits[0]);
printk(" Auxiliary Features: %08"PRIx32"\n",
boot_cpu_data.aux32.bits[0]);
printk(" Memory Model Features: "
"%08"PRIx32" %08"PRIx32" %08"PRIx32" %08"PRIx32"\n",
boot_cpu_data.mm32.bits[0], boot_cpu_data.mm32.bits[1],
boot_cpu_data.mm32.bits[2], boot_cpu_data.mm32.bits[3]);
printk(" ISA Features: %08x %08x %08x %08x %08x %08x\n",
boot_cpu_data.isa32.bits[0], boot_cpu_data.isa32.bits[1],
boot_cpu_data.isa32.bits[2], boot_cpu_data.isa32.bits[3],
boot_cpu_data.isa32.bits[4], boot_cpu_data.isa32.bits[5]);
}
else
{
printk("32-bit Execution: Unsupported\n");
}
}
void __init discard_initial_modules(void)
@@ -379,6 +434,8 @@ void __init start_xen(unsigned long boot_phys_offset,
console_init_preirq();
#endif
processor_id();
init_xen_time();
gic_init();
@@ -400,8 +457,6 @@ void __init start_xen(unsigned long boot_phys_offset,
*/
WRITE_SYSREG32(0x80002558, VTCR_EL2); isb();
processor_id();
enable_vfp();
softirq_init();
+7
View File
@@ -38,6 +38,8 @@ EXPORT_SYMBOL(cpu_online_map);
cpumask_t cpu_possible_map;
EXPORT_SYMBOL(cpu_possible_map);
struct cpuinfo_arm cpu_data[NR_CPUS];
/* Fake one node for now. See also include/asm-arm/numa.h */
nodemask_t __read_mostly node_online_map = { { [0] = 1UL } };
@@ -136,11 +138,16 @@ void __cpuinit start_secondary(unsigned long boot_phys_offset,
unsigned long fdt_paddr,
unsigned long cpuid)
{
struct cpuinfo_arm *c = cpu_data + cpuid;
memset(get_cpu_info(), 0, sizeof (struct cpu_info));
/* TODO: handle boards where CPUIDs are not contiguous */
set_processor_id(cpuid);
*c = boot_cpu_data;
identify_cpu(c);
/* Setup Hyp vector base */
WRITE_SYSREG((vaddr_t)hyp_traps_vector, VBAR_EL2);
+2 -3
View File
@@ -31,6 +31,7 @@
#include <asm/system.h>
#include <asm/time.h>
#include <asm/gic.h>
#include <asm/cpufeature.h>
/*
* Unfortunately the hypervisor timer interrupt appears to be buggy in
@@ -90,10 +91,8 @@ static uint32_t calibrate_timer(void)
int __init init_xen_time(void)
{
/* Check that this CPU supports the Generic Timer interface */
#if defined(CONFIG_ARM_32)
if ( (READ_CP32(ID_PFR1) & ID_PFR1_GT_MASK) != ID_PFR1_GT_v1 )
if ( !cpu_has_gentimer )
panic("CPU does not support the Generic Timer v1 interface.\n");
#endif
cpu_khz = READ_SYSREG32(CNTFRQ_EL0) / 1000;
boot_count = READ_SYSREG64(CNTPCT_EL0);
+6 -5
View File
@@ -265,10 +265,14 @@
#define ID_PFR0_EL1 ID_PFR0
#define ID_PFR1_EL1 ID_PFR1
#define IFSR32_EL2 IFSR
#define MIDR_EL1 MIDR
#define MPIDR_EL1 MPIDR
#define PAR_EL1 PAR
#define SCTLR_EL1 SCTLR
#define SCTLR_EL2 HSCTLR
#define TCR_EL1 TTBCR
#define TEECR32_EL1 TEECR
#define TEEHBR32_EL1 TEEHBR
#define TPIDRRO_EL0 TPIDRURO
#define TPIDR_EL0 TPIDRURW
#define TPIDR_EL1 TPIDRPRW
@@ -278,13 +282,10 @@
#define TTBR1_EL1 TTBR1
#define VBAR_EL1 VBAR
#define VBAR_EL2 HVBAR
#define VMPIDR_EL2 VMPIDR
#define VPIDR_EL2 VPIDR
#define VTCR_EL2 VTCR
#define VTTBR_EL2 VTTBR
#define MIDR_EL1 MIDR
#define VPIDR_EL2 VPIDR
#define MPIDR_EL1 MPIDR
#define VMPIDR_EL2 VMPIDR
#endif
#endif
+40
View File
@@ -0,0 +1,40 @@
#ifndef __ASM_ARM_CPUFEATURE_H
#define __ASM_ARM_CPUFEATURE_H
#ifdef CONFIG_ARM_64
#define cpu_feature64(c, feat) ((c)->pfr64.feat)
#define boot_cpu_feature64(feat) (boot_cpu_data.pfr64.feat)
#define cpu_has_el0_32 (boot_cpu_feature64(el0) == 2)
#define cpu_has_el0_64 (boot_cpu_feature64(el0) >= 1)
#define cpu_has_el1_32 (boot_cpu_feature64(el1) == 2)
#define cpu_has_el1_64 (boot_cpu_feature64(el1) >= 1)
#define cpu_has_el2_32 (boot_cpu_feature64(el2) == 2)
#define cpu_has_el2_64 (boot_cpu_feature64(el2) >= 1)
#define cpu_has_el3_32 (boot_cpu_feature64(el3) == 2)
#define cpu_has_el3_64 (boot_cpu_feature64(el3) >= 1)
#define cpu_has_fp (boot_cpu_feature64(fp) == 0)
#define cpu_has_simd (boot_cpu_feature64(simd) == 0)
#endif
#define cpu_feature32(c, feat) ((c)->pfr32.feat)
#define boot_cpu_feature32(feat) (boot_cpu_data.pfr32.feat)
#define cpu_has_aarch32 (boot_cpu_feature32(arm) == 1)
#define cpu_has_thumb (boot_cpu_feature32(thumb) >= 1)
#define cpu_has_thumb2 (boot_cpu_feature32(thumb) >= 3)
#define cpu_has_jazelle (boot_cpu_feature32(jazelle) >= 0)
#define cpu_has_thumbee (boot_cpu_feature32(thumbee) == 1)
#define cpu_has_gentimer (boot_cpu_feature32(gentimer) == 1)
#define cpu_has_security (boot_cpu_feature32(security) > 0)
#endif
/*
* Local variables:
* mode: C
* c-set-style: "BSD"
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/
+9 -1
View File
@@ -57,6 +57,10 @@ struct arch_domain
struct hvm_domain hvm_domain;
xen_pfn_t *grant_table_gpfn;
/* Virtual CPUID */
uint32_t vpidr;
register_t vmpidr;
struct {
/*
* Covers access to other members of this struct _except_ for
@@ -166,8 +170,12 @@ struct arch_vcpu
register_t tpidr_el1;
register_t tpidrro_el0;
uint32_t teecr, teehbr; /* ThumbEE, 32-bit guests only */
#ifdef CONFIG_ARM_32
uint32_t teecr, teehbr;
/*
* ARMv8 only supports a trivial implementation on Jazelle when in AArch32
* mode and therefore has no extended control registers.
*/
uint32_t joscr, jmcr;
#endif
+121 -4
View File
@@ -91,6 +91,123 @@
#define HSR_EC_DATA_ABORT_HYP 0x25
#ifndef __ASSEMBLY__
#include <xen/types.h>
struct cpuinfo_arm {
union {
uint32_t bits;
struct {
unsigned long revision:4;
unsigned long part_number:12;
unsigned long architecture:4;
unsigned long variant:4;
unsigned long implementer:8;
};
} midr;
union {
register_t bits;
struct {
unsigned long aff0:8;
unsigned long aff1:8;
unsigned long aff2:8;
unsigned long mt:1; /* Multi-thread, iff MP == 1 */
unsigned long __res0:5;
unsigned long up:1; /* UP system, iff MP == 1 */
unsigned long mp:1; /* MP extensions */
#ifdef CONFIG_ARM_64
unsigned long aff3:8;
unsigned long __res1:24;
#endif
};
} mpidr;
#ifdef CONFIG_ARM_64
/* 64-bit CPUID registers. */
union {
uint64_t bits[2];
struct {
unsigned long el0:4;
unsigned long el1:4;
unsigned long el2:4;
unsigned long el3:4;
unsigned long fp:4; /* Floating Point */
unsigned long simd:4; /* Advanced SIMD */
unsigned long __res0:8;
unsigned long __res1;
};
} pfr64;
struct {
uint64_t bits[2];
} dbg64;
struct {
uint64_t bits[2];
} aux64;
struct {
uint64_t bits[2];
} mm64;
struct {
uint64_t bits[2];
} isa64;
#endif
/*
* 32-bit CPUID registers. On ARMv8 these describe the properties
* when running in 32-bit mode.
*/
union {
uint32_t bits[2];
struct {
unsigned long arm:4;
unsigned long thumb:4;
unsigned long jazelle:4;
unsigned long thumbee:4;
unsigned long __res0:16;
unsigned long progmodel:4;
unsigned long security:4;
unsigned long mprofile:4;
unsigned long virt:4;
unsigned long gentimer:4;
unsigned long __res1:12;
};
} pfr32;
struct {
uint32_t bits[1];
} dbg32;
struct {
uint32_t bits[1];
} aux32;
struct {
uint32_t bits[4];
} mm32;
struct {
uint32_t bits[6];
} isa32;
};
/*
* capabilities of CPUs
*/
extern struct cpuinfo_arm boot_cpu_data;
extern void identify_cpu(struct cpuinfo_arm *);
extern struct cpuinfo_arm cpu_data[];
#define current_cpu_data cpu_data[smp_processor_id()]
union hsr {
uint32_t bits;
struct {
@@ -225,10 +342,6 @@ union hsr {
#define CNTx_CTL_MASK (1u<<1) /* Mask IRQ */
#define CNTx_CTL_PENDING (1u<<2) /* IRQ pending */
/* CPUID bits */
#define ID_PFR1_GT_MASK 0x000F0000 /* Generic Timer interface support */
#define ID_PFR1_GT_v1 0x00010000
#if defined(CONFIG_ARM_32)
# include <asm/arm32/processor.h>
#elif defined(CONFIG_ARM_64)
@@ -260,6 +373,10 @@ void vcpu_regs_hyp_to_user(const struct vcpu *vcpu,
void vcpu_regs_user_to_hyp(struct vcpu *vcpu,
const struct vcpu_guest_core_regs *regs);
struct cpuinfo_x86 {
uint32_t pfr32[2];
};
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ARM_PROCESSOR_H */
/*
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.