target-arm queue:

* Fix physical address resolution for Stage2
  * pl011: refactoring, implement reset method
  * Support GICv3 with hvf acceleration
  * sbsa-ref: remove cortex-a76 from list of supported cpus
  * Correct syndrome for ATS12NSO* traps at Secure EL1
  * Fix priority of HSTR_EL2 traps vs UNDEFs
  * Implement FEAT_FGT for '-cpu max'
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmPdGisZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3iTND/4qnI00PcqPhdZAD083admx
 Tn+7OaTd8aaWHDMvbnV3fNsvAEt//j8DdzeBGDLbgfhBuOCPB8z7oDSr7oqczmys
 Yjnh25o6IDUYtMnKR+dBwFKGvAqWwM4UdEllkHJvvM+QpnlH7iu9lCkgYr6PvBYA
 h4ajfZ5J7C2OmFJZqsKa2Ot3mveFxos1QzgWSmsWNGTJiZTOCiD7AvuCnEsBBaVP
 pESY+5eGjVmjv6ocHxcHG4LA456bHAf6JiCgKqgwowRBlJenpsnNgKleIN4gQA/J
 wtfLALNe6FkTV9tzK/MgtO1qOhxkUHrnTrYTtTLmk4H1VryFdDvomYB34zBIgfMY
 l1LmMba6UCoxtck13D5jv1xkE56o7Z3kqrhyOvP+aHFdi+dvYQ/z+b8pqUeYeSiu
 EbVWa/270JwVdbBT08vfW33Ci9n7fxZtRCrvj2viMgOiQOKwXYEb5AVxM9TRZSKC
 Y+1m5frW2HQ+KNvjEyHdMJ8q4nFhaS5Bq2A2RMaQCV2QBuBJvFkGL3ul6M0lw/eq
 cAZDKN6H/8N2l2DPcPHUy6RMiqUPSnemvFI814ElKeHGa1V1c7Iw9C4lWAV5Ue5E
 gotHC1ros89xV0Eg0gaB9UgX8TgbQUfc3g1g6YUvTCfQdvxL0H1rY+wUWU1h1V2r
 VdhxI95gUkgmoVnk8KnwIw==
 =hk0j
 -----END PGP SIGNATURE-----

Merge tag 'pull-target-arm-20230203' of https://git.linaro.org/people/pmaydell/qemu-arm into staging

target-arm queue:
 * Fix physical address resolution for Stage2
 * pl011: refactoring, implement reset method
 * Support GICv3 with hvf acceleration
 * sbsa-ref: remove cortex-a76 from list of supported cpus
 * Correct syndrome for ATS12NSO* traps at Secure EL1
 * Fix priority of HSTR_EL2 traps vs UNDEFs
 * Implement FEAT_FGT for '-cpu max'

# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmPdGisZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3iTND/4qnI00PcqPhdZAD083admx
# Tn+7OaTd8aaWHDMvbnV3fNsvAEt//j8DdzeBGDLbgfhBuOCPB8z7oDSr7oqczmys
# Yjnh25o6IDUYtMnKR+dBwFKGvAqWwM4UdEllkHJvvM+QpnlH7iu9lCkgYr6PvBYA
# h4ajfZ5J7C2OmFJZqsKa2Ot3mveFxos1QzgWSmsWNGTJiZTOCiD7AvuCnEsBBaVP
# pESY+5eGjVmjv6ocHxcHG4LA456bHAf6JiCgKqgwowRBlJenpsnNgKleIN4gQA/J
# wtfLALNe6FkTV9tzK/MgtO1qOhxkUHrnTrYTtTLmk4H1VryFdDvomYB34zBIgfMY
# l1LmMba6UCoxtck13D5jv1xkE56o7Z3kqrhyOvP+aHFdi+dvYQ/z+b8pqUeYeSiu
# EbVWa/270JwVdbBT08vfW33Ci9n7fxZtRCrvj2viMgOiQOKwXYEb5AVxM9TRZSKC
# Y+1m5frW2HQ+KNvjEyHdMJ8q4nFhaS5Bq2A2RMaQCV2QBuBJvFkGL3ul6M0lw/eq
# cAZDKN6H/8N2l2DPcPHUy6RMiqUPSnemvFI814ElKeHGa1V1c7Iw9C4lWAV5Ue5E
# gotHC1ros89xV0Eg0gaB9UgX8TgbQUfc3g1g6YUvTCfQdvxL0H1rY+wUWU1h1V2r
# VdhxI95gUkgmoVnk8KnwIw==
# =hk0j
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 03 Feb 2023 14:28:59 GMT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20230203' of https://git.linaro.org/people/pmaydell/qemu-arm: (33 commits)
  target/arm: Enable FEAT_FGT on '-cpu max'
  target/arm: Implement MDCR_EL2.TDCC and MDCR_EL3.TDCC traps
  target/arm: Implement the HFGITR_EL2.SVC_EL0 and SVC_EL1 traps
  target/arm: Implement the HFGITR_EL2.ERET trap
  target/arm: Mark up sysregs for HFGITR bits 48..63
  target/arm: Mark up sysregs for HFGITR bits 18..47
  target/arm: Mark up sysregs for HFGITR bits 12..17
  target/arm: Mark up sysregs for HFGITR bits 0..11
  target/arm: Mark up sysregs for HDFGRTR bits 12..63
  target/arm: Mark up sysregs for HDFGRTR bits 0..11
  target/arm: Mark up sysregs for HFGRTR bits 36..63
  target/arm: Mark up sysregs for HFGRTR bits 24..35
  target/arm: Mark up sysregs for HFGRTR bits 12..23
  target/arm: Mark up sysregs for HFGRTR bits 0..11
  target/arm: Implement FGT trapping infrastructure
  target/arm: Define the FEAT_FGT registers
  target/arm: Disable HSTR_EL2 traps if EL2 is not enabled
  target/arm: Make HSTR_EL2 traps take priority over UNDEF-at-EL1
  target/arm: All UNDEF-at-EL0 traps take priority over HSTR_EL2 traps
  target/arm: Move do_coproc_insn() syndrome calculation earlier
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2023-02-03 15:33:05 +00:00
commit 0730eab4d3
21 changed files with 1340 additions and 189 deletions

View File

@ -30,6 +30,7 @@ the following architecture extensions:
- FEAT_ETS (Enhanced Translation Synchronization) - FEAT_ETS (Enhanced Translation Synchronization)
- FEAT_EVT (Enhanced Virtualization Traps) - FEAT_EVT (Enhanced Virtualization Traps)
- FEAT_FCMA (Floating-point complex number instructions) - FEAT_FCMA (Floating-point complex number instructions)
- FEAT_FGT (Fine-Grained Traps)
- FEAT_FHM (Floating-point half-precision multiplication instructions) - FEAT_FHM (Floating-point half-precision multiplication instructions)
- FEAT_FP16 (Half-precision floating-point data processing) - FEAT_FP16 (Half-precision floating-point data processing)
- FEAT_FRINTTS (Floating-point to integer instructions) - FEAT_FRINTTS (Floating-point to integer instructions)

View File

@ -29,6 +29,7 @@
#include "exec/hwaddr.h" #include "exec/hwaddr.h"
#include "kvm_arm.h" #include "kvm_arm.h"
#include "hw/arm/boot.h" #include "hw/arm/boot.h"
#include "hw/arm/smmuv3.h"
#include "hw/block/flash.h" #include "hw/block/flash.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/ide/internal.h" #include "hw/ide/internal.h"
@ -145,7 +146,6 @@ static const int sbsa_ref_irqmap[] = {
static const char * const valid_cpus[] = { static const char * const valid_cpus[] = {
ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a57"),
ARM_CPU_TYPE_NAME("cortex-a72"), ARM_CPU_TYPE_NAME("cortex-a72"),
ARM_CPU_TYPE_NAME("cortex-a76"),
ARM_CPU_TYPE_NAME("neoverse-n1"), ARM_CPU_TYPE_NAME("neoverse-n1"),
ARM_CPU_TYPE_NAME("max"), ARM_CPU_TYPE_NAME("max"),
}; };
@ -574,7 +574,7 @@ static void create_smmu(const SBSAMachineState *sms, PCIBus *bus)
DeviceState *dev; DeviceState *dev;
int i; int i;
dev = qdev_new("arm-smmuv3"); dev = qdev_new(TYPE_ARM_SMMUV3);
object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus), object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus),
&error_abort); &error_abort);

View File

