2012-03-29 06:50:31 +02:00
|
|
|
/*
|
|
|
|
* QEMU ARM CPU
|
|
|
|
*
|
|
|
|
* Copyright (c) 2012 SUSE LINUX Products GmbH
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, see
|
|
|
|
* <http://www.gnu.org/licenses/gpl-2.0.html>
|
|
|
|
*/
|
|
|
|
|
2015-12-07 17:23:44 +01:00
|
|
|
#include "qemu/osdep.h"
|
2019-07-01 18:26:20 +02:00
|
|
|
#include "qemu/qemu-print.h"
|
2019-05-23 16:35:08 +02:00
|
|
|
#include "qemu-common.h"
|
2018-03-02 11:45:36 +01:00
|
|
|
#include "target/arm/idau.h"
|
2019-05-23 16:35:07 +02:00
|
|
|
#include "qemu/module.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 09:01:28 +01:00
|
|
|
#include "qapi/error.h"
|
2019-02-28 11:55:15 +01:00
|
|
|
#include "qapi/visitor.h"
|
2012-04-20 09:39:14 +02:00
|
|
|
#include "cpu.h"
|
2014-04-15 20:18:37 +02:00
|
|
|
#include "internals.h"
|
2016-03-15 13:18:37 +01:00
|
|
|
#include "exec/exec-all.h"
|
2013-11-22 18:17:13 +01:00
|
|
|
#include "hw/qdev-properties.h"
|
2012-04-20 19:58:36 +02:00
|
|
|
#if !defined(CONFIG_USER_ONLY)
|
|
|
|
#include "hw/loader.h"
|
2019-05-18 22:54:26 +02:00
|
|
|
#include "hw/boards.h"
|
2012-04-20 19:58:36 +02:00
|
|
|
#endif
|
2012-12-17 18:20:04 +01:00
|
|
|
#include "sysemu/sysemu.h"
|
2019-05-23 16:35:05 +02:00
|
|
|
#include "sysemu/tcg.h"
|
2017-01-10 11:59:55 +01:00
|
|
|
#include "sysemu/hw_accel.h"
|
2013-03-20 13:11:56 +01:00
|
|
|
#include "kvm_arm.h"
|
2017-09-14 18:51:06 +02:00
|
|
|
#include "disas/capstone.h"
|
2018-01-19 19:24:22 +01:00
|
|
|
#include "fpu/softfloat.h"
|
2012-03-29 06:50:31 +02:00
|
|
|
|
2013-06-21 19:09:18 +02:00
|
|
|
static void arm_cpu_set_pc(CPUState *cs, vaddr value)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(cs);
|
2019-02-01 15:55:46 +01:00
|
|
|
CPUARMState *env = &cpu->env;
|
|
|
|
|
|
|
|
if (is_a64(env)) {
|
|
|
|
env->pc = value;
|
|
|
|
env->thumb = 0;
|
|
|
|
} else {
|
|
|
|
env->regs[15] = value & ~1;
|
|
|
|
env->thumb = value & 1;
|
|
|
|
}
|
|
|
|
}
|
2013-06-21 19:09:18 +02:00
|
|
|
|
2019-02-01 15:55:46 +01:00
|
|
|
static void arm_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(cs);
|
|
|
|
CPUARMState *env = &cpu->env;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It's OK to look at env for the current mode here, because it's
|
|
|
|
* never possible for an AArch64 TB to chain to an AArch32 TB.
|
|
|
|
*/
|
|
|
|
if (is_a64(env)) {
|
|
|
|
env->pc = tb->pc;
|
|
|
|
} else {
|
|
|
|
env->regs[15] = tb->pc;
|
|
|
|
}
|
2013-06-21 19:09:18 +02:00
|
|
|
}
|
|
|
|
|
2013-08-25 18:53:55 +02:00
|
|
|
static bool arm_cpu_has_work(CPUState *cs)
|
|
|
|
{
|
2014-10-24 13:19:12 +02:00
|
|
|
ARMCPU *cpu = ARM_CPU(cs);
|
|
|
|
|
2017-02-23 19:29:23 +01:00
|
|
|
return (cpu->power_state != PSCI_OFF)
|
2014-10-24 13:19:12 +02:00
|
|
|
&& cs->interrupt_request &
|
2014-09-29 19:48:51 +02:00
|
|
|
(CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD
|
|
|
|
| CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ
|
|
|
|
| CPU_INTERRUPT_EXITTB);
|
2013-08-25 18:53:55 +02:00
|
|
|
}
|
|
|
|
|
2018-04-26 12:04:39 +02:00
|
|
|
void arm_register_pre_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
ARMELChangeHook *entry = g_new0(ARMELChangeHook, 1);
|
|
|
|
|
|
|
|
entry->hook = hook;
|
|
|
|
entry->opaque = opaque;
|
|
|
|
|
|
|
|
QLIST_INSERT_HEAD(&cpu->pre_el_change_hooks, entry, node);
|
|
|
|
}
|
|
|
|
|
2018-04-26 12:04:39 +02:00
|
|
|
void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
|
2016-06-17 16:23:46 +02:00
|
|
|
void *opaque)
|
|
|
|
{
|
2018-04-26 12:04:39 +02:00
|
|
|
ARMELChangeHook *entry = g_new0(ARMELChangeHook, 1);
|
|
|
|
|
|
|
|
entry->hook = hook;
|
|
|
|
entry->opaque = opaque;
|
|
|
|
|
|
|
|
QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node);
|
2016-06-17 16:23:46 +02:00
|
|
|
}
|
|
|
|
|
2012-06-20 13:57:06 +02:00
|
|
|
static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
|
|
|
|
{
|
|
|
|
/* Reset a single ARMCPRegInfo register */
|
|
|
|
ARMCPRegInfo *ri = value;
|
|
|
|
ARMCPU *cpu = opaque;
|
|
|
|
|
2015-06-19 15:17:44 +02:00
|
|
|
if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS)) {
|
2012-06-20 13:57:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ri->resetfn) {
|
|
|
|
ri->resetfn(&cpu->env, ri);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* A zero offset is never possible as it would be regs[0]
|
|
|
|
* so we use it to indicate that reset is being handled elsewhere.
|
|
|
|
* This is basically only used for fields in non-core coprocessors
|
|
|
|
* (like the pxa2xx ones).
|
|
|
|
*/
|
|
|
|
if (!ri->fieldoffset) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-26 18:20:01 +01:00
|
|
|
if (cpreg_field_is_64bit(ri)) {
|
2012-06-20 13:57:06 +02:00
|
|
|
CPREG_FIELD64(&cpu->env, ri) = ri->resetvalue;
|
|
|
|
} else {
|
|
|
|
CPREG_FIELD32(&cpu->env, ri) = ri->resetvalue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-13 12:26:21 +02:00
|
|
|
static void cp_reg_check_reset(gpointer key, gpointer value, gpointer opaque)
|
|
|
|
{
|
|
|
|
/* Purely an assertion check: we've already done reset once,
|
|
|
|
* so now check that running the reset for the cpreg doesn't
|
|
|
|
* change its value. This traps bugs where two different cpregs
|
|
|
|
* both try to reset the same state field but to different values.
|
|
|
|
*/
|
|
|
|
ARMCPRegInfo *ri = value;
|
|
|
|
ARMCPU *cpu = opaque;
|
|
|
|
uint64_t oldvalue, newvalue;
|
|
|
|
|
|
|
|
if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS | ARM_CP_NO_RAW)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
oldvalue = read_raw_cp_reg(&cpu->env, ri);
|
|
|
|
cp_reg_reset(key, value, opaque);
|
|
|
|
newvalue = read_raw_cp_reg(&cpu->env, ri);
|
|
|
|
assert(oldvalue == newvalue);
|
|
|
|
}
|
|
|
|
|
cpu: Use DeviceClass reset instead of a special CPUClass reset
The CPUClass has a 'reset' method. This is a legacy from when
TYPE_CPU used not to inherit from TYPE_DEVICE. We don't need it any
more, as we can simply use the TYPE_DEVICE reset. The 'cpu_reset()'
function is kept as the API which most places use to reset a CPU; it
is now a wrapper which calls device_cold_reset() and then the
tracepoint function.
This change should not cause CPU objects to be reset more often
than they are at the moment, because:
* nobody is directly calling device_cold_reset() or
qdev_reset_all() on CPU objects
* no CPU object is on a qbus, so they will not be reset either
by somebody calling qbus_reset_all()/bus_cold_reset(), or
by the main "reset sysbus and everything in the qbus tree"
reset that most devices are reset by
Note that this does not change the need for each machine or whatever
to use qemu_register_reset() to arrange to call cpu_reset() -- that
is necessary because CPU objects are not on any qbus, so they don't
get reset when the qbus tree rooted at the sysbus bus is reset, and
this isn't being changed here.
All the changes to the files under target/ were made using the
included Coccinelle script, except:
(1) the deletion of the now-inaccurate and not terribly useful
"CPUClass::reset" comments was done with a perl one-liner afterwards:
perl -n -i -e '/ CPUClass::reset/ or print' target/*/*.c
(2) this bit of the s390 change was done by hand, because the
Coccinelle script is not sophisticated enough to handle the
parent_reset call being inside another function:
| @@ -96,8 +96,9 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
| S390CPU *cpu = S390_CPU(s);
| S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
| CPUS390XState *env = &cpu->env;
|+ DeviceState *dev = DEVICE(s);
|
|- scc->parent_reset(s);
|+ scc->parent_reset(dev);
| cpu->env.sigp_order = 0;
| s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-Id: <20200303100511.5498-1-peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2020-03-03 11:05:11 +01:00
|
|
|
static void arm_cpu_reset(DeviceState *dev)
|
2012-03-29 06:50:31 +02:00
|
|
|
{
|
cpu: Use DeviceClass reset instead of a special CPUClass reset
The CPUClass has a 'reset' method. This is a legacy from when
TYPE_CPU used not to inherit from TYPE_DEVICE. We don't need it any
more, as we can simply use the TYPE_DEVICE reset. The 'cpu_reset()'
function is kept as the API which most places use to reset a CPU; it
is now a wrapper which calls device_cold_reset() and then the
tracepoint function.
This change should not cause CPU objects to be reset more often
than they are at the moment, because:
* nobody is directly calling device_cold_reset() or
qdev_reset_all() on CPU objects
* no CPU object is on a qbus, so they will not be reset either
by somebody calling qbus_reset_all()/bus_cold_reset(), or
by the main "reset sysbus and everything in the qbus tree"
reset that most devices are reset by
Note that this does not change the need for each machine or whatever
to use qemu_register_reset() to arrange to call cpu_reset() -- that
is necessary because CPU objects are not on any qbus, so they don't
get reset when the qbus tree rooted at the sysbus bus is reset, and
this isn't being changed here.
All the changes to the files under target/ were made using the
included Coccinelle script, except:
(1) the deletion of the now-inaccurate and not terribly useful
"CPUClass::reset" comments was done with a perl one-liner afterwards:
perl -n -i -e '/ CPUClass::reset/ or print' target/*/*.c
(2) this bit of the s390 change was done by hand, because the
Coccinelle script is not sophisticated enough to handle the
parent_reset call being inside another function:
| @@ -96,8 +96,9 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
| S390CPU *cpu = S390_CPU(s);
| S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
| CPUS390XState *env = &cpu->env;
|+ DeviceState *dev = DEVICE(s);
|
|- scc->parent_reset(s);
|+ scc->parent_reset(dev);
| cpu->env.sigp_order = 0;
| s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-Id: <20200303100511.5498-1-peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2020-03-03 11:05:11 +01:00
|
|
|
CPUState *s = CPU(dev);
|
2012-03-29 06:50:31 +02:00
|
|
|
ARMCPU *cpu = ARM_CPU(s);
|
|
|
|
ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
|
2012-04-20 19:58:36 +02:00
|
|
|
CPUARMState *env = &cpu->env;
|
|
|
|
|
cpu: Use DeviceClass reset instead of a special CPUClass reset
The CPUClass has a 'reset' method. This is a legacy from when
TYPE_CPU used not to inherit from TYPE_DEVICE. We don't need it any
more, as we can simply use the TYPE_DEVICE reset. The 'cpu_reset()'
function is kept as the API which most places use to reset a CPU; it
is now a wrapper which calls device_cold_reset() and then the
tracepoint function.
This change should not cause CPU objects to be reset more often
than they are at the moment, because:
* nobody is directly calling device_cold_reset() or
qdev_reset_all() on CPU objects
* no CPU object is on a qbus, so they will not be reset either
by somebody calling qbus_reset_all()/bus_cold_reset(), or
by the main "reset sysbus and everything in the qbus tree"
reset that most devices are reset by
Note that this does not change the need for each machine or whatever
to use qemu_register_reset() to arrange to call cpu_reset() -- that
is necessary because CPU objects are not on any qbus, so they don't
get reset when the qbus tree rooted at the sysbus bus is reset, and
this isn't being changed here.
All the changes to the files under target/ were made using the
included Coccinelle script, except:
(1) the deletion of the now-inaccurate and not terribly useful
"CPUClass::reset" comments was done with a perl one-liner afterwards:
perl -n -i -e '/ CPUClass::reset/ or print' target/*/*.c
(2) this bit of the s390 change was done by hand, because the
Coccinelle script is not sophisticated enough to handle the
parent_reset call being inside another function:
| @@ -96,8 +96,9 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
| S390CPU *cpu = S390_CPU(s);
| S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
| CPUS390XState *env = &cpu->env;
|+ DeviceState *dev = DEVICE(s);
|
|- scc->parent_reset(s);
|+ scc->parent_reset(dev);
| cpu->env.sigp_order = 0;
| s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-Id: <20200303100511.5498-1-peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2020-03-03 11:05:11 +01:00
|
|
|
acc->parent_reset(dev);
|
2012-03-29 06:50:31 +02:00
|
|
|
|
2016-11-14 15:19:17 +01:00
|
|
|
memset(env, 0, offsetof(CPUARMState, end_reset_fields));
|
|
|
|
|
2012-06-20 13:57:06 +02:00
|
|
|
g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu);
|
2015-08-13 12:26:21 +02:00
|
|
|
g_hash_table_foreach(cpu->cp_regs, cp_reg_check_reset, cpu);
|
|
|
|
|
2012-04-20 19:58:36 +02:00
|
|
|
env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
|
2018-10-24 08:50:16 +02:00
|
|
|
env->vfp.xregs[ARM_VFP_MVFR0] = cpu->isar.mvfr0;
|
|
|
|
env->vfp.xregs[ARM_VFP_MVFR1] = cpu->isar.mvfr1;
|
|
|
|
env->vfp.xregs[ARM_VFP_MVFR2] = cpu->isar.mvfr2;
|
2012-04-20 19:58:36 +02:00
|
|
|
|
2017-02-23 19:29:23 +01:00
|
|
|
cpu->power_state = cpu->start_powered_off ? PSCI_OFF : PSCI_ON;
|
2014-10-24 13:19:12 +02:00
|
|
|
s->halted = cpu->start_powered_off;
|
|
|
|
|
2012-04-20 19:58:36 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
|
|
|
|
env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
|
|
|
|
}
|
|
|
|
|
2013-09-03 21:12:09 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
|
|
|
|
/* 64 bit CPUs always start in 64 bit mode */
|
|
|
|
env->aarch64 = 1;
|
2013-12-17 20:42:30 +01:00
|
|
|
#if defined(CONFIG_USER_ONLY)
|
|
|
|
env->pstate = PSTATE_MODE_EL0t;
|
2014-10-24 13:19:13 +02:00
|
|
|
/* Userspace expects access to DC ZVA, CTL_EL0 and the cache ops */
|
2014-12-11 13:07:50 +01:00
|
|
|
env->cp15.sctlr_el[1] |= SCTLR_UCT | SCTLR_UCI | SCTLR_DZE;
|
2019-01-25 23:57:08 +01:00
|
|
|
/* Enable all PAC keys. */
|
|
|
|
env->cp15.sctlr_el[1] |= (SCTLR_EnIA | SCTLR_EnIB |
|
|
|
|
SCTLR_EnDA | SCTLR_EnDB);
|
2014-04-15 20:18:39 +02:00
|
|
|
/* and to the FP/Neon instructions */
|
2015-04-26 17:49:25 +02:00
|
|
|
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 2, 3);
|
2018-06-29 16:11:15 +02:00
|
|
|
/* and to the SVE instructions */
|
|
|
|
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3);
|
2020-03-16 18:21:44 +01:00
|
|
|
/* with reasonable vector length */
|
|
|
|
if (cpu_isar_feature(aa64_sve, cpu)) {
|
|
|
|
env->vfp.zcr_el[1] = MIN(cpu->sve_max_vq - 1, 3);
|
|
|
|
}
|
2019-02-05 17:52:40 +01:00
|
|
|
/*
|
|
|
|
* Enable TBI0 and TBI1. While the real kernel only enables TBI0,
|
|
|
|
* turning on both here will produce smaller code and otherwise
|
|
|
|
* make no difference to the user-level emulation.
|
|
|
|
*/
|
|
|
|
env->cp15.tcr_el[1].raw_tcr = (3ULL << 37);
|
2013-12-17 20:42:30 +01:00
|
|
|
#else
|
2015-02-05 14:37:22 +01:00
|
|
|
/* Reset into the highest available EL */
|
|
|
|
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
|
|
|
env->pstate = PSTATE_MODE_EL3h;
|
|
|
|
} else if (arm_feature(env, ARM_FEATURE_EL2)) {
|
|
|
|
env->pstate = PSTATE_MODE_EL2h;
|
|
|
|
} else {
|
|
|
|
env->pstate = PSTATE_MODE_EL1h;
|
|
|
|
}
|
2014-04-15 20:18:48 +02:00
|
|
|
env->pc = cpu->rvbar;
|
2014-04-15 20:18:39 +02:00
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
#if defined(CONFIG_USER_ONLY)
|
|
|
|
/* Userspace expects access to cp10 and cp11 for FP/Neon */
|
2015-04-26 17:49:25 +02:00
|
|
|
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 4, 0xf);
|
2013-12-17 20:42:30 +01:00
|
|
|
#endif
|
2013-09-03 21:12:09 +02:00
|
|
|
}
|
|
|
|
|
2012-04-20 19:58:36 +02:00
|
|
|
#if defined(CONFIG_USER_ONLY)
|
|
|
|
env->uncached_cpsr = ARM_CPU_MODE_USR;
|
|
|
|
/* For user mode we must enable access to coprocessors */
|
|
|
|
env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
|
|
|
|
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
|
|
|
|
env->cp15.c15_cpar = 3;
|
|
|
|
} else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
|
|
|
|
env->cp15.c15_cpar = 1;
|
|
|
|
}
|
|
|
|
#else
|
2018-09-25 15:02:33 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the highest available EL is EL2, AArch32 will start in Hyp
|
|
|
|
* mode; otherwise it starts in SVC. Note that if we start in
|
|
|
|
* AArch64 then these values in the uncached_cpsr will be ignored.
|
|
|
|
*/
|
|
|
|
if (arm_feature(env, ARM_FEATURE_EL2) &&
|
|
|
|
!arm_feature(env, ARM_FEATURE_EL3)) {
|
|
|
|
env->uncached_cpsr = ARM_CPU_MODE_HYP;
|
|
|
|
} else {
|
|
|
|
env->uncached_cpsr = ARM_CPU_MODE_SVC;
|
|
|
|
}
|
2014-02-26 18:20:06 +01:00
|
|
|
env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
|
2017-01-27 16:20:24 +01:00
|
|
|
|
2017-01-27 16:20:22 +01:00
|
|
|
if (arm_feature(env, ARM_FEATURE_M)) {
|
2014-09-12 15:06:48 +02:00
|
|
|
uint32_t initial_msp; /* Loaded from 0x0 */
|
|
|
|
uint32_t initial_pc; /* Loaded from 0x4 */
|
2012-04-20 19:58:36 +02:00
|
|
|
uint8_t *rom;
|
2018-03-02 11:45:37 +01:00
|
|
|
uint32_t vecbase;
|
2014-09-12 15:06:48 +02:00
|
|
|
|
2017-09-07 14:54:52 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
|
|
|
env->v7m.secure = true;
|
2017-09-12 20:13:52 +02:00
|
|
|
} else {
|
|
|
|
/* This bit resets to 0 if security is supported, but 1 if
|
|
|
|
* it is not. The bit is not present in v7M, but we set it
|
|
|
|
* here so we can avoid having to make checks on it conditional
|
|
|
|
* on ARM_FEATURE_V8 (we don't let the guest see the bit).
|
|
|
|
*/
|
|
|
|
env->v7m.aircr = R_V7M_AIRCR_BFHFNMINS_MASK;
|
2019-08-01 12:57:42 +02:00
|
|
|
/*
|
|
|
|
* Set NSACR to indicate "NS access permitted to everything";
|
|
|
|
* this avoids having to have all the tests of it being
|
|
|
|
* conditional on ARM_FEATURE_M_SECURITY. Note also that from
|
|
|
|
* v8.1M the guest-visible value of NSACR in a CPU without the
|
|
|
|
* Security Extension is 0xcff.
|
|
|
|
*/
|
|
|
|
env->v7m.nsacr = 0xcff;
|
2017-09-07 14:54:52 +02:00
|
|
|
}
|
|
|
|
|
2017-09-07 14:54:54 +02:00
|
|
|
/* In v7M the reset value of this bit is IMPDEF, but ARM recommends
|
armv7m: add state for v7M CCR, CFSR, HFSR, DFSR, MMFAR, BFAR
Add the structure fields, VMState fields, reset code and macros for
the v7M system control registers CCR, CFSR, HFSR, DFSR, MMFAR and
BFAR.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 1485285380-10565-4-git-send-email-peter.maydell@linaro.org
2017-01-27 16:20:23 +01:00
|
|
|
* that it resets to 1, so QEMU always does that rather than making
|
2017-09-07 14:54:54 +02:00
|
|
|
* it dependent on CPU model. In v8M it is RES1.
|
armv7m: add state for v7M CCR, CFSR, HFSR, DFSR, MMFAR, BFAR
Add the structure fields, VMState fields, reset code and macros for
the v7M system control registers CCR, CFSR, HFSR, DFSR, MMFAR and
BFAR.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 1485285380-10565-4-git-send-email-peter.maydell@linaro.org
2017-01-27 16:20:23 +01:00
|
|
|
*/
|
2017-09-07 14:54:54 +02:00
|
|
|
env->v7m.ccr[M_REG_NS] = R_V7M_CCR_STKALIGN_MASK;
|
|
|
|
env->v7m.ccr[M_REG_S] = R_V7M_CCR_STKALIGN_MASK;
|
|
|
|
if (arm_feature(env, ARM_FEATURE_V8)) {
|
|
|
|
/* in v8M the NONBASETHRDENA bit [0] is RES1 */
|
|
|
|
env->v7m.ccr[M_REG_NS] |= R_V7M_CCR_NONBASETHRDENA_MASK;
|
|
|
|
env->v7m.ccr[M_REG_S] |= R_V7M_CCR_NONBASETHRDENA_MASK;
|
|
|
|
}
|
2018-08-14 18:17:19 +02:00
|
|
|
if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
|
|
|
|
env->v7m.ccr[M_REG_NS] |= R_V7M_CCR_UNALIGN_TRP_MASK;
|
|
|
|
env->v7m.ccr[M_REG_S] |= R_V7M_CCR_UNALIGN_TRP_MASK;
|
|
|
|
}
|
armv7m: add state for v7M CCR, CFSR, HFSR, DFSR, MMFAR, BFAR
Add the structure fields, VMState fields, reset code and macros for
the v7M system control registers CCR, CFSR, HFSR, DFSR, MMFAR and
BFAR.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 1485285380-10565-4-git-send-email-peter.maydell@linaro.org
2017-01-27 16:20:23 +01:00
|
|
|
|
2020-02-24 23:22:16 +01:00
|
|
|
if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
2019-04-29 18:35:58 +02:00
|
|
|
env->v7m.fpccr[M_REG_NS] = R_V7M_FPCCR_ASPEN_MASK;
|
|
|
|
env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK |
|
|
|
|
R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK;
|
|
|
|
}
|
2017-01-27 16:20:24 +01:00
|
|
|
/* Unlike A/R profile, M profile defines the reset LR value */
|
|
|
|
env->regs[14] = 0xffffffff;
|
|
|
|
|
2018-03-02 11:45:37 +01:00
|
|
|
env->v7m.vecbase[M_REG_S] = cpu->init_svtor & 0xffffff80;
|
|
|
|
|
|
|
|
/* Load the initial SP and PC from offset 0 and 4 in the vector table */
|
|
|
|
vecbase = env->v7m.vecbase[env->v7m.secure];
|
2018-06-26 11:35:40 +02:00
|
|
|
rom = rom_ptr(vecbase, 8);
|
2012-04-20 19:58:36 +02:00
|
|
|
if (rom) {
|
2014-09-12 15:06:48 +02:00
|
|
|
/* Address zero is covered by ROM which hasn't yet been
|
|
|
|
* copied into physical memory.
|
|
|
|
*/
|
|
|
|
initial_msp = ldl_p(rom);
|
|
|
|
initial_pc = ldl_p(rom + 4);
|
|
|
|
} else {
|
|
|
|
/* Address zero not covered by a ROM blob, or the ROM blob
|
|
|
|
* is in non-modifiable memory and this is a second reset after
|
|
|
|
* it got copied into memory. In the latter case, rom_ptr
|
|
|
|
* will return a NULL pointer and we should use ldl_phys instead.
|
|
|
|
*/
|
2018-03-02 11:45:37 +01:00
|
|
|
initial_msp = ldl_phys(s->as, vecbase);
|
|
|
|
initial_pc = ldl_phys(s->as, vecbase + 4);
|
2012-04-20 19:58:36 +02:00
|
|
|
}
|
2014-09-12 15:06:48 +02:00
|
|
|
|
|
|
|
env->regs[13] = initial_msp & 0xFFFFFFFC;
|
|
|
|
env->regs[15] = initial_pc & ~1;
|
|
|
|
env->thumb = initial_pc & 1;
|
2012-04-20 19:58:36 +02:00
|
|
|
}
|
2013-12-17 20:42:29 +01:00
|
|
|
|
2014-12-11 13:07:50 +01:00
|
|
|
/* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently
|
|
|
|
* executing as AArch32 then check if highvecs are enabled and
|
|
|
|
* adjust the PC accordingly.
|
|
|
|
*/
|
|
|
|
if (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_V) {
|
2014-09-12 15:06:48 +02:00
|
|
|
env->regs[15] = 0xFFFF0000;
|
2013-12-17 20:42:29 +01:00
|
|
|
}
|
|
|
|
|
2017-09-14 19:43:16 +02:00
|
|
|
/* M profile requires that reset clears the exclusive monitor;
|
|
|
|
* A profile does not, but clearing it makes more sense than having it
|
|
|
|
* set with an exclusive access on address zero.
|
|
|
|
*/
|
|
|
|
arm_clear_exclusive(env);
|
|
|
|
|
2012-04-20 19:58:36 +02:00
|
|
|
env->vfp.xregs[ARM_VFP_FPEXC] = 0;
|
|
|
|
#endif
|
2017-07-27 12:59:09 +02:00
|
|
|
|
2017-09-07 14:54:51 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_PMSA)) {
|
2017-07-27 12:59:09 +02:00
|
|
|
if (cpu->pmsav7_dregion > 0) {
|
2017-09-07 14:54:51 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_V8)) {
|
2017-09-07 14:54:53 +02:00
|
|
|
memset(env->pmsav8.rbar[M_REG_NS], 0,
|
|
|
|
sizeof(*env->pmsav8.rbar[M_REG_NS])
|
|
|
|
* cpu->pmsav7_dregion);
|
|
|
|
memset(env->pmsav8.rlar[M_REG_NS], 0,
|
|
|
|
sizeof(*env->pmsav8.rlar[M_REG_NS])
|
|
|
|
* cpu->pmsav7_dregion);
|
|
|
|
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
|
|
|
memset(env->pmsav8.rbar[M_REG_S], 0,
|
|
|
|
sizeof(*env->pmsav8.rbar[M_REG_S])
|
|
|
|
* cpu->pmsav7_dregion);
|
|
|
|
memset(env->pmsav8.rlar[M_REG_S], 0,
|
|
|
|
sizeof(*env->pmsav8.rlar[M_REG_S])
|
|
|
|
* cpu->pmsav7_dregion);
|
|
|
|
}
|
2017-09-07 14:54:51 +02:00
|
|
|
} else if (arm_feature(env, ARM_FEATURE_V7)) {
|
|
|
|
memset(env->pmsav7.drbar, 0,
|
|
|
|
sizeof(*env->pmsav7.drbar) * cpu->pmsav7_dregion);
|
|
|
|
memset(env->pmsav7.drsr, 0,
|
|
|
|
sizeof(*env->pmsav7.drsr) * cpu->pmsav7_dregion);
|
|
|
|
memset(env->pmsav7.dracr, 0,
|
|
|
|
sizeof(*env->pmsav7.dracr) * cpu->pmsav7_dregion);
|
|
|
|
}
|
2017-07-27 12:59:09 +02:00
|
|
|
}
|
2017-09-07 14:54:53 +02:00
|
|
|
env->pmsav7.rnr[M_REG_NS] = 0;
|
|
|
|
env->pmsav7.rnr[M_REG_S] = 0;
|
2017-09-07 14:54:53 +02:00
|
|
|
env->pmsav8.mair0[M_REG_NS] = 0;
|
|
|
|
env->pmsav8.mair0[M_REG_S] = 0;
|
|
|
|
env->pmsav8.mair1[M_REG_NS] = 0;
|
|
|
|
env->pmsav8.mair1[M_REG_S] = 0;
|
2017-07-27 12:59:09 +02:00
|
|
|
}
|
|
|
|
|
2017-10-06 17:46:49 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
|
|
|
if (cpu->sau_sregion > 0) {
|
|
|
|
memset(env->sau.rbar, 0, sizeof(*env->sau.rbar) * cpu->sau_sregion);
|
|
|
|
memset(env->sau.rlar, 0, sizeof(*env->sau.rlar) * cpu->sau_sregion);
|
|
|
|
}
|
|
|
|
env->sau.rnr = 0;
|
|
|
|
/* SAU_CTRL reset value is IMPDEF; we choose 0, which is what
|
|
|
|
* the Cortex-M33 does.
|
|
|
|
*/
|
|
|
|
env->sau.ctrl = 0;
|
|
|
|
}
|
|
|
|
|
2012-04-20 19:58:36 +02:00
|
|
|
set_flush_to_zero(1, &env->vfp.standard_fp_status);
|
|
|
|
set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
|
|
|
|
set_default_nan_mode(1, &env->vfp.standard_fp_status);
|
|
|
|
set_float_detect_tininess(float_tininess_before_rounding,
|
|
|
|
&env->vfp.fp_status);
|
|
|
|
set_float_detect_tininess(float_tininess_before_rounding,
|
|
|
|
&env->vfp.standard_fp_status);
|
2018-05-15 15:58:42 +02:00
|
|
|
set_float_detect_tininess(float_tininess_before_rounding,
|
|
|
|
&env->vfp.fp_status_f16);
|
2013-03-20 13:11:56 +01:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
if (kvm_enabled()) {
|
|
|
|
kvm_arm_reset_vcpu(cpu);
|
|
|
|
}
|
|
|
|
#endif
|
2014-09-12 15:06:49 +02:00
|
|
|
|
2014-09-29 19:48:46 +02:00
|
|
|
hw_breakpoint_update_all(cpu);
|
2014-09-12 15:06:49 +02:00
|
|
|
hw_watchpoint_update_all(cpu);
|
2019-10-23 17:00:49 +02:00
|
|
|
arm_rebuild_hflags(env);
|
2012-03-29 06:50:31 +02:00
|
|
|
}
|
|
|
|
|
2020-02-07 15:04:27 +01:00
|
|
|
static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
|
2020-02-07 15:04:27 +01:00
|
|
|
unsigned int target_el,
|
|
|
|
unsigned int cur_el, bool secure,
|
|
|
|
uint64_t hcr_el2)
|
2020-02-07 15:04:27 +01:00
|
|
|
{
|
|
|
|
CPUARMState *env = cs->env_ptr;
|
|
|
|
bool pstate_unmasked;
|
2020-02-07 15:04:27 +01:00
|
|
|
bool unmasked = false;
|
2020-02-07 15:04:27 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't take exceptions if they target a lower EL.
|
|
|
|
* This check should catch any exceptions that would not be taken
|
|
|
|
* but left pending.
|
|
|
|
*/
|
|
|
|
if (cur_el > target_el) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (excp_idx) {
|
|
|
|
case EXCP_FIQ:
|
|
|
|
pstate_unmasked = !(env->daif & PSTATE_F);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EXCP_IRQ:
|
|
|
|
pstate_unmasked = !(env->daif & PSTATE_I);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EXCP_VFIQ:
|
|
|
|
if (secure || !(hcr_el2 & HCR_FMO) || (hcr_el2 & HCR_TGE)) {
|
|
|
|
/* VFIQs are only taken when hypervized and non-secure. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return !(env->daif & PSTATE_F);
|
|
|
|
case EXCP_VIRQ:
|
|
|
|
if (secure || !(hcr_el2 & HCR_IMO) || (hcr_el2 & HCR_TGE)) {
|
|
|
|
/* VIRQs are only taken when hypervized and non-secure. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return !(env->daif & PSTATE_I);
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use the target EL, current execution state and SCR/HCR settings to
|
|
|
|
* determine whether the corresponding CPSR bit is used to mask the
|
|
|
|
* interrupt.
|
|
|
|
*/
|
|
|
|
if ((target_el > cur_el) && (target_el != 1)) {
|
|
|
|
/* Exceptions targeting a higher EL may not be maskable */
|
|
|
|
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
|
|
|
|
/*
|
|
|
|
* 64-bit masking rules are simple: exceptions to EL3
|
|
|
|
* can't be masked, and exceptions to EL2 can only be
|
|
|
|
* masked from Secure state. The HCR and SCR settings
|
|
|
|
* don't affect the masking logic, only the interrupt routing.
|
|
|
|
*/
|
|
|
|
if (target_el == 3 || !secure) {
|
2020-02-07 15:04:27 +01:00
|
|
|
unmasked = true;
|
2020-02-07 15:04:27 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* The old 32-bit-only environment has a more complicated
|
|
|
|
* masking setup. HCR and SCR bits not only affect interrupt
|
|
|
|
* routing but also change the behaviour of masking.
|
|
|
|
*/
|
|
|
|
bool hcr, scr;
|
|
|
|
|
|
|
|
switch (excp_idx) {
|
|
|
|
case EXCP_FIQ:
|
|
|
|
/*
|
|
|
|
* If FIQs are routed to EL3 or EL2 then there are cases where
|
|
|
|
* we override the CPSR.F in determining if the exception is
|
|
|
|
* masked or not. If neither of these are set then we fall back
|
|
|
|
* to the CPSR.F setting otherwise we further assess the state
|
|
|
|
* below.
|
|
|
|
*/
|
|
|
|
hcr = hcr_el2 & HCR_FMO;
|
|
|
|
scr = (env->cp15.scr_el3 & SCR_FIQ);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When EL3 is 32-bit, the SCR.FW bit controls whether the
|
|
|
|
* CPSR.F bit masks FIQ interrupts when taken in non-secure
|
|
|
|
* state. If SCR.FW is set then FIQs can be masked by CPSR.F
|
|
|
|
* when non-secure but only when FIQs are only routed to EL3.
|
|
|
|
*/
|
|
|
|
scr = scr && !((env->cp15.scr_el3 & SCR_FW) && !hcr);
|
|
|
|
break;
|
|
|
|
case EXCP_IRQ:
|
|
|
|
/*
|
|
|
|
* When EL3 execution state is 32-bit, if HCR.IMO is set then
|
|
|
|
* we may override the CPSR.I masking when in non-secure state.
|
|
|
|
* The SCR.IRQ setting has already been taken into consideration
|
|
|
|
* when setting the target EL, so it does not have a further
|
|
|
|
* affect here.
|
|
|
|
*/
|
|
|
|
hcr = hcr_el2 & HCR_IMO;
|
|
|
|
scr = false;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((scr || hcr) && !secure) {
|
2020-02-07 15:04:27 +01:00
|
|
|
unmasked = true;
|
2020-02-07 15:04:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The PSTATE bits only mask the interrupt if we have not overriden the
|
|
|
|
* ability above.
|
|
|
|
*/
|
|
|
|
return unmasked || pstate_unmasked;
|
|
|
|
}
|
|
|
|
|
2014-09-13 18:45:25 +02:00
|
|
|
bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
|
|
|
{
|
|
|
|
CPUClass *cc = CPU_GET_CLASS(cs);
|
2015-05-29 12:28:51 +02:00
|
|
|
CPUARMState *env = cs->env_ptr;
|
|
|
|
uint32_t cur_el = arm_current_el(env);
|
|
|
|
bool secure = arm_is_secure(env);
|
2020-02-07 15:04:27 +01:00
|
|
|
uint64_t hcr_el2 = arm_hcr_el2_eff(env);
|
2015-05-29 12:28:51 +02:00
|
|
|
uint32_t target_el;
|
|
|
|
uint32_t excp_idx;
|
2020-02-07 15:04:27 +01:00
|
|
|
|
|
|
|
/* The prioritization of interrupts is IMPLEMENTATION DEFINED. */
|
2014-09-13 18:45:25 +02:00
|
|
|
|
2015-05-29 12:28:51 +02:00
|
|
|
if (interrupt_request & CPU_INTERRUPT_FIQ) {
|
|
|
|
excp_idx = EXCP_FIQ;
|
|
|
|
target_el = arm_phys_excp_target_el(cs, excp_idx, cur_el, secure);
|
2020-02-07 15:04:27 +01:00
|
|
|
if (arm_excp_unmasked(cs, excp_idx, target_el,
|
|
|
|
cur_el, secure, hcr_el2)) {
|
2020-02-07 15:04:27 +01:00
|
|
|
goto found;
|
2015-05-29 12:28:51 +02:00
|
|
|
}
|
2014-09-13 18:45:25 +02:00
|
|
|
}
|
2015-05-29 12:28:51 +02:00
|
|
|
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
|
|
|
excp_idx = EXCP_IRQ;
|
|
|
|
target_el = arm_phys_excp_target_el(cs, excp_idx, cur_el, secure);
|
2020-02-07 15:04:27 +01:00
|
|
|
if (arm_excp_unmasked(cs, excp_idx, target_el,
|
|
|
|
cur_el, secure, hcr_el2)) {
|
2020-02-07 15:04:27 +01:00
|
|
|
goto found;
|
2015-05-29 12:28:51 +02:00
|
|
|
}
|
2014-09-13 18:45:25 +02:00
|
|
|
}
|
2015-05-29 12:28:51 +02:00
|
|
|
if (interrupt_request & CPU_INTERRUPT_VIRQ) {
|
|
|
|
excp_idx = EXCP_VIRQ;
|
|
|
|
target_el = 1;
|
2020-02-07 15:04:27 +01:00
|
|
|
if (arm_excp_unmasked(cs, excp_idx, target_el,
|
|
|
|
cur_el, secure, hcr_el2)) {
|
2020-02-07 15:04:27 +01:00
|
|
|
goto found;
|
2015-05-29 12:28:51 +02:00
|
|
|
}
|
2014-09-29 19:48:51 +02:00
|
|
|
}
|
2015-05-29 12:28:51 +02:00
|
|
|
if (interrupt_request & CPU_INTERRUPT_VFIQ) {
|
|
|
|
excp_idx = EXCP_VFIQ;
|
|
|
|
target_el = 1;
|
2020-02-07 15:04:27 +01:00
|
|
|
if (arm_excp_unmasked(cs, excp_idx, target_el,
|
|
|
|
cur_el, secure, hcr_el2)) {
|
2020-02-07 15:04:27 +01:00
|
|
|
goto found;
|
2015-05-29 12:28:51 +02:00
|
|
|
}
|
2014-09-29 19:48:51 +02:00
|
|
|
}
|
2020-02-07 15:04:27 +01:00
|
|
|
return false;
|
2014-09-13 18:45:25 +02:00
|
|
|
|
2020-02-07 15:04:27 +01:00
|
|
|
found:
|
|
|
|
cs->exception_index = excp_idx;
|
|
|
|
env->exception.target_el = target_el;
|
|
|
|
cc->do_interrupt(cs);
|
|
|
|
return true;
|
2014-09-13 18:45:25 +02:00
|
|
|
}
|
|
|
|
|
2018-11-13 11:47:59 +01:00
|
|
|
void arm_cpu_update_virq(ARMCPU *cpu)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Update the interrupt level for VIRQ, which is the logical OR of
|
|
|
|
* the HCR_EL2.VI bit and the input line level from the GIC.
|
|
|
|
*/
|
|
|
|
CPUARMState *env = &cpu->env;
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
|
|
|
|
bool new_state = (env->cp15.hcr_el2 & HCR_VI) ||
|
|
|
|
(env->irq_line_state & CPU_INTERRUPT_VIRQ);
|
|
|
|
|
|
|
|
if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VIRQ) != 0)) {
|
|
|
|
if (new_state) {
|
|
|
|
cpu_interrupt(cs, CPU_INTERRUPT_VIRQ);
|
|
|
|
} else {
|
|
|
|
cpu_reset_interrupt(cs, CPU_INTERRUPT_VIRQ);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void arm_cpu_update_vfiq(ARMCPU *cpu)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Update the interrupt level for VFIQ, which is the logical OR of
|
|
|
|
* the HCR_EL2.VF bit and the input line level from the GIC.
|
|
|
|
*/
|
|
|
|
CPUARMState *env = &cpu->env;
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
|
|
|
|
bool new_state = (env->cp15.hcr_el2 & HCR_VF) ||
|
|
|
|
(env->irq_line_state & CPU_INTERRUPT_VFIQ);
|
|
|
|
|
|
|
|
if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VFIQ) != 0)) {
|
|
|
|
if (new_state) {
|
|
|
|
cpu_interrupt(cs, CPU_INTERRUPT_VFIQ);
|
|
|
|
} else {
|
|
|
|
cpu_reset_interrupt(cs, CPU_INTERRUPT_VFIQ);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-20 15:54:28 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
static void arm_cpu_set_irq(void *opaque, int irq, int level)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = opaque;
|
2014-09-29 19:48:51 +02:00
|
|
|
CPUARMState *env = &cpu->env;
|
2013-08-20 15:54:28 +02:00
|
|
|
CPUState *cs = CPU(cpu);
|
2014-09-29 19:48:51 +02:00
|
|
|
static const int mask[] = {
|
|
|
|
[ARM_CPU_IRQ] = CPU_INTERRUPT_HARD,
|
|
|
|
[ARM_CPU_FIQ] = CPU_INTERRUPT_FIQ,
|
|
|
|
[ARM_CPU_VIRQ] = CPU_INTERRUPT_VIRQ,
|
|
|
|
[ARM_CPU_VFIQ] = CPU_INTERRUPT_VFIQ
|
|
|
|
};
|
2013-08-20 15:54:28 +02:00
|
|
|
|
2018-11-13 11:47:59 +01:00
|
|
|
if (level) {
|
|
|
|
env->irq_line_state |= mask[irq];
|
|
|
|
} else {
|
|
|
|
env->irq_line_state &= ~mask[irq];
|
|
|
|
}
|
|
|
|
|
2013-08-20 15:54:28 +02:00
|
|
|
switch (irq) {
|
2014-09-29 19:48:51 +02:00
|
|
|
case ARM_CPU_VIRQ:
|
2018-11-13 11:47:59 +01:00
|
|
|
assert(arm_feature(env, ARM_FEATURE_EL2));
|
|
|
|
arm_cpu_update_virq(cpu);
|
|
|
|
break;
|
2014-09-29 19:48:51 +02:00
|
|
|
case ARM_CPU_VFIQ:
|
2015-09-07 11:39:29 +02:00
|
|
|
assert(arm_feature(env, ARM_FEATURE_EL2));
|
2018-11-13 11:47:59 +01:00
|
|
|
arm_cpu_update_vfiq(cpu);
|
|
|
|
break;
|
2014-09-29 19:48:51 +02:00
|
|
|
case ARM_CPU_IRQ:
|
2013-08-20 15:54:28 +02:00
|
|
|
case ARM_CPU_FIQ:
|
|
|
|
if (level) {
|
2014-09-29 19:48:51 +02:00
|
|
|
cpu_interrupt(cs, mask[irq]);
|
2013-08-20 15:54:28 +02:00
|
|
|
} else {
|
2014-09-29 19:48:51 +02:00
|
|
|
cpu_reset_interrupt(cs, mask[irq]);
|
2013-08-20 15:54:28 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2015-09-07 11:39:29 +02:00
|
|
|
g_assert_not_reached();
|
2013-08-20 15:54:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
ARMCPU *cpu = opaque;
|
2018-11-13 11:47:59 +01:00
|
|
|
CPUARMState *env = &cpu->env;
|
2013-08-20 15:54:28 +02:00
|
|
|
CPUState *cs = CPU(cpu);
|
2018-11-13 11:47:59 +01:00
|
|
|
uint32_t linestate_bit;
|
2019-10-03 17:46:39 +02:00
|
|
|
int irq_id;
|
2013-08-20 15:54:28 +02:00
|
|
|
|
|
|
|
switch (irq) {
|
|
|
|
case ARM_CPU_IRQ:
|
2019-10-03 17:46:39 +02:00
|
|
|
irq_id = KVM_ARM_IRQ_CPU_IRQ;
|
2018-11-13 11:47:59 +01:00
|
|
|
linestate_bit = CPU_INTERRUPT_HARD;
|
2013-08-20 15:54:28 +02:00
|
|
|
break;
|
|
|
|
case ARM_CPU_FIQ:
|
2019-10-03 17:46:39 +02:00
|
|
|
irq_id = KVM_ARM_IRQ_CPU_FIQ;
|
2018-11-13 11:47:59 +01:00
|
|
|
linestate_bit = CPU_INTERRUPT_FIQ;
|
2013-08-20 15:54:28 +02:00
|
|
|
break;
|
|
|
|
default:
|
2015-09-07 11:39:29 +02:00
|
|
|
g_assert_not_reached();
|
2013-08-20 15:54:28 +02:00
|
|
|
}
|
2018-11-13 11:47:59 +01:00
|
|
|
|
|
|
|
if (level) {
|
|
|
|
env->irq_line_state |= linestate_bit;
|
|
|
|
} else {
|
|
|
|
env->irq_line_state &= ~linestate_bit;
|
|
|
|
}
|
2019-10-03 17:46:39 +02:00
|
|
|
kvm_arm_set_irq(cs->cpu_index, KVM_ARM_IRQ_TYPE_CPU, irq_id, !!level);
|
2013-08-20 15:54:28 +02:00
|
|
|
#endif
|
|
|
|
}
|
2015-02-05 14:37:25 +01:00
|
|
|
|
2016-03-04 12:30:19 +01:00
|
|
|
static bool arm_cpu_virtio_is_big_endian(CPUState *cs)
|
2015-02-05 14:37:25 +01:00
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(cs);
|
|
|
|
CPUARMState *env = &cpu->env;
|
|
|
|
|
|
|
|
cpu_synchronize_state(cs);
|
2016-03-04 12:30:19 +01:00
|
|
|
return arm_cpu_data_is_big_endian(env);
|
2015-02-05 14:37:25 +01:00
|
|
|
}
|
|
|
|
|
2013-08-20 15:54:28 +02:00
|
|
|
#endif
|
|
|
|
|
2015-06-24 05:57:35 +02:00
|
|
|
static int
|
|
|
|
print_insn_thumb1(bfd_vma pc, disassemble_info *info)
|
|
|
|
{
|
|
|
|
return print_insn_arm(pc | 1, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void arm_disas_set_info(CPUState *cpu, disassemble_info *info)
|
|
|
|
{
|
|
|
|
ARMCPU *ac = ARM_CPU(cpu);
|
|
|
|
CPUARMState *env = &ac->env;
|
2017-10-19 23:13:02 +02:00
|
|
|
bool sctlr_b;
|
2015-06-24 05:57:35 +02:00
|
|
|
|
|
|
|
if (is_a64(env)) {
|
|
|
|
/* We might not be compiled with the A64 disassembler
|
|
|
|
* because it needs a C++ compiler. Leave print_insn
|
|
|
|
* unset in this case to use the caller default behaviour.
|
|
|
|
*/
|
|
|
|
#if defined(CONFIG_ARM_A64_DIS)
|
|
|
|
info->print_insn = print_insn_arm_a64;
|
|
|
|
#endif
|
2017-09-14 18:51:06 +02:00
|
|
|
info->cap_arch = CS_ARCH_ARM64;
|
2017-11-07 13:19:18 +01:00
|
|
|
info->cap_insn_unit = 4;
|
|
|
|
info->cap_insn_split = 4;
|
2015-06-24 05:57:35 +02:00
|
|
|
} else {
|
2017-09-14 18:51:06 +02:00
|
|
|
int cap_mode;
|
|
|
|
if (env->thumb) {
|
|
|
|
info->print_insn = print_insn_thumb1;
|
2017-11-07 13:19:18 +01:00
|
|
|
info->cap_insn_unit = 2;
|
|
|
|
info->cap_insn_split = 4;
|
2017-09-14 18:51:06 +02:00
|
|
|
cap_mode = CS_MODE_THUMB;
|
|
|
|
} else {
|
|
|
|
info->print_insn = print_insn_arm;
|
2017-11-07 13:19:18 +01:00
|
|
|
info->cap_insn_unit = 4;
|
|
|
|
info->cap_insn_split = 4;
|
2017-09-14 18:51:06 +02:00
|
|
|
cap_mode = CS_MODE_ARM;
|
|
|
|
}
|
|
|
|
if (arm_feature(env, ARM_FEATURE_V8)) {
|
|
|
|
cap_mode |= CS_MODE_V8;
|
|
|
|
}
|
|
|
|
if (arm_feature(env, ARM_FEATURE_M)) {
|
|
|
|
cap_mode |= CS_MODE_MCLASS;
|
|
|
|
}
|
|
|
|
info->cap_arch = CS_ARCH_ARM;
|
|
|
|
info->cap_mode = cap_mode;
|
2015-06-24 05:57:35 +02:00
|
|
|
}
|
2017-10-19 23:13:02 +02:00
|
|
|
|
|
|
|
sctlr_b = arm_sctlr_b(env);
|
|
|
|
if (bswap_code(sctlr_b)) {
|
2015-06-24 05:57:35 +02:00
|
|
|
#ifdef TARGET_WORDS_BIGENDIAN
|
|
|
|
info->endian = BFD_ENDIAN_LITTLE;
|
|
|
|
#else
|
|
|
|
info->endian = BFD_ENDIAN_BIG;
|
|
|
|
#endif
|
|
|
|
}
|
2017-02-07 19:29:59 +01:00
|
|
|
info->flags &= ~INSN_ARM_BE32;
|
2017-10-19 23:13:02 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
if (sctlr_b) {
|
2017-02-07 19:29:59 +01:00
|
|
|
info->flags |= INSN_ARM_BE32;
|
|
|
|
}
|
2017-10-19 23:13:02 +02:00
|
|
|
#endif
|
2015-06-24 05:57:35 +02:00
|
|
|
}
|
|
|
|
|
2019-07-01 18:26:20 +02:00
|
|
|
#ifdef TARGET_AARCH64
|
|
|
|
|
|
|
|
static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(cs);
|
|
|
|
CPUARMState *env = &cpu->env;
|
|
|
|
uint32_t psr = pstate_read(env);
|
|
|
|
int i;
|
|
|
|
int el = arm_current_el(env);
|
|
|
|
const char *ns_status;
|
|
|
|
|
|
|
|
qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
if (i == 31) {
|
|
|
|
qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]);
|
|
|
|
} else {
|
|
|
|
qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i],
|
|
|
|
(i + 2) % 3 ? " " : "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) {
|
|
|
|
ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
|
|
|
|
} else {
|
|
|
|
ns_status = "";
|
|
|
|
}
|
|
|
|
qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
|
|
|
|
psr,
|
|
|
|
psr & PSTATE_N ? 'N' : '-',
|
|
|
|
psr & PSTATE_Z ? 'Z' : '-',
|
|
|
|
psr & PSTATE_C ? 'C' : '-',
|
|
|
|
psr & PSTATE_V ? 'V' : '-',
|
|
|
|
ns_status,
|
|
|
|
el,
|
|
|
|
psr & PSTATE_SP ? 'h' : 't');
|
|
|
|
|
|
|
|
if (cpu_isar_feature(aa64_bti, cpu)) {
|
|
|
|
qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
|
|
|
|
}
|
|
|
|
if (!(flags & CPU_DUMP_FPU)) {
|
|
|
|
qemu_fprintf(f, "\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (fp_exception_el(env, el) != 0) {
|
|
|
|
qemu_fprintf(f, " FPU disabled\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
qemu_fprintf(f, " FPCR=%08x FPSR=%08x\n",
|
|
|
|
vfp_get_fpcr(env), vfp_get_fpsr(env));
|
|
|
|
|
|
|
|
if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) {
|
|
|
|
int j, zcr_len = sve_zcr_len_for_el(env, el);
|
|
|
|
|
|
|
|
for (i = 0; i <= FFR_PRED_NUM; i++) {
|
|
|
|
bool eol;
|
|
|
|
if (i == FFR_PRED_NUM) {
|
|
|
|
qemu_fprintf(f, "FFR=");
|
|
|
|
/* It's last, so end the line. */
|
|
|
|
eol = true;
|
|
|
|
} else {
|
|
|
|
qemu_fprintf(f, "P%02d=", i);
|
|
|
|
switch (zcr_len) {
|
|
|
|
case 0:
|
|
|
|
eol = i % 8 == 7;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
eol = i % 6 == 5;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
|
|
eol = i % 3 == 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* More than one quadword per predicate. */
|
|
|
|
eol = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (j = zcr_len / 4; j >= 0; j--) {
|
|
|
|
int digits;
|
|
|
|
if (j * 4 + 4 <= zcr_len + 1) {
|
|
|
|
digits = 16;
|
|
|
|
} else {
|
|
|
|
digits = (zcr_len % 4 + 1) * 4;
|
|
|
|
}
|
|
|
|
qemu_fprintf(f, "%0*" PRIx64 "%s", digits,
|
|
|
|
env->vfp.pregs[i].p[j],
|
|
|
|
j ? ":" : eol ? "\n" : " ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
if (zcr_len == 0) {
|
|
|
|
qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s",
|
|
|
|
i, env->vfp.zregs[i].d[1],
|
|
|
|
env->vfp.zregs[i].d[0], i & 1 ? "\n" : " ");
|
|
|
|
} else if (zcr_len == 1) {
|
|
|
|
qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64
|
|
|
|
":%016" PRIx64 ":%016" PRIx64 "\n",
|
|
|
|
i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2],
|
|
|
|
env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]);
|
|
|
|
} else {
|
|
|
|
for (j = zcr_len; j >= 0; j--) {
|
|
|
|
bool odd = (zcr_len - j) % 2 != 0;
|
|
|
|
if (j == zcr_len) {
|
|
|
|
qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1);
|
|
|
|
} else if (!odd) {
|
|
|
|
if (j > 0) {
|
|
|
|
qemu_fprintf(f, " [%x-%x]=", j, j - 1);
|
|
|
|
} else {
|
|
|
|
qemu_fprintf(f, " [%x]=", j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
|
|
|
|
env->vfp.zregs[i].d[j * 2 + 1],
|
|
|
|
env->vfp.zregs[i].d[j * 2],
|
|
|
|
odd || j == 0 ? "\n" : ":");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
uint64_t *q = aa64_vfp_qreg(env, i);
|
|
|
|
qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s",
|
|
|
|
i, q[1], q[0], (i & 1 ? "\n" : " "));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
|
|
|
{
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(cs);
|
|
|
|
CPUARMState *env = &cpu->env;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (is_a64(env)) {
|
|
|
|
aarch64_cpu_dump_state(cs, f, flags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
|
|
|
|
if ((i % 4) == 3) {
|
|
|
|
qemu_fprintf(f, "\n");
|
|
|
|
} else {
|
|
|
|
qemu_fprintf(f, " ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arm_feature(env, ARM_FEATURE_M)) {
|
|
|
|
uint32_t xpsr = xpsr_read(env);
|
|
|
|
const char *mode;
|
|
|
|
const char *ns_status = "";
|
|
|
|
|
|
|
|
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
|
|
|
ns_status = env->v7m.secure ? "S " : "NS ";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xpsr & XPSR_EXCP) {
|
|
|
|
mode = "handler";
|
|
|
|
} else {
|
|
|
|
if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) {
|
|
|
|
mode = "unpriv-thread";
|
|
|
|
} else {
|
|
|
|
mode = "priv-thread";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n",
|
|
|
|
xpsr,
|
|
|
|
xpsr & XPSR_N ? 'N' : '-',
|
|
|
|
xpsr & XPSR_Z ? 'Z' : '-',
|
|
|
|
xpsr & XPSR_C ? 'C' : '-',
|
|
|
|
xpsr & XPSR_V ? 'V' : '-',
|
|
|
|
xpsr & XPSR_T ? 'T' : 'A',
|
|
|
|
ns_status,
|
|
|
|
mode);
|
|
|
|
} else {
|
|
|
|
uint32_t psr = cpsr_read(env);
|
|
|
|
const char *ns_status = "";
|
|
|
|
|
|
|
|
if (arm_feature(env, ARM_FEATURE_EL3) &&
|
|
|
|
(psr & CPSR_M) != ARM_CPU_MODE_MON) {
|
|
|
|
ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
|
|
|
|
}
|
|
|
|
|
|
|
|
qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
|
|
|
|
psr,
|
|
|
|
psr & CPSR_N ? 'N' : '-',
|
|
|
|
psr & CPSR_Z ? 'Z' : '-',
|
|
|
|
psr & CPSR_C ? 'C' : '-',
|
|
|
|
psr & CPSR_V ? 'V' : '-',
|
|
|
|
psr & CPSR_T ? 'T' : 'A',
|
|
|
|
ns_status,
|
|
|
|
aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & CPU_DUMP_FPU) {
|
|
|
|
int numvfpregs = 0;
|
2020-02-14 19:15:31 +01:00
|
|
|
if (cpu_isar_feature(aa32_simd_r32, cpu)) {
|
|
|
|
numvfpregs = 32;
|
2020-02-24 23:22:16 +01:00
|
|
|
} else if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
|
2020-02-14 19:15:31 +01:00
|
|
|
numvfpregs = 16;
|
2019-07-01 18:26:20 +02:00
|
|
|
}
|
|
|
|
for (i = 0; i < numvfpregs; i++) {
|
|
|
|
uint64_t v = *aa32_vfp_dreg(env, i);
|
|
|
|
qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
|
|
|
|
i * 2, (uint32_t)v,
|
|
|
|
i * 2 + 1, (uint32_t)(v >> 32),
|
|
|
|
i, v);
|
|
|
|
}
|
|
|
|
qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-03 14:56:56 +02:00
|
|
|
uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz)
|
|
|
|
{
|
|
|
|
uint32_t Aff1 = idx / clustersz;
|
|
|
|
uint32_t Aff0 = idx % clustersz;
|
|
|
|
return (Aff1 << ARM_AFF1_SHIFT) | Aff0;
|
|
|
|
}
|
|
|
|
|
2018-12-14 14:30:53 +01:00
|
|
|
static void cpreg_hashtable_data_destroy(gpointer data)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Destroy function for cpu->cp_regs hashtable data entries.
|
|
|
|
* We must free the name string because it was g_strdup()ed in
|
|
|
|
* add_cpreg_to_hashtable(). It's OK to cast away the 'const'
|
|
|
|
* from r->name because we know we definitely allocated it.
|
|
|
|
*/
|
|
|
|
ARMCPRegInfo *r = data;
|
|
|
|
|
|
|
|
g_free((void *)r->name);
|
|
|
|
g_free(r);
|
|
|
|
}
|
|
|
|
|
2012-04-20 19:58:31 +02:00
|
|
|
static void arm_cpu_initfn(Object *obj)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
|
|
|
|
2019-03-28 22:26:22 +01:00
|
|
|
cpu_set_cpustate_pointers(cpu);
|
2012-06-20 13:57:06 +02:00
|
|
|
cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal,
|
2018-12-14 14:30:53 +01:00
|
|
|
g_free, cpreg_hashtable_data_destroy);
|
2013-01-19 07:37:45 +01:00
|
|
|
|
2018-04-26 12:04:39 +02:00
|
|
|
QLIST_INIT(&cpu->pre_el_change_hooks);
|
2018-04-26 12:04:39 +02:00
|
|
|
QLIST_INIT(&cpu->el_change_hooks);
|
|
|
|
|
2013-08-20 15:54:28 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
/* Our inbound IRQ and FIQ lines */
|
|
|
|
if (kvm_enabled()) {
|
2014-09-29 19:48:51 +02:00
|
|
|
/* VIRQ and VFIQ are unused with KVM but we add them to maintain
|
|
|
|
* the same interface as non-KVM CPUs.
|
|
|
|
*/
|
|
|
|
qdev_init_gpio_in(DEVICE(cpu), arm_cpu_kvm_set_irq, 4);
|
2013-08-20 15:54:28 +02:00
|
|
|
} else {
|
2014-09-29 19:48:51 +02:00
|
|
|
qdev_init_gpio_in(DEVICE(cpu), arm_cpu_set_irq, 4);
|
2013-08-20 15:54:28 +02:00
|
|
|
}
|
2013-08-20 15:54:31 +02:00
|
|
|
|
|
|
|
qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs,
|
|
|
|
ARRAY_SIZE(cpu->gt_timer_outputs));
|
2017-01-20 12:15:09 +01:00
|
|
|
|
|
|
|
qdev_init_gpio_out_named(DEVICE(cpu), &cpu->gicv3_maintenance_interrupt,
|
|
|
|
"gicv3-maintenance-interrupt", 1);
|
2017-09-04 16:21:53 +02:00
|
|
|
qdev_init_gpio_out_named(DEVICE(cpu), &cpu->pmu_interrupt,
|
|
|
|
"pmu-interrupt", 1);
|
2013-08-20 15:54:28 +02:00
|
|
|
#endif
|
|
|
|
|
2013-11-22 18:17:12 +01:00
|
|
|
/* DTB consumers generally don't in fact care what the 'compatible'
|
|
|
|
* string is, so always provide some string and trust that a hypothetical
|
|
|
|
* picky DTB consumer will also provide a helpful error message.
|
|
|
|
*/
|
|
|
|
cpu->dtb_compatible = "qemu,unknown";
|
2014-06-19 19:06:26 +02:00
|
|
|
cpu->psci_version = 1; /* By default assume PSCI v0.1 */
|
2013-11-22 18:17:16 +01:00
|
|
|
cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
|
2013-11-22 18:17:12 +01:00
|
|
|
|
2014-10-24 13:19:13 +02:00
|
|
|
if (tcg_enabled()) {
|
|
|
|
cpu->psci_version = 2; /* TCG implements PSCI 0.2 */
|
2013-01-19 07:37:45 +01:00
|
|
|
}
|
2012-06-20 13:57:06 +02:00
|
|
|
}
|
|
|
|
|
2019-12-20 15:02:59 +01:00
|
|
|
static Property arm_cpu_gt_cntfrq_property =
|
|
|
|
DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq_hz,
|
|
|
|
NANOSECONDS_PER_SECOND / GTIMER_SCALE);
|
|
|
|
|
2013-12-17 20:42:28 +01:00
|
|
|
static Property arm_cpu_reset_cbar_property =
|
2014-04-15 20:18:49 +02:00
|
|
|
DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
|
2013-12-17 20:42:28 +01:00
|
|
|
|
2013-12-17 20:42:29 +01:00
|
|
|
static Property arm_cpu_reset_hivecs_property =
|
|
|
|
DEFINE_PROP_BOOL("reset-hivecs", ARMCPU, reset_hivecs, false);
|
|
|
|
|
2014-04-15 20:18:48 +02:00
|
|
|
static Property arm_cpu_rvbar_property =
|
|
|
|
DEFINE_PROP_UINT64("rvbar", ARMCPU, rvbar, 0);
|
|
|
|
|
2020-03-05 17:09:17 +01:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
2017-01-20 12:15:10 +01:00
|
|
|
static Property arm_cpu_has_el2_property =
|
|
|
|
DEFINE_PROP_BOOL("has_el2", ARMCPU, has_el2, true);
|
|
|
|
|
2014-12-16 00:09:46 +01:00
|
|
|
static Property arm_cpu_has_el3_property =
|
|
|
|
DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
|
2020-03-05 17:09:17 +01:00
|
|
|
#endif
|
2014-12-16 00:09:46 +01:00
|
|
|
|
2017-02-07 19:29:59 +01:00
|
|
|
static Property arm_cpu_cfgend_property =
|
|
|
|
DEFINE_PROP_BOOL("cfgend", ARMCPU, cfgend, false);
|
|
|
|
|
2019-05-17 19:40:43 +02:00
|
|
|
static Property arm_cpu_has_vfp_property =
|
|
|
|
DEFINE_PROP_BOOL("vfp", ARMCPU, has_vfp, true);
|
|
|
|
|
|
|
|
static Property arm_cpu_has_neon_property =
|
|
|
|
DEFINE_PROP_BOOL("neon", ARMCPU, has_neon, true);
|
|
|
|
|
2019-05-17 19:40:44 +02:00
|
|
|
static Property arm_cpu_has_dsp_property =
|
|
|
|
DEFINE_PROP_BOOL("dsp", ARMCPU, has_dsp, true);
|
|
|
|
|
2015-06-15 19:06:10 +02:00
|
|
|
static Property arm_cpu_has_mpu_property =
|
|
|
|
DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
|
|
|
|
|
2017-07-17 14:36:07 +02:00
|
|
|
/* This is like DEFINE_PROP_UINT32 but it doesn't set the default value,
|
|
|
|
* because the CPU initfn will have already set cpu->pmsav7_dregion to
|
|
|
|
* the right value for that particular CPU type, and we don't want
|
|
|
|
* to override that with an incorrect constant value.
|
|
|
|
*/
|
2015-06-19 15:17:44 +02:00
|
|
|
static Property arm_cpu_pmsav7_dregion_property =
|
2017-07-17 14:36:07 +02:00
|
|
|
DEFINE_PROP_UNSIGNED_NODEFAULT("pmsav7-dregion", ARMCPU,
|
|
|
|
pmsav7_dregion,
|
|
|
|
qdev_prop_uint32, uint32_t);
|
2015-06-19 15:17:44 +02:00
|
|
|
|
2019-08-02 14:25:27 +02:00
|
|
|
static bool arm_get_pmu(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
|
|
|
|
|
|
|
return cpu->has_pmu;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void arm_set_pmu(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
|
|
|
|
|
|
|
if (value) {
|
|
|
|
if (kvm_enabled() && !kvm_arm_pmu_supported(CPU(cpu))) {
|
|
|
|
error_setg(errp, "'pmu' feature not supported by KVM on this host");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
|
|
|
} else {
|
|
|
|
unset_feature(&cpu->env, ARM_FEATURE_PMU);
|
|
|
|
}
|
|
|
|
cpu->has_pmu = value;
|
|
|
|
}
|
|
|
|
|
2019-12-20 15:02:59 +01:00
|
|
|
unsigned int gt_cntfrq_period_ns(ARMCPU *cpu)
|
|
|
|
{
|
2019-12-20 15:02:59 +01:00
|
|
|
/*
|
|
|
|
* The exact approach to calculating guest ticks is:
|
|
|
|
*
|
|
|
|
* muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), cpu->gt_cntfrq_hz,
|
|
|
|
* NANOSECONDS_PER_SECOND);
|
|
|
|
*
|
|
|
|
* We don't do that. Rather we intentionally use integer division
|
|
|
|
* truncation below and in the caller for the conversion of host monotonic
|
|
|
|
* time to guest ticks to provide the exact inverse for the semantics of
|
|
|
|
* the QEMUTimer scale factor. QEMUTimer's scale facter is an integer, so
|
|
|
|
* it loses precision when representing frequencies where
|
|
|
|
* `(NANOSECONDS_PER_SECOND % cpu->gt_cntfrq) > 0` holds. Failing to
|
|
|
|
* provide an exact inverse leads to scheduling timers with negative
|
|
|
|
* periods, which in turn leads to sticky behaviour in the guest.
|
|
|
|
*
|
|
|
|
* Finally, CNTFRQ is effectively capped at 1GHz to ensure our scale factor
|
|
|
|
* cannot become zero.
|
|
|
|
*/
|
2019-12-20 15:02:59 +01:00
|
|
|
return NANOSECONDS_PER_SECOND > cpu->gt_cntfrq_hz ?
|
|
|
|
NANOSECONDS_PER_SECOND / cpu->gt_cntfrq_hz : 1;
|
|
|
|
}
|
|
|
|
|
2018-11-27 09:55:59 +01:00
|
|
|
void arm_cpu_post_init(Object *obj)
|
2013-12-17 20:42:28 +01:00
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
|
|
|
|
2017-06-02 12:51:48 +02:00
|
|
|
/* M profile implies PMSA. We have to do this here rather than
|
|
|
|
* in realize with the other feature-implication checks because
|
|
|
|
* we look at the PMSA bit to see if we should add some properties.
|
|
|
|
*/
|
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_PMSA);
|
|
|
|
}
|
|
|
|
|
2014-04-15 20:18:49 +02:00
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_CBAR) ||
|
|
|
|
arm_feature(&cpu->env, ARM_FEATURE_CBAR_RO)) {
|
2020-01-10 16:30:16 +01:00
|
|
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_cbar_property);
|
2013-12-17 20:42:28 +01:00
|
|
|
}
|
2013-12-17 20:42:29 +01:00
|
|
|
|
|
|
|
if (!arm_feature(&cpu->env, ARM_FEATURE_M)) {
|
2020-01-10 16:30:16 +01:00
|
|
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_hivecs_property);
|
2013-12-17 20:42:29 +01:00
|
|
|
}
|
2014-04-15 20:18:48 +02:00
|
|
|
|
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
|
2020-01-10 16:30:16 +01:00
|
|
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_rvbar_property);
|
2014-04-15 20:18:48 +02:00
|
|
|
}
|
2014-12-16 00:09:46 +01:00
|
|
|
|
2020-03-05 17:09:17 +01:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
2014-12-16 00:09:46 +01:00
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
|
|
|
|
/* Add the has_el3 state CPU property only if EL3 is allowed. This will
|
|
|
|
* prevent "has_el3" from existing on CPUs which cannot support EL3.
|
|
|
|
*/
|
2020-01-10 16:30:16 +01:00
|
|
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el3_property);
|
2016-01-21 15:15:06 +01:00
|
|
|
|
|
|
|
object_property_add_link(obj, "secure-memory",
|
|
|
|
TYPE_MEMORY_REGION,
|
|
|
|
(Object **)&cpu->secure_memory,
|
|
|
|
qdev_prop_allow_set_link_before_realize,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 17:29:22 +02:00
|
|
|
OBJ_PROP_LINK_STRONG);
|
2014-12-16 00:09:46 +01:00
|
|
|
}
|
2015-06-15 19:06:10 +02:00
|
|
|
|
2017-01-20 12:15:10 +01:00
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) {
|
2020-01-10 16:30:16 +01:00
|
|
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el2_property);
|
2017-01-20 12:15:10 +01:00
|
|
|
}
|
2020-03-05 17:09:17 +01:00
|
|
|
#endif
|
2017-01-20 12:15:10 +01:00
|
|
|
|
2016-10-28 15:12:31 +02:00
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_PMU)) {
|
2019-08-02 14:25:27 +02:00
|
|
|
cpu->has_pmu = true;
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 17:29:22 +02:00
|
|
|
object_property_add_bool(obj, "pmu", arm_get_pmu, arm_set_pmu);
|
2016-10-28 15:12:31 +02:00
|
|
|
}
|
|
|
|
|
2019-05-17 19:40:43 +02:00
|
|
|
/*
|
|
|
|
* Allow user to turn off VFP and Neon support, but only for TCG --
|
|
|
|
* KVM does not currently allow us to lie to the guest about its
|
|
|
|
* ID/feature registers, so the guest always sees what the host has.
|
|
|
|
*/
|
2020-02-24 23:22:19 +01:00
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)
|
|
|
|
? cpu_isar_feature(aa64_fp_simd, cpu)
|
|
|
|
: cpu_isar_feature(aa32_vfp, cpu)) {
|
2019-05-17 19:40:43 +02:00
|
|
|
cpu->has_vfp = true;
|
|
|
|
if (!kvm_enabled()) {
|
2020-01-10 16:30:16 +01:00
|
|
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_vfp_property);
|
2019-05-17 19:40:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_NEON)) {
|
|
|
|
cpu->has_neon = true;
|
|
|
|
if (!kvm_enabled()) {
|
2020-01-10 16:30:16 +01:00
|
|
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_neon_property);
|
2019-05-17 19:40:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-17 19:40:44 +02:00
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_M) &&
|
|
|
|
arm_feature(&cpu->env, ARM_FEATURE_THUMB_DSP)) {
|
2020-01-10 16:30:16 +01:00
|
|
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_dsp_property);
|
2019-05-17 19:40:44 +02:00
|
|
|
}
|
|
|
|
|
2017-06-02 12:51:47 +02:00
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_PMSA)) {
|
2020-01-10 16:30:16 +01:00
|
|
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property);
|
2015-06-19 15:17:44 +02:00
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
|
|
|
|
qdev_property_add_static(DEVICE(obj),
|
2020-01-10 16:30:16 +01:00
|
|
|
&arm_cpu_pmsav7_dregion_property);
|
2015-06-19 15:17:44 +02:00
|
|
|
}
|
2015-06-15 19:06:10 +02:00
|
|
|
}
|
|
|
|
|
2018-03-02 11:45:36 +01:00
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_M_SECURITY)) {
|
|
|
|
object_property_add_link(obj, "idau", TYPE_IDAU_INTERFACE, &cpu->idau,
|
|
|
|
qdev_prop_allow_set_link_before_realize,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 17:29:22 +02:00
|
|
|
OBJ_PROP_LINK_STRONG);
|
2019-02-28 11:55:15 +01:00
|
|
|
/*
|
|
|
|
* M profile: initial value of the Secure VTOR. We can't just use
|
|
|
|
* a simple DEFINE_PROP_UINT32 for this because we want to permit
|
|
|
|
* the property to be set after realize.
|
|
|
|
*/
|
2020-02-04 14:16:01 +01:00
|
|
|
object_property_add_uint32_ptr(obj, "init-svtor",
|
|
|
|
&cpu->init_svtor,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 17:29:22 +02:00
|
|
|
OBJ_PROP_FLAG_READWRITE);
|
2018-03-02 11:45:36 +01:00
|
|
|
}
|
|
|
|
|
2020-01-10 16:30:16 +01:00
|
|
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property);
|
2019-12-20 15:02:59 +01:00
|
|
|
|
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER)) {
|
2020-01-10 16:30:16 +01:00
|
|
|
qdev_property_add_static(DEVICE(cpu), &arm_cpu_gt_cntfrq_property);
|
2019-12-20 15:02:59 +01:00
|
|
|
}
|
2013-12-17 20:42:28 +01:00
|
|
|
}
|
|
|
|
|
2012-06-20 13:57:06 +02:00
|
|
|
static void arm_cpu_finalizefn(Object *obj)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
2018-04-26 12:04:39 +02:00
|
|
|
ARMELChangeHook *hook, *next;
|
|
|
|
|
2012-06-20 13:57:06 +02:00
|
|
|
g_hash_table_destroy(cpu->cp_regs);
|
2018-04-26 12:04:39 +02:00
|
|
|
|
2018-04-26 12:04:39 +02:00
|
|
|
QLIST_FOREACH_SAFE(hook, &cpu->pre_el_change_hooks, node, next) {
|
|
|
|
QLIST_REMOVE(hook, node);
|
|
|
|
g_free(hook);
|
|
|
|
}
|
2018-04-26 12:04:39 +02:00
|
|
|
QLIST_FOREACH_SAFE(hook, &cpu->el_change_hooks, node, next) {
|
|
|
|
QLIST_REMOVE(hook, node);
|
|
|
|
g_free(hook);
|
|
|
|
}
|
2019-02-01 15:55:45 +01:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
if (cpu->pmu_timer) {
|
|
|
|
timer_del(cpu->pmu_timer);
|
|
|
|
timer_deinit(cpu->pmu_timer);
|
|
|
|
timer_free(cpu->pmu_timer);
|
|
|
|
}
|
|
|
|
#endif
|
2012-04-20 19:58:31 +02:00
|
|
|
}
|
|
|
|
|
target/arm/cpu64: max cpu: Introduce sve<N> properties
Introduce cpu properties to give fine control over SVE vector lengths.
We introduce a property for each valid length up to the current
maximum supported, which is 2048-bits. The properties are named, e.g.
sve128, sve256, sve384, sve512, ..., where the number is the number of
bits. See the updates to docs/arm-cpu-features.rst for a description
of the semantics and for example uses.
Note, as sve-max-vq is still present and we'd like to be able to
support qmp_query_cpu_model_expansion with guests launched with e.g.
-cpu max,sve-max-vq=8 on their command lines, then we do allow
sve-max-vq and sve<N> properties to be provided at the same time, but
this is not recommended, and is why sve-max-vq is not mentioned in the
document. If sve-max-vq is provided then it enables all lengths smaller
than and including the max and disables all lengths larger. It also has
the side-effect that no larger lengths may be enabled and that the max
itself cannot be disabled. Smaller non-power-of-two lengths may,
however, be disabled, e.g. -cpu max,sve-max-vq=4,sve384=off provides a
guest the vector lengths 128, 256, and 512 bits.
This patch has been co-authored with Richard Henderson, who reworked
the target/arm/cpu64.c changes in order to push all the validation and
auto-enabling/disabling steps into the finalizer, resulting in a nice
LOC reduction.
Signed-off-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
Reviewed-by: Beata Michalska <beata.michalska@linaro.org>
Message-id: 20191031142734.8590-5-drjones@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2019-10-31 15:27:29 +01:00
|
|
|
void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
|
|
|
|
{
|
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
|
|
|
|
arm_cpu_sve_finalize(cpu, &local_err);
|
|
|
|
if (local_err != NULL) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-05 10:18:18 +01:00
|
|
|
static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
2012-04-20 19:58:31 +02:00
|
|
|
{
|
2013-07-27 02:53:25 +02:00
|
|
|
CPUState *cs = CPU(dev);
|
2013-01-05 10:18:18 +01:00
|
|
|
ARMCPU *cpu = ARM_CPU(dev);
|
|
|
|
ARMCPUClass *acc = ARM_CPU_GET_CLASS(dev);
|
2012-04-20 19:58:31 +02:00
|
|
|
CPUARMState *env = &cpu->env;
|
2016-10-24 17:26:50 +02:00
|
|
|
int pagebits;
|
2016-10-20 13:26:03 +02:00
|
|
|
Error *local_err = NULL;
|
2018-11-02 11:20:25 +01:00
|
|
|
bool no_aa32 = false;
|
2016-10-20 13:26:03 +02:00
|
|
|
|
2018-03-09 18:09:44 +01:00
|
|
|
/* If we needed to query the host kernel for the CPU features
|
|
|
|
* then it's possible that might have failed in the initfn, but
|
|
|
|
* this is the first point where we can report it.
|
|
|
|
*/
|
|
|
|
if (cpu->host_cpu_probe_failed) {
|
|
|
|
if (!kvm_enabled()) {
|
|
|
|
error_setg(errp, "The 'host' CPU type can only be used with KVM");
|
|
|
|
} else {
|
|
|
|
error_setg(errp, "Failed to retrieve host CPU features");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-15 15:57:13 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
/* The NVIC and M-profile CPU are two halves of a single piece of
|
|
|
|
* hardware; trying to use one without the other is a command line
|
|
|
|
* error and will result in segfaults if not caught here.
|
|
|
|
*/
|
|
|
|
if (arm_feature(env, ARM_FEATURE_M)) {
|
|
|
|
if (!env->nvic) {
|
|
|
|
error_setg(errp, "This board cannot be used with Cortex-M CPUs");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (env->nvic) {
|
|
|
|
error_setg(errp, "This board can only be used with Cortex-M CPUs");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2018-12-14 14:30:55 +01:00
|
|
|
|
2019-12-20 15:02:59 +01:00
|
|
|
{
|
|
|
|
uint64_t scale;
|
|
|
|
|
|
|
|
if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
|
|
|
|
if (!cpu->gt_cntfrq_hz) {
|
|
|
|
error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz",
|
|
|
|
cpu->gt_cntfrq_hz);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
scale = gt_cntfrq_period_ns(cpu);
|
|
|
|
} else {
|
|
|
|
scale = GTIMER_SCALE;
|
|
|
|
}
|
|
|
|
|
|
|
|
cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
|
|
|
|
arm_gt_ptimer_cb, cpu);
|
|
|
|
cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
|
|
|
|
arm_gt_vtimer_cb, cpu);
|
|
|
|
cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
|
|
|
|
arm_gt_htimer_cb, cpu);
|
|
|
|
cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
|
|
|
|
arm_gt_stimer_cb, cpu);
|
2020-02-07 15:04:25 +01:00
|
|
|
cpu->gt_timer[GTIMER_HYPVIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
|
|
|
|
arm_gt_hvtimer_cb, cpu);
|
2019-12-20 15:02:59 +01:00
|
|
|
}
|
2018-06-15 15:57:13 +02:00
|
|
|
#endif
|
|
|
|
|
2016-10-20 13:26:03 +02:00
|
|
|
cpu_exec_realizefn(cs, &local_err);
|
|
|
|
if (local_err != NULL) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
2013-01-05 10:18:18 +01:00
|
|
|
|
target/arm/cpu64: max cpu: Introduce sve<N> properties
Introduce cpu properties to give fine control over SVE vector lengths.
We introduce a property for each valid length up to the current
maximum supported, which is 2048-bits. The properties are named, e.g.
sve128, sve256, sve384, sve512, ..., where the number is the number of
bits. See the updates to docs/arm-cpu-features.rst for a description
of the semantics and for example uses.
Note, as sve-max-vq is still present and we'd like to be able to
support qmp_query_cpu_model_expansion with guests launched with e.g.
-cpu max,sve-max-vq=8 on their command lines, then we do allow
sve-max-vq and sve<N> properties to be provided at the same time, but
this is not recommended, and is why sve-max-vq is not mentioned in the
document. If sve-max-vq is provided then it enables all lengths smaller
than and including the max and disables all lengths larger. It also has
the side-effect that no larger lengths may be enabled and that the max
itself cannot be disabled. Smaller non-power-of-two lengths may,
however, be disabled, e.g. -cpu max,sve-max-vq=4,sve384=off provides a
guest the vector lengths 128, 256, and 512 bits.
This patch has been co-authored with Richard Henderson, who reworked
the target/arm/cpu64.c changes in order to push all the validation and
auto-enabling/disabling steps into the finalizer, resulting in a nice
LOC reduction.
Signed-off-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
Reviewed-by: Beata Michalska <beata.michalska@linaro.org>
Message-id: 20191031142734.8590-5-drjones@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2019-10-31 15:27:29 +01:00
|
|
|
arm_cpu_finalize_features(cpu, &local_err);
|
|
|
|
if (local_err != NULL) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-17 19:40:43 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_AARCH64) &&
|
|
|
|
cpu->has_vfp != cpu->has_neon) {
|
|
|
|
/*
|
|
|
|
* This is an architectural requirement for AArch64; AArch32 is
|
|
|
|
* more flexible and permits VFP-no-Neon and Neon-no-VFP.
|
|
|
|
*/
|
|
|
|
error_setg(errp,
|
|
|
|
"AArch64 CPUs must have both VFP and Neon or neither");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cpu->has_vfp) {
|
|
|
|
uint64_t t;
|
|
|
|
uint32_t u;
|
|
|
|
|
|
|
|
t = cpu->isar.id_aa64isar1;
|
|
|
|
t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 0);
|
|
|
|
cpu->isar.id_aa64isar1 = t;
|
|
|
|
|
|
|
|
t = cpu->isar.id_aa64pfr0;
|
|
|
|
t = FIELD_DP64(t, ID_AA64PFR0, FP, 0xf);
|
|
|
|
cpu->isar.id_aa64pfr0 = t;
|
|
|
|
|
|
|
|
u = cpu->isar.id_isar6;
|
|
|
|
u = FIELD_DP32(u, ID_ISAR6, JSCVT, 0);
|
|
|
|
cpu->isar.id_isar6 = u;
|
|
|
|
|
|
|
|
u = cpu->isar.mvfr0;
|
|
|
|
u = FIELD_DP32(u, MVFR0, FPSP, 0);
|
|
|
|
u = FIELD_DP32(u, MVFR0, FPDP, 0);
|
|
|
|
u = FIELD_DP32(u, MVFR0, FPTRAP, 0);
|
|
|
|
u = FIELD_DP32(u, MVFR0, FPDIVIDE, 0);
|
|
|
|
u = FIELD_DP32(u, MVFR0, FPSQRT, 0);
|
|
|
|
u = FIELD_DP32(u, MVFR0, FPSHVEC, 0);
|
|
|
|
u = FIELD_DP32(u, MVFR0, FPROUND, 0);
|
|
|
|
cpu->isar.mvfr0 = u;
|
|
|
|
|
|
|
|
u = cpu->isar.mvfr1;
|
|
|
|
u = FIELD_DP32(u, MVFR1, FPFTZ, 0);
|
|
|
|
u = FIELD_DP32(u, MVFR1, FPDNAN, 0);
|
|
|
|
u = FIELD_DP32(u, MVFR1, FPHP, 0);
|
|
|
|
cpu->isar.mvfr1 = u;
|
|
|
|
|
|
|
|
u = cpu->isar.mvfr2;
|
|
|
|
u = FIELD_DP32(u, MVFR2, FPMISC, 0);
|
|
|
|
cpu->isar.mvfr2 = u;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cpu->has_neon) {
|
|
|
|
uint64_t t;
|
|
|
|
uint32_t u;
|
|
|
|
|
|
|
|
unset_feature(env, ARM_FEATURE_NEON);
|
|
|
|
|
|
|
|
t = cpu->isar.id_aa64isar0;
|
|
|
|
t = FIELD_DP64(t, ID_AA64ISAR0, DP, 0);
|
|
|
|
cpu->isar.id_aa64isar0 = t;
|
|
|
|
|
|
|
|
t = cpu->isar.id_aa64isar1;
|
|
|
|
t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 0);
|
|
|
|
cpu->isar.id_aa64isar1 = t;
|
|
|
|
|
|
|
|
t = cpu->isar.id_aa64pfr0;
|
|
|
|
t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 0xf);
|
|
|
|
cpu->isar.id_aa64pfr0 = t;
|
|
|
|
|
|
|
|
u = cpu->isar.id_isar5;
|
|
|
|
u = FIELD_DP32(u, ID_ISAR5, RDM, 0);
|
|
|
|
u = FIELD_DP32(u, ID_ISAR5, VCMA, 0);
|
|
|
|
cpu->isar.id_isar5 = u;
|
|
|
|
|
|
|
|
u = cpu->isar.id_isar6;
|
|
|
|
u = FIELD_DP32(u, ID_ISAR6, DP, 0);
|
|
|
|
u = FIELD_DP32(u, ID_ISAR6, FHM, 0);
|
|
|
|
cpu->isar.id_isar6 = u;
|
|
|
|
|
|
|
|
u = cpu->isar.mvfr1;
|
|
|
|
u = FIELD_DP32(u, MVFR1, SIMDLS, 0);
|
|
|
|
u = FIELD_DP32(u, MVFR1, SIMDINT, 0);
|
|
|
|
u = FIELD_DP32(u, MVFR1, SIMDSP, 0);
|
|
|
|
u = FIELD_DP32(u, MVFR1, SIMDHP, 0);
|
|
|
|
cpu->isar.mvfr1 = u;
|
|
|
|
|
|
|
|
u = cpu->isar.mvfr2;
|
|
|
|
u = FIELD_DP32(u, MVFR2, SIMDMISC, 0);
|
|
|
|
cpu->isar.mvfr2 = u;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cpu->has_neon && !cpu->has_vfp) {
|
|
|
|
uint64_t t;
|
|
|
|
uint32_t u;
|
|
|
|
|
|
|
|
t = cpu->isar.id_aa64isar0;
|
|
|
|
t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 0);
|
|
|
|
cpu->isar.id_aa64isar0 = t;
|
|
|
|
|
|
|
|
t = cpu->isar.id_aa64isar1;
|
|
|
|
t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 0);
|
|
|
|
cpu->isar.id_aa64isar1 = t;
|
|
|
|
|
|
|
|
u = cpu->isar.mvfr0;
|
|
|
|
u = FIELD_DP32(u, MVFR0, SIMDREG, 0);
|
|
|
|
cpu->isar.mvfr0 = u;
|
2020-02-24 23:22:24 +01:00
|
|
|
|
|
|
|
/* Despite the name, this field covers both VFP and Neon */
|
|
|
|
u = cpu->isar.mvfr1;
|
|
|
|
u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0);
|
|
|
|
cpu->isar.mvfr1 = u;
|
2019-05-17 19:40:43 +02:00
|
|
|
}
|
|
|
|
|
2019-05-17 19:40:44 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_M) && !cpu->has_dsp) {
|
|
|
|
uint32_t u;
|
|
|
|
|
|
|
|
unset_feature(env, ARM_FEATURE_THUMB_DSP);
|
|
|
|
|
|
|
|
u = cpu->isar.id_isar1;
|
|
|
|
u = FIELD_DP32(u, ID_ISAR1, EXTEND, 1);
|
|
|
|
cpu->isar.id_isar1 = u;
|
|
|
|
|
|
|
|
u = cpu->isar.id_isar2;
|
|
|
|
u = FIELD_DP32(u, ID_ISAR2, MULTU, 1);
|
|
|
|
u = FIELD_DP32(u, ID_ISAR2, MULTS, 1);
|
|
|
|
cpu->isar.id_isar2 = u;
|
|
|
|
|
|
|
|
u = cpu->isar.id_isar3;
|
|
|
|
u = FIELD_DP32(u, ID_ISAR3, SIMD, 1);
|
|
|
|
u = FIELD_DP32(u, ID_ISAR3, SATURATE, 0);
|
|
|
|
cpu->isar.id_isar3 = u;
|
|
|
|
}
|
|
|
|
|
2012-04-20 19:58:31 +02:00
|
|
|
/* Some features automatically imply others: */
|
2013-07-15 15:35:25 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_V8)) {
|
2018-10-24 08:50:16 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_M)) {
|
|
|
|
set_feature(env, ARM_FEATURE_V7);
|
|
|
|
} else {
|
|
|
|
set_feature(env, ARM_FEATURE_V7VE);
|
|
|
|
}
|
2018-06-29 16:11:17 +02:00
|
|
|
}
|
2018-11-02 11:20:25 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* There exist AArch64 cpus without AArch32 support. When KVM
|
|
|
|
* queries ID_ISAR0_EL1 on such a host, the value is UNKNOWN.
|
|
|
|
* Similarly, we cannot check ID_AA64PFR0 without AArch64 support.
|
2019-07-22 15:07:39 +02:00
|
|
|
* As a general principle, we also do not make ID register
|
|
|
|
* consistency checks anywhere unless using TCG, because only
|
|
|
|
* for TCG would a consistency-check failure be a QEMU bug.
|
2018-11-02 11:20:25 +01:00
|
|
|
*/
|
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
|
|
|
|
no_aa32 = !cpu_isar_feature(aa64_aa32, cpu);
|
|
|
|
}
|
|
|
|
|
2018-06-29 16:11:17 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_V7VE)) {
|
|
|
|
/* v7 Virtualization Extensions. In real hardware this implies
|
|
|
|
* EL2 and also the presence of the Security Extensions.
|
|
|
|
* For QEMU, for backwards-compatibility we implement some
|
|
|
|
* CPUs or CPU configs which have no actual EL2 or EL3 but do
|
|
|
|
* include the various other features that V7VE implies.
|
|
|
|
* Presence of EL2 itself is ARM_FEATURE_EL2, and of the
|
|
|
|
* Security Extensions is ARM_FEATURE_EL3.
|
|
|
|
*/
|
2020-02-14 18:50:56 +01:00
|
|
|
assert(!tcg_enabled() || no_aa32 ||
|
|
|
|
cpu_isar_feature(aa32_arm_div, cpu));
|
2013-07-15 15:35:25 +02:00
|
|
|
set_feature(env, ARM_FEATURE_LPAE);
|
2018-06-29 16:11:17 +02:00
|
|
|
set_feature(env, ARM_FEATURE_V7);
|
2013-07-15 15:35:25 +02:00
|
|
|
}
|
2012-04-20 19:58:31 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_V7)) {
|
|
|
|
set_feature(env, ARM_FEATURE_VAPA);
|
|
|
|
set_feature(env, ARM_FEATURE_THUMB2);
|
2012-06-20 13:57:20 +02:00
|
|
|
set_feature(env, ARM_FEATURE_MPIDR);
|
2012-04-20 19:58:31 +02:00
|
|
|
if (!arm_feature(env, ARM_FEATURE_M)) {
|
|
|
|
set_feature(env, ARM_FEATURE_V6K);
|
|
|
|
} else {
|
|
|
|
set_feature(env, ARM_FEATURE_V6);
|
|
|
|
}
|
2016-12-27 15:59:30 +01:00
|
|
|
|
|
|
|
/* Always define VBAR for V7 CPUs even if it doesn't exist in
|
|
|
|
* non-EL3 configs. This is needed by some legacy boards.
|
|
|
|
*/
|
|
|
|
set_feature(env, ARM_FEATURE_VBAR);
|
2012-04-20 19:58:31 +02:00
|
|
|
}
|
|
|
|
if (arm_feature(env, ARM_FEATURE_V6K)) {
|
|
|
|
set_feature(env, ARM_FEATURE_V6);
|
|
|
|
set_feature(env, ARM_FEATURE_MVFR);
|
|
|
|
}
|
|
|
|
if (arm_feature(env, ARM_FEATURE_V6)) {
|
|
|
|
set_feature(env, ARM_FEATURE_V5);
|
|
|
|
if (!arm_feature(env, ARM_FEATURE_M)) {
|
2020-02-14 18:50:56 +01:00
|
|
|
assert(!tcg_enabled() || no_aa32 ||
|
|
|
|
cpu_isar_feature(aa32_jazelle, cpu));
|
2012-04-20 19:58:31 +02:00
|
|
|
set_feature(env, ARM_FEATURE_AUXCR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (arm_feature(env, ARM_FEATURE_V5)) {
|
|
|
|
set_feature(env, ARM_FEATURE_V4T);
|
|
|
|
}
|
2012-07-12 12:59:05 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_LPAE)) {
|
2013-06-25 19:16:08 +02:00
|
|
|
set_feature(env, ARM_FEATURE_V7MP);
|
2012-07-12 12:59:05 +02:00
|
|
|
set_feature(env, ARM_FEATURE_PXN);
|
|
|
|
}
|
2014-04-15 20:18:49 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_CBAR_RO)) {
|
|
|
|
set_feature(env, ARM_FEATURE_CBAR);
|
|
|
|
}
|
2015-06-15 19:06:09 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_THUMB2) &&
|
|
|
|
!arm_feature(env, ARM_FEATURE_M)) {
|
|
|
|
set_feature(env, ARM_FEATURE_THUMB_DSP);
|
|
|
|
}
|
2012-06-20 13:57:09 +02:00
|
|
|
|
2019-04-29 18:36:01 +02:00
|
|
|
/*
|
|
|
|
* We rely on no XScale CPU having VFP so we can use the same bits in the
|
|
|
|
* TB flags field for VECSTRIDE and XSCALE_CPAR.
|
|
|
|
*/
|
2020-02-24 23:22:19 +01:00
|
|
|
assert(arm_feature(&cpu->env, ARM_FEATURE_AARCH64) ||
|
|
|
|
!cpu_isar_feature(aa32_vfp_simd, cpu) ||
|
|
|
|
!arm_feature(env, ARM_FEATURE_XSCALE));
|
2019-04-29 18:36:01 +02:00
|
|
|
|
2016-10-24 17:26:50 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_V7) &&
|
|
|
|
!arm_feature(env, ARM_FEATURE_M) &&
|
2017-06-02 12:51:47 +02:00
|
|
|
!arm_feature(env, ARM_FEATURE_PMSA)) {
|
2016-10-24 17:26:50 +02:00
|
|
|
/* v7VMSA drops support for the old ARMv5 tiny pages, so we
|
|
|
|
* can use 4K pages.
|
|
|
|
*/
|
|
|
|
pagebits = 12;
|
|
|
|
} else {
|
|
|
|
/* For CPUs which might have tiny 1K pages, or which have an
|
|
|
|
* MPU and might have small region sizes, stick with 1K pages.
|
|
|
|
*/
|
|
|
|
pagebits = 10;
|
|
|
|
}
|
|
|
|
if (!set_preferred_target_page_bits(pagebits)) {
|
|
|
|
/* This can only ever happen for hotplugging a CPU, or if
|
|
|
|
* the board code incorrectly creates a CPU which it has
|
|
|
|
* promised via minimum_page_size that it will not.
|
|
|
|
*/
|
|
|
|
error_setg(errp, "This CPU requires a smaller page size than the "
|
|
|
|
"system is using");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-20 13:26:03 +02:00
|
|
|
/* This cpu-id-to-MPIDR affinity is used only for TCG; KVM will override it.
|
|
|
|
* We don't support setting cluster ID ([16..23]) (known as Aff2
|
|
|
|
* in later ARM ARM versions), or any of the higher affinity level fields,
|
|
|
|
* so these bits always RAZ.
|
|
|
|
*/
|
|
|
|
if (cpu->mp_affinity == ARM64_AFFINITY_INVALID) {
|
2017-05-03 14:56:56 +02:00
|
|
|
cpu->mp_affinity = arm_cpu_mp_affinity(cs->cpu_index,
|
|
|
|
ARM_DEFAULT_CPUS_PER_CLUSTER);
|
2016-10-20 13:26:03 +02:00
|
|
|
}
|
|
|
|
|
2013-12-17 20:42:29 +01:00
|
|
|
if (cpu->reset_hivecs) {
|
|
|
|
cpu->reset_sctlr |= (1 << 13);
|
|
|
|
}
|
|
|
|
|
2017-02-07 19:29:59 +01:00
|
|
|
if (cpu->cfgend) {
|
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
|
|
|
|
cpu->reset_sctlr |= SCTLR_EE;
|
|
|
|
} else {
|
|
|
|
cpu->reset_sctlr |= SCTLR_B;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-16 00:09:46 +01:00
|
|
|
if (!cpu->has_el3) {
|
|
|
|
/* If the has_el3 CPU property is disabled then we need to disable the
|
|
|
|
* feature.
|
|
|
|
*/
|
|
|
|
unset_feature(env, ARM_FEATURE_EL3);
|
|
|
|
|
|
|
|
/* Disable the security extension feature bits in the processor feature
|
2015-04-26 17:49:26 +02:00
|
|
|
* registers as well. These are id_pfr1[7:4] and id_aa64pfr0[15:12].
|
2014-12-16 00:09:46 +01:00
|
|
|
*/
|
|
|
|
cpu->id_pfr1 &= ~0xf0;
|
2018-10-24 08:50:16 +02:00
|
|
|
cpu->isar.id_aa64pfr0 &= ~0xf000;
|
2014-12-16 00:09:46 +01:00
|
|
|
}
|
|
|
|
|
2017-01-20 12:15:10 +01:00
|
|
|
if (!cpu->has_el2) {
|
|
|
|
unset_feature(env, ARM_FEATURE_EL2);
|
|
|
|
}
|
|
|
|
|
2017-02-10 18:40:28 +01:00
|
|
|
if (!cpu->has_pmu) {
|
2016-10-28 15:12:31 +02:00
|
|
|
unset_feature(env, ARM_FEATURE_PMU);
|
2019-01-21 11:23:14 +01:00
|
|
|
}
|
|
|
|
if (arm_feature(env, ARM_FEATURE_PMU)) {
|
2019-01-29 12:46:04 +01:00
|
|
|
pmu_init(cpu);
|
2019-01-21 11:23:14 +01:00
|
|
|
|
|
|
|
if (!kvm_enabled()) {
|
|
|
|
arm_register_pre_el_change_hook(cpu, &pmu_pre_el_change, 0);
|
|
|
|
arm_register_el_change_hook(cpu, &pmu_post_el_change, 0);
|
|
|
|
}
|
2019-02-01 15:55:45 +01:00
|
|
|
|
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
cpu->pmu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, arm_pmu_timer_cb,
|
|
|
|
cpu);
|
|
|
|
#endif
|
2019-01-21 11:23:14 +01:00
|
|
|
} else {
|
2020-02-14 18:51:04 +01:00
|
|
|
cpu->isar.id_aa64dfr0 =
|
|
|
|
FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, PMUVER, 0);
|
2020-02-14 18:51:03 +01:00
|
|
|
cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, PERFMON, 0);
|
2019-01-21 11:23:14 +01:00
|
|
|
cpu->pmceid0 = 0;
|
|
|
|
cpu->pmceid1 = 0;
|
2016-10-28 15:12:31 +02:00
|
|
|
}
|
|
|
|
|
2016-02-02 19:20:42 +01:00
|
|
|
if (!arm_feature(env, ARM_FEATURE_EL2)) {
|
|
|
|
/* Disable the hypervisor feature bits in the processor feature
|
|
|
|
* registers if we don't have EL2. These are id_pfr1[15:12] and
|
|
|
|
* id_aa64pfr0_el1[11:8].
|
|
|
|
*/
|
2018-10-24 08:50:16 +02:00
|
|
|
cpu->isar.id_aa64pfr0 &= ~0xf00;
|
2016-02-02 19:20:42 +01:00
|
|
|
cpu->id_pfr1 &= ~0xf000;
|
|
|
|
}
|
|
|
|
|
2017-06-02 12:51:47 +02:00
|
|
|
/* MPU can be configured out of a PMSA CPU either by setting has-mpu
|
|
|
|
* to false or by setting pmsav7-dregion to 0.
|
|
|
|
*/
|
2015-06-15 19:06:10 +02:00
|
|
|
if (!cpu->has_mpu) {
|
2017-06-02 12:51:47 +02:00
|
|
|
cpu->pmsav7_dregion = 0;
|
|
|
|
}
|
|
|
|
if (cpu->pmsav7_dregion == 0) {
|
|
|
|
cpu->has_mpu = false;
|
2015-06-15 19:06:10 +02:00
|
|
|
}
|
|
|
|
|
2017-06-02 12:51:47 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_PMSA) &&
|
2015-06-19 15:17:44 +02:00
|
|
|
arm_feature(env, ARM_FEATURE_V7)) {
|
|
|
|
uint32_t nr = cpu->pmsav7_dregion;
|
|
|
|
|
|
|
|
if (nr > 0xff) {
|
2015-12-18 16:35:19 +01:00
|
|
|
error_setg(errp, "PMSAv7 MPU #regions invalid %" PRIu32, nr);
|
2015-06-19 15:17:44 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-06-19 15:17:44 +02:00
|
|
|
|
|
|
|
if (nr) {
|
2017-09-07 14:54:51 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_V8)) {
|
|
|
|
/* PMSAv8 */
|
2017-09-07 14:54:53 +02:00
|
|
|
env->pmsav8.rbar[M_REG_NS] = g_new0(uint32_t, nr);
|
|
|
|
env->pmsav8.rlar[M_REG_NS] = g_new0(uint32_t, nr);
|
|
|
|
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
|
|
|
env->pmsav8.rbar[M_REG_S] = g_new0(uint32_t, nr);
|
|
|
|
env->pmsav8.rlar[M_REG_S] = g_new0(uint32_t, nr);
|
|
|
|
}
|
2017-09-07 14:54:51 +02:00
|
|
|
} else {
|
|
|
|
env->pmsav7.drbar = g_new0(uint32_t, nr);
|
|
|
|
env->pmsav7.drsr = g_new0(uint32_t, nr);
|
|
|
|
env->pmsav7.dracr = g_new0(uint32_t, nr);
|
|
|
|
}
|
2015-06-19 15:17:44 +02:00
|
|
|
}
|
2015-06-19 15:17:44 +02:00
|
|
|
}
|
|
|
|
|
2017-10-06 17:46:49 +02:00
|
|
|
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
|
|
|
uint32_t nr = cpu->sau_sregion;
|
|
|
|
|
|
|
|
if (nr > 0xff) {
|
|
|
|
error_setg(errp, "v8M SAU #regions invalid %" PRIu32, nr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nr) {
|
|
|
|
env->sau.rbar = g_new0(uint32_t, nr);
|
|
|
|
env->sau.rlar = g_new0(uint32_t, nr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-27 15:59:30 +01:00
|
|
|
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
|
|
|
set_feature(env, ARM_FEATURE_VBAR);
|
|
|
|
}
|
|
|
|
|
2012-06-20 13:57:09 +02:00
|
|
|
register_cp_regs_for_features(cpu);
|
2013-01-05 10:18:18 +01:00
|
|
|
arm_cpu_register_gdb_regs_for_features(cpu);
|
|
|
|
|
2013-06-25 19:16:07 +02:00
|
|
|
init_cpreg_list(cpu);
|
|
|
|
|
2016-01-21 15:15:06 +01:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
2019-05-18 22:54:26 +02:00
|
|
|
MachineState *ms = MACHINE(qdev_get_machine());
|
|
|
|
unsigned int smp_cpus = ms->smp.cpus;
|
|
|
|
|
2017-09-07 14:54:52 +02:00
|
|
|
if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
|
|
|
cs->num_ases = 2;
|
|
|
|
|
2016-01-21 15:15:06 +01:00
|
|
|
if (!cpu->secure_memory) {
|
|
|
|
cpu->secure_memory = cs->memory;
|
|
|
|
}
|
2017-11-23 10:23:32 +01:00
|
|
|
cpu_address_space_init(cs, ARMASIdx_S, "cpu-secure-memory",
|
|
|
|
cpu->secure_memory);
|
2017-09-07 14:54:52 +02:00
|
|
|
} else {
|
|
|
|
cs->num_ases = 1;
|
2016-01-21 15:15:06 +01:00
|
|
|
}
|
2017-11-23 10:23:32 +01:00
|
|
|
cpu_address_space_init(cs, ARMASIdx_NS, "cpu-memory", cs->memory);
|
2018-03-09 18:09:43 +01:00
|
|
|
|
|
|
|
/* No core_count specified, default to smp_cpus. */
|
|
|
|
if (cpu->core_count == -1) {
|
|
|
|
cpu->core_count = smp_cpus;
|
|
|
|
}
|
2016-01-21 15:15:06 +01:00
|
|
|
#endif
|
|
|
|
|
2013-07-27 02:53:25 +02:00
|
|
|
qemu_init_vcpu(cs);
|
2014-05-27 14:37:43 +02:00
|
|
|
cpu_reset(cs);
|
2013-01-05 10:18:18 +01:00
|
|
|
|
|
|
|
acc->parent_realize(dev, errp);
|
2012-04-20 19:58:31 +02:00
|
|
|
}
|
|
|
|
|
2013-01-21 16:11:43 +01:00
|
|
|
static ObjectClass *arm_cpu_class_by_name(const char *cpu_model)
|
|
|
|
{
|
|
|
|
ObjectClass *oc;
|
2013-01-27 17:30:10 +01:00
|
|
|
char *typename;
|
2015-02-13 06:46:08 +01:00
|
|
|
char **cpuname;
|
2018-03-09 18:09:44 +01:00
|
|
|
const char *cpunamestr;
|
2013-01-21 16:11:43 +01:00
|
|
|
|
2015-02-13 06:46:08 +01:00
|
|
|
cpuname = g_strsplit(cpu_model, ",", 1);
|
2018-03-09 18:09:44 +01:00
|
|
|
cpunamestr = cpuname[0];
|
|
|
|
#ifdef CONFIG_USER_ONLY
|
|
|
|
/* For backwards compatibility usermode emulation allows "-cpu any",
|
|
|
|
* which has the same semantics as "-cpu max".
|
|
|
|
*/
|
|
|
|
if (!strcmp(cpunamestr, "any")) {
|
|
|
|
cpunamestr = "max";
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
typename = g_strdup_printf(ARM_CPU_TYPE_NAME("%s"), cpunamestr);
|
2013-01-27 17:30:10 +01:00
|
|
|
oc = object_class_by_name(typename);
|
2015-02-13 06:46:08 +01:00
|
|
|
g_strfreev(cpuname);
|
2013-01-27 17:30:10 +01:00
|
|
|
g_free(typename);
|
2013-01-23 12:32:49 +01:00
|
|
|
if (!oc || !object_class_dynamic_cast(oc, TYPE_ARM_CPU) ||
|
|
|
|
object_class_is_abstract(oc)) {
|
2013-01-21 16:11:43 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return oc;
|
|
|
|
}
|
|
|
|
|
2013-09-03 21:12:08 +02:00
|
|
|
/* CPU models. These are not needed for the AArch64 linux-user build. */
|
|
|
|
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
|
|
|
|
|
2012-06-20 13:57:18 +02:00
|
|
|
static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
|
|
|
|
{ .name = "L2LOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 0,
|
|
|
|
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
|
|
|
{ .name = "L2AUXCR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2,
|
|
|
|
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
|
|
|
REGINFO_SENTINEL
|
|
|
|
};
|
|
|
|
|
2012-04-20 19:58:31 +02:00
|
|
|
static void cortex_a8_initfn(Object *obj)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
2013-11-22 18:17:12 +01:00
|
|
|
|
|
|
|
cpu->dtb_compatible = "arm,cortex-a8";
|
2012-04-20 19:58:31 +02:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_V7);
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
2012-06-20 13:57:17 +02:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
2014-12-16 00:09:52 +01:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
2012-06-20 13:57:23 +02:00
|
|
|
cpu->midr = 0x410fc080;
|
2012-04-20 19:58:32 +02:00
|
|
|
cpu->reset_fpsid = 0x410330c0;
|
2018-10-24 08:50:16 +02:00
|
|
|
cpu->isar.mvfr0 = 0x11110222;
|
|
|
|
cpu->isar.mvfr1 = 0x00011111;
|
2012-04-20 19:58:33 +02:00
|
|
|
cpu->ctr = 0x82048004;
|
2012-04-20 19:58:33 +02:00
|
|
|
cpu->reset_sctlr = 0x00c50078;
|
2012-04-20 19:58:34 +02:00
|
|
|
cpu->id_pfr0 = 0x1031;
|
|
|
|
cpu->id_pfr1 = 0x11;
|
2020-02-14 18:51:03 +01:00
|
|
|
cpu->isar.id_dfr0 = 0x400;
|
2012-04-20 19:58:34 +02:00
|
|
|
cpu->id_afr0 = 0;
|
2020-02-14 18:51:13 +01:00
|
|
|
cpu->isar.id_mmfr0 = 0x31100003;
|
|
|
|
cpu->isar.id_mmfr1 = 0x20000000;
|
|
|
|
cpu->isar.id_mmfr2 = 0x01202000;
|
|
|
|
cpu->isar.id_mmfr3 = 0x11;
|
2018-10-24 08:50:16 +02:00
|
|
|
cpu->isar.id_isar0 = 0x00101111;
|
|
|
|
cpu->isar.id_isar1 = 0x12112111;
|
|
|
|
cpu->isar.id_isar2 = 0x21232031;
|
|
|
|
cpu->isar.id_isar3 = 0x11112131;
|
|
|
|
cpu->isar.id_isar4 = 0x00111142;
|
2020-02-14 18:51:06 +01:00
|
|
|
cpu->isar.dbgdidr = 0x15141000;
|
2012-04-20 19:58:35 +02:00
|
|
|
cpu->clidr = (1 << 27) | (2 << 24) | 3;
|
|
|
|
cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */
|
|
|
|
cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */
|
|
|
|
cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */
|
2012-06-20 13:57:18 +02:00
|
|
|
cpu->reset_auxcr = 2;
|
2012-06-20 13:57:18 +02:00
|
|
|
define_arm_cp_regs(cpu, cortexa8_cp_reginfo);
|
2012-04-20 19:58:31 +02:00
|
|
|
}
|
|
|
|
|
2012-06-20 13:57:15 +02:00
|
|
|
static const ARMCPRegInfo cortexa9_cp_reginfo[] = {
|
|
|
|
/* power_control should be set to maximum latency. Again,
|
|
|
|
* default to 0 and set by private hook
|
|
|
|
*/
|
|
|
|
{ .name = "A9_PWRCTL", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0,
|
|
|
|
.access = PL1_RW, .resetvalue = 0,
|
|
|
|
.fieldoffset = offsetof(CPUARMState, cp15.c15_power_control) },
|
|
|
|
{ .name = "A9_DIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 1,
|
|
|
|
.access = PL1_RW, .resetvalue = 0,
|
|
|
|
.fieldoffset = offsetof(CPUARMState, cp15.c15_diagnostic) },
|
|
|
|
{ .name = "A9_PWRDIAG", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 2,
|
|
|
|
.access = PL1_RW, .resetvalue = 0,
|
|
|
|
.fieldoffset = offsetof(CPUARMState, cp15.c15_power_diagnostic) },
|
|
|
|
{ .name = "NEONBUSY", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0,
|
|
|
|
.access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
|
|
|
|
/* TLB lockdown control */
|
|
|
|
{ .name = "TLB_LOCKR", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 2,
|
|
|
|
.access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP },
|
|
|
|
{ .name = "TLB_LOCKW", .cp = 15, .crn = 15, .crm = 4, .opc1 = 5, .opc2 = 4,
|
|
|
|
.access = PL1_W, .resetvalue = 0, .type = ARM_CP_NOP },
|
|
|
|
{ .name = "TLB_VA", .cp = 15, .crn = 15, .crm = 5, .opc1 = 5, .opc2 = 2,
|
|
|
|
.access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
|
|
|
|
{ .name = "TLB_PA", .cp = 15, .crn = 15, .crm = 6, .opc1 = 5, .opc2 = 2,
|
|
|
|
.access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
|
|
|
|
{ .name = "TLB_ATTR", .cp = 15, .crn = 15, .crm = 7, .opc1 = 5, .opc2 = 2,
|
|
|
|
.access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
|
|
|
|
REGINFO_SENTINEL
|
|
|
|
};
|
|
|
|
|
2012-04-20 19:58:31 +02:00
|
|
|
static void cortex_a9_initfn(Object *obj)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
2013-11-22 18:17:12 +01:00
|
|
|
|
|
|
|
cpu->dtb_compatible = "arm,cortex-a9";
|
2012-04-20 19:58:31 +02:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_V7);
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
2014-12-16 00:09:52 +01:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
2012-04-20 19:58:31 +02:00
|
|
|
/* Note that A9 supports the MP extensions even for
|
|
|
|
* A9UP and single-core A9MP (which are both different
|
|
|
|
* and valid configurations; we don't model A9UP).
|
|
|
|
*/
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_V7MP);
|
2013-12-17 20:42:28 +01:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_CBAR);
|
2012-06-20 13:57:23 +02:00
|
|
|
cpu->midr = 0x410fc090;
|
2012-04-20 19:58:32 +02:00
|
|
|
cpu->reset_fpsid = 0x41033090;
|
2018-10-24 08:50:16 +02:00
|
|
|
cpu->isar.mvfr0 = 0x11110222;
|
|
|
|
cpu->isar.mvfr1 = 0x01111111;
|
2012-04-20 19:58:33 +02:00
|
|
|
cpu->ctr = 0x80038003;
|
2012-04-20 19:58:33 +02:00
|
|
|
cpu->reset_sctlr = 0x00c50078;
|
2012-04-20 19:58:34 +02:00
|
|
|
cpu->id_pfr0 = 0x1031;
|
|
|
|
cpu->id_pfr1 = 0x11;
|
2020-02-14 18:51:03 +01:00
|
|
|
cpu->isar.id_dfr0 = 0x000;
|
2012-04-20 19:58:34 +02:00
|
|
|
cpu->id_afr0 = 0;
|
2020-02-14 18:51:13 +01:00
|
|
|
cpu->isar.id_mmfr0 = 0x00100103;
|
|
|
|
cpu->isar.id_mmfr1 = 0x20000000;
|
|
|
|
cpu->isar.id_mmfr2 = 0x01230000;
|
|
|
|
cpu->isar.id_mmfr3 = 0x00002111;
|
2018-10-24 08:50:16 +02:00
|
|
|
cpu->isar.id_isar0 = 0x00101111;
|
|
|
|
cpu->isar.id_isar1 = 0x13112111;
|
|
|
|
cpu->isar.id_isar2 = 0x21232041;
|
|
|
|
cpu->isar.id_isar3 = 0x11112131;
|
|
|
|
cpu->isar.id_isar4 = 0x00111142;
|
2020-02-14 18:51:06 +01:00
|
|
|
cpu->isar.dbgdidr = 0x35141000;
|
2012-04-20 19:58:35 +02:00
|
|
|
cpu->clidr = (1 << 27) | (1 << 24) | 3;
|
2014-08-19 19:56:27 +02:00
|
|
|
cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */
|
|
|
|
cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */
|
2013-12-17 20:42:28 +01:00
|
|
|
define_arm_cp_regs(cpu, cortexa9_cp_reginfo);
|
2012-04-20 19:58:31 +02:00
|
|
|
}
|
|
|
|
|
2012-06-20 13:57:18 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
2014-02-20 11:35:54 +01:00
|
|
|
static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
2012-06-20 13:57:18 +02:00
|
|
|
{
|
2019-05-18 22:54:26 +02:00
|
|
|
MachineState *ms = MACHINE(qdev_get_machine());
|
|
|
|
|
2012-06-20 13:57:18 +02:00
|
|
|
/* Linux wants the number of processors from here.
|
|
|
|
* Might as well set the interrupt-controller bit too.
|
|
|
|
*/
|
2019-05-18 22:54:26 +02:00
|
|
|
return ((ms->smp.cpus - 1) << 24) | (1 << 23);
|
2012-06-20 13:57:18 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static const ARMCPRegInfo cortexa15_cp_reginfo[] = {
|
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
|
|
{ .name = "L2CTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2,
|
|
|
|
.access = PL1_RW, .resetvalue = 0, .readfn = a15_l2ctlr_read,
|
|
|
|
.writefn = arm_cp_write_ignore, },
|
|
|
|
#endif
|
|
|
|
{ .name = "L2ECTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 3,
|
|
|
|
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
|
|
|
REGINFO_SENTINEL
|
|
|
|
};
|
|
|
|
|
2016-09-22 19:13:05 +02:00
|
|
|
static void cortex_a7_initfn(Object *obj)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
|
|
|
|
|
|
|
cpu->dtb_compatible = "arm,cortex-a7";
|
2018-06-29 16:11:17 +02:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_V7VE);
|
2016-09-22 19:13:05 +02:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
|
2018-11-13 11:47:59 +01:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_EL2);
|
2016-09-22 19:13:05 +02:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
2019-03-25 15:16:47 +01:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
2016-09-22 19:13:05 +02:00
|
|
|
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7;
|
|
|
|
cpu->midr = 0x410fc075;
|
|
|
|
cpu->reset_fpsid = 0x41023075;
|
2018-10-24 08:50:16 +02:00
|
|
|
cpu->isar.mvfr0 = 0x10110222;
|
|
|
|
cpu->isar.mvfr1 = 0x11111111;
|
2016-09-22 19:13:05 +02:00
|
|
|
cpu->ctr = 0x84448003;
|
|
|
|
cpu->reset_sctlr = 0x00c50078;
|
|
|
|
cpu->id_pfr0 = 0x00001131;
|
|
|
|
cpu->id_pfr1 = 0x00011011;
|
2020-02-14 18:51:03 +01:00
|
|
|
cpu->isar.id_dfr0 = 0x02010555;
|
2016-09-22 19:13:05 +02:00
|
|
|
cpu->id_afr0 = 0x00000000;
|
2020-02-14 18:51:13 +01:00
|
|
|
cpu->isar.id_mmfr0 = 0x10101105;
|
|
|
|
cpu->isar.id_mmfr1 = 0x40000000;
|
|
|
|
cpu->isar.id_mmfr2 = 0x01240000;
|
|
|
|
cpu->isar.id_mmfr3 = 0x02102211;
|
2018-10-08 23:22:00 +02:00
|
|
|
/* a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but
|
|
|
|
* table 4-41 gives 0x02101110, which includes the arm div insns.
|
|
|
|
*/
|
2018-10-24 08:50:16 +02:00
|
|
|
cpu->isar.id_isar0 = 0x02101110;
|
|
|
|
cpu->isar.id_isar1 = 0x13112111;
|
|
|
|
cpu->isar.id_isar2 = 0x21232041;
|
|
|
|
cpu->isar.id_isar3 = 0x11112131;
|
|
|
|
cpu->isar.id_isar4 = 0x10011142;
|
2020-02-14 18:51:06 +01:00
|
|
|
cpu->isar.dbgdidr = 0x3515f005;
|
2016-09-22 19:13:05 +02:00
|
|
|
cpu->clidr = 0x0a200023;
|
|
|
|
cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
|
|
|
|
cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
|
|
|
|
cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
|
|
|
|
define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */
|
|
|
|
}
|
|
|
|
|
2012-04-20 19:58:31 +02:00
|
|
|
static void cortex_a15_initfn(Object *obj)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
2013-11-22 18:17:12 +01:00
|
|
|
|
|
|
|
cpu->dtb_compatible = "arm,cortex-a15";
|
2018-06-29 16:11:17 +02:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_V7VE);
|
2012-04-20 19:58:31 +02:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
|
|
|
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
2012-06-20 13:57:17 +02:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
2014-04-15 20:18:49 +02:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
|
2018-11-13 11:47:59 +01:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_EL2);
|
2014-12-16 00:09:52 +01:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
2019-03-25 15:16:47 +01:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
2013-11-22 18:17:16 +01:00
|
|
|
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15;
|
2012-06-20 13:57:23 +02:00
|
|
|
cpu->midr = 0x412fc0f1;
|
2012-04-20 19:58:32 +02:00
|
|
|
cpu->reset_fpsid = 0x410430f0;
|
2018-10-24 08:50:16 +02:00
|
|
|
cpu->isar.mvfr0 = 0x10110222;
|
|
|
|
cpu->isar.mvfr1 = 0x11111111;
|
2012-04-20 19:58:33 +02:00
|
|
|
cpu->ctr = 0x8444c004;
|
2012-04-20 19:58:33 +02:00
|
|
|
cpu->reset_sctlr = 0x00c50078;
|
2012-04-20 19:58:34 +02:00
|
|
|
cpu->id_pfr0 = 0x00001131;
|
|
|
|
cpu->id_pfr1 = 0x00011011;
|
2020-02-14 18:51:03 +01:00
|
|
|
cpu->isar.id_dfr0 = 0x02010555;
|
2012-04-20 19:58:34 +02:00
|
|
|
cpu->id_afr0 = 0x00000000;
|
2020-02-14 18:51:13 +01:00
|
|
|
cpu->isar.id_mmfr0 = 0x10201105;
|
|
|
|
cpu->isar.id_mmfr1 = 0x20000000;
|
|
|
|
cpu->isar.id_mmfr2 = 0x01240000;
|
|
|
|
cpu->isar.id_mmfr3 = 0x02102211;
|
2018-10-24 08:50:16 +02:00
|
|
|
cpu->isar.id_isar0 = 0x02101110;
|
|
|
|
cpu->isar.id_isar1 = 0x13112111;
|
|
|
|
cpu->isar.id_isar2 = 0x21232041;
|
|
|
|
cpu->isar.id_isar3 = 0x11112131;
|
|
|
|
cpu->isar.id_isar4 = 0x10011142;
|
2020-02-14 18:51:06 +01:00
|
|
|
cpu->isar.dbgdidr = 0x3515f021;
|
2012-04-20 19:58:35 +02:00
|
|
|
cpu->clidr = 0x0a200023;
|
|
|
|
cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
|
|
|
|
cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
|
|
|
|
cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
|
2012-06-20 13:57:18 +02:00
|
|
|
define_arm_cp_regs(cpu, cortexa15_cp_reginfo);
|
2012-04-20 19:58:31 +02:00
|
|
|
}
|
|
|
|
|
2018-03-09 18:09:44 +01:00
|
|
|
#ifndef TARGET_AARCH64
|
|
|
|
/* -cpu max: if KVM is enabled, like -cpu host (best possible with this host);
|
|
|
|
* otherwise, a CPU with as many features enabled as our emulation supports.
|
|
|
|
* The version of '-cpu max' for qemu-system-aarch64 is defined in cpu64.c;
|
|
|
|
* this only needs to handle 32 bits.
|
|
|
|
*/
|
|
|
|
static void arm_max_initfn(Object *obj)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
|
|
|
|
|
|
|
if (kvm_enabled()) {
|
|
|
|
kvm_arm_set_cpu_features_from_host(cpu);
|
2020-01-30 17:02:06 +01:00
|
|
|
kvm_arm_add_vcpu_properties(obj);
|
2018-03-09 18:09:44 +01:00
|
|
|
} else {
|
|
|
|
cortex_a15_initfn(obj);
|
2019-06-11 17:39:42 +02:00
|
|
|
|
|
|
|
/* old-style VFP short-vector support */
|
|
|
|
cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1);
|
|
|
|
|
2018-03-09 18:09:44 +01:00
|
|
|
#ifdef CONFIG_USER_ONLY
|
|
|
|
/* We don't set these in system emulation mode for the moment,
|
2018-10-24 08:50:16 +02:00
|
|
|
* since we don't correctly set (all of) the ID registers to
|
|
|
|
* advertise them.
|
2018-03-09 18:09:44 +01:00
|
|
|
*/
|
2018-03-09 18:09:44 +01:00
|
|
|
set_feature(&cpu->env, ARM_FEATURE_V8);
|
2018-10-24 08:50:16 +02:00
|
|
|
{
|
|
|
|
uint32_t t;
|
|
|
|
|
|
|
|
t = cpu->isar.id_isar5;
|
|
|
|
t = FIELD_DP32(t, ID_ISAR5, AES, 2);
|
|
|
|
t = FIELD_DP32(t, ID_ISAR5, SHA1, 1);
|
|
|
|
t = FIELD_DP32(t, ID_ISAR5, SHA2, 1);
|
|
|
|
t = FIELD_DP32(t, ID_ISAR5, CRC32, 1);
|
|
|
|
t = FIELD_DP32(t, ID_ISAR5, RDM, 1);
|
|
|
|
t = FIELD_DP32(t, ID_ISAR5, VCMA, 1);
|
|
|
|
cpu->isar.id_isar5 = t;
|
|
|
|
|
|
|
|
t = cpu->isar.id_isar6;
|
2019-02-21 19:17:46 +01:00
|
|
|
t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1);
|
2018-10-24 08:50:16 +02:00
|
|
|
t = FIELD_DP32(t, ID_ISAR6, DP, 1);
|
2019-02-28 11:55:17 +01:00
|
|
|
t = FIELD_DP32(t, ID_ISAR6, FHM, 1);
|
2019-03-01 21:04:53 +01:00
|
|
|
t = FIELD_DP32(t, ID_ISAR6, SB, 1);
|
2019-03-01 21:04:54 +01:00
|
|
|
t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1);
|
2018-10-24 08:50:16 +02:00
|
|
|
cpu->isar.id_isar6 = t;
|
2018-12-13 14:48:07 +01:00
|
|
|
|
2019-07-15 15:17:02 +02:00
|
|
|
t = cpu->isar.mvfr1;
|
|
|
|
t = FIELD_DP32(t, MVFR1, FPHP, 2); /* v8.0 FP support */
|
|
|
|
cpu->isar.mvfr1 = t;
|
|
|
|
|
2019-03-26 13:53:26 +01:00
|
|
|
t = cpu->isar.mvfr2;
|
|
|
|
t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */
|
|
|
|
t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */
|
|
|
|
cpu->isar.mvfr2 = t;
|
|
|
|
|
2020-02-14 18:51:13 +01:00
|
|
|
t = cpu->isar.id_mmfr3;
|
2020-02-08 13:58:12 +01:00
|
|
|
t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */
|
2020-02-14 18:51:13 +01:00
|
|
|
cpu->isar.id_mmfr3 = t;
|
2020-02-08 13:58:12 +01:00
|
|
|
|
2020-02-14 18:51:13 +01:00
|
|
|
t = cpu->isar.id_mmfr4;
|
2018-12-13 14:48:07 +01:00
|
|
|
t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */
|
2020-02-14 18:51:16 +01:00
|
|
|
t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */
|
2020-03-05 17:09:14 +01:00
|
|
|
t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */
|
2020-03-30 23:04:00 +02:00
|
|
|
t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */
|
2020-02-14 18:51:13 +01:00
|
|
|
cpu->isar.id_mmfr4 = t;
|
2018-10-24 08:50:16 +02:00
|
|
|
}
|
2018-03-09 18:09:44 +01:00
|
|
|
#endif
|
2018-03-09 18:09:44 +01:00
|
|
|
}
|
2012-04-20 19:58:31 +02:00
|
|
|
}
|
2013-09-10 20:09:32 +02:00
|
|
|
#endif
|
2012-04-20 19:58:31 +02:00
|
|
|
|
2013-09-03 21:12:08 +02:00
|
|
|
#endif /* !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) */
|
|
|
|
|
2012-04-20 19:58:31 +02:00
|
|
|
static const ARMCPUInfo arm_cpus[] = {
|
2013-09-03 21:12:08 +02:00
|
|
|
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
|
2016-09-22 19:13:05 +02:00
|
|
|
{ .name = "cortex-a7", .initfn = cortex_a7_initfn },
|
2012-04-20 19:58:31 +02:00
|
|
|
{ .name = "cortex-a8", .initfn = cortex_a8_initfn },
|
|
|
|
{ .name = "cortex-a9", .initfn = cortex_a9_initfn },
|
|
|
|
{ .name = "cortex-a15", .initfn = cortex_a15_initfn },
|
2018-03-09 18:09:44 +01:00
|
|
|
#ifndef TARGET_AARCH64
|
|
|
|
{ .name = "max", .initfn = arm_max_initfn },
|
|
|
|
#endif
|
2013-09-10 20:09:32 +02:00
|
|
|
#ifdef CONFIG_USER_ONLY
|
2018-03-09 18:09:44 +01:00
|
|
|
{ .name = "any", .initfn = arm_max_initfn },
|
2013-09-10 20:09:32 +02:00
|
|
|
#endif
|
2013-09-03 21:12:08 +02:00
|
|
|
#endif
|
2012-04-20 19:58:31 +02:00
|
|
|
};
|
|
|
|
|
2013-11-22 18:17:13 +01:00
|
|
|
static Property arm_cpu_properties[] = {
|
|
|
|
DEFINE_PROP_BOOL("start-powered-off", ARMCPU, start_powered_off, false),
|
2014-10-24 13:19:13 +02:00
|
|
|
DEFINE_PROP_UINT32("psci-conduit", ARMCPU, psci_conduit, 0),
|
2020-04-28 19:26:34 +02:00
|
|
|
DEFINE_PROP_UINT64("midr", ARMCPU, midr, 0),
|
2016-10-20 13:26:03 +02:00
|
|
|
DEFINE_PROP_UINT64("mp-affinity", ARMCPU,
|
|
|
|
mp_affinity, ARM64_AFFINITY_INVALID),
|
2017-05-30 18:24:00 +02:00
|
|
|
DEFINE_PROP_INT32("node-id", ARMCPU, node_id, CPU_UNSET_NUMA_NODE_ID),
|
2018-03-09 18:09:43 +01:00
|
|
|
DEFINE_PROP_INT32("core-count", ARMCPU, core_count, -1),
|
2013-11-22 18:17:13 +01:00
|
|
|
DEFINE_PROP_END_OF_LIST()
|
|
|
|
};
|
|
|
|
|
2015-12-03 13:14:41 +01:00
|
|
|
static gchar *arm_gdb_arch_name(CPUState *cs)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(cs);
|
|
|
|
CPUARMState *env = &cpu->env;
|
|
|
|
|
|
|
|
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
|
|
|
|
return g_strdup("iwmmxt");
|
|
|
|
}
|
|
|
|
return g_strdup("arm");
|
|
|
|
}
|
|
|
|
|
2012-03-29 06:50:31 +02:00
|
|
|
static void arm_cpu_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
ARMCPUClass *acc = ARM_CPU_CLASS(oc);
|
|
|
|
CPUClass *cc = CPU_CLASS(acc);
|
2013-01-05 10:18:18 +01:00
|
|
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
|
|
|
|
2018-01-14 03:04:12 +01:00
|
|
|
device_class_set_parent_realize(dc, arm_cpu_realizefn,
|
|
|
|
&acc->parent_realize);
|
2012-03-29 06:50:31 +02:00
|
|
|
|
2020-01-10 16:30:32 +01:00
|
|
|
device_class_set_props(dc, arm_cpu_properties);
|
cpu: Use DeviceClass reset instead of a special CPUClass reset
The CPUClass has a 'reset' method. This is a legacy from when
TYPE_CPU used not to inherit from TYPE_DEVICE. We don't need it any
more, as we can simply use the TYPE_DEVICE reset. The 'cpu_reset()'
function is kept as the API which most places use to reset a CPU; it
is now a wrapper which calls device_cold_reset() and then the
tracepoint function.
This change should not cause CPU objects to be reset more often
than they are at the moment, because:
* nobody is directly calling device_cold_reset() or
qdev_reset_all() on CPU objects
* no CPU object is on a qbus, so they will not be reset either
by somebody calling qbus_reset_all()/bus_cold_reset(), or
by the main "reset sysbus and everything in the qbus tree"
reset that most devices are reset by
Note that this does not change the need for each machine or whatever
to use qemu_register_reset() to arrange to call cpu_reset() -- that
is necessary because CPU objects are not on any qbus, so they don't
get reset when the qbus tree rooted at the sysbus bus is reset, and
this isn't being changed here.
All the changes to the files under target/ were made using the
included Coccinelle script, except:
(1) the deletion of the now-inaccurate and not terribly useful
"CPUClass::reset" comments was done with a perl one-liner afterwards:
perl -n -i -e '/ CPUClass::reset/ or print' target/*/*.c
(2) this bit of the s390 change was done by hand, because the
Coccinelle script is not sophisticated enough to handle the
parent_reset call being inside another function:
| @@ -96,8 +96,9 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
| S390CPU *cpu = S390_CPU(s);
| S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
| CPUS390XState *env = &cpu->env;
|+ DeviceState *dev = DEVICE(s);
|
|- scc->parent_reset(s);
|+ scc->parent_reset(dev);
| cpu->env.sigp_order = 0;
| s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-Id: <20200303100511.5498-1-peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2020-03-03 11:05:11 +01:00
|
|
|
device_class_set_parent_reset(dc, arm_cpu_reset, &acc->parent_reset);
|
2013-01-21 16:11:43 +01:00
|
|
|
|
|
|
|
cc->class_by_name = arm_cpu_class_by_name;
|
2013-08-25 18:53:55 +02:00
|
|
|
cc->has_work = arm_cpu_has_work;
|
2014-09-13 18:45:25 +02:00
|
|
|
cc->cpu_exec_interrupt = arm_cpu_exec_interrupt;
|
2013-05-27 01:33:50 +02:00
|
|
|
cc->dump_state = arm_cpu_dump_state;
|
2013-06-21 19:09:18 +02:00
|
|
|
cc->set_pc = arm_cpu_set_pc;
|
2019-02-01 15:55:46 +01:00
|
|
|
cc->synchronize_from_tb = arm_cpu_synchronize_from_tb;
|
2013-06-29 04:18:45 +02:00
|
|
|
cc->gdb_read_register = arm_cpu_gdb_read_register;
|
|
|
|
cc->gdb_write_register = arm_cpu_gdb_write_register;
|
2019-04-02 10:12:58 +02:00
|
|
|
#ifndef CONFIG_USER_ONLY
|
2014-10-24 13:19:12 +02:00
|
|
|
cc->do_interrupt = arm_cpu_do_interrupt;
|
2016-01-21 15:15:07 +01:00
|
|
|
cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
|
2016-01-21 15:15:06 +01:00
|
|
|
cc->asidx_from_attrs = arm_asidx_from_attrs;
|
2013-06-29 18:55:54 +02:00
|
|
|
cc->vmsd = &vmstate_arm_cpu;
|
2016-03-04 12:30:19 +01:00
|
|
|
cc->virtio_is_big_endian = arm_cpu_virtio_is_big_endian;
|
2016-01-11 20:56:22 +01:00
|
|
|
cc->write_elf64_note = arm_cpu_write_elf64_note;
|
|
|
|
cc->write_elf32_note = arm_cpu_write_elf32_note;
|
2013-06-29 18:55:54 +02:00
|
|
|
#endif
|
2013-06-28 23:18:47 +02:00
|
|
|
cc->gdb_num_core_regs = 26;
|
2013-07-07 15:08:22 +02:00
|
|
|
cc->gdb_core_xml_file = "arm-core.xml";
|
2015-12-03 13:14:41 +01:00
|
|
|
cc->gdb_arch_name = arm_gdb_arch_name;
|
2018-05-18 18:48:07 +02:00
|
|
|
cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml;
|
2014-09-12 20:04:17 +02:00
|
|
|
cc->gdb_stop_before_watchpoint = true;
|
2015-06-24 05:57:35 +02:00
|
|
|
cc->disas_set_info = arm_disas_set_info;
|
2017-10-26 15:58:14 +02:00
|
|
|
#ifdef CONFIG_TCG
|
2017-10-16 04:02:42 +02:00
|
|
|
cc->tcg_initialize = arm_translate_init;
|
2019-04-02 10:12:58 +02:00
|
|
|
cc->tlb_fill = arm_cpu_tlb_fill;
|
2019-07-04 18:14:43 +02:00
|
|
|
cc->debug_excp_handler = arm_debug_excp_handler;
|
|
|
|
cc->debug_check_watchpoint = arm_debug_check_watchpoint;
|
2019-07-01 18:26:21 +02:00
|
|
|
#if !defined(CONFIG_USER_ONLY)
|
|
|
|
cc->do_unaligned_access = arm_cpu_do_unaligned_access;
|
|
|
|
cc->do_transaction_failed = arm_cpu_do_transaction_failed;
|
2019-07-04 18:14:43 +02:00
|
|
|
cc->adjust_watchpoint_address = arm_adjust_watchpoint_address;
|
2019-07-01 18:26:21 +02:00
|
|
|
#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */
|
2017-10-26 15:58:14 +02:00
|
|
|
#endif
|
2012-03-29 06:50:31 +02:00
|
|
|
}
|
|
|
|
|
2018-03-09 18:09:44 +01:00
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
static void arm_host_initfn(Object *obj)
|
|
|
|
{
|
|
|
|
ARMCPU *cpu = ARM_CPU(obj);
|
|
|
|
|
|
|
|
kvm_arm_set_cpu_features_from_host(cpu);
|
2019-10-31 15:27:34 +01:00
|
|
|
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
|
|
|
|
aarch64_add_sve_properties(obj);
|
|
|
|
}
|
2020-01-30 17:02:06 +01:00
|
|
|
kvm_arm_add_vcpu_properties(obj);
|
2018-11-27 09:55:59 +01:00
|
|
|
arm_cpu_post_init(obj);
|
2018-03-09 18:09:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo host_arm_cpu_type_info = {
|
|
|
|
.name = TYPE_ARM_HOST_CPU,
|
|
|
|
#ifdef TARGET_AARCH64
|
|
|
|
.parent = TYPE_AARCH64_CPU,
|
|
|
|
#else
|
|
|
|
.parent = TYPE_ARM_CPU,
|
|
|
|
#endif
|
|
|
|
.instance_init = arm_host_initfn,
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2018-11-27 09:55:59 +01:00
|
|
|
static void arm_cpu_instance_init(Object *obj)
|
|
|
|
{
|
|
|
|
ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj);
|
|
|
|
|
|
|
|
acc->info->initfn(obj);
|
|
|
|
arm_cpu_post_init(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cpu_register_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
ARMCPUClass *acc = ARM_CPU_CLASS(oc);
|
|
|
|
|
|
|
|
acc->info = data;
|
|
|
|
}
|
|
|
|
|
2020-04-23 09:33:55 +02:00
|
|
|
void arm_cpu_register(const ARMCPUInfo *info)
|
2012-04-20 19:58:31 +02:00
|
|
|
{
|
|
|
|
TypeInfo type_info = {
|
|
|
|
.parent = TYPE_ARM_CPU,
|
|
|
|
.instance_size = sizeof(ARMCPU),
|
2018-11-27 09:55:59 +01:00
|
|
|
.instance_init = arm_cpu_instance_init,
|
2012-04-20 19:58:31 +02:00
|
|
|
.class_size = sizeof(ARMCPUClass),
|
2018-11-27 09:55:59 +01:00
|
|
|
.class_init = info->class_init ?: cpu_register_class_init,
|
|
|
|
.class_data = (void *)info,
|
2012-04-20 19:58:31 +02:00
|
|
|
};
|
|
|
|
|
2013-01-27 17:30:10 +01:00
|
|
|
type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name);
|
2013-01-11 16:21:22 +01:00
|
|
|
type_register(&type_info);
|
2013-01-27 17:30:10 +01:00
|
|
|
g_free((void *)type_info.name);
|
2012-04-20 19:58:31 +02:00
|
|
|
}
|
|
|
|
|
2012-03-29 06:50:31 +02:00
|
|
|
static const TypeInfo arm_cpu_type_info = {
|
|
|
|
.name = TYPE_ARM_CPU,
|
|
|
|
.parent = TYPE_CPU,
|
|
|
|
.instance_size = sizeof(ARMCPU),
|
2012-04-20 19:58:31 +02:00
|
|
|
.instance_init = arm_cpu_initfn,
|
2012-06-20 13:57:06 +02:00
|
|
|
.instance_finalize = arm_cpu_finalizefn,
|
2012-04-20 19:58:31 +02:00
|
|
|
.abstract = true,
|
2012-03-29 06:50:31 +02:00
|
|
|
.class_size = sizeof(ARMCPUClass),
|
|
|
|
.class_init = arm_cpu_class_init,
|
|
|
|
};
|
|
|
|
|
2018-03-02 11:45:36 +01:00
|
|
|
static const TypeInfo idau_interface_type_info = {
|
|
|
|
.name = TYPE_IDAU_INTERFACE,
|
|
|
|
.parent = TYPE_INTERFACE,
|
|
|
|
.class_size = sizeof(IDAUInterfaceClass),
|
|
|
|
};
|
|
|
|
|
2012-03-29 06:50:31 +02:00
|
|
|
static void arm_cpu_register_types(void)
|
|
|
|
{
|
2020-05-04 19:24:46 +02:00
|
|
|
const size_t cpu_count = ARRAY_SIZE(arm_cpus);
|
2012-04-20 19:58:31 +02:00
|
|
|
|
2012-03-29 06:50:31 +02:00
|
|
|
type_register_static(&arm_cpu_type_info);
|
2014-01-13 11:26:16 +01:00
|
|
|
|
2018-03-09 18:09:44 +01:00
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
type_register_static(&host_arm_cpu_type_info);
|
|
|
|
#endif
|
2020-05-04 19:24:46 +02:00
|
|
|
|
|
|
|
if (cpu_count) {
|
|
|
|
size_t i;
|
|
|
|
|
2020-05-04 19:24:47 +02:00
|
|
|
type_register_static(&idau_interface_type_info);
|
2020-05-04 19:24:46 +02:00
|
|
|
for (i = 0; i < cpu_count; ++i) {
|
|
|
|
arm_cpu_register(&arm_cpus[i]);
|
|
|
|
}
|
|
|
|
}
|
2012-03-29 06:50:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type_init(arm_cpu_register_types)
|