mirror of https://github.com/xemu-project/xemu.git
target-arm queue:
* fix some missing traps for EL3 support * enable EL3 on Cortex-A53 and Cortex-A57 * fix syndrome IL bit for Thumb coprocessor, VFP and Neon traps * fix mishandling of architectural watchpoints * avoid buffer overflow in sd.c * fix max-cpus check in virt board * implement 'get board revision' query for BCM2835 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJWvG9DAAoJEDwlJe0UNgzei1cQAJPn9Lk0eny6pIQNvW8a1gLB 4FM6s9Vmu107b1aoWmUObxmW3MqD6eWYa+kLJ1z5he970lQ9S3ypX06x9J+FA5g4 i1VrSh2p+Turt5MqsD2euC4vaa8KzBTG9fdqSveseln3RvwfMjCVDThbd9n5jzNu /sLExJVc9C8z5PlBmluE3a3Fxhez9xt1qXSQUBRZ6/HP3VAhIXircSTikk/IAECJ sNw5+1P9TZndL7PPVMOg0BQWPodJGui6+WfjHHW0T4unTvbWOBaulz7X1Uy5UhEg /rtJHRPbEGtLvEQwzVIS7wOmx9FxAOYWKDbdCrrATgREq7ZqaiivOeb/oVQWhNmE abxnDZiXZimBQw1/r3xqweZsOl3j/JofZS8i0rj+xyM6OctEthu4wcenX5wMxGjk wodq/1xGd68uzPXUBSMBkl4NT8WbEQxaHJ0s8yL4ph6RREuDLzmxkaeDryFYxhK+ vmQnDusezTRb8WiTZy8DrMaGfEzRFO5Y5uizBnKHg6eWLXrJx5+YGHc3OVrXzDPb NNCsCymyqVwsbvRa9BGycp6HbBSk9wD4dCBWNUIUZ8pTNS7D+scHHACaoGxh4XBN GX/smnMBC7H18nDekqivaFk4qYeq+uipiaqeZJbnAeCTI03XLYz9nETy9eoUdQgP C74nIJZDqsQlnU+Vd6Pi =DZ6v -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160211' into staging target-arm queue: * fix some missing traps for EL3 support * enable EL3 on Cortex-A53 and Cortex-A57 * fix syndrome IL bit for Thumb coprocessor, VFP and Neon traps * fix mishandling of architectural watchpoints * avoid buffer overflow in sd.c * fix max-cpus check in virt board * implement 'get board revision' query for BCM2835 # gpg: Signature made Thu 11 Feb 2016 11:23:47 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" * remotes/pmaydell/tags/pull-target-arm-20160211: bcm2835_property: implement "get board revision" query hw/arm/virt: fix max-cpus check sd: limit 'req.cmd' while using as an array index target-arm: Implement checking of fired watchpoint cpu: Add callback to check architectural watchpoint match target-arm: Fix IL bit reported for Thumb VFP and Neon traps target-arm: Fix IL bit reported for Thumb coprocessor traps target-arm: Correct misleading 'is_thumb' syn_* parameter names target-arm: Enable EL3 for Cortex-A53 and Cortex-A57 target-arm: Implement NSACR trapping behaviour target-arm: Add isread parameter to CPAccessFns target-arm: Update arm_generate_debug_exceptions() to handle EL2/EL3 target-arm: Use access_trap_aa32s_el1() for SCR and MVBAR target-arm: Implement MDCR_EL3 and SDCR target-arm: Fix typo in comment in arm_is_secure_below_el3() Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
36a9abd9be
6
exec.c
6
exec.c
|
@ -2070,6 +2070,7 @@ static const MemoryRegionOps notdirty_mem_ops = {
|
|||
static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
|
||||
{
|
||||
CPUState *cpu = current_cpu;
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
target_ulong pc, cs_base;
|
||||
target_ulong vaddr;
|
||||
|
@ -2095,6 +2096,11 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
|
|||
wp->hitaddr = vaddr;
|
||||
wp->hitattrs = attrs;
|
||||
if (!cpu->watchpoint_hit) {
|
||||
if (wp->flags & BP_CPU &&
|
||||
!cc->debug_check_watchpoint(cpu, wp)) {
|
||||
wp->flags &= ~BP_WATCHPOINT_HIT;
|
||||
continue;
|
||||
}
|
||||
cpu->watchpoint_hit = wp;
|
||||
tb_check_watchpoint(cpu);
|
||||
if (wp->flags & BP_STOP_BEFORE_ACCESS) {
|
||||
|
|
|
@ -58,6 +58,8 @@ static void bcm2835_peripherals_init(Object *obj)
|
|||
/* Property channel */
|
||||
object_initialize(&s->property, sizeof(s->property), TYPE_BCM2835_PROPERTY);
|
||||
object_property_add_child(obj, "property", OBJECT(&s->property), NULL);
|
||||
object_property_add_alias(obj, "board-rev", OBJECT(&s->property),
|
||||
"board-rev", &error_abort);
|
||||
qdev_set_parent_bus(DEVICE(&s->property), sysbus_get_default());
|
||||
|
||||
object_property_add_const_link(OBJECT(&s->property), "dma-mr",
|
||||
|
|
|
@ -39,6 +39,8 @@ static void bcm2836_init(Object *obj)
|
|||
TYPE_BCM2835_PERIPHERALS);
|
||||
object_property_add_child(obj, "peripherals", OBJECT(&s->peripherals),
|
||||
&error_abort);
|
||||
object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
|
||||
"board-rev", &error_abort);
|
||||
qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default());
|
||||
}
|
||||
|
||||
|
|
|
@ -128,6 +128,8 @@ static void raspi2_init(MachineState *machine)
|
|||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->soc), smp_cpus, "enabled-cpus",
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->soc), 0xa21041, "board-rev",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort);
|
||||
|
||||
setup_boot(machine, 2, machine->ram_size);
|
||||
|
|
|
@ -1013,7 +1013,7 @@ static void machvirt_init(MachineState *machine)
|
|||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *secure_sysmem = NULL;
|
||||
int gic_version = vms->gic_version;
|
||||
int n, max_cpus;
|
||||
int n, virt_max_cpus;
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
VirtBoardInfo *vbi;
|
||||
|
@ -1051,15 +1051,15 @@ static void machvirt_init(MachineState *machine)
|
|||
* many redistributors we can fit into the memory map.
|
||||
*/
|
||||
if (gic_version == 3) {
|
||||
max_cpus = vbi->memmap[VIRT_GIC_REDIST].size / 0x20000;
|
||||
virt_max_cpus = vbi->memmap[VIRT_GIC_REDIST].size / 0x20000;
|
||||
} else {
|
||||
max_cpus = GIC_NCPU;
|
||||
virt_max_cpus = GIC_NCPU;
|
||||
}
|
||||
|
||||
if (smp_cpus > max_cpus) {
|
||||
if (max_cpus > virt_max_cpus) {
|
||||
error_report("Number of SMP CPUs requested (%d) exceeds max CPUs "
|
||||
"supported by machine 'mach-virt' (%d)",
|
||||
smp_cpus, max_cpus);
|
||||
max_cpus, virt_max_cpus);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,8 +43,7 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
|||
resplen = 4;
|
||||
break;
|
||||
case 0x00010002: /* Get board revision */
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"bcm2835_property: %x get board revision NYI\n", tag);
|
||||
stl_phys(&s->dma_as, value + 12, s->board_rev);
|
||||
resplen = 4;
|
||||
break;
|
||||
case 0x00010003: /* Get board MAC address */
|
||||
|
@ -258,6 +257,7 @@ static void bcm2835_property_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
|
||||
static Property bcm2835_property_props[] = {
|
||||
DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0),
|
||||
DEFINE_PROP_UINT32("ram-size", BCM2835PropertyState, ram_size, 0),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
|
|
@ -669,8 +669,10 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
|
|||
/* Not interpreting this as an app command */
|
||||
sd->card_status &= ~APP_CMD;
|
||||
|
||||
if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
|
||||
if (sd_cmd_type[req.cmd & 0x3F] == sd_ac
|
||||
|| sd_cmd_type[req.cmd & 0x3F] == sd_adtc) {
|
||||
rca = req.arg >> 16;
|
||||
}
|
||||
|
||||
DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state);
|
||||
switch (req.cmd) {
|
||||
|
@ -1341,7 +1343,8 @@ static int cmd_valid_while_locked(SDState *sd, SDRequest *req)
|
|||
if (req->cmd == 16 || req->cmd == 55) {
|
||||
return 1;
|
||||
}
|
||||
return sd_cmd_class[req->cmd] == 0 || sd_cmd_class[req->cmd] == 7;
|
||||
return sd_cmd_class[req->cmd & 0x3F] == 0
|
||||
|| sd_cmd_class[req->cmd & 0x3F] == 7;
|
||||
}
|
||||
|
||||
int sd_do_command(SDState *sd, SDRequest *req,
|
||||
|
|
|
@ -23,6 +23,7 @@ typedef struct {
|
|||
MemoryRegion iomem;
|
||||
qemu_irq mbox_irq;
|
||||
MACAddr macaddr;
|
||||
uint32_t board_rev;
|
||||
uint32_t ram_size;
|
||||
uint32_t addr;
|
||||
bool pending;
|
||||
|
|
|
@ -64,6 +64,7 @@ typedef uint64_t vaddr;
|
|||
#define CPU_GET_CLASS(obj) OBJECT_GET_CLASS(CPUClass, (obj), TYPE_CPU)
|
||||
|
||||
typedef struct CPUState CPUState;
|
||||
typedef struct CPUWatchpoint CPUWatchpoint;
|
||||
|
||||
typedef void (*CPUUnassignedAccess)(CPUState *cpu, hwaddr addr,
|
||||
bool is_write, bool is_exec, int opaque,
|
||||
|
@ -106,6 +107,8 @@ struct TranslationBlock;
|
|||
* a memory access with the specified memory transaction attributes.
|
||||
* @gdb_read_register: Callback for letting GDB read a register.
|
||||
* @gdb_write_register: Callback for letting GDB write a register.
|
||||
* @debug_check_watchpoint: Callback: return true if the architectural
|
||||
* watchpoint whose address has matched should really fire.
|
||||
* @debug_excp_handler: Callback for handling debug exceptions.
|
||||
* @write_elf64_note: Callback for writing a CPU-specific ELF note to a
|
||||
* 64-bit VM coredump.
|
||||
|
@ -165,6 +168,7 @@ typedef struct CPUClass {
|
|||
int (*asidx_from_attrs)(CPUState *cpu, MemTxAttrs attrs);
|
||||
int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
|
||||
bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp);
|
||||
void (*debug_excp_handler)(CPUState *cpu);
|
||||
|
||||
int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu,
|
||||
|
@ -207,14 +211,14 @@ typedef struct CPUBreakpoint {
|
|||
QTAILQ_ENTRY(CPUBreakpoint) entry;
|
||||
} CPUBreakpoint;
|
||||
|
||||
typedef struct CPUWatchpoint {
|
||||
struct CPUWatchpoint {
|
||||
vaddr vaddr;
|
||||
vaddr len;
|
||||
vaddr hitaddr;
|
||||
MemTxAttrs hitattrs;
|
||||
int flags; /* BP_* */
|
||||
QTAILQ_ENTRY(CPUWatchpoint) entry;
|
||||
} CPUWatchpoint;
|
||||
};
|
||||
|
||||
struct KVMState;
|
||||
struct kvm_run;
|
||||
|
|
|
@ -189,6 +189,14 @@ static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool cpu_common_debug_check_watchpoint(CPUState *cpu, CPUWatchpoint *wp)
|
||||
{
|
||||
/* If no extra check is required, QEMU watchpoint match can be considered
|
||||
* as an architectural match.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
bool target_words_bigendian(void);
|
||||
static bool cpu_common_virtio_is_big_endian(CPUState *cpu)
|
||||
{
|
||||
|
@ -353,6 +361,7 @@ static void cpu_class_init(ObjectClass *klass, void *data)
|
|||
k->gdb_write_register = cpu_common_gdb_write_register;
|
||||
k->virtio_is_big_endian = cpu_common_virtio_is_big_endian;
|
||||
k->debug_excp_handler = cpu_common_noop;
|
||||
k->debug_check_watchpoint = cpu_common_debug_check_watchpoint;
|
||||
k->cpu_exec_enter = cpu_common_noop;
|
||||
k->cpu_exec_exit = cpu_common_noop;
|
||||
k->cpu_exec_interrupt = cpu_common_exec_interrupt;
|
||||
|
|
|
@ -1483,6 +1483,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
|
|||
cc->gdb_arch_name = arm_gdb_arch_name;
|
||||
cc->gdb_stop_before_watchpoint = true;
|
||||
cc->debug_excp_handler = arm_debug_excp_handler;
|
||||
cc->debug_check_watchpoint = arm_debug_check_watchpoint;
|
||||
|
||||
cc->disas_set_info = arm_disas_set_info;
|
||||
|
||||
|
|
|
@ -382,6 +382,7 @@ typedef struct CPUARMState {
|
|||
uint64_t mdscr_el1;
|
||||
uint64_t oslsr_el1; /* OS Lock Status */
|
||||
uint64_t mdcr_el2;
|
||||
uint64_t mdcr_el3;
|
||||
/* If the counter is enabled, this stores the last time the counter
|
||||
* was reset. Otherwise it stores the counter value
|
||||
*/
|
||||
|
@ -931,7 +932,7 @@ static inline bool arm_is_secure_below_el3(CPUARMState *env)
|
|||
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
||||
return !(env->cp15.scr_el3 & SCR_NS);
|
||||
} else {
|
||||
/* If EL2 is not supported then the secure state is implementation
|
||||
/* If EL3 is not supported then the secure state is implementation
|
||||
* defined, in which case QEMU defaults to non-secure.
|
||||
*/
|
||||
return false;
|
||||
|
@ -1318,7 +1319,9 @@ typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque);
|
|||
typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
|
||||
uint64_t value);
|
||||
/* Access permission check functions for coprocessor registers. */
|
||||
typedef CPAccessResult CPAccessFn(CPUARMState *env, const ARMCPRegInfo *opaque);
|
||||
typedef CPAccessResult CPAccessFn(CPUARMState *env,
|
||||
const ARMCPRegInfo *opaque,
|
||||
bool isread);
|
||||
/* Hook function for register reset */
|
||||
typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
|
||||
|
||||
|
@ -1741,9 +1744,7 @@ typedef enum ARMASIdx {
|
|||
ARMASIdx_S = 1,
|
||||
} ARMASIdx;
|
||||
|
||||
/* Return the Exception Level targeted by debug exceptions;
|
||||
* currently always EL1 since we don't implement EL2 or EL3.
|
||||
*/
|
||||
/* Return the Exception Level targeted by debug exceptions. */
|
||||
static inline int arm_debug_target_el(CPUARMState *env)
|
||||
{
|
||||
bool secure = arm_is_secure(env);
|
||||
|
@ -1766,6 +1767,14 @@ static inline int arm_debug_target_el(CPUARMState *env)
|
|||
|
||||
static inline bool aa64_generate_debug_exceptions(CPUARMState *env)
|
||||
{
|
||||
if (arm_is_secure(env)) {
|
||||
/* MDCR_EL3.SDD disables debug events from Secure state */
|
||||
if (extract32(env->cp15.mdcr_el3, 16, 1) != 0
|
||||
|| arm_current_el(env) == 3) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (arm_current_el(env) == arm_debug_target_el(env)) {
|
||||
if ((extract32(env->cp15.mdscr_el1, 13, 1) == 0)
|
||||
|| (env->daif & PSTATE_D)) {
|
||||
|
@ -1777,10 +1786,42 @@ static inline bool aa64_generate_debug_exceptions(CPUARMState *env)
|
|||
|
||||
static inline bool aa32_generate_debug_exceptions(CPUARMState *env)
|
||||
{
|
||||
if (arm_current_el(env) == 0 && arm_el_is_aa64(env, 1)) {
|
||||
int el = arm_current_el(env);
|
||||
|
||||
if (el == 0 && arm_el_is_aa64(env, 1)) {
|
||||
return aa64_generate_debug_exceptions(env);
|
||||
}
|
||||
return arm_current_el(env) != 2;
|
||||
|
||||
if (arm_is_secure(env)) {
|
||||
int spd;
|
||||
|
||||
if (el == 0 && (env->cp15.sder & 1)) {
|
||||
/* SDER.SUIDEN means debug exceptions from Secure EL0
|
||||
* are always enabled. Otherwise they are controlled by
|
||||
* SDCR.SPD like those from other Secure ELs.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
spd = extract32(env->cp15.mdcr_el3, 14, 2);
|
||||
switch (spd) {
|
||||
case 1:
|
||||
/* SPD == 0b01 is reserved, but behaves as 0b00. */
|
||||
case 0:
|
||||
/* For 0b00 we return true if external secure invasive debug
|
||||
* is enabled. On real hardware this is controlled by external
|
||||
* signals to the core. QEMU always permits debug, and behaves
|
||||
* as if DBGEN, SPIDEN, NIDEN and SPNIDEN are all tied high.
|
||||
*/
|
||||
return true;
|
||||
case 2:
|
||||
return false;
|
||||
case 3:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return el != 2;
|
||||
}
|
||||
|
||||
/* Return true if debugging exceptions are currently enabled.
|
||||
|
|
|
@ -109,6 +109,7 @@ static void aarch64_a57_initfn(Object *obj)
|
|||
set_feature(&cpu->env, ARM_FEATURE_V8_SHA256);
|
||||
set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
|
||||
set_feature(&cpu->env, ARM_FEATURE_CRC);
|
||||
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
||||
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
|
||||
cpu->midr = 0x411fd070;
|
||||
cpu->revidr = 0x00000000;
|
||||
|
@ -161,6 +162,7 @@ static void aarch64_a53_initfn(Object *obj)
|
|||
set_feature(&cpu->env, ARM_FEATURE_V8_SHA256);
|
||||
set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
|
||||
set_feature(&cpu->env, ARM_FEATURE_CRC);
|
||||
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
||||
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
|
||||
cpu->midr = 0x410fd034;
|
||||
cpu->revidr = 0x00000000;
|
||||
|
|
|
@ -344,7 +344,8 @@ void init_cpreg_list(ARMCPU *cpu)
|
|||
* access_el3_aa32ns_aa64any: Used to check both AArch32/64 register views.
|
||||
*/
|
||||
static CPAccessResult access_el3_aa32ns(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
bool secure = arm_is_secure_below_el3(env);
|
||||
|
||||
|
@ -356,14 +357,34 @@ static CPAccessResult access_el3_aa32ns(CPUARMState *env,
|
|||
}
|
||||
|
||||
static CPAccessResult access_el3_aa32ns_aa64any(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (!arm_el_is_aa64(env, 3)) {
|
||||
return access_el3_aa32ns(env, ri);
|
||||
return access_el3_aa32ns(env, ri, isread);
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
/* Some secure-only AArch32 registers trap to EL3 if used from
|
||||
* Secure EL1 (but are just ordinary UNDEF in other non-EL3 contexts).
|
||||
* Note that an access from Secure EL1 can only happen if EL3 is AArch64.
|
||||
* We assume that the .access field is set to PL1_RW.
|
||||
*/
|
||||
static CPAccessResult access_trap_aa32s_el1(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_current_el(env) == 3) {
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
if (arm_is_secure_below_el3(env)) {
|
||||
return CP_ACCESS_TRAP_EL3;
|
||||
}
|
||||
/* This will be EL1 NS and EL2 NS, which just UNDEF */
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
}
|
||||
|
||||
static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
|
@ -634,7 +655,8 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
env->cp15.cpacr_el1 = value;
|
||||
}
|
||||
|
||||
static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
/* Check if CPACR accesses are to be trapped to EL2 */
|
||||
|
@ -651,7 +673,8 @@ static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static CPAccessResult cptr_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult cptr_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* Check if CPTR accesses are set to trap to EL3 */
|
||||
if (arm_current_el(env) == 2 && (env->cp15.cptr_el[3] & CPTR_TCPAC)) {
|
||||
|
@ -693,7 +716,8 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
|
|||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* Performance monitor registers user accessibility is controlled
|
||||
* by PMUSERENR.
|
||||
|
@ -1137,7 +1161,8 @@ static void teecr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
env->teecr = value;
|
||||
}
|
||||
|
||||
static CPAccessResult teehbr_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult teehbr_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_current_el(env) == 0 && (env->teecr & 1)) {
|
||||
return CP_ACCESS_TRAP;
|
||||
|
@ -1190,7 +1215,8 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
|
|||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* CNTFRQ: not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero */
|
||||
if (arm_current_el(env) == 0 && !extract32(env->cp15.c14_cntkctl, 0, 2)) {
|
||||
|
@ -1199,7 +1225,8 @@ static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx)
|
||||
static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx,
|
||||
bool isread)
|
||||
{
|
||||
unsigned int cur_el = arm_current_el(env);
|
||||
bool secure = arm_is_secure(env);
|
||||
|
@ -1218,7 +1245,8 @@ static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx)
|
|||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx)
|
||||
static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx,
|
||||
bool isread)
|
||||
{
|
||||
unsigned int cur_el = arm_current_el(env);
|
||||
bool secure = arm_is_secure(env);
|
||||
|
@ -1240,29 +1268,34 @@ static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx)
|
|||
}
|
||||
|
||||
static CPAccessResult gt_pct_access(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
return gt_counter_access(env, GTIMER_PHYS);
|
||||
return gt_counter_access(env, GTIMER_PHYS, isread);
|
||||
}
|
||||
|
||||
static CPAccessResult gt_vct_access(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
return gt_counter_access(env, GTIMER_VIRT);
|
||||
return gt_counter_access(env, GTIMER_VIRT, isread);
|
||||
}
|
||||
|
||||
static CPAccessResult gt_ptimer_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult gt_ptimer_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
return gt_timer_access(env, GTIMER_PHYS);
|
||||
return gt_timer_access(env, GTIMER_PHYS, isread);
|
||||
}
|
||||
|
||||
static CPAccessResult gt_vtimer_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult gt_vtimer_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
return gt_timer_access(env, GTIMER_VIRT);
|
||||
return gt_timer_access(env, GTIMER_VIRT, isread);
|
||||
}
|
||||
|
||||
static CPAccessResult gt_stimer_access(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* The AArch64 register view of the secure physical timer is
|
||||
* always accessible from EL3, and configurably accessible from
|
||||
|
@ -1759,7 +1792,8 @@ static void par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
|||
#ifndef CONFIG_USER_ONLY
|
||||
/* get_phys_addr() isn't present for user-mode-only targets */
|
||||
|
||||
static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (ri->opc2 & 4) {
|
||||
/* The ATS12NSO* operations must trap to EL3 if executed in
|
||||
|
@ -1904,7 +1938,8 @@ static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
A32_BANKED_CURRENT_REG_SET(env, par, par64);
|
||||
}
|
||||
|
||||
static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_current_el(env) == 3 && !(env->cp15.scr_el3 & SCR_NS)) {
|
||||
return CP_ACCESS_TRAP;
|
||||
|
@ -2558,7 +2593,8 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
vfp_set_fpsr(env, value);
|
||||
}
|
||||
|
||||
static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) {
|
||||
return CP_ACCESS_TRAP;
|
||||
|
@ -2573,7 +2609,8 @@ static void aa64_daif_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
}
|
||||
|
||||
static CPAccessResult aa64_cacheop_access(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* Cache invalidate/clean: NOP, but EL0 must UNDEF unless
|
||||
* SCTLR_EL1.UCI is set.
|
||||
|
@ -2829,7 +2866,8 @@ static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
}
|
||||
}
|
||||
|
||||
static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* We don't implement EL2, so the only control on DC ZVA is the
|
||||
* bit in the SCTLR which can prohibit access for EL0.
|
||||
|
@ -2846,13 +2884,14 @@ static uint64_t aa64_dczid_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
int dzp_bit = 1 << 4;
|
||||
|
||||
/* DZP indicates whether DC ZVA access is allowed */
|
||||
if (aa64_zva_access(env, NULL) == CP_ACCESS_OK) {
|
||||
if (aa64_zva_access(env, NULL, false) == CP_ACCESS_OK) {
|
||||
dzp_bit = 0;
|
||||
}
|
||||
return cpu->dcz_blocksize | dzp_bit;
|
||||
}
|
||||
|
||||
static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (!(env->pstate & PSTATE_SP)) {
|
||||
/* Access to SP_EL0 is undefined if it's being used as
|
||||
|
@ -2891,7 +2930,8 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
tlb_flush(CPU(cpu), 1);
|
||||
}
|
||||
|
||||
static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if ((env->cp15.cptr_el[2] & CPTR_TFP) && arm_current_el(env) == 2) {
|
||||
return CP_ACCESS_TRAP_EL2;
|
||||
|
@ -3523,6 +3563,25 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
|
|||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* The NSACR is RW at EL3, and RO for NS EL1 and NS EL2.
|
||||
* At Secure EL1 it traps to EL3.
|
||||
*/
|
||||
if (arm_current_el(env) == 3) {
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
if (arm_is_secure_below_el3(env)) {
|
||||
return CP_ACCESS_TRAP_EL3;
|
||||
}
|
||||
/* Accesses from EL1 NS and EL2 NS are UNDEF for write but allow reads. */
|
||||
if (isread) {
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo el3_cp_reginfo[] = {
|
||||
{ .name = "SCR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 0,
|
||||
|
@ -3530,8 +3589,17 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
|
|||
.resetvalue = 0, .writefn = scr_write },
|
||||
{ .name = "SCR", .type = ARM_CP_ALIAS,
|
||||
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 0,
|
||||
.access = PL3_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3),
|
||||
.access = PL1_RW, .accessfn = access_trap_aa32s_el1,
|
||||
.fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3),
|
||||
.writefn = scr_write },
|
||||
{ .name = "MDCR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 3, .opc2 = 1,
|
||||
.resetvalue = 0,
|
||||
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el3) },
|
||||
{ .name = "SDCR", .type = ARM_CP_ALIAS,
|
||||
.cp = 15, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 1,
|
||||
.access = PL1_RW, .accessfn = access_trap_aa32s_el1,
|
||||
.fieldoffset = offsetoflow32(CPUARMState, cp15.mdcr_el3) },
|
||||
{ .name = "SDER32_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 1,
|
||||
.access = PL3_RW, .resetvalue = 0,
|
||||
|
@ -3540,12 +3608,9 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
|
|||
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 1,
|
||||
.access = PL3_RW, .resetvalue = 0,
|
||||
.fieldoffset = offsetoflow32(CPUARMState, cp15.sder) },
|
||||
/* TODO: Implement NSACR trapping of secure EL1 accesses to EL3 */
|
||||
{ .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2,
|
||||
.access = PL3_W | PL1_R, .resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.nsacr) },
|
||||
{ .name = "MVBAR", .cp = 15, .opc1 = 0, .crn = 12, .crm = 0, .opc2 = 1,
|
||||
.access = PL3_RW, .writefn = vbar_write, .resetvalue = 0,
|
||||
.access = PL1_RW, .accessfn = access_trap_aa32s_el1,
|
||||
.writefn = vbar_write, .resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.mvbar) },
|
||||
{ .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_ALIAS, /* reset handled by AArch32 view */
|
||||
|
@ -3630,7 +3695,8 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
|
|||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
|
||||
* but the AArch32 CTR has its own reginfo struct)
|
||||
|
@ -4312,6 +4378,45 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
|||
};
|
||||
define_one_arm_cp_reg(cpu, &rvbar);
|
||||
}
|
||||
/* The behaviour of NSACR is sufficiently various that we don't
|
||||
* try to describe it in a single reginfo:
|
||||
* if EL3 is 64 bit, then trap to EL3 from S EL1,
|
||||
* reads as constant 0xc00 from NS EL1 and NS EL2
|
||||
* if EL3 is 32 bit, then RW at EL3, RO at NS EL1 and NS EL2
|
||||
* if v7 without EL3, register doesn't exist
|
||||
* if v8 without EL3, reads as constant 0xc00 from NS EL1 and NS EL2
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
||||
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
|
||||
ARMCPRegInfo nsacr = {
|
||||
.name = "NSACR", .type = ARM_CP_CONST,
|
||||
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2,
|
||||
.access = PL1_RW, .accessfn = nsacr_access,
|
||||
.resetvalue = 0xc00
|
||||
};
|
||||
define_one_arm_cp_reg(cpu, &nsacr);
|
||||
} else {
|
||||
ARMCPRegInfo nsacr = {
|
||||
.name = "NSACR",
|
||||
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2,
|
||||
.access = PL3_RW | PL1_R,
|
||||
.resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.nsacr)
|
||||
};
|
||||
define_one_arm_cp_reg(cpu, &nsacr);
|
||||
}
|
||||
} else {
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
ARMCPRegInfo nsacr = {
|
||||
.name = "NSACR", .type = ARM_CP_CONST,
|
||||
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2,
|
||||
.access = PL1_R,
|
||||
.resetvalue = 0xc00
|
||||
};
|
||||
define_one_arm_cp_reg(cpu, &nsacr);
|
||||
}
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
||||
if (arm_feature(env, ARM_FEATURE_V6)) {
|
||||
/* PMSAv6 not implemented */
|
||||
|
|
|
@ -62,7 +62,7 @@ DEF_HELPER_1(cpsr_read, i32, env)
|
|||
DEF_HELPER_3(v7m_msr, void, env, i32, i32)
|
||||
DEF_HELPER_2(v7m_mrs, i32, env, i32)
|
||||
|
||||
DEF_HELPER_3(access_check_cp_reg, void, env, ptr, i32)
|
||||
DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32)
|
||||
DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
|
||||
DEF_HELPER_2(get_cp_reg, i32, env, ptr)
|
||||
DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
|
||||
|
|
|
@ -270,10 +270,10 @@ static inline uint32_t syn_aa64_smc(uint32_t imm16)
|
|||
return (EC_AA64_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_thumb)
|
||||
static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_16bit)
|
||||
{
|
||||
return (EC_AA32_SVC << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
|
||||
| (is_thumb ? 0 : ARM_EL_IL);
|
||||
| (is_16bit ? 0 : ARM_EL_IL);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa32_hvc(uint32_t imm16)
|
||||
|
@ -291,10 +291,10 @@ static inline uint32_t syn_aa64_bkpt(uint32_t imm16)
|
|||
return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_thumb)
|
||||
static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_16bit)
|
||||
{
|
||||
return (EC_AA32_BKPT << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
|
||||
| (is_thumb ? 0 : ARM_EL_IL);
|
||||
| (is_16bit ? 0 : ARM_EL_IL);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2,
|
||||
|
@ -308,48 +308,48 @@ static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2,
|
|||
|
||||
static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2,
|
||||
int crn, int crm, int rt, int isread,
|
||||
bool is_thumb)
|
||||
bool is_16bit)
|
||||
{
|
||||
return (EC_CP14RTTRAP << ARM_EL_EC_SHIFT)
|
||||
| (is_thumb ? 0 : ARM_EL_IL)
|
||||
| (is_16bit ? 0 : ARM_EL_IL)
|
||||
| (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
|
||||
| (crn << 10) | (rt << 5) | (crm << 1) | isread;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_cp15_rt_trap(int cv, int cond, int opc1, int opc2,
|
||||
int crn, int crm, int rt, int isread,
|
||||
bool is_thumb)
|
||||
bool is_16bit)
|
||||
{
|
||||
return (EC_CP15RTTRAP << ARM_EL_EC_SHIFT)
|
||||
| (is_thumb ? 0 : ARM_EL_IL)
|
||||
| (is_16bit ? 0 : ARM_EL_IL)
|
||||
| (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
|
||||
| (crn << 10) | (rt << 5) | (crm << 1) | isread;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_cp14_rrt_trap(int cv, int cond, int opc1, int crm,
|
||||
int rt, int rt2, int isread,
|
||||
bool is_thumb)
|
||||
bool is_16bit)
|
||||
{
|
||||
return (EC_CP14RRTTRAP << ARM_EL_EC_SHIFT)
|
||||
| (is_thumb ? 0 : ARM_EL_IL)
|
||||
| (is_16bit ? 0 : ARM_EL_IL)
|
||||
| (cv << 24) | (cond << 20) | (opc1 << 16)
|
||||
| (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
|
||||
int rt, int rt2, int isread,
|
||||
bool is_thumb)
|
||||
bool is_16bit)
|
||||
{
|
||||
return (EC_CP15RRTTRAP << ARM_EL_EC_SHIFT)
|
||||
| (is_thumb ? 0 : ARM_EL_IL)
|
||||
| (is_16bit ? 0 : ARM_EL_IL)
|
||||
| (cv << 24) | (cond << 20) | (opc1 << 16)
|
||||
| (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_thumb)
|
||||
static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit)
|
||||
{
|
||||
return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
|
||||
| (is_thumb ? 0 : ARM_EL_IL)
|
||||
| (is_16bit ? 0 : ARM_EL_IL)
|
||||
| (cv << 24) | (cond << 20);
|
||||
}
|
||||
|
||||
|
@ -409,6 +409,9 @@ void hw_breakpoint_update(ARMCPU *cpu, int n);
|
|||
*/
|
||||
void hw_breakpoint_update_all(ARMCPU *cpu);
|
||||
|
||||
/* Callback function for checking if a watchpoint should trigger. */
|
||||
bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp);
|
||||
|
||||
/* Callback function for when a watchpoint or breakpoint triggers. */
|
||||
void arm_debug_excp_handler(CPUState *cs);
|
||||
|
||||
|
|
|
@ -457,7 +457,8 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
|
|||
}
|
||||
}
|
||||
|
||||
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
|
||||
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
|
||||
uint32_t isread)
|
||||
{
|
||||
const ARMCPRegInfo *ri = rip;
|
||||
int target_el;
|
||||
|
@ -471,7 +472,7 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
|
|||
return;
|
||||
}
|
||||
|
||||
switch (ri->accessfn(env, ri)) {
|
||||
switch (ri->accessfn(env, ri, isread)) {
|
||||
case CP_ACCESS_OK:
|
||||
return;
|
||||
case CP_ACCESS_TRAP:
|
||||
|
@ -975,6 +976,16 @@ void HELPER(check_breakpoints)(CPUARMState *env)
|
|||
}
|
||||
}
|
||||
|
||||
bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
|
||||
{
|
||||
/* Called by core code when a CPU watchpoint fires; need to check if this
|
||||
* is also an architectural watchpoint match.
|
||||
*/
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
|
||||
return check_watchpoints(cpu);
|
||||
}
|
||||
|
||||
void arm_debug_excp_handler(CPUState *cs)
|
||||
{
|
||||
/* Called by core code when a watchpoint or breakpoint fires;
|
||||
|
@ -986,23 +997,20 @@ void arm_debug_excp_handler(CPUState *cs)
|
|||
|
||||
if (wp_hit) {
|
||||
if (wp_hit->flags & BP_CPU) {
|
||||
cs->watchpoint_hit = NULL;
|
||||
if (check_watchpoints(cpu)) {
|
||||
bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0;
|
||||
bool same_el = arm_debug_target_el(env) == arm_current_el(env);
|
||||
bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0;
|
||||
bool same_el = arm_debug_target_el(env) == arm_current_el(env);
|
||||
|
||||
if (extended_addresses_enabled(env)) {
|
||||
env->exception.fsr = (1 << 9) | 0x22;
|
||||
} else {
|
||||
env->exception.fsr = 0x2;
|
||||
}
|
||||
env->exception.vaddress = wp_hit->hitaddr;
|
||||
raise_exception(env, EXCP_DATA_ABORT,
|
||||
syn_watchpoint(same_el, 0, wnr),
|
||||
arm_debug_target_el(env));
|
||||
cs->watchpoint_hit = NULL;
|
||||
|
||||
if (extended_addresses_enabled(env)) {
|
||||
env->exception.fsr = (1 << 9) | 0x22;
|
||||
} else {
|
||||
cpu_resume_from_signal(cs, NULL);
|
||||
env->exception.fsr = 0x2;
|
||||
}
|
||||
env->exception.vaddress = wp_hit->hitaddr;
|
||||
raise_exception(env, EXCP_DATA_ABORT,
|
||||
syn_watchpoint(same_el, 0, wnr),
|
||||
arm_debug_target_el(env));
|
||||
}
|
||||
} else {
|
||||
uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
|
||||
|
|
|
@ -1367,16 +1367,18 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
|||
* runtime; this may result in an exception.
|
||||
*/
|
||||
TCGv_ptr tmpptr;
|
||||
TCGv_i32 tcg_syn;
|
||||
TCGv_i32 tcg_syn, tcg_isread;
|
||||
uint32_t syndrome;
|
||||
|
||||
gen_a64_set_pc_im(s->pc - 4);
|
||||
tmpptr = tcg_const_ptr(ri);
|
||||
syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
|
||||
tcg_syn = tcg_const_i32(syndrome);
|
||||
gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn);
|
||||
tcg_isread = tcg_const_i32(isread);
|
||||
gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn, tcg_isread);
|
||||
tcg_temp_free_ptr(tmpptr);
|
||||
tcg_temp_free_i32(tcg_syn);
|
||||
tcg_temp_free_i32(tcg_isread);
|
||||
}
|
||||
|
||||
/* Handle special cases first */
|
||||
|
|
|
@ -3077,7 +3077,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
|
|||
*/
|
||||
if (s->fp_excp_el) {
|
||||
gen_exception_insn(s, 4, EXCP_UDEF,
|
||||
syn_fp_access_trap(1, 0xe, s->thumb), s->fp_excp_el);
|
||||
syn_fp_access_trap(1, 0xe, false), s->fp_excp_el);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4399,7 +4399,7 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
|
|||
*/
|
||||
if (s->fp_excp_el) {
|
||||
gen_exception_insn(s, 4, EXCP_UDEF,
|
||||
syn_fp_access_trap(1, 0xe, s->thumb), s->fp_excp_el);
|
||||
syn_fp_access_trap(1, 0xe, false), s->fp_excp_el);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -5137,7 +5137,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
|||
*/
|
||||
if (s->fp_excp_el) {
|
||||
gen_exception_insn(s, 4, EXCP_UDEF,
|
||||
syn_fp_access_trap(1, 0xe, s->thumb), s->fp_excp_el);
|
||||
syn_fp_access_trap(1, 0xe, false), s->fp_excp_el);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -7169,7 +7169,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
|
|||
* call in order to handle c15_cpar.
|
||||
*/
|
||||
TCGv_ptr tmpptr;
|
||||
TCGv_i32 tcg_syn;
|
||||
TCGv_i32 tcg_syn, tcg_isread;
|
||||
uint32_t syndrome;
|
||||
|
||||
/* Note that since we are an implementation which takes an
|
||||
|
@ -7184,19 +7184,19 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
|
|||
case 14:
|
||||
if (is64) {
|
||||
syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
|
||||
isread, s->thumb);
|
||||
isread, false);
|
||||
} else {
|
||||
syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm,
|
||||
rt, isread, s->thumb);
|
||||
rt, isread, false);
|
||||
}
|
||||
break;
|
||||
case 15:
|
||||
if (is64) {
|
||||
syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
|
||||
isread, s->thumb);
|
||||
isread, false);
|
||||
} else {
|
||||
syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm,
|
||||
rt, isread, s->thumb);
|
||||
rt, isread, false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -7214,9 +7214,12 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
|
|||
gen_set_pc_im(s, s->pc - 4);
|
||||
tmpptr = tcg_const_ptr(ri);
|
||||
tcg_syn = tcg_const_i32(syndrome);
|
||||
gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn);
|
||||
tcg_isread = tcg_const_i32(isread);
|
||||
gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn,
|
||||
tcg_isread);
|
||||
tcg_temp_free_ptr(tmpptr);
|
||||
tcg_temp_free_i32(tcg_syn);
|
||||
tcg_temp_free_i32(tcg_isread);
|
||||
}
|
||||
|
||||
/* Handle special cases first */
|
||||
|
|
Loading…
Reference in New Issue