@ -47,8 +47,10 @@
#include "sysemu/numa.h" #include "sysemu/numa.h"
#include "sysemu/runstate.h" #include "sysemu/runstate.h"
#include "sysemu/tpm.h" #include "sysemu/tpm.h"
#include "sysemu/tcg.h"
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
#include "sysemu/hvf.h" #include "sysemu/hvf.h"
#include "sysemu/qtest.h"
#include "hw/loader.h" #include "hw/loader.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/bitops.h" #include "qemu/bitops.h"
@ -1343,7 +1345,7 @@ static void create_smmu(const VirtMachineState *vms,
return; return;
} }
dev = qdev_new("arm-smmuv3"); dev = qdev_new(TYPE_ARM_SMMUV3);
object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus), object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus),
&error_abort); &error_abort);
@ -1820,6 +1822,84 @@ static void virt_set_memmap(VirtMachineState *vms, int pa_bits)
} }
} }
static VirtGICType finalize_gic_version_do(const char *accel_name,
VirtGICType gic_version,
int gics_supported,
unsigned int max_cpus)
{
/* Convert host/max/nosel to GIC version number */
switch (gic_version) {
case VIRT_GIC_VERSION_HOST:
if (!kvm_enabled()) {
error_report("gic-version=host requires KVM");
exit(1);
}
/* For KVM, gic-version=host means gic-version=max */
return finalize_gic_version_do(accel_name, VIRT_GIC_VERSION_MAX,
gics_supported, max_cpus);
case VIRT_GIC_VERSION_MAX:
if (gics_supported & VIRT_GIC_VERSION_4_MASK) {
gic_version = VIRT_GIC_VERSION_4;
} else if (gics_supported & VIRT_GIC_VERSION_3_MASK) {
gic_version = VIRT_GIC_VERSION_3;
} else {
gic_version = VIRT_GIC_VERSION_2;
}
break;
case VIRT_GIC_VERSION_NOSEL:
if ((gics_supported & VIRT_GIC_VERSION_2_MASK) &&
max_cpus <= GIC_NCPU) {
gic_version = VIRT_GIC_VERSION_2;
} else if (gics_supported & VIRT_GIC_VERSION_3_MASK) {
/*
* in case the host does not support v2 emulation or
* the end-user requested more than 8 VCPUs we now default
* to v3. In any case defaulting to v2 would be broken.
*/
gic_version = VIRT_GIC_VERSION_3;
} else if (max_cpus > GIC_NCPU) {
error_report("%s only supports GICv2 emulation but more than 8 "
"vcpus are requested", accel_name);
exit(1);
}
break;
case VIRT_GIC_VERSION_2:
case VIRT_GIC_VERSION_3:
case VIRT_GIC_VERSION_4:
break;
}
/* Check chosen version is effectively supported */
switch (gic_version) {
case VIRT_GIC_VERSION_2:
if (!(gics_supported & VIRT_GIC_VERSION_2_MASK)) {
error_report("%s does not support GICv2 emulation", accel_name);
exit(1);
}
break;
case VIRT_GIC_VERSION_3:
if (!(gics_supported & VIRT_GIC_VERSION_3_MASK)) {
error_report("%s does not support GICv3 emulation", accel_name);
exit(1);
}
break;
case VIRT_GIC_VERSION_4:
if (!(gics_supported & VIRT_GIC_VERSION_4_MASK)) {
error_report("%s does not support GICv4 emulation, is virtualization=on?",
accel_name);
exit(1);
}
break;
default:
error_report("logic error in finalize_gic_version");
exit(1);
break;
}
return gic_version;
}
/* /*
* finalize_gic_version - Determines the final gic_version * finalize_gic_version - Determines the final gic_version
* according to the gic-version property * according to the gic-version property
@ -1828,118 +1908,49 @@ static void virt_set_memmap(VirtMachineState *vms, int pa_bits)
*/ */
static void finalize_gic_version(VirtMachineState *vms) static void finalize_gic_version(VirtMachineState *vms)
{ {
const char *accel_name = current_accel_name();
unsigned int max_cpus = MACHINE(vms)->smp.max_cpus; unsigned int max_cpus = MACHINE(vms)->smp.max_cpus;
int gics_supported = 0;
if (kvm_enabled()) { /* Determine which GIC versions the current environment supports */
int probe_bitmap; if (kvm_enabled() && kvm_irqchip_in_kernel()) {
int probe_bitmap = kvm_arm_vgic_probe();
if (!kvm_irqchip_in_kernel()) {
switch (vms->gic_version) {
case VIRT_GIC_VERSION_HOST:
warn_report(
"gic-version=host not relevant with kernel-irqchip=off "
"as only userspace GICv2 is supported. Using v2 ...");
return;
case VIRT_GIC_VERSION_MAX:
case VIRT_GIC_VERSION_NOSEL:
vms->gic_version = VIRT_GIC_VERSION_2;
return;
case VIRT_GIC_VERSION_2:
return;
case VIRT_GIC_VERSION_3:
error_report(
"gic-version=3 is not supported with kernel-irqchip=off");
exit(1);
case VIRT_GIC_VERSION_4:
error_report(
"gic-version=4 is not supported with kernel-irqchip=off");
exit(1);
}
}
probe_bitmap = kvm_arm_vgic_probe();
if (!probe_bitmap) { if (!probe_bitmap) {
error_report("Unable to determine GIC version supported by host"); error_report("Unable to determine GIC version supported by host");
exit(1); exit(1);
} }
switch (vms->gic_version) { if (probe_bitmap & KVM_ARM_VGIC_V2) {
case VIRT_GIC_VERSION_HOST: gics_supported |= VIRT_GIC_VERSION_2_MASK;
case VIRT_GIC_VERSION_MAX:
if (probe_bitmap & KVM_ARM_VGIC_V3) {
vms->gic_version = VIRT_GIC_VERSION_3;
} else {
vms->gic_version = VIRT_GIC_VERSION_2;
}
return;
case VIRT_GIC_VERSION_NOSEL:
if ((probe_bitmap & KVM_ARM_VGIC_V2) && max_cpus <= GIC_NCPU) {
vms->gic_version = VIRT_GIC_VERSION_2;
} else if (probe_bitmap & KVM_ARM_VGIC_V3) {
/*
* in case the host does not support v2 in-kernel emulation or
* the end-user requested more than 8 VCPUs we now default
* to v3. In any case defaulting to v2 would be broken.
*/
vms->gic_version = VIRT_GIC_VERSION_3;
} else if (max_cpus > GIC_NCPU) {
error_report("host only supports in-kernel GICv2 emulation "
"but more than 8 vcpus are requested");
exit(1);
}
break;
case VIRT_GIC_VERSION_2:
case VIRT_GIC_VERSION_3:
break;
case VIRT_GIC_VERSION_4:
error_report("gic-version=4 is not supported with KVM");
exit(1);
} }
if (probe_bitmap & KVM_ARM_VGIC_V3) {
/* Check chosen version is effectively supported by the host */ gics_supported |= VIRT_GIC_VERSION_3_MASK;
if (vms->gic_version == VIRT_GIC_VERSION_2 &&
!(probe_bitmap & KVM_ARM_VGIC_V2)) {
error_report("host does not support in-kernel GICv2 emulation");
exit(1);
} else if (vms->gic_version == VIRT_GIC_VERSION_3 &&
!(probe_bitmap & KVM_ARM_VGIC_V3)) {
error_report("host does not support in-kernel GICv3 emulation");
exit(1);
} }
return; } else if (kvm_enabled() && !kvm_irqchip_in_kernel()) {
} /* KVM w/o kernel irqchip can only deal with GICv2 */
gics_supported |= VIRT_GIC_VERSION_2_MASK;
/* TCG mode */ accel_name = "KVM with kernel-irqchip=off";
switch (vms->gic_version) { } else if (tcg_enabled() || hvf_enabled() || qtest_enabled()) {
case VIRT_GIC_VERSION_NOSEL: gics_supported |= VIRT_GIC_VERSION_2_MASK;
vms->gic_version = VIRT_GIC_VERSION_2;
break;
case VIRT_GIC_VERSION_MAX:
if (module_object_class_by_name("arm-gicv3")) { if (module_object_class_by_name("arm-gicv3")) {
/* CONFIG_ARM_GICV3_TCG was set */ gics_supported |= VIRT_GIC_VERSION_3_MASK;
if (vms->virt) { if (vms->virt) {
/* GICv4 only makes sense if CPU has EL2 */ /* GICv4 only makes sense if CPU has EL2 */
vms->gic_version = VIRT_GIC_VERSION_4; gics_supported |= VIRT_GIC_VERSION_4_MASK;
} else {
vms->gic_version = VIRT_GIC_VERSION_3;
} }
} else {
vms->gic_version = VIRT_GIC_VERSION_2;
} }
break; } else {
case VIRT_GIC_VERSION_HOST: error_report("Unsupported accelerator, can not determine GIC support");
error_report("gic-version=host requires KVM");
exit(1); exit(1);
case VIRT_GIC_VERSION_4:
if (!vms->virt) {
error_report("gic-version=4 requires virtualization enabled");
exit(1);
}
break;
case VIRT_GIC_VERSION_2:
case VIRT_GIC_VERSION_3:
break;
} }
/*
* Then convert helpers like host/max to concrete GIC versions and ensure
* the desired version is supported
*/
vms->gic_version = finalize_gic_version_do(accel_name, vms->gic_version,
gics_supported, max_cpus);
} }
/* /*

View File

@ -81,6 +81,27 @@ static void pl011_update(PL011State *s)
} }
} }
static bool pl011_is_fifo_enabled(PL011State *s)
{
return (s->lcr & 0x10) != 0;
}
static inline unsigned pl011_get_fifo_depth(PL011State *s)
{
/* Note: FIFO depth is expected to be power-of-2 */
return pl011_is_fifo_enabled(s) ? PL011_FIFO_DEPTH : 1;
}
static inline void pl011_reset_fifo(PL011State *s)
{
s->read_count = 0;
s->read_pos = 0;
/* Reset FIFO flags */
s->flags &= ~(PL011_FLAG_RXFF | PL011_FLAG_TXFF);
s->flags |= PL011_FLAG_RXFE | PL011_FLAG_TXFE;
}
static uint64_t pl011_read(void *opaque, hwaddr offset, static uint64_t pl011_read(void *opaque, hwaddr offset,
unsigned size) unsigned size)
{ {
@ -94,8 +115,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset,
c = s->read_fifo[s->read_pos]; c = s->read_fifo[s->read_pos];
if (s->read_count > 0) { if (s->read_count > 0) {
s->read_count--; s->read_count--;
if (++s->read_pos == 16) s->read_pos = (s->read_pos + 1) & (pl011_get_fifo_depth(s) - 1);
s->read_pos = 0;
} }
if (s->read_count == 0) { if (s->read_count == 0) {
s->flags |= PL011_FLAG_RXFE; s->flags |= PL011_FLAG_RXFE;
@ -229,8 +249,7 @@ static void pl011_write(void *opaque, hwaddr offset,
case 11: /* UARTLCR_H */ case 11: /* UARTLCR_H */
/* Reset the FIFO state on FIFO enable or disable */ /* Reset the FIFO state on FIFO enable or disable */
if ((s->lcr ^ value) & 0x10) { if ((s->lcr ^ value) & 0x10) {
s->read_count = 0; pl011_reset_fifo(s);
s->read_pos = 0;
} }
if ((s->lcr ^ value) & 0x1) { if ((s->lcr ^ value) & 0x1) {
int break_enable = value & 0x1; int break_enable = value & 0x1;
@ -273,11 +292,7 @@ static int pl011_can_receive(void *opaque)
PL011State *s = (PL011State *)opaque; PL011State *s = (PL011State *)opaque;
int r; int r;
if (s->lcr & 0x10) { r = s->read_count < pl011_get_fifo_depth(s);
r = s->read_count < 16;
} else {
r = s->read_count < 1;
}
trace_pl011_can_receive(s->lcr, s->read_count, r); trace_pl011_can_receive(s->lcr, s->read_count, r);
return r; return r;
} }
@ -286,15 +301,15 @@ static void pl011_put_fifo(void *opaque, uint32_t value)
{ {
PL011State *s = (PL011State *)opaque; PL011State *s = (PL011State *)opaque;
int slot; int slot;
unsigned pipe_depth;
slot = s->read_pos + s->read_count; pipe_depth = pl011_get_fifo_depth(s);
if (slot >= 16) slot = (s->read_pos + s->read_count) & (pipe_depth - 1);
slot -= 16;
s->read_fifo[slot] = value; s->read_fifo[slot] = value;
s->read_count++; s->read_count++;
s->flags &= ~PL011_FLAG_RXFE; s->flags &= ~PL011_FLAG_RXFE;
trace_pl011_put_fifo(value, s->read_count); trace_pl011_put_fifo(value, s->read_count);
if (!(s->lcr & 0x10) || s->read_count == 16) { if (s->read_count == pipe_depth) {
trace_pl011_put_fifo_full(); trace_pl011_put_fifo_full();
s->flags |= PL011_FLAG_RXFF; s->flags |= PL011_FLAG_RXFF;
} }
@ -346,10 +361,35 @@ static const VMStateDescription vmstate_pl011_clock = {
} }
}; };
static int pl011_post_load(void *opaque, int version_id)
{
PL011State* s = opaque;
/* Sanity-check input state */
if (s->read_pos >= ARRAY_SIZE(s->read_fifo) ||
s->read_count > ARRAY_SIZE(s->read_fifo)) {
return -1;
}
if (!pl011_is_fifo_enabled(s) && s->read_count > 0 && s->read_pos > 0) {
/*
* Older versions of PL011 didn't ensure that the single
* character in the FIFO in FIFO-disabled mode is in
* element 0 of the array; convert to follow the current
* code's assumptions.
*/
s->read_fifo[0] = s->read_fifo[s->read_pos];
s->read_pos = 0;
}
return 0;
}
static const VMStateDescription vmstate_pl011 = { static const VMStateDescription vmstate_pl011 = {
.name = "pl011", .name = "pl011",
.version_id = 2, .version_id = 2,
.minimum_version_id = 2, .minimum_version_id = 2,
.post_load = pl011_post_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(readbuff, PL011State), VMSTATE_UINT32(readbuff, PL011State),
VMSTATE_UINT32(flags, PL011State), VMSTATE_UINT32(flags, PL011State),
@ -359,7 +399,7 @@ static const VMStateDescription vmstate_pl011 = {
VMSTATE_UINT32(dmacr, PL011State), VMSTATE_UINT32(dmacr, PL011State),
VMSTATE_UINT32(int_enabled, PL011State), VMSTATE_UINT32(int_enabled, PL011State),
VMSTATE_UINT32(int_level, PL011State), VMSTATE_UINT32(int_level, PL011State),
VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16), VMSTATE_UINT32_ARRAY(read_fifo, PL011State, PL011_FIFO_DEPTH),
VMSTATE_UINT32(ilpr, PL011State), VMSTATE_UINT32(ilpr, PL011State),
VMSTATE_UINT32(ibrd, PL011State), VMSTATE_UINT32(ibrd, PL011State),
VMSTATE_UINT32(fbrd, PL011State), VMSTATE_UINT32(fbrd, PL011State),
@ -396,11 +436,6 @@ static void pl011_init(Object *obj)
s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s, s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s,
ClockUpdate); ClockUpdate);
s->read_trigger = 1;
s->ifl = 0x12;
s->cr = 0x300;
s->flags = 0x90;
s->id = pl011_id_arm; s->id = pl011_id_arm;
} }
@ -412,11 +447,31 @@ static void pl011_realize(DeviceState *dev, Error **errp)
pl011_event, NULL, s, NULL, true); pl011_event, NULL, s, NULL, true);
} }
static void pl011_reset(DeviceState *dev)
{
PL011State *s = PL011(dev);
s->lcr = 0;
s->rsr = 0;
s->dmacr = 0;
s->int_enabled = 0;
s->int_level = 0;
s->ilpr = 0;
s->ibrd = 0;
s->fbrd = 0;
s->read_trigger = 1;
s->ifl = 0x12;
s->cr = 0x300;
s->flags = 0;
pl011_reset_fifo(s);
}
static void pl011_class_init(ObjectClass *oc, void *data) static void pl011_class_init(ObjectClass *oc, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = pl011_realize; dc->realize = pl011_realize;
dc->reset = pl011_reset;
dc->vmsd = &vmstate_pl011; dc->vmsd = &vmstate_pl011;
device_class_set_props(dc, pl011_properties); device_class_set_props(dc, pl011_properties);
} }

View File

