/*
* Contains CPU feature definitions
*
* Copyright (C) 2015 ARM Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
DECLARE_BITMAP(cpu_hwcaps, ARM_NCAPS);
struct cpuinfo_arm __read_mostly guest_cpuinfo;
void update_cpu_capabilities(const struct arm_cpu_capabilities *caps,
const char *info)
{
int i;
for ( i = 0; caps[i].matches; i++ )
{
if ( !caps[i].matches(&caps[i]) )
continue;
if ( !cpus_have_cap(caps[i].capability) && caps[i].desc )
printk(XENLOG_INFO "%s: %s\n", info, caps[i].desc);
cpus_set_cap(caps[i].capability);
}
}
/*
* Run through the enabled capabilities and enable() it on all active
* CPUs.
*/
void __init enable_cpu_capabilities(const struct arm_cpu_capabilities *caps)
{
for ( ; caps->matches; caps++ )
{
if ( !cpus_have_cap(caps->capability) )
continue;
if ( caps->enable )
{
int ret;
/*
* Use stop_machine_run() as it schedules the work allowing
* us to modify PSTATE, instead of on_each_cpu() which uses
* an IPI, giving us a PSTATE that disappears when we
* return.
*/
ret = stop_machine_run(caps->enable, (void *)caps, NR_CPUS);
/* stop_machine_run should never fail at this stage of the boot. */
BUG_ON(ret);
}
}
}
/*
* Run through the enabled capabilities and enable() them on the calling CPU.
* If enabling of any capability fails the error is returned. After enabling a
* capability fails the error will be remembered into 'rc' and the remaining
* capabilities will be enabled. If enabling multiple capabilities fail the
* error returned by this function represents the error code of the last
* failure.
*/
int enable_nonboot_cpu_caps(const struct arm_cpu_capabilities *caps)
{
int rc = 0;
for ( ; caps->matches; caps++ )
{
if ( !cpus_have_cap(caps->capability) )
continue;
if ( caps->enable )
{
int ret = caps->enable((void *)caps);
if ( ret )
rc = ret;
}
}
return rc;
}
void identify_cpu(struct cpuinfo_arm *c)
{
bool aarch32_el0 = true;
c->midr.bits = READ_SYSREG(MIDR_EL1);
c->mpidr.bits = READ_SYSREG(MPIDR_EL1);
#ifdef CONFIG_ARM_64
c->pfr64.bits[0] = READ_SYSREG(ID_AA64PFR0_EL1);
c->pfr64.bits[1] = READ_SYSREG(ID_AA64PFR1_EL1);
c->dbg64.bits[0] = READ_SYSREG(ID_AA64DFR0_EL1);
c->dbg64.bits[1] = READ_SYSREG(ID_AA64DFR1_EL1);
c->aux64.bits[0] = READ_SYSREG(ID_AA64AFR0_EL1);
c->aux64.bits[1] = READ_SYSREG(ID_AA64AFR1_EL1);
c->mm64.bits[0] = READ_SYSREG(ID_AA64MMFR0_EL1);
c->mm64.bits[1] = READ_SYSREG(ID_AA64MMFR1_EL1);
c->mm64.bits[2] = READ_SYSREG(ID_AA64MMFR2_EL1);
c->isa64.bits[0] = READ_SYSREG(ID_AA64ISAR0_EL1);
c->isa64.bits[1] = READ_SYSREG(ID_AA64ISAR1_EL1);
c->zfr64.bits[0] = READ_SYSREG(ID_AA64ZFR0_EL1);
c->dczid.bits[0] = READ_SYSREG(DCZID_EL0);
c->ctr.bits[0] = READ_SYSREG(CTR_EL0);
aarch32_el0 = cpu_feature64_has_el0_32(c);
#endif
if ( aarch32_el0 )
{
c->pfr32.bits[0] = READ_SYSREG(ID_PFR0_EL1);
c->pfr32.bits[1] = READ_SYSREG(ID_PFR1_EL1);
c->pfr32.bits[2] = READ_SYSREG(ID_PFR2_EL1);
c->dbg32.bits[0] = READ_SYSREG(ID_DFR0_EL1);
c->dbg32.bits[1] = READ_SYSREG(ID_DFR1_EL1);
c->aux32.bits[0] = READ_SYSREG(ID_AFR0_EL1);
c->mm32.bits[0] = READ_SYSREG(ID_MMFR0_EL1);
c->mm32.bits[1] = READ_SYSREG(ID_MMFR1_EL1);
c->mm32.bits[2] = READ_SYSREG(ID_MMFR2_EL1);
c->mm32.bits[3] = READ_SYSREG(ID_MMFR3_EL1);
c->mm32.bits[4] = READ_SYSREG(ID_MMFR4_EL1);
c->mm32.bits[5] = READ_SYSREG(ID_MMFR5_EL1);
c->isa32.bits[0] = READ_SYSREG(ID_ISAR0_EL1);
c->isa32.bits[1] = READ_SYSREG(ID_ISAR1_EL1);
c->isa32.bits[2] = READ_SYSREG(ID_ISAR2_EL1);
c->isa32.bits[3] = READ_SYSREG(ID_ISAR3_EL1);
c->isa32.bits[4] = READ_SYSREG(ID_ISAR4_EL1);
c->isa32.bits[5] = READ_SYSREG(ID_ISAR5_EL1);
c->isa32.bits[6] = READ_SYSREG(ID_ISAR6_EL1);
c->mvfr.bits[0] = READ_SYSREG(MVFR0_EL1);
c->mvfr.bits[1] = READ_SYSREG(MVFR1_EL1);
#ifndef MVFR2_MAYBE_UNDEFINED
c->mvfr.bits[2] = READ_SYSREG(MVFR2_EL1);
#endif
}
}
/*
* This function is creating a cpuinfo structure with values modified to mask
* all cpu features that should not be published to guest.
* The created structure is then used to provide ID registers values to guests.
*/
static int __init create_guest_cpuinfo(void)
{
/* Use the sanitized cpuinfo as initial guest cpuinfo */
guest_cpuinfo = system_cpuinfo;
#ifdef CONFIG_ARM_64
/* Hide MPAM support as xen does not support it */
guest_cpuinfo.pfr64.mpam = 0;
guest_cpuinfo.pfr64.mpam_frac = 0;
/* Hide SVE as Xen does not support it */
guest_cpuinfo.pfr64.sve = 0;
guest_cpuinfo.zfr64.bits[0] = 0;
/* Hide MTE support as Xen does not support it */
guest_cpuinfo.pfr64.mte = 0;
/* Hide PAC support as Xen does not support it */
guest_cpuinfo.isa64.apa = 0;
guest_cpuinfo.isa64.api = 0;
guest_cpuinfo.isa64.gpa = 0;
guest_cpuinfo.isa64.gpi = 0;
#endif
/* Hide AMU support */
#ifdef CONFIG_ARM_64
guest_cpuinfo.pfr64.amu = 0;
#endif
guest_cpuinfo.pfr32.amu = 0;
/* Hide RAS support as Xen does not support it */
#ifdef CONFIG_ARM_64
guest_cpuinfo.pfr64.ras = 0;
guest_cpuinfo.pfr64.ras_frac = 0;
#endif
guest_cpuinfo.pfr32.ras = 0;
guest_cpuinfo.pfr32.ras_frac = 0;
return 0;
}
/*
* This function needs to be run after all smp are started to have
* cpuinfo structures for all cores.
*/
__initcall(create_guest_cpuinfo);
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/