@ -21,6 +21,8 @@
#include "hw/irq.h" #include "hw/irq.h"
#include "cpu.h" #include "cpu.h"
#include "target/arm/cpregs.h" #include "target/arm/cpregs.h"
#include "sysemu/tcg.h"
#include "sysemu/qtest.h"
/* /*
* Special case return value from hppvi_index(); must be larger than * Special case return value from hppvi_index(); must be larger than
@ -2376,6 +2378,7 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 6, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 6,
.type = ARM_CP_IO | ARM_CP_NO_RAW, .type = ARM_CP_IO | ARM_CP_NO_RAW,
.access = PL1_RW, .accessfn = gicv3_fiq_access, .access = PL1_RW, .accessfn = gicv3_fiq_access,
.fgt = FGT_ICC_IGRPENN_EL1,
.readfn = icc_igrpen_read, .readfn = icc_igrpen_read,
.writefn = icc_igrpen_write, .writefn = icc_igrpen_write,
}, },
@ -2384,6 +2387,7 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 7, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 7,
.type = ARM_CP_IO | ARM_CP_NO_RAW, .type = ARM_CP_IO | ARM_CP_NO_RAW,
.access = PL1_RW, .accessfn = gicv3_irq_access, .access = PL1_RW, .accessfn = gicv3_irq_access,
.fgt = FGT_ICC_IGRPENN_EL1,
.readfn = icc_igrpen_read, .readfn = icc_igrpen_read,
.writefn = icc_igrpen_write, .writefn = icc_igrpen_write,
}, },
@ -2810,6 +2814,8 @@ void gicv3_init_cpuif(GICv3State *s)
* which case we'd get the wrong value. * which case we'd get the wrong value.
* So instead we define the regs with no ri->opaque info, and * So instead we define the regs with no ri->opaque info, and
* get back to the GICv3CPUState from the CPUARMState. * get back to the GICv3CPUState from the CPUARMState.
*
* These CP regs callbacks can be called from either TCG or HVF code.
*/ */
define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
@ -2905,6 +2911,16 @@ void gicv3_init_cpuif(GICv3State *s)
define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo); define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo);
} }
} }
arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs); if (tcg_enabled() || qtest_enabled()) {
/*
* We can only trap EL changes with TCG. However the GIC interrupt
* state only changes on EL changes involving EL2 or EL3, so for
* the non-TCG case this is OK, as EL2 and EL3 can't exist.
*/
arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs);
} else {
assert(!arm_feature(&cpu->env, ARM_FEATURE_EL2));
assert(!arm_feature(&cpu->env, ARM_FEATURE_EL3));
}
} }
} }

View File

@ -109,14 +109,19 @@ typedef enum VirtMSIControllerType {
} VirtMSIControllerType; } VirtMSIControllerType;
typedef enum VirtGICType { typedef enum VirtGICType {
VIRT_GIC_VERSION_MAX, VIRT_GIC_VERSION_MAX = 0,
VIRT_GIC_VERSION_HOST, VIRT_GIC_VERSION_HOST = 1,
VIRT_GIC_VERSION_2, /* The concrete GIC values have to match the GIC version number */
VIRT_GIC_VERSION_3, VIRT_GIC_VERSION_2 = 2,
VIRT_GIC_VERSION_4, VIRT_GIC_VERSION_3 = 3,
VIRT_GIC_VERSION_4 = 4,
VIRT_GIC_VERSION_NOSEL, VIRT_GIC_VERSION_NOSEL,
} VirtGICType; } VirtGICType;
#define VIRT_GIC_VERSION_2_MASK BIT(VIRT_GIC_VERSION_2)
#define VIRT_GIC_VERSION_3_MASK BIT(VIRT_GIC_VERSION_3)
#define VIRT_GIC_VERSION_4_MASK BIT(VIRT_GIC_VERSION_4)
struct VirtMachineClass { struct VirtMachineClass {
MachineClass parent; MachineClass parent;
bool disallow_affinity_adjustment; bool disallow_affinity_adjustment;

View File

@ -27,6 +27,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(PL011State, PL011)
/* This shares the same struct (and cast macro) as the base pl011 device */ /* This shares the same struct (and cast macro) as the base pl011 device */
#define TYPE_PL011_LUMINARY "pl011_luminary" #define TYPE_PL011_LUMINARY "pl011_luminary"
/* Depth of UART FIFO in bytes, when FIFO mode is enabled (else depth == 1) */
#define PL011_FIFO_DEPTH 16
struct PL011State { struct PL011State {
SysBusDevice parent_obj; SysBusDevice parent_obj;
@ -39,7 +42,7 @@ struct PL011State {
uint32_t dmacr; uint32_t dmacr;
uint32_t int_enabled; uint32_t int_enabled;
uint32_t int_level; uint32_t int_level;
uint32_t read_fifo[16]; uint32_t read_fifo[PL011_FIFO_DEPTH];
uint32_t ilpr; uint32_t ilpr;
uint32_t ibrd; uint32_t ibrd;
uint32_t fbrd; uint32_t fbrd;

View File

@ -224,12 +224,487 @@ typedef enum CPAccessResult {
* Access fails and results in an exception syndrome 0x0 ("uncategorized"). * Access fails and results in an exception syndrome 0x0 ("uncategorized").
* Note that this is not a catch-all case -- the set of cases which may * Note that this is not a catch-all case -- the set of cases which may
* result in this failure is specifically defined by the architecture. * result in this failure is specifically defined by the architecture.
* This trap is always to the usual target EL, never directly to a
* specified target EL.
*/ */
CP_ACCESS_TRAP_UNCATEGORIZED = (2 << 2), CP_ACCESS_TRAP_UNCATEGORIZED = (2 << 2),
CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = CP_ACCESS_TRAP_UNCATEGORIZED | 2,
CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = CP_ACCESS_TRAP_UNCATEGORIZED | 3,
} CPAccessResult; } CPAccessResult;
/* Indexes into fgt_read[] */
#define FGTREG_HFGRTR 0
#define FGTREG_HDFGRTR 1
/* Indexes into fgt_write[] */
#define FGTREG_HFGWTR 0
#define FGTREG_HDFGWTR 1
/* Indexes into fgt_exec[] */
#define FGTREG_HFGITR 0
FIELD(HFGRTR_EL2, AFSR0_EL1, 0, 1)
FIELD(HFGRTR_EL2, AFSR1_EL1, 1, 1)
FIELD(HFGRTR_EL2, AIDR_EL1, 2, 1)
FIELD(HFGRTR_EL2, AMAIR_EL1, 3, 1)
FIELD(HFGRTR_EL2, APDAKEY, 4, 1)
FIELD(HFGRTR_EL2, APDBKEY, 5, 1)
FIELD(HFGRTR_EL2, APGAKEY, 6, 1)
FIELD(HFGRTR_EL2, APIAKEY, 7, 1)
FIELD(HFGRTR_EL2, APIBKEY, 8, 1)
FIELD(HFGRTR_EL2, CCSIDR_EL1, 9, 1)
FIELD(HFGRTR_EL2, CLIDR_EL1, 10, 1)
FIELD(HFGRTR_EL2, CONTEXTIDR_EL1, 11, 1)
FIELD(HFGRTR_EL2, CPACR_EL1, 12, 1)
FIELD(HFGRTR_EL2, CSSELR_EL1, 13, 1)
FIELD(HFGRTR_EL2, CTR_EL0, 14, 1)
FIELD(HFGRTR_EL2, DCZID_EL0, 15, 1)
FIELD(HFGRTR_EL2, ESR_EL1, 16, 1)
FIELD(HFGRTR_EL2, FAR_EL1, 17, 1)
FIELD(HFGRTR_EL2, ISR_EL1, 18, 1)
FIELD(HFGRTR_EL2, LORC_EL1, 19, 1)
FIELD(HFGRTR_EL2, LOREA_EL1, 20, 1)
FIELD(HFGRTR_EL2, LORID_EL1, 21, 1)
FIELD(HFGRTR_EL2, LORN_EL1, 22, 1)
FIELD(HFGRTR_EL2, LORSA_EL1, 23, 1)
FIELD(HFGRTR_EL2, MAIR_EL1, 24, 1)
FIELD(HFGRTR_EL2, MIDR_EL1, 25, 1)
FIELD(HFGRTR_EL2, MPIDR_EL1, 26, 1)
FIELD(HFGRTR_EL2, PAR_EL1, 27, 1)
FIELD(HFGRTR_EL2, REVIDR_EL1, 28, 1)
FIELD(HFGRTR_EL2, SCTLR_EL1, 29, 1)
FIELD(HFGRTR_EL2, SCXTNUM_EL1, 30, 1)
FIELD(HFGRTR_EL2, SCXTNUM_EL0, 31, 1)
FIELD(HFGRTR_EL2, TCR_EL1, 32, 1)
FIELD(HFGRTR_EL2, TPIDR_EL1, 33, 1)
FIELD(HFGRTR_EL2, TPIDRRO_EL0, 34, 1)
FIELD(HFGRTR_EL2, TPIDR_EL0, 35, 1)
FIELD(HFGRTR_EL2, TTBR0_EL1, 36, 1)
FIELD(HFGRTR_EL2, TTBR1_EL1, 37, 1)
FIELD(HFGRTR_EL2, VBAR_EL1, 38, 1)
FIELD(HFGRTR_EL2, ICC_IGRPENN_EL1, 39, 1)
FIELD(HFGRTR_EL2, ERRIDR_EL1, 40, 1)
FIELD(HFGRTR_EL2, ERRSELR_EL1, 41, 1)
FIELD(HFGRTR_EL2, ERXFR_EL1, 42, 1)
FIELD(HFGRTR_EL2, ERXCTLR_EL1, 43, 1)
FIELD(HFGRTR_EL2, ERXSTATUS_EL1, 44, 1)
FIELD(HFGRTR_EL2, ERXMISCN_EL1, 45, 1)
FIELD(HFGRTR_EL2, ERXPFGF_EL1, 46, 1)
FIELD(HFGRTR_EL2, ERXPFGCTL_EL1, 47, 1)
FIELD(HFGRTR_EL2, ERXPFGCDN_EL1, 48, 1)
FIELD(HFGRTR_EL2, ERXADDR_EL1, 49, 1)
FIELD(HFGRTR_EL2, NACCDATA_EL1, 50, 1)
/* 51-53: RES0 */
FIELD(HFGRTR_EL2, NSMPRI_EL1, 54, 1)
FIELD(HFGRTR_EL2, NTPIDR2_EL0, 55, 1)
/* 56-63: RES0 */
/* These match HFGRTR but bits for RO registers are RES0 */
FIELD(HFGWTR_EL2, AFSR0_EL1, 0, 1)
FIELD(HFGWTR_EL2, AFSR1_EL1, 1, 1)
FIELD(HFGWTR_EL2, AMAIR_EL1, 3, 1)
FIELD(HFGWTR_EL2, APDAKEY, 4, 1)
FIELD(HFGWTR_EL2, APDBKEY, 5, 1)
FIELD(HFGWTR_EL2, APGAKEY, 6, 1)
FIELD(HFGWTR_EL2, APIAKEY, 7, 1)
FIELD(HFGWTR_EL2, APIBKEY, 8, 1)
FIELD(HFGWTR_EL2, CONTEXTIDR_EL1, 11, 1)
FIELD(HFGWTR_EL2, CPACR_EL1, 12, 1)
FIELD(HFGWTR_EL2, CSSELR_EL1, 13, 1)
FIELD(HFGWTR_EL2, ESR_EL1, 16, 1)
FIELD(HFGWTR_EL2, FAR_EL1, 17, 1)
FIELD(HFGWTR_EL2, LORC_EL1, 19, 1)
FIELD(HFGWTR_EL2, LOREA_EL1, 20, 1)
FIELD(HFGWTR_EL2, LORN_EL1, 22, 1)
FIELD(HFGWTR_EL2, LORSA_EL1, 23, 1)
FIELD(HFGWTR_EL2, MAIR_EL1, 24, 1)
FIELD(HFGWTR_EL2, PAR_EL1, 27, 1)
FIELD(HFGWTR_EL2, SCTLR_EL1, 29, 1)
FIELD(HFGWTR_EL2, SCXTNUM_EL1, 30, 1)
FIELD(HFGWTR_EL2, SCXTNUM_EL0, 31, 1)
FIELD(HFGWTR_EL2, TCR_EL1, 32, 1)
FIELD(HFGWTR_EL2, TPIDR_EL1, 33, 1)
FIELD(HFGWTR_EL2, TPIDRRO_EL0, 34, 1)
FIELD(HFGWTR_EL2, TPIDR_EL0, 35, 1)
FIELD(HFGWTR_EL2, TTBR0_EL1, 36, 1)
FIELD(HFGWTR_EL2, TTBR1_EL1, 37, 1)
FIELD(HFGWTR_EL2, VBAR_EL1, 38, 1)
FIELD(HFGWTR_EL2, ICC_IGRPENN_EL1, 39, 1)
FIELD(HFGWTR_EL2, ERRSELR_EL1, 41, 1)
FIELD(HFGWTR_EL2, ERXCTLR_EL1, 43, 1)
FIELD(HFGWTR_EL2, ERXSTATUS_EL1, 44, 1)
FIELD(HFGWTR_EL2, ERXMISCN_EL1, 45, 1)
FIELD(HFGWTR_EL2, ERXPFGCTL_EL1, 47, 1)
FIELD(HFGWTR_EL2, ERXPFGCDN_EL1, 48, 1)
FIELD(HFGWTR_EL2, ERXADDR_EL1, 49, 1)
FIELD(HFGWTR_EL2, NACCDATA_EL1, 50, 1)
FIELD(HFGWTR_EL2, NSMPRI_EL1, 54, 1)
FIELD(HFGWTR_EL2, NTPIDR2_EL0, 55, 1)
FIELD(HFGITR_EL2, ICIALLUIS, 0, 1)
FIELD(HFGITR_EL2, ICIALLU, 1, 1)
FIELD(HFGITR_EL2, ICIVAU, 2, 1)
FIELD(HFGITR_EL2, DCIVAC, 3, 1)
FIELD(HFGITR_EL2, DCISW, 4, 1)
FIELD(HFGITR_EL2, DCCSW, 5, 1)
FIELD(HFGITR_EL2, DCCISW, 6, 1)
FIELD(HFGITR_EL2, DCCVAU, 7, 1)
FIELD(HFGITR_EL2, DCCVAP, 8, 1)
FIELD(HFGITR_EL2, DCCVADP, 9, 1)
FIELD(HFGITR_EL2, DCCIVAC, 10, 1)
FIELD(HFGITR_EL2, DCZVA, 11, 1)
FIELD(HFGITR_EL2, ATS1E1R, 12, 1)
FIELD(HFGITR_EL2, ATS1E1W, 13, 1)
FIELD(HFGITR_EL2, ATS1E0R, 14, 1)
FIELD(HFGITR_EL2, ATS1E0W, 15, 1)
FIELD(HFGITR_EL2, ATS1E1RP, 16, 1)
FIELD(HFGITR_EL2, ATS1E1WP, 17, 1)
FIELD(HFGITR_EL2, TLBIVMALLE1OS, 18, 1)
FIELD(HFGITR_EL2, TLBIVAE1OS, 19, 1)
FIELD(HFGITR_EL2, TLBIASIDE1OS, 20, 1)
FIELD(HFGITR_EL2, TLBIVAAE1OS, 21, 1)
FIELD(HFGITR_EL2, TLBIVALE1OS, 22, 1)
FIELD(HFGITR_EL2, TLBIVAALE1OS, 23, 1)
FIELD(HFGITR_EL2, TLBIRVAE1OS, 24, 1)
FIELD(HFGITR_EL2, TLBIRVAAE1OS, 25, 1)
FIELD(HFGITR_EL2, TLBIRVALE1OS, 26, 1)
FIELD(HFGITR_EL2, TLBIRVAALE1OS, 27, 1)
FIELD(HFGITR_EL2, TLBIVMALLE1IS, 28, 1)
FIELD(HFGITR_EL2, TLBIVAE1IS, 29, 1)
FIELD(HFGITR_EL2, TLBIASIDE1IS, 30, 1)
FIELD(HFGITR_EL2, TLBIVAAE1IS, 31, 1)
FIELD(HFGITR_EL2, TLBIVALE1IS, 32, 1)
FIELD(HFGITR_EL2, TLBIVAALE1IS, 33, 1)
FIELD(HFGITR_EL2, TLBIRVAE1IS, 34, 1)
FIELD(HFGITR_EL2, TLBIRVAAE1IS, 35, 1)
FIELD(HFGITR_EL2, TLBIRVALE1IS, 36, 1)
FIELD(HFGITR_EL2, TLBIRVAALE1IS, 37, 1)
FIELD(HFGITR_EL2, TLBIRVAE1, 38, 1)
FIELD(HFGITR_EL2, TLBIRVAAE1, 39, 1)
FIELD(HFGITR_EL2, TLBIRVALE1, 40, 1)
FIELD(HFGITR_EL2, TLBIRVAALE1, 41, 1)
FIELD(HFGITR_EL2, TLBIVMALLE1, 42, 1)
FIELD(HFGITR_EL2, TLBIVAE1, 43, 1)
FIELD(HFGITR_EL2, TLBIASIDE1, 44, 1)
FIELD(HFGITR_EL2, TLBIVAAE1, 45, 1)
FIELD(HFGITR_EL2, TLBIVALE1, 46, 1)
FIELD(HFGITR_EL2, TLBIVAALE1, 47, 1)
FIELD(HFGITR_EL2, CFPRCTX, 48, 1)
FIELD(HFGITR_EL2, DVPRCTX, 49, 1)
FIELD(HFGITR_EL2, CPPRCTX, 50, 1)
FIELD(HFGITR_EL2, ERET, 51, 1)
FIELD(HFGITR_EL2, SVC_EL0, 52, 1)
FIELD(HFGITR_EL2, SVC_EL1, 53, 1)
FIELD(HFGITR_EL2, DCCVAC, 54, 1)
FIELD(HFGITR_EL2, NBRBINJ, 55, 1)
FIELD(HFGITR_EL2, NBRBIALL, 56, 1)
FIELD(HDFGRTR_EL2, DBGBCRN_EL1, 0, 1)
FIELD(HDFGRTR_EL2, DBGBVRN_EL1, 1, 1)
FIELD(HDFGRTR_EL2, DBGWCRN_EL1, 2, 1)
FIELD(HDFGRTR_EL2, DBGWVRN_EL1, 3, 1)
FIELD(HDFGRTR_EL2, MDSCR_EL1, 4, 1)
FIELD(HDFGRTR_EL2, DBGCLAIM, 5, 1)
FIELD(HDFGRTR_EL2, DBGAUTHSTATUS_EL1, 6, 1)
FIELD(HDFGRTR_EL2, DBGPRCR_EL1, 7, 1)
/* 8: RES0: OSLAR_EL1 is WO */
FIELD(HDFGRTR_EL2, OSLSR_EL1, 9, 1)
FIELD(HDFGRTR_EL2, OSECCR_EL1, 10, 1)
FIELD(HDFGRTR_EL2, OSDLR_EL1, 11, 1)
FIELD(HDFGRTR_EL2, PMEVCNTRN_EL0, 12, 1)
FIELD(HDFGRTR_EL2, PMEVTYPERN_EL0, 13, 1)
FIELD(HDFGRTR_EL2, PMCCFILTR_EL0, 14, 1)
FIELD(HDFGRTR_EL2, PMCCNTR_EL0, 15, 1)
FIELD(HDFGRTR_EL2, PMCNTEN, 16, 1)
FIELD(HDFGRTR_EL2, PMINTEN, 17, 1)
FIELD(HDFGRTR_EL2, PMOVS, 18, 1)
FIELD(HDFGRTR_EL2, PMSELR_EL0, 19, 1)
/* 20: RES0: PMSWINC_EL0 is WO */
/* 21: RES0: PMCR_EL0 is WO */
FIELD(HDFGRTR_EL2, PMMIR_EL1, 22, 1)
FIELD(HDFGRTR_EL2, PMBLIMITR_EL1, 23, 1)
FIELD(HDFGRTR_EL2, PMBPTR_EL1, 24, 1)
FIELD(HDFGRTR_EL2, PMBSR_EL1, 25, 1)
FIELD(HDFGRTR_EL2, PMSCR_EL1, 26, 1)
FIELD(HDFGRTR_EL2, PMSEVFR_EL1, 27, 1)
FIELD(HDFGRTR_EL2, PMSFCR_EL1, 28, 1)
FIELD(HDFGRTR_EL2, PMSICR_EL1, 29, 1)
FIELD(HDFGRTR_EL2, PMSIDR_EL1, 30, 1)
FIELD(HDFGRTR_EL2, PMSIRR_EL1, 31, 1)
FIELD(HDFGRTR_EL2, PMSLATFR_EL1, 32, 1)
FIELD(HDFGRTR_EL2, TRC, 33, 1)
FIELD(HDFGRTR_EL2, TRCAUTHSTATUS, 34, 1)
FIELD(HDFGRTR_EL2, TRCAUXCTLR, 35, 1)
FIELD(HDFGRTR_EL2, TRCCLAIM, 36, 1)
FIELD(HDFGRTR_EL2, TRCCNTVRn, 37, 1)
/* 38, 39: RES0 */
FIELD(HDFGRTR_EL2, TRCID, 40, 1)
FIELD(HDFGRTR_EL2, TRCIMSPECN, 41, 1)
/* 42: RES0: TRCOSLAR is WO */
FIELD(HDFGRTR_EL2, TRCOSLSR, 43, 1)
FIELD(HDFGRTR_EL2, TRCPRGCTLR, 44, 1)
FIELD(HDFGRTR_EL2, TRCSEQSTR, 45, 1)
FIELD(HDFGRTR_EL2, TRCSSCSRN, 46, 1)
FIELD(HDFGRTR_EL2, TRCSTATR, 47, 1)
FIELD(HDFGRTR_EL2, TRCVICTLR, 48, 1)
/* 49: RES0: TRFCR_EL1 is WO */
FIELD(HDFGRTR_EL2, TRBBASER_EL1, 50, 1)
FIELD(HDFGRTR_EL2, TRBIDR_EL1, 51, 1)
FIELD(HDFGRTR_EL2, TRBLIMITR_EL1, 52, 1)
FIELD(HDFGRTR_EL2, TRBMAR_EL1, 53, 1)
FIELD(HDFGRTR_EL2, TRBPTR_EL1, 54, 1)
FIELD(HDFGRTR_EL2, TRBSR_EL1, 55, 1)
FIELD(HDFGRTR_EL2, TRBTRG_EL1, 56, 1)
FIELD(HDFGRTR_EL2, PMUSERENR_EL0, 57, 1)
FIELD(HDFGRTR_EL2, PMCEIDN_EL0, 58, 1)
FIELD(HDFGRTR_EL2, NBRBIDR, 59, 1)
FIELD(HDFGRTR_EL2, NBRBCTL, 60, 1)
FIELD(HDFGRTR_EL2, NBRBDATA, 61, 1)
FIELD(HDFGRTR_EL2, NPMSNEVFR_EL1, 62, 1)
FIELD(HDFGRTR_EL2, PMBIDR_EL1, 63, 1)
/*
* These match HDFGRTR_EL2, but bits for RO registers are RES0.
* A few bits are for WO registers, where the HDFGRTR_EL2 bit is RES0.
*/
FIELD(HDFGWTR_EL2, DBGBCRN_EL1, 0, 1)
FIELD(HDFGWTR_EL2, DBGBVRN_EL1, 1, 1)
FIELD(HDFGWTR_EL2, DBGWCRN_EL1, 2, 1)
FIELD(HDFGWTR_EL2, DBGWVRN_EL1, 3, 1)
FIELD(HDFGWTR_EL2, MDSCR_EL1, 4, 1)
FIELD(HDFGWTR_EL2, DBGCLAIM, 5, 1)
FIELD(HDFGWTR_EL2, DBGPRCR_EL1, 7, 1)
FIELD(HDFGWTR_EL2, OSLAR_EL1, 8, 1)
FIELD(HDFGWTR_EL2, OSLSR_EL1, 9, 1)
FIELD(HDFGWTR_EL2, OSECCR_EL1, 10, 1)
FIELD(HDFGWTR_EL2, OSDLR_EL1, 11, 1)
FIELD(HDFGWTR_EL2, PMEVCNTRN_EL0, 12, 1)
FIELD(HDFGWTR_EL2, PMEVTYPERN_EL0, 13, 1)
FIELD(HDFGWTR_EL2, PMCCFILTR_EL0, 14, 1)
FIELD(HDFGWTR_EL2, PMCCNTR_EL0, 15, 1)
FIELD(HDFGWTR_EL2, PMCNTEN, 16, 1)
FIELD(HDFGWTR_EL2, PMINTEN, 17, 1)
FIELD(HDFGWTR_EL2, PMOVS, 18, 1)
FIELD(HDFGWTR_EL2, PMSELR_EL0, 19, 1)
FIELD(HDFGWTR_EL2, PMSWINC_EL0, 20, 1)
FIELD(HDFGWTR_EL2, PMCR_EL0, 21, 1)
FIELD(HDFGWTR_EL2, PMBLIMITR_EL1, 23, 1)
FIELD(HDFGWTR_EL2, PMBPTR_EL1, 24, 1)
FIELD(HDFGWTR_EL2, PMBSR_EL1, 25, 1)
FIELD(HDFGWTR_EL2, PMSCR_EL1, 26, 1)
FIELD(HDFGWTR_EL2, PMSEVFR_EL1, 27, 1)
FIELD(HDFGWTR_EL2, PMSFCR_EL1, 28, 1)
FIELD(HDFGWTR_EL2, PMSICR_EL1, 29, 1)
FIELD(HDFGWTR_EL2, PMSIRR_EL1, 31, 1)
FIELD(HDFGWTR_EL2, PMSLATFR_EL1, 32, 1)
FIELD(HDFGWTR_EL2, TRC, 33, 1)
FIELD(HDFGWTR_EL2, TRCAUXCTLR, 35, 1)
FIELD(HDFGWTR_EL2, TRCCLAIM, 36, 1)
FIELD(HDFGWTR_EL2, TRCCNTVRn, 37, 1)
FIELD(HDFGWTR_EL2, TRCIMSPECN, 41, 1)
FIELD(HDFGWTR_EL2, TRCOSLAR, 42, 1)
FIELD(HDFGWTR_EL2, TRCPRGCTLR, 44, 1)
FIELD(HDFGWTR_EL2, TRCSEQSTR, 45, 1)
FIELD(HDFGWTR_EL2, TRCSSCSRN, 46, 1)
FIELD(HDFGWTR_EL2, TRCVICTLR, 48, 1)
FIELD(HDFGWTR_EL2, TRFCR_EL1, 49, 1)
FIELD(HDFGWTR_EL2, TRBBASER_EL1, 50, 1)
FIELD(HDFGWTR_EL2, TRBLIMITR_EL1, 52, 1)
FIELD(HDFGWTR_EL2, TRBMAR_EL1, 53, 1)
FIELD(HDFGWTR_EL2, TRBPTR_EL1, 54, 1)
FIELD(HDFGWTR_EL2, TRBSR_EL1, 55, 1)
FIELD(HDFGWTR_EL2, TRBTRG_EL1, 56, 1)
FIELD(HDFGWTR_EL2, PMUSERENR_EL0, 57, 1)
FIELD(HDFGWTR_EL2, NBRBCTL, 60, 1)
FIELD(HDFGWTR_EL2, NBRBDATA, 61, 1)
FIELD(HDFGWTR_EL2, NPMSNEVFR_EL1, 62, 1)
/* Which fine-grained trap bit register to check, if any */
FIELD(FGT, TYPE, 10, 3)
FIELD(FGT, REV, 9, 1) /* Is bit sense reversed? */
FIELD(FGT, IDX, 6, 3) /* Index within a uint64_t[] array */
FIELD(FGT, BITPOS, 0, 6) /* Bit position within the uint64_t */
/*
* Macros to define FGT_##bitname enum constants to use in ARMCPRegInfo::fgt
* fields. We assume for brevity's sake that there are no duplicated
* bit names across the various FGT registers.
*/
#define DO_BIT(REG, BITNAME) \
FGT_##BITNAME = FGT_##REG | R_##REG##_EL2_##BITNAME##_SHIFT
/* Some bits have reversed sense, so 0 means trap and 1 means not */
#define DO_REV_BIT(REG, BITNAME) \
FGT_##BITNAME = FGT_##REG | FGT_REV | R_##REG##_EL2_##BITNAME##_SHIFT
typedef enum FGTBit {
/*
* These bits tell us which register arrays to use:
* if FGT_R is set then reads are checked against fgt_read[];
* if FGT_W is set then writes are checked against fgt_write[];
* if FGT_EXEC is set then all accesses are checked against fgt_exec[].
*
* For almost all bits in the R/W register pairs, the bit exists in
* both registers for a RW register, in HFGRTR/HDFGRTR for a RO register
* with the corresponding HFGWTR/HDFGTWTR bit being RES0, and vice-versa
* for a WO register. There are unfortunately a couple of exceptions
* (PMCR_EL0, TRFCR_EL1) where the register being trapped is RW but
* the FGT system only allows trapping of writes, not reads.
*
* Note that we arrange these bits so that a 0 FGTBit means "no trap".
*/
FGT_R = 1 << R_FGT_TYPE_SHIFT,
FGT_W = 2 << R_FGT_TYPE_SHIFT,
FGT_EXEC = 4 << R_FGT_TYPE_SHIFT,
FGT_RW = FGT_R | FGT_W,
/* Bit to identify whether trap bit is reversed sense */
FGT_REV = R_FGT_REV_MASK,
/*
* If a bit exists in HFGRTR/HDFGRTR then either the register being
* trapped is RO or the bit also exists in HFGWTR/HDFGWTR, so we either
* want to trap for both reads and writes or else it's harmless to mark
* it as trap-on-writes.
* If a bit exists only in HFGWTR/HDFGWTR then either the register being
* trapped is WO, or else it is one of the two oddball special cases
* which are RW but have only a write trap. We mark these as only
* FGT_W so we get the right behaviour for those special cases.
* (If a bit was added in future that provided only a read trap for an
* RW register we'd need to do something special to get the FGT_R bit
* only. But this seems unlikely to happen.)
*
* So for the DO_BIT/DO_REV_BIT macros: use FGT_HFGRTR/FGT_HDFGRTR if
* the bit exists in that register. Otherwise use FGT_HFGWTR/FGT_HDFGWTR.
*/
FGT_HFGRTR = FGT_RW | (FGTREG_HFGRTR << R_FGT_IDX_SHIFT),
FGT_HFGWTR = FGT_W | (FGTREG_HFGWTR << R_FGT_IDX_SHIFT),
FGT_HDFGRTR = FGT_RW | (FGTREG_HDFGRTR << R_FGT_IDX_SHIFT),
FGT_HDFGWTR = FGT_W | (FGTREG_HDFGWTR << R_FGT_IDX_SHIFT),
FGT_HFGITR = FGT_EXEC | (FGTREG_HFGITR << R_FGT_IDX_SHIFT),
/* Trap bits in HFGRTR_EL2 / HFGWTR_EL2, starting from bit 0. */
DO_BIT(HFGRTR, AFSR0_EL1),
DO_BIT(HFGRTR, AFSR1_EL1),
DO_BIT(HFGRTR, AIDR_EL1),
DO_BIT(HFGRTR, AMAIR_EL1),
DO_BIT(HFGRTR, APDAKEY),
DO_BIT(HFGRTR, APDBKEY),
DO_BIT(HFGRTR, APGAKEY),
DO_BIT(HFGRTR, APIAKEY),
DO_BIT(HFGRTR, APIBKEY),
DO_BIT(HFGRTR, CCSIDR_EL1),
DO_BIT(HFGRTR, CLIDR_EL1),
DO_BIT(HFGRTR, CONTEXTIDR_EL1),
DO_BIT(HFGRTR, CPACR_EL1),
DO_BIT(HFGRTR, CSSELR_EL1),
DO_BIT(HFGRTR, CTR_EL0),
DO_BIT(HFGRTR, DCZID_EL0),
DO_BIT(HFGRTR, ESR_EL1),
DO_BIT(HFGRTR, FAR_EL1),
DO_BIT(HFGRTR, ISR_EL1),
DO_BIT(HFGRTR, LORC_EL1),
DO_BIT(HFGRTR, LOREA_EL1),
DO_BIT(HFGRTR, LORID_EL1),
DO_BIT(HFGRTR, LORN_EL1),
DO_BIT(HFGRTR, LORSA_EL1),
DO_BIT(HFGRTR, MAIR_EL1),
DO_BIT(HFGRTR, MIDR_EL1),
DO_BIT(HFGRTR, MPIDR_EL1),
DO_BIT(HFGRTR, PAR_EL1),
DO_BIT(HFGRTR, REVIDR_EL1),
DO_BIT(HFGRTR, SCTLR_EL1),
DO_BIT(HFGRTR, SCXTNUM_EL1),
DO_BIT(HFGRTR, SCXTNUM_EL0),
DO_BIT(HFGRTR, TCR_EL1),
DO_BIT(HFGRTR, TPIDR_EL1),
DO_BIT(HFGRTR, TPIDRRO_EL0),
DO_BIT(HFGRTR, TPIDR_EL0),
DO_BIT(HFGRTR, TTBR0_EL1),
DO_BIT(HFGRTR, TTBR1_EL1),
DO_BIT(HFGRTR, VBAR_EL1),
DO_BIT(HFGRTR, ICC_IGRPENN_EL1),
DO_BIT(HFGRTR, ERRIDR_EL1),
DO_REV_BIT(HFGRTR, NSMPRI_EL1),
DO_REV_BIT(HFGRTR, NTPIDR2_EL0),
/* Trap bits in HDFGRTR_EL2 / HDFGWTR_EL2, starting from bit 0. */
DO_BIT(HDFGRTR, DBGBCRN_EL1),
DO_BIT(HDFGRTR, DBGBVRN_EL1),
DO_BIT(HDFGRTR, DBGWCRN_EL1),
DO_BIT(HDFGRTR, DBGWVRN_EL1),
DO_BIT(HDFGRTR, MDSCR_EL1),
DO_BIT(HDFGRTR, DBGCLAIM),
DO_BIT(HDFGWTR, OSLAR_EL1),
DO_BIT(HDFGRTR, OSLSR_EL1),
DO_BIT(HDFGRTR, OSECCR_EL1),
DO_BIT(HDFGRTR, OSDLR_EL1),
DO_BIT(HDFGRTR, PMEVCNTRN_EL0),
DO_BIT(HDFGRTR, PMEVTYPERN_EL0),
DO_BIT(HDFGRTR, PMCCFILTR_EL0),
DO_BIT(HDFGRTR, PMCCNTR_EL0),
DO_BIT(HDFGRTR, PMCNTEN),
DO_BIT(HDFGRTR, PMINTEN),
DO_BIT(HDFGRTR, PMOVS),
DO_BIT(HDFGRTR, PMSELR_EL0),
DO_BIT(HDFGWTR, PMSWINC_EL0),
DO_BIT(HDFGWTR, PMCR_EL0),
DO_BIT(HDFGRTR, PMMIR_EL1),
DO_BIT(HDFGRTR, PMCEIDN_EL0),
/* Trap bits in HFGITR_EL2, starting from bit 0 */
DO_BIT(HFGITR, ICIALLUIS),
DO_BIT(HFGITR, ICIALLU),
DO_BIT(HFGITR, ICIVAU),
DO_BIT(HFGITR, DCIVAC),
DO_BIT(HFGITR, DCISW),
DO_BIT(HFGITR, DCCSW),
DO_BIT(HFGITR, DCCISW),
DO_BIT(HFGITR, DCCVAU),
DO_BIT(HFGITR, DCCVAP),
DO_BIT(HFGITR, DCCVADP),
DO_BIT(HFGITR, DCCIVAC),
DO_BIT(HFGITR, DCZVA),
DO_BIT(HFGITR, ATS1E1R),
DO_BIT(HFGITR, ATS1E1W),
DO_BIT(HFGITR, ATS1E0R),
DO_BIT(HFGITR, ATS1E0W),
DO_BIT(HFGITR, ATS1E1RP),
DO_BIT(HFGITR, ATS1E1WP),
DO_BIT(HFGITR, TLBIVMALLE1OS),
DO_BIT(HFGITR, TLBIVAE1OS),
DO_BIT(HFGITR, TLBIASIDE1OS),
DO_BIT(HFGITR, TLBIVAAE1OS),
DO_BIT(HFGITR, TLBIVALE1OS),
DO_BIT(HFGITR, TLBIVAALE1OS),
DO_BIT(HFGITR, TLBIRVAE1OS),
DO_BIT(HFGITR, TLBIRVAAE1OS),
DO_BIT(HFGITR, TLBIRVALE1OS),
DO_BIT(HFGITR, TLBIRVAALE1OS),
DO_BIT(HFGITR, TLBIVMALLE1IS),
DO_BIT(HFGITR, TLBIVAE1IS),
DO_BIT(HFGITR, TLBIASIDE1IS),
DO_BIT(HFGITR, TLBIVAAE1IS),
DO_BIT(HFGITR, TLBIVALE1IS),
DO_BIT(HFGITR, TLBIVAALE1IS),
DO_BIT(HFGITR, TLBIRVAE1IS),
DO_BIT(HFGITR, TLBIRVAAE1IS),
DO_BIT(HFGITR, TLBIRVALE1IS),
DO_BIT(HFGITR, TLBIRVAALE1IS),
DO_BIT(HFGITR, TLBIRVAE1),
DO_BIT(HFGITR, TLBIRVAAE1),
DO_BIT(HFGITR, TLBIRVALE1),
DO_BIT(HFGITR, TLBIRVAALE1),
DO_BIT(HFGITR, TLBIVMALLE1),
DO_BIT(HFGITR, TLBIVAE1),
DO_BIT(HFGITR, TLBIASIDE1),
DO_BIT(HFGITR, TLBIVAAE1),
DO_BIT(HFGITR, TLBIVALE1),
DO_BIT(HFGITR, TLBIVAALE1),
DO_BIT(HFGITR, CFPRCTX),
DO_BIT(HFGITR, DVPRCTX),
DO_BIT(HFGITR, CPPRCTX),
DO_BIT(HFGITR, DCCVAC),
} FGTBit;
#undef DO_BIT
#undef DO_REV_BIT
typedef struct ARMCPRegInfo ARMCPRegInfo; typedef struct ARMCPRegInfo ARMCPRegInfo;
/* /*
@ -284,6 +759,11 @@ struct ARMCPRegInfo {
CPAccessRights access; CPAccessRights access;
/* Security state: ARM_CP_SECSTATE_* bits/values */ /* Security state: ARM_CP_SECSTATE_* bits/values */
CPSecureState secure; CPSecureState secure;
/*
* Which fine-grained trap register bit to check, if any. This
* value encodes both the trap register and bit within it.
*/
FGTBit fgt;
/* /*
* The opaque pointer passed to define_arm_cp_regs_with_opaque() when * The opaque pointer passed to define_arm_cp_regs_with_opaque() when
* this register was defined: can be used to hand data through to the * this register was defined: can be used to hand data through to the

View File

@ -529,6 +529,16 @@ typedef struct CPUArchState {
uint64_t disr_el1; uint64_t disr_el1;
uint64_t vdisr_el2; uint64_t vdisr_el2;
uint64_t vsesr_el2; uint64_t vsesr_el2;
/*
* Fine-Grained Trap registers. We store these as arrays so the
* access checking code doesn't have to manually select
* HFGRTR_EL2 vs HFDFGRTR_EL2 etc when looking up the bit to test.
* FEAT_FGT2 will add more elements to these arrays.
*/
uint64_t fgt_read[2]; /* HFGRTR, HDFGRTR */
uint64_t fgt_write[2]; /* HFGWTR, HDFGWTR */
uint64_t fgt_exec[1]; /* HFGITR */
} cp15; } cp15;
struct { struct {
@ -3160,6 +3170,8 @@ FIELD(TBFLAG_ANY, FPEXC_EL, 8, 2)
/* Memory operations require alignment: SCTLR_ELx.A or CCR.UNALIGN_TRP */ /* Memory operations require alignment: SCTLR_ELx.A or CCR.UNALIGN_TRP */
FIELD(TBFLAG_ANY, ALIGN_MEM, 10, 1) FIELD(TBFLAG_ANY, ALIGN_MEM, 10, 1)
FIELD(TBFLAG_ANY, PSTATE__IL, 11, 1) FIELD(TBFLAG_ANY, PSTATE__IL, 11, 1)
FIELD(TBFLAG_ANY, FGT_ACTIVE, 12, 1)
FIELD(TBFLAG_ANY, FGT_SVC, 13, 1)
/* /*
* Bit usage when in AArch32 state, both A- and M-profile. * Bit usage when in AArch32 state, both A- and M-profile.
@ -3234,6 +3246,7 @@ FIELD(TBFLAG_A64, PSTATE_ZA, 23, 1)
FIELD(TBFLAG_A64, SVL, 24, 4) FIELD(TBFLAG_A64, SVL, 24, 4)
/* Indicates that SME Streaming mode is active, and SMCR_ELx.FA64 is not. */ /* Indicates that SME Streaming mode is active, and SMCR_ELx.FA64 is not. */
FIELD(TBFLAG_A64, SME_TRAP_NONSTREAMING, 28, 1) FIELD(TBFLAG_A64, SME_TRAP_NONSTREAMING, 28, 1)
FIELD(TBFLAG_A64, FGT_ERET, 29, 1)
/* /*
* Helpers for using the above. * Helpers for using the above.
@ -4164,6 +4177,11 @@ static inline bool isar_feature_aa64_tgran64_2(const ARMISARegisters *id)
return t >= 2 || (t == 0 && isar_feature_aa64_tgran64(id)); return t >= 2 || (t == 0 && isar_feature_aa64_tgran64(id));
} }
static inline bool isar_feature_aa64_fgt(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, FGT) != 0;
}
static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id) static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id)
{ {
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0; return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0;

View File

@ -1224,6 +1224,7 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 2); /* 16k stage2 supported */ t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 2); /* 16k stage2 supported */
t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN64_2, 2); /* 64k stage2 supported */ t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN64_2, 2); /* 64k stage2 supported */
t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 2); /* 4k stage2 supported */ t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 2); /* 4k stage2 supported */
t = FIELD_DP64(t, ID_AA64MMFR0, FGT, 1); /* FEAT_FGT */
cpu->isar.id_aa64mmfr0 = t; cpu->isar.id_aa64mmfr0 = t;
t = cpu->isar.id_aa64mmfr1; t = cpu->isar.id_aa64mmfr1;

View File

@ -599,6 +599,33 @@ static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
return CP_ACCESS_OK; return CP_ACCESS_OK;
} }
/*
* Check for traps to Debug Comms Channel registers. If FEAT_FGT
* is implemented then these are controlled by MDCR_EL2.TDCC for
* EL2 and MDCR_EL3.TDCC for EL3. They are also controlled by
* the general debug access trap bits MDCR_EL2.TDA and MDCR_EL3.TDA.
*/
static CPAccessResult access_tdcc(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
int el = arm_current_el(env);
uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
bool mdcr_el2_tda = (mdcr_el2 & MDCR_TDA) || (mdcr_el2 & MDCR_TDE) ||
(arm_hcr_el2_eff(env) & HCR_TGE);
bool mdcr_el2_tdcc = cpu_isar_feature(aa64_fgt, env_archcpu(env)) &&
(mdcr_el2 & MDCR_TDCC);
bool mdcr_el3_tdcc = cpu_isar_feature(aa64_fgt, env_archcpu(env)) &&
(env->cp15.mdcr_el3 & MDCR_TDCC);
if (el < 2 && (mdcr_el2_tda || mdcr_el2_tdcc)) {
return CP_ACCESS_TRAP_EL2;
}
if (el < 3 && ((env->cp15.mdcr_el3 & MDCR_TDA) || mdcr_el3_tdcc)) {
return CP_ACCESS_TRAP_EL3;
}
return CP_ACCESS_OK;
}
static void oslar_write(CPUARMState *env, const ARMCPRegInfo *ri, static void oslar_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value) uint64_t value)
{ {
@ -672,6 +699,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
{ .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH, { .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
.access = PL1_RW, .accessfn = access_tda, .access = PL1_RW, .accessfn = access_tda,
.fgt = FGT_MDSCR_EL1,
.fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
.resetvalue = 0 }, .resetvalue = 0 },
/* /*
@ -680,7 +708,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
*/ */
{ .name = "MDCCSR_EL0", .state = ARM_CP_STATE_AA64, { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 2, .opc1 = 3, .crn = 0, .crm = 1, .opc2 = 0, .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 1, .opc2 = 0,
.access = PL0_R, .accessfn = access_tda, .access = PL0_R, .accessfn = access_tdcc,
.type = ARM_CP_CONST, .resetvalue = 0 }, .type = ARM_CP_CONST, .resetvalue = 0 },
/* /*
* OSDTRRX_EL1/OSDTRTX_EL1 are used for save and restore of DBGDTRRX_EL0. * OSDTRRX_EL1/OSDTRTX_EL1 are used for save and restore of DBGDTRRX_EL0.
@ -688,11 +716,11 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
*/ */
{ .name = "OSDTRRX_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, { .name = "OSDTRRX_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14,
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 2, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 2,
.access = PL1_RW, .accessfn = access_tda, .access = PL1_RW, .accessfn = access_tdcc,
.type = ARM_CP_CONST, .resetvalue = 0 }, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "OSDTRTX_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, { .name = "OSDTRTX_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14,
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2,
.access = PL1_RW, .accessfn = access_tda, .access = PL1_RW, .accessfn = access_tdcc,
.type = ARM_CP_CONST, .resetvalue = 0 }, .type = ARM_CP_CONST, .resetvalue = 0 },
/* /*
* OSECCR_EL1 provides a mechanism for an operating system * OSECCR_EL1 provides a mechanism for an operating system
@ -702,6 +730,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
{ .name = "OSECCR_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, { .name = "OSECCR_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14,
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 2, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 2,
.access = PL1_RW, .accessfn = access_tda, .access = PL1_RW, .accessfn = access_tda,
.fgt = FGT_OSECCR_EL1,
.type = ARM_CP_CONST, .resetvalue = 0 }, .type = ARM_CP_CONST, .resetvalue = 0 },
/* /*
* DBGDSCRint[15,12,5:2] map to MDSCR_EL1[15,12,5:2]. Map all bits as * DBGDSCRint[15,12,5:2] map to MDSCR_EL1[15,12,5:2]. Map all bits as
@ -717,16 +746,19 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4,
.access = PL1_W, .type = ARM_CP_NO_RAW, .access = PL1_W, .type = ARM_CP_NO_RAW,
.accessfn = access_tdosa, .accessfn = access_tdosa,
.fgt = FGT_OSLAR_EL1,
.writefn = oslar_write }, .writefn = oslar_write },
{ .name = "OSLSR_EL1", .state = ARM_CP_STATE_BOTH, { .name = "OSLSR_EL1", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 4, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 4,
.access = PL1_R, .resetvalue = 10, .access = PL1_R, .resetvalue = 10,
.accessfn = access_tdosa, .accessfn = access_tdosa,
.fgt = FGT_OSLSR_EL1,
.fieldoffset = offsetof(CPUARMState, cp15.oslsr_el1) }, .fieldoffset = offsetof(CPUARMState, cp15.oslsr_el1) },
/* Dummy OSDLR_EL1: 32-bit Linux will read this */ /* Dummy OSDLR_EL1: 32-bit Linux will read this */
{ .name = "OSDLR_EL1", .state = ARM_CP_STATE_BOTH, { .name = "OSDLR_EL1", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 4, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 4,
.access = PL1_RW, .accessfn = access_tdosa, .access = PL1_RW, .accessfn = access_tdosa,
.fgt = FGT_OSDLR_EL1,
.writefn = osdlr_write, .writefn = osdlr_write,
.fieldoffset = offsetof(CPUARMState, cp15.osdlr_el1) }, .fieldoffset = offsetof(CPUARMState, cp15.osdlr_el1) },
/* /*
@ -752,7 +784,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
*/ */
{ .name = "MDCCINT_EL1", .state = ARM_CP_STATE_BOTH, { .name = "MDCCINT_EL1", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0,
.access = PL1_RW, .accessfn = access_tda, .access = PL1_RW, .accessfn = access_tdcc,
.type = ARM_CP_NOP }, .type = ARM_CP_NOP },
/* /*
* Dummy DBGCLAIM registers. * Dummy DBGCLAIM registers.
@ -763,10 +795,12 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 6, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 6,
.type = ARM_CP_ALIAS, .type = ARM_CP_ALIAS,
.access = PL1_RW, .accessfn = access_tda, .access = PL1_RW, .accessfn = access_tda,
.fgt = FGT_DBGCLAIM,
.writefn = dbgclaimset_write, .readfn = dbgclaimset_read }, .writefn = dbgclaimset_write, .readfn = dbgclaimset_read },
{ .name = "DBGCLAIMCLR_EL1", .state = ARM_CP_STATE_BOTH, { .name = "DBGCLAIMCLR_EL1", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 6, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 6,
.access = PL1_RW, .accessfn = access_tda, .access = PL1_RW, .accessfn = access_tda,
.fgt = FGT_DBGCLAIM,
.writefn = dbgclaimclr_write, .raw_writefn = raw_write, .writefn = dbgclaimclr_write, .raw_writefn = raw_write,
.fieldoffset = offsetof(CPUARMState, cp15.dbgclaim) }, .fieldoffset = offsetof(CPUARMState, cp15.dbgclaim) },
}; };
@ -1127,12 +1161,14 @@ void define_debug_regs(ARMCPU *cpu)
{ .name = dbgbvr_el1_name, .state = ARM_CP_STATE_BOTH, { .name = dbgbvr_el1_name, .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4,
.access = PL1_RW, .accessfn = access_tda, .access = PL1_RW, .accessfn = access_tda,
.fgt = FGT_DBGBVRN_EL1,
.fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]), .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]),
.writefn = dbgbvr_write, .raw_writefn = raw_write .writefn = dbgbvr_write, .raw_writefn = raw_write
}, },
{ .name = dbgbcr_el1_name, .state = ARM_CP_STATE_BOTH, { .name = dbgbcr_el1_name, .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5,
.access = PL1_RW, .accessfn = access_tda, .access = PL1_RW, .accessfn = access_tda,
.fgt = FGT_DBGBCRN_EL1,
.fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]), .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]),
.writefn = dbgbcr_write, .raw_writefn = raw_write .writefn = dbgbcr_write, .raw_writefn = raw_write
}, },
@ -1149,12 +1185,14 @@ void define_debug_regs(ARMCPU *cpu)
{ .name = dbgwvr_el1_name, .state = ARM_CP_STATE_BOTH, { .name = dbgwvr_el1_name, .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6,
.access = PL1_RW, .accessfn = access_tda, .access = PL1_RW, .accessfn = access_tda,
.fgt = FGT_DBGWVRN_EL1,
.fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]), .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]),
.writefn = dbgwvr_write, .raw_writefn = raw_write .writefn = dbgwvr_write, .raw_writefn = raw_write
}, },
{ .name = dbgwcr_el1_name, .state = ARM_CP_STATE_BOTH, { .name = dbgwcr_el1_name, .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7,
.access = PL1_RW, .accessfn = access_tda, .access = PL1_RW, .accessfn = access_tda,
.fgt = FGT_DBGWCRN_EL1,
.fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]), .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]),
.writefn = dbgwcr_write, .raw_writefn = raw_write .writefn = dbgwcr_write, .raw_writefn = raw_write
}, },

File diff suppressed because it is too large Load Diff

View File

@ -80,6 +80,33 @@
#define SYSREG_PMCCNTR_EL0 SYSREG(3, 3, 9, 13, 0) #define SYSREG_PMCCNTR_EL0 SYSREG(3, 3, 9, 13, 0)
#define SYSREG_PMCCFILTR_EL0 SYSREG(3, 3, 14, 15, 7) #define SYSREG_PMCCFILTR_EL0 SYSREG(3, 3, 14, 15, 7)
#define SYSREG_ICC_AP0R0_EL1 SYSREG(3, 0, 12, 8, 4)
#define SYSREG_ICC_AP0R1_EL1 SYSREG(3, 0, 12, 8, 5)
#define SYSREG_ICC_AP0R2_EL1 SYSREG(3, 0, 12, 8, 6)
#define SYSREG_ICC_AP0R3_EL1 SYSREG(3, 0, 12, 8, 7)
#define SYSREG_ICC_AP1R0_EL1 SYSREG(3, 0, 12, 9, 0)
#define SYSREG_ICC_AP1R1_EL1 SYSREG(3, 0, 12, 9, 1)
#define SYSREG_ICC_AP1R2_EL1 SYSREG(3, 0, 12, 9, 2)
#define SYSREG_ICC_AP1R3_EL1 SYSREG(3, 0, 12, 9, 3)
#define SYSREG_ICC_ASGI1R_EL1 SYSREG(3, 0, 12, 11, 6)
#define SYSREG_ICC_BPR0_EL1 SYSREG(3, 0, 12, 8, 3)
#define SYSREG_ICC_BPR1_EL1 SYSREG(3, 0, 12, 12, 3)
#define SYSREG_ICC_CTLR_EL1 SYSREG(3, 0, 12, 12, 4)
#define SYSREG_ICC_DIR_EL1 SYSREG(3, 0, 12, 11, 1)
#define SYSREG_ICC_EOIR0_EL1 SYSREG(3, 0, 12, 8, 1)
#define SYSREG_ICC_EOIR1_EL1 SYSREG(3, 0, 12, 12, 1)
#define SYSREG_ICC_HPPIR0_EL1 SYSREG(3, 0, 12, 8, 2)
#define SYSREG_ICC_HPPIR1_EL1 SYSREG(3, 0, 12, 12, 2)
#define SYSREG_ICC_IAR0_EL1 SYSREG(3, 0, 12, 8, 0)
#define SYSREG_ICC_IAR1_EL1 SYSREG(3, 0, 12, 12, 0)
#define SYSREG_ICC_IGRPEN0_EL1 SYSREG(3, 0, 12, 12, 6)
#define SYSREG_ICC_IGRPEN1_EL1 SYSREG(3, 0, 12, 12, 7)
#define SYSREG_ICC_PMR_EL1 SYSREG(3, 0, 4, 6, 0)
#define SYSREG_ICC_RPR_EL1 SYSREG(3, 0, 12, 11, 3)
#define SYSREG_ICC_SGI0R_EL1 SYSREG(3, 0, 12, 11, 7)
#define SYSREG_ICC_SGI1R_EL1 SYSREG(3, 0, 12, 11, 5)
#define SYSREG_ICC_SRE_EL1 SYSREG(3, 0, 12, 12, 5)
#define WFX_IS_WFE (1 << 0) #define WFX_IS_WFE (1 << 0)
#define TMR_CTL_ENABLE (1 << 0) #define TMR_CTL_ENABLE (1 << 0)
@ -788,6 +815,43 @@ static bool is_id_sysreg(uint32_t reg)
SYSREG_CRM(reg) < 8; SYSREG_CRM(reg) < 8;
} }
static uint32_t hvf_reg2cp_reg(uint32_t reg)
{
return ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
(reg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK,
(reg >> SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK,
(reg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK,
(reg >> SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK,
(reg >> SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK);
}
static bool hvf_sysreg_read_cp(CPUState *cpu, uint32_t reg, uint64_t *val)
{
ARMCPU *arm_cpu = ARM_CPU(cpu);
CPUARMState *env = &arm_cpu->env;
const ARMCPRegInfo *ri;
ri = get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_reg2cp_reg(reg));
if (ri) {
if (ri->accessfn) {
if (ri->accessfn(env, ri, true) != CP_ACCESS_OK) {
return false;
}
}
if (ri->type & ARM_CP_CONST) {
*val = ri->resetvalue;
} else if (ri->readfn) {
*val = ri->readfn(env, ri);
} else {
*val = CPREG_FIELD64(env, ri);
}
trace_hvf_vgic_read(ri->name, *val);
return true;
}
return false;
}
static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt) static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
{ {
ARMCPU *arm_cpu = ARM_CPU(cpu); ARMCPU *arm_cpu = ARM_CPU(cpu);
@ -839,6 +903,36 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
case SYSREG_OSDLR_EL1: case SYSREG_OSDLR_EL1:
/* Dummy register */ /* Dummy register */
break; break;
case SYSREG_ICC_AP0R0_EL1:
case SYSREG_ICC_AP0R1_EL1:
case SYSREG_ICC_AP0R2_EL1:
case SYSREG_ICC_AP0R3_EL1:
case SYSREG_ICC_AP1R0_EL1:
case SYSREG_ICC_AP1R1_EL1:
case SYSREG_ICC_AP1R2_EL1:
case SYSREG_ICC_AP1R3_EL1:
case SYSREG_ICC_ASGI1R_EL1:
case SYSREG_ICC_BPR0_EL1:
case SYSREG_ICC_BPR1_EL1:
case SYSREG_ICC_DIR_EL1:
case SYSREG_ICC_EOIR0_EL1:
case SYSREG_ICC_EOIR1_EL1:
case SYSREG_ICC_HPPIR0_EL1:
case SYSREG_ICC_HPPIR1_EL1:
case SYSREG_ICC_IAR0_EL1:
case SYSREG_ICC_IAR1_EL1:
case SYSREG_ICC_IGRPEN0_EL1:
case SYSREG_ICC_IGRPEN1_EL1:
case SYSREG_ICC_PMR_EL1:
case SYSREG_ICC_SGI0R_EL1:
case SYSREG_ICC_SGI1R_EL1:
case SYSREG_ICC_SRE_EL1:
case SYSREG_ICC_CTLR_EL1:
/* Call the TCG sysreg handler. This is only safe for GICv3 regs. */
if (!hvf_sysreg_read_cp(cpu, reg, &val)) {
hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
}
break;
default: default:
if (is_id_sysreg(reg)) { if (is_id_sysreg(reg)) {
/* ID system registers read as RES0 */ /* ID system registers read as RES0 */
@ -944,6 +1038,33 @@ static void pmswinc_write(CPUARMState *env, uint64_t value)
} }
} }
static bool hvf_sysreg_write_cp(CPUState *cpu, uint32_t reg, uint64_t val)
{
ARMCPU *arm_cpu = ARM_CPU(cpu);
CPUARMState *env = &arm_cpu->env;
const ARMCPRegInfo *ri;
ri = get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_reg2cp_reg(reg));
if (ri) {
if (ri->accessfn) {
if (ri->accessfn(env, ri, false) != CP_ACCESS_OK) {
return false;
}
}
if (ri->writefn) {
ri->writefn(env, ri, val);
} else {
CPREG_FIELD64(env, ri) = val;
}
trace_hvf_vgic_write(ri->name, val);
return true;
}
return false;
}
static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
{ {
ARMCPU *arm_cpu = ARM_CPU(cpu); ARMCPU *arm_cpu = ARM_CPU(cpu);
@ -1021,6 +1142,36 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
case SYSREG_OSDLR_EL1: case SYSREG_OSDLR_EL1:
/* Dummy register */ /* Dummy register */
break; break;
case SYSREG_ICC_AP0R0_EL1:
case SYSREG_ICC_AP0R1_EL1:
case SYSREG_ICC_AP0R2_EL1:
case SYSREG_ICC_AP0R3_EL1:
case SYSREG_ICC_AP1R0_EL1:
case SYSREG_ICC_AP1R1_EL1:
case SYSREG_ICC_AP1R2_EL1:
case SYSREG_ICC_AP1R3_EL1:
case SYSREG_ICC_ASGI1R_EL1:
case SYSREG_ICC_BPR0_EL1:
case SYSREG_ICC_BPR1_EL1:
case SYSREG_ICC_CTLR_EL1:
case SYSREG_ICC_DIR_EL1:
case SYSREG_ICC_EOIR0_EL1:
case SYSREG_ICC_EOIR1_EL1:
case SYSREG_ICC_HPPIR0_EL1:
case SYSREG_ICC_HPPIR1_EL1:
case SYSREG_ICC_IAR0_EL1:
case SYSREG_ICC_IAR1_EL1:
case SYSREG_ICC_IGRPEN0_EL1:
case SYSREG_ICC_IGRPEN1_EL1:
case SYSREG_ICC_PMR_EL1:
case SYSREG_ICC_SGI0R_EL1:
case SYSREG_ICC_SGI1R_EL1:
case SYSREG_ICC_SRE_EL1:
/* Call the TCG sysreg handler. This is only safe for GICv3 regs. */
if (!hvf_sysreg_write_cp(cpu, reg, val)) {
hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
}
break;
default: default:
cpu_synchronize_state(cpu); cpu_synchronize_state(cpu);
trace_hvf_unhandled_sysreg_write(env->pc, reg, trace_hvf_unhandled_sysreg_write(env->pc, reg,

View File

@ -9,3 +9,5 @@ hvf_unknown_hvc(uint64_t x0) "unknown HVC! 0x%016"PRIx64
hvf_unknown_smc(uint64_t x0) "unknown SMC! 0x%016"PRIx64 hvf_unknown_smc(uint64_t x0) "unknown SMC! 0x%016"PRIx64
hvf_exit(uint64_t syndrome, uint32_t ec, uint64_t pc) "exit: 0x%"PRIx64" [ec=0x%x pc=0x%"PRIx64"]" hvf_exit(uint64_t syndrome, uint32_t ec, uint64_t pc) "exit: 0x%"PRIx64" [ec=0x%x pc=0x%"PRIx64"]"
hvf_psci_call(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint32_t cpuid) "PSCI Call x0=0x%016"PRIx64" x1=0x%016"PRIx64" x2=0x%016"PRIx64" x3=0x%016"PRIx64" cpu=0x%x" hvf_psci_call(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint32_t cpuid) "PSCI Call x0=0x%016"PRIx64" x1=0x%016"PRIx64" x2=0x%016"PRIx64" x3=0x%016"PRIx64" cpu=0x%x"
hvf_vgic_write(const char *name, uint64_t val) "vgic write to %s [val=0x%016"PRIx64"]"
hvf_vgic_read(const char *name, uint64_t val) "vgic read from %s [val=0x%016"PRIx64"]"

View File

@ -1377,4 +1377,24 @@ static inline uint64_t arm_mdcr_el2_eff(CPUARMState *env)
((1 << (1 - 1)) | (1 << (2 - 1)) | \ ((1 << (1 - 1)) | (1 << (2 - 1)) | \
(1 << (4 - 1)) | (1 << (8 - 1)) | (1 << (16 - 1))) (1 << (4 - 1)) | (1 << (8 - 1)) | (1 << (16 - 1)))
/*
* Return true if it is possible to take a fine-grained-trap to EL2.
*/
static inline bool arm_fgt_active(CPUARMState *env, int el)
{
/*
* The Arm ARM only requires the "{E2H,TGE} != {1,1}" test for traps
* that can affect EL0, but it is harmless to do the test also for
* traps on registers that are only accessible at EL1 because if the test
* returns true then we can't be executing at EL1 anyway.
* FGT traps only happen when EL2 is enabled and EL1 is AArch64;
* traps from AArch32 only happen for the EL0 is AArch32 case.
*/
return cpu_isar_feature(aa64_fgt, env_archcpu(env)) &&
el < 2 && arm_is_el2_enabled(env) &&
arm_el_is_aa64(env, 1) &&
(arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE) &&
(!arm_feature(env, ARM_FEATURE_EL3) || (env->cp15.scr_el3 & SCR_FGTEN));
}
#endif #endif

View File

@ -640,11 +640,30 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
goto fail; goto fail;
} }
if (ri->accessfn) {
res = ri->accessfn(env, ri, isread);
}
/* /*
* Check for an EL2 trap due to HSTR_EL2. We expect EL0 accesses * If the access function indicates a trap from EL0 to EL1 then
* to sysregs non accessible at EL0 to have UNDEF-ed already. * that always takes priority over the HSTR_EL2 trap. (If it indicates
* a trap to EL3, then the HSTR_EL2 trap takes priority; if it indicates
* a trap to EL2, then the syndrome is the same either way so we don't
* care whether technically the architecture says that HSTR_EL2 trap or
* the other trap takes priority. So we take the "check HSTR_EL2" path
* for all of those cases.)
*/ */
if (!is_a64(env) && arm_current_el(env) < 2 && ri->cp == 15 && if (res != CP_ACCESS_OK && ((res & CP_ACCESS_EL_MASK) == 0) &&
arm_current_el(env) == 0) {
goto fail;
}
/*
* HSTR_EL2 traps from EL1 are checked earlier, in generated code;
* we only need to check here for traps from EL0.
*/
if (!is_a64(env) && arm_current_el(env) == 0 && ri->cp == 15 &&
arm_is_el2_enabled(env) &&
(arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
uint32_t mask = 1 << ri->crn; uint32_t mask = 1 << ri->crn;
@ -661,9 +680,36 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
} }
} }
if (ri->accessfn) { /*
res = ri->accessfn(env, ri, isread); * Fine-grained traps also are lower priority than undef-to-EL1,
* higher priority than trap-to-EL3, and we don't care about priority
* order with other EL2 traps because the syndrome value is the same.
*/
if (arm_fgt_active(env, arm_current_el(env))) {
uint64_t trapword = 0;
unsigned int idx = FIELD_EX32(ri->fgt, FGT, IDX);
unsigned int bitpos = FIELD_EX32(ri->fgt, FGT, BITPOS);
bool rev = FIELD_EX32(ri->fgt, FGT, REV);
bool trapbit;
if (ri->fgt & FGT_EXEC) {
assert(idx < ARRAY_SIZE(env->cp15.fgt_exec));
trapword = env->cp15.fgt_exec[idx];
} else if (isread && (ri->fgt & FGT_R)) {
assert(idx < ARRAY_SIZE(env->cp15.fgt_read));
trapword = env->cp15.fgt_read[idx];
} else if (!isread && (ri->fgt & FGT_W)) {
assert(idx < ARRAY_SIZE(env->cp15.fgt_write));
trapword = env->cp15.fgt_write[idx];
}
trapbit = extract64(trapword, bitpos, 1);
if (trapbit != rev) {
res = CP_ACCESS_TRAP_EL2;
goto fail;
}
} }
if (likely(res == CP_ACCESS_OK)) { if (likely(res == CP_ACCESS_OK)) {
return ri; return ri;
} }
@ -673,6 +719,8 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
case CP_ACCESS_TRAP: case CP_ACCESS_TRAP:
break; break;
case CP_ACCESS_TRAP_UNCATEGORIZED: case CP_ACCESS_TRAP_UNCATEGORIZED:
/* Only CP_ACCESS_TRAP traps are direct to a specified EL */
assert((res & CP_ACCESS_EL_MASK) == 0);
if (cpu_isar_feature(aa64_ids, cpu) && isread && if (cpu_isar_feature(aa64_ids, cpu) && isread &&
arm_cpreg_in_idspace(ri)) { arm_cpreg_in_idspace(ri)) {
/* /*

View File

@ -266,7 +266,7 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
if (unlikely(flags & TLB_INVALID_MASK)) { if (unlikely(flags & TLB_INVALID_MASK)) {
goto fail; goto fail;
} }
ptw->out_phys = full->phys_addr; ptw->out_phys = full->phys_addr | (addr & ~TARGET_PAGE_MASK);
ptw->out_rw = full->prot & PAGE_WRITE; ptw->out_rw = full->prot & PAGE_WRITE;
pte_attrs = full->pte_attrs; pte_attrs = full->pte_attrs;
pte_secure = full->attrs.secure; pte_secure = full->attrs.secure;

View File

@ -48,6 +48,7 @@ enum arm_exception_class {
EC_AA64_SMC = 0x17, EC_AA64_SMC = 0x17,
EC_SYSTEMREGISTERTRAP = 0x18, EC_SYSTEMREGISTERTRAP = 0x18,
EC_SVEACCESSTRAP = 0x19, EC_SVEACCESSTRAP = 0x19,
EC_ERETTRAP = 0x1a,
EC_SMETRAP = 0x1d, EC_SMETRAP = 0x1d,
EC_INSNABORT = 0x20, EC_INSNABORT = 0x20,
EC_INSNABORT_SAME_EL = 0x21, EC_INSNABORT_SAME_EL = 0x21,
@ -215,6 +216,15 @@ static inline uint32_t syn_sve_access_trap(void)
return EC_SVEACCESSTRAP << ARM_EL_EC_SHIFT; return EC_SVEACCESSTRAP << ARM_EL_EC_SHIFT;
} }
/*
* eret_op is bits [1:0] of the ERET instruction, so:
* 0 for ERET, 2 for ERETAA, 3 for ERETAB.
*/
static inline uint32_t syn_erettrap(int eret_op)
{
return (EC_ERETTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | eret_op;
}
static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit) static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit)
{ {
return (EC_SMETRAP << ARM_EL_EC_SHIFT) return (EC_SMETRAP << ARM_EL_EC_SHIFT)

View File

@ -1962,7 +1962,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
return; return;
} }
if (ri->accessfn) { if (ri->accessfn || (ri->fgt && s->fgt_active)) {
/* Emit code to perform further access permissions checks at /* Emit code to perform further access permissions checks at
* runtime; this may result in an exception. * runtime; this may result in an exception.
*/ */
@ -2179,6 +2179,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
int opc = extract32(insn, 21, 3); int opc = extract32(insn, 21, 3);
int op2_ll = extract32(insn, 0, 5); int op2_ll = extract32(insn, 0, 5);
int imm16 = extract32(insn, 5, 16); int imm16 = extract32(insn, 5, 16);
uint32_t syndrome;
switch (opc) { switch (opc) {
case 0: case 0:
@ -2189,8 +2190,13 @@ static void disas_exc(DisasContext *s, uint32_t insn)
*/ */
switch (op2_ll) { switch (op2_ll) {
case 1: /* SVC */ case 1: /* SVC */
syndrome = syn_aa64_svc(imm16);
if (s->fgt_svc) {
gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2);
break;
}
gen_ss_advance(s); gen_ss_advance(s);
gen_exception_insn(s, 4, EXCP_SWI, syn_aa64_svc(imm16)); gen_exception_insn(s, 4, EXCP_SWI, syndrome);
break; break;
case 2: /* HVC */ case 2: /* HVC */
if (s->current_el == 0) { if (s->current_el == 0) {
@ -2385,6 +2391,10 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
if (op4 != 0) { if (op4 != 0) {
goto do_unallocated; goto do_unallocated;
} }
if (s->fgt_eret) {
gen_exception_insn_el(s, 0, EXCP_UDEF, syn_erettrap(op3), 2);
return;
}
dst = tcg_temp_new_i64(); dst = tcg_temp_new_i64();
tcg_gen_ld_i64(dst, cpu_env, tcg_gen_ld_i64(dst, cpu_env,
offsetof(CPUARMState, elr_el[s->current_el])); offsetof(CPUARMState, elr_el[s->current_el]));
@ -2398,6 +2408,11 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
if (rn != 0x1f || op4 != 0x1f) { if (rn != 0x1f || op4 != 0x1f) {
goto do_unallocated; goto do_unallocated;
} }
/* The FGT trap takes precedence over an auth trap. */
if (s->fgt_eret) {
gen_exception_insn_el(s, 0, EXCP_UDEF, syn_erettrap(op3), 2);
return;
}
dst = tcg_temp_new_i64(); dst = tcg_temp_new_i64();
tcg_gen_ld_i64(dst, cpu_env, tcg_gen_ld_i64(dst, cpu_env,
offsetof(CPUARMState, elr_el[s->current_el])); offsetof(CPUARMState, elr_el[s->current_el]));
@ -14741,6 +14756,9 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL); dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE);
dc->fgt_svc = EX_TBFLAG_ANY(tb_flags, FGT_SVC);
dc->fgt_eret = EX_TBFLAG_A64(tb_flags, FGT_ERET);
dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL); dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL);
dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL); dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL);
dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16; dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16;

View File

@ -4718,6 +4718,73 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key); const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
TCGv_ptr tcg_ri = NULL; TCGv_ptr tcg_ri = NULL;
bool need_exit_tb; bool need_exit_tb;
uint32_t syndrome;
/*
* Note that since we are an implementation which takes an
* exception on a trapped conditional instruction only if the
* instruction passes its condition code check, we can take
* advantage of the clause in the ARM ARM that allows us to set
* the COND field in the instruction to 0xE in all cases.
* We could fish the actual condition out of the insn (ARM)
* or the condexec bits (Thumb) but it isn't necessary.
*/
switch (cpnum) {
case 14:
if (is64) {
syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
isread, false);
} else {
syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm,
rt, isread, false);
}
break;
case 15:
if (is64) {
syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
isread, false);
} else {
syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm,
rt, isread, false);
}
break;
default:
/*
* ARMv8 defines that only coprocessors 14 and 15 exist,
* so this can only happen if this is an ARMv7 or earlier CPU,
* in which case the syndrome information won't actually be
* guest visible.
*/
assert(!arm_dc_feature(s, ARM_FEATURE_V8));
syndrome = syn_uncategorized();
break;
}
if (s->hstr_active && cpnum == 15 && s->current_el == 1) {
/*
* At EL1, check for a HSTR_EL2 trap, which must take precedence
* over the UNDEF for "no such register" or the UNDEF for "access
* permissions forbid this EL1 access". HSTR_EL2 traps from EL0
* only happen if the cpreg doesn't UNDEF at EL0, so we do those in
* access_check_cp_reg(), after the checks for whether the access
* configurably trapped to EL1.
*/
uint32_t maskbit = is64 ? crm : crn;
if (maskbit != 4 && maskbit != 14) {
/* T4 and T14 are RES0 so never cause traps */
TCGv_i32 t;
DisasLabel over = gen_disas_label(s);
t = load_cpu_offset(offsetoflow32(CPUARMState, cp15.hstr_el2));
tcg_gen_andi_i32(t, t, 1u << maskbit);
tcg_gen_brcondi_i32(TCG_COND_EQ, t, 0, over.label);
tcg_temp_free_i32(t);
gen_exception_insn(s, 0, EXCP_UDEF, syndrome);
set_disas_label(s, over);
}
}
if (!ri) { if (!ri) {
/* /*
@ -4747,7 +4814,8 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
return; return;
} }
if (s->hstr_active || ri->accessfn || if ((s->hstr_active && s->current_el == 0) || ri->accessfn ||
(ri->fgt && s->fgt_active) ||
(arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) { (arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) {
/* /*
* Emit code to perform further access permissions checks at * Emit code to perform further access permissions checks at
@ -4755,48 +4823,6 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
* Note that on XScale all cp0..c13 registers do an access check * Note that on XScale all cp0..c13 registers do an access check
* call in order to handle c15_cpar. * call in order to handle c15_cpar.
*/ */
uint32_t syndrome;
/*
* Note that since we are an implementation which takes an
* exception on a trapped conditional instruction only if the
* instruction passes its condition code check, we can take
* advantage of the clause in the ARM ARM that allows us to set
* the COND field in the instruction to 0xE in all cases.
* We could fish the actual condition out of the insn (ARM)
* or the condexec bits (Thumb) but it isn't necessary.
*/
switch (cpnum) {
case 14:
if (is64) {
syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
isread, false);
} else {
syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm,
rt, isread, false);
}
break;
case 15:
if (is64) {
syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
isread, false);
} else {
syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm,
rt, isread, false);
}
break;
default:
/*
* ARMv8 defines that only coprocessors 14 and 15 exist,
* so this can only happen if this is an ARMv7 or earlier CPU,
* in which case the syndrome information won't actually be
* guest visible.
*/
assert(!arm_dc_feature(s, ARM_FEATURE_V8));
syndrome = syn_uncategorized();
break;
}
gen_set_condexec(s); gen_set_condexec(s);
gen_update_pc(s, 0); gen_update_pc(s, 0);
tcg_ri = tcg_temp_new_ptr(); tcg_ri = tcg_temp_new_ptr();
@ -8808,9 +8834,14 @@ static bool trans_SVC(DisasContext *s, arg_SVC *a)
(a->imm == semihost_imm)) { (a->imm == semihost_imm)) {
gen_exception_internal_insn(s, EXCP_SEMIHOST); gen_exception_internal_insn(s, EXCP_SEMIHOST);
} else { } else {
gen_update_pc(s, curr_insn_len(s)); if (s->fgt_svc) {
s->svc_imm = a->imm; uint32_t syndrome = syn_aa32_svc(a->imm, s->thumb);
s->base.is_jmp = DISAS_SWI; gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2);
} else {
gen_update_pc(s, curr_insn_len(s));
s->svc_imm = a->imm;
s->base.is_jmp = DISAS_SWI;
}
} }
return true; return true;
} }
@ -9390,6 +9421,8 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL); dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE);
dc->fgt_svc = EX_TBFLAG_ANY(tb_flags, FGT_SVC);
if (arm_feature(env, ARM_FEATURE_M)) { if (arm_feature(env, ARM_FEATURE_M)) {
dc->vfp_enabled = 1; dc->vfp_enabled = 1;

View File

@ -130,6 +130,12 @@ typedef struct DisasContext {
bool is_nonstreaming; bool is_nonstreaming;
/* True if MVE insns are definitely not predicated by VPR or LTPSIZE */ /* True if MVE insns are definitely not predicated by VPR or LTPSIZE */
bool mve_no_pred; bool mve_no_pred;
/* True if fine-grained traps are active */
bool fgt_active;
/* True if fine-grained trap on ERET is enabled */
bool fgt_eret;
/* True if fine-grained trap on SVC is enabled */
bool fgt_svc;
/* /*
* >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI. * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
* < 0, set by the current instruction. * < 0, set by the current instruction.