target-arm:

* cleanups converting to DEFINE_PROP_LINK
  * allwinner-a10: mark as not user-creatable
  * initial patches working towards ARMv8M support
  * implement generating aborts on memory transaction failures
  * make BXJ behave correctly (ie not UNDEF) on ARMv6-and-later
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJZsUjvAAoJEDwlJe0UNgzey10P+wf1TRxRMGnoDftimLyPt9Pt
 cXYSP1KKF4qn618ZSJHPHJasWEx2obAP8JrrA8qLz0quWpWlXZ40bhgxKX9iKb2l
 4jrt/DjfTH7RWMRs94lOb0ZOtMokLfjHMSBhP31xR4Lgia0HdlmwqUPLr2T10ffE
 B9BKvPbXcee9Ss7osDqQr3OMUtSMjuc3G3z3WaySwG80od9MB8mblnMU0h9gZEeT
 6csGRHU8rfOkv9ZzrSJRWBuhmxC0Mrg3lB3iZffupFnI//q+PZfW2+ojAyn+pATu
 3YgHjgfgw4P5N2iGlg8c4y6mrig0fQNHWIXWFk7zWp7kWCdXnq5doFpJmi+CfMlE
 yQqMYzuy2Bd9n2fAB036nvb1LBHEKFYfKxqPoeJzuB9wEcXjmnbwuJ+iAKo/DP94
 9wE/cPNKySFmZJFEz+byAZvnEp0ynpQtDoCnaIJPbx6ytkKfL9xXX78+mmlTn8hj
 55NyH2aaEXpuxJKkld1pP2O+r/amFJ603rujSEaK0Or2YGcE1fit+YZSSh1glt25
 b3vEKn1ydWV4udRjBIEd0l/PIhGenILXC3bDONiWqEIPaMVeOxjhl+lvEHmELOjd
 t+o4ntQfU94Z6eDXPhx/bXqIZi9qtDbMZosojWL6wMAIMEiuXlB/a9vhcs9uBnRJ
 M0PiR5jVpZgDfLipV/8A
 =URgX
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20170907' into staging

target-arm:
 * cleanups converting to DEFINE_PROP_LINK
 * allwinner-a10: mark as not user-creatable
 * initial patches working towards ARMv8M support
 * implement generating aborts on memory transaction failures
 * make BXJ behave correctly (ie not UNDEF) on ARMv6-and-later

# gpg: Signature made Thu 07 Sep 2017 14:26:07 BST
# gpg:                using RSA key 0x3C2525ED14360CDE
# 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>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20170907: (31 commits)
  target/arm: Add Jazelle feature
  target/arm: Implement new do_transaction_failed hook
  hw/arm: Set ignore_memory_transaction_failures for most ARM boards
  boards.h: Define new flag ignore_memory_transaction_failures
  target/arm: Implement BXNS, and banked stack pointers
  target/arm: Move regime_is_secure() to target/arm/internals.h
  target/arm: Make CFSR register banked for v8M
  target/arm: Make MMFAR banked for v8M
  target/arm: Make CCR register banked for v8M
  target/arm: Make MPU_CTRL register banked for v8M
  target/arm: Make MPU_RNR register banked for v8M
  target/arm: Make MPU_RBAR, MPU_RLAR banked for v8M
  target/arm: Make MPU_MAIR0, MPU_MAIR1 registers banked for v8M
  target/arm: Make VTOR register banked for v8M
  nvic: Add NS alias SCS region
  target/arm: Make CONTROL register banked for v8M
  target/arm: Make FAULTMASK register banked for v8M
  target/arm: Make PRIMASK register banked for v8M
  target/arm: Make BASEPRI register banked for v8M
  target/arm: Add MMU indexes for secure v8M
  ...

# Conflicts:
#	target/arm/translate.c
This commit is contained in:
Peter Maydell 2017-09-07 16:42:55 +01:00
commit ef475b5dd1
48 changed files with 978 additions and 213 deletions

View file

@ -118,6 +118,8 @@ static void aw_a10_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = aw_a10_realize;
/* Reason: Uses serial_hds in realize and nd_table in instance_init */
dc->user_creatable = false;
}
static const TypeInfo aw_a10_type_info = {

View file

@ -97,12 +97,6 @@ static void bitband_init(Object *obj)
BitBandState *s = BITBAND(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
object_property_add_link(obj, "source-memory",
TYPE_MEMORY_REGION,
(Object **)&s->source_memory,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
memory_region_init_io(&s->iomem, obj, &bitband_ops, s,
"bitband", 0x02000000);
sysbus_init_mmio(dev, &s->iomem);
@ -138,12 +132,6 @@ static void armv7m_instance_init(Object *obj)
/* Can't init the cpu here, we don't yet know which model to use */
object_property_add_link(obj, "memory",
TYPE_MEMORY_REGION,
(Object **)&s->board_memory,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
memory_region_init(&s->container, obj, "armv7m-container", UINT64_MAX);
object_initialize(&s->nvic, sizeof(s->nvic), TYPE_NVIC);
@ -254,6 +242,8 @@ static void armv7m_realize(DeviceState *dev, Error **errp)
static Property armv7m_properties[] = {
DEFINE_PROP_STRING("cpu-model", ARMv7MState, cpu_model),
DEFINE_PROP_LINK("memory", ARMv7MState, board_memory, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_END_OF_LIST(),
};
@ -349,6 +339,8 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size)
static Property bitband_properties[] = {
DEFINE_PROP_UINT32("base", BitBandState, base, 0),
DEFINE_PROP_LINK("source-memory", BitBandState, source_memory,
TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_PROP_END_OF_LIST(),
};

View file

@ -270,6 +270,7 @@ static void palmetto_bmc_class_init(ObjectClass *oc, void *data)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo palmetto_bmc_type = {
@ -302,6 +303,7 @@ static void ast2500_evb_class_init(ObjectClass *oc, void *data)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo ast2500_evb_type = {
@ -326,6 +328,7 @@ static void romulus_bmc_class_init(ObjectClass *oc, void *data)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo romulus_bmc_type = {

View file

@ -64,6 +64,7 @@ static void collie_machine_init(MachineClass *mc)
{
mc->desc = "Sharp SL-5500 (Collie) PDA (SA-1110)";
mc->init = collie_init;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("collie", collie_machine_init)

View file

@ -86,6 +86,7 @@ static void cubieboard_machine_init(MachineClass *mc)
mc->init = cubieboard_init;
mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("cubieboard", cubieboard_machine_init)

View file

@ -155,6 +155,7 @@ static void canon_a1100_machine_init(MachineClass *mc)
{
mc->desc = "Canon PowerShot A1100 IS";
mc->init = &canon_a1100_init;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("canon-a1100", canon_a1100_machine_init)

View file

@ -189,6 +189,7 @@ static void nuri_class_init(ObjectClass *oc, void *data)
mc->desc = "Samsung NURI board (Exynos4210)";
mc->init = nuri_init;
mc->max_cpus = EXYNOS4210_NCPUS;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo nuri_type = {
@ -204,6 +205,7 @@ static void smdkc210_class_init(ObjectClass *oc, void *data)
mc->desc = "Samsung SMDKC210 board (Exynos4210)";
mc->init = smdkc210_init;
mc->max_cpus = EXYNOS4210_NCPUS;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo smdkc210_type = {

View file

@ -128,6 +128,7 @@ static void connex_class_init(ObjectClass *oc, void *data)
mc->desc = "Gumstix Connex (PXA255)";
mc->init = connex_init;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo connex_type = {
@ -142,6 +143,7 @@ static void verdex_class_init(ObjectClass *oc, void *data)
mc->desc = "Gumstix Verdex (PXA270)";
mc->init = verdex_init;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo verdex_type = {

View file

@ -413,6 +413,7 @@ static void highbank_class_init(ObjectClass *oc, void *data)
mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1;
mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo highbank_type = {
@ -430,6 +431,7 @@ static void midway_class_init(ObjectClass *oc, void *data)
mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1;
mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo midway_type = {

View file

@ -148,6 +148,7 @@ static void imx25_pdk_machine_init(MachineClass *mc)
{
mc->desc = "ARM i.MX25 PDK board (ARM926)";
mc->init = imx25_pdk_init;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("imx25-pdk", imx25_pdk_machine_init)

View file

@ -681,6 +681,7 @@ static void integratorcp_machine_init(MachineClass *mc)
{
mc->desc = "ARM Integrator/CP (ARM926EJ-S)";
mc->init = integratorcp_init;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("integratorcp", integratorcp_machine_init)

View file

@ -142,6 +142,7 @@ static void kzm_machine_init(MachineClass *mc)
{
mc->desc = "ARM KZM Emulation Baseboard (ARM1136)";
mc->init = kzm_init;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("kzm", kzm_machine_init)

View file

@ -196,6 +196,7 @@ static void mainstone2_machine_init(MachineClass *mc)
{
mc->desc = "Mainstone II (PXA27x)";
mc->init = mainstone_init;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("mainstone", mainstone2_machine_init)

View file

@ -1718,6 +1718,7 @@ static void musicpal_machine_init(MachineClass *mc)
{
mc->desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)";
mc->init = musicpal_init;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("musicpal", musicpal_machine_init)

View file

@ -45,6 +45,7 @@ static void netduino2_machine_init(MachineClass *mc)
{
mc->desc = "Netduino 2 Machine";
mc->init = netduino2_init;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("netduino2", netduino2_machine_init)

View file

@ -1425,6 +1425,7 @@ static void n800_class_init(ObjectClass *oc, void *data)
mc->desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)";
mc->init = n800_init;
mc->default_boot_order = "";
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo n800_type = {
@ -1440,6 +1441,7 @@ static void n810_class_init(ObjectClass *oc, void *data)
mc->desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)";
mc->init = n810_init;
mc->default_boot_order = "";
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo n810_type = {

View file

@ -223,6 +223,7 @@ static void sx1_machine_v2_class_init(ObjectClass *oc, void *data)
mc->desc = "Siemens SX1 (OMAP310) V2";
mc->init = sx1_init_v2;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo sx1_machine_v2_type = {
@ -237,6 +238,7 @@ static void sx1_machine_v1_class_init(ObjectClass *oc, void *data)
mc->desc = "Siemens SX1 (OMAP310) V1";
mc->init = sx1_init_v1;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo sx1_machine_v1_type = {

View file

@ -274,6 +274,7 @@ static void palmte_machine_init(MachineClass *mc)
{
mc->desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)";
mc->init = palmte_init;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("cheetah", palmte_machine_init)

View file

@ -168,5 +168,6 @@ static void raspi2_machine_init(MachineClass *mc)
mc->no_cdrom = 1;
mc->max_cpus = BCM2836_NCPUS;
mc->default_ram_size = 1024 * 1024 * 1024;
mc->ignore_memory_transaction_failures = true;
};
DEFINE_MACHINE("raspi2", raspi2_machine_init)

View file

@ -398,6 +398,7 @@ static void realview_eb_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)";
mc->init = realview_eb_init;
mc->block_default_type = IF_SCSI;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo realview_eb_type = {
@ -414,6 +415,7 @@ static void realview_eb_mpcore_class_init(ObjectClass *oc, void *data)
mc->init = realview_eb_mpcore_init;
mc->block_default_type = IF_SCSI;
mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo realview_eb_mpcore_type = {
@ -428,6 +430,7 @@ static void realview_pb_a8_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM RealView Platform Baseboard for Cortex-A8";
mc->init = realview_pb_a8_init;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo realview_pb_a8_type = {
@ -443,6 +446,7 @@ static void realview_pbx_a9_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM RealView Platform Baseboard Explore for Cortex-A9";
mc->init = realview_pbx_a9_init;
mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo realview_pbx_a9_type = {

View file

@ -122,6 +122,7 @@ static void sabrelite_machine_init(MachineClass *mc)
mc->desc = "Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)";
mc->init = sabrelite_init;
mc->max_cpus = FSL_IMX6_NUM_CPUS;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("sabrelite", sabrelite_machine_init)

View file

@ -983,6 +983,7 @@ static void akitapda_class_init(ObjectClass *oc, void *data)
mc->desc = "Sharp SL-C1000 (Akita) PDA (PXA270)";
mc->init = akita_init;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo akitapda_type = {
@ -998,6 +999,7 @@ static void spitzpda_class_init(ObjectClass *oc, void *data)
mc->desc = "Sharp SL-C3000 (Spitz) PDA (PXA270)";
mc->init = spitz_init;
mc->block_default_type = IF_IDE;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo spitzpda_type = {
@ -1013,6 +1015,7 @@ static void borzoipda_class_init(ObjectClass *oc, void *data)
mc->desc = "Sharp SL-C3100 (Borzoi) PDA (PXA270)";
mc->init = borzoi_init;
mc->block_default_type = IF_IDE;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo borzoipda_type = {
@ -1028,6 +1031,7 @@ static void terrierpda_class_init(ObjectClass *oc, void *data)
mc->desc = "Sharp SL-C3200 (Terrier) PDA (PXA270)";
mc->init = terrier_init;
mc->block_default_type = IF_IDE;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo terrierpda_type = {

View file

@ -1453,6 +1453,7 @@ static void lm3s811evb_class_init(ObjectClass *oc, void *data)
mc->desc = "Stellaris LM3S811EVB";
mc->init = lm3s811evb_init;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo lm3s811evb_type = {
@ -1467,6 +1468,7 @@ static void lm3s6965evb_class_init(ObjectClass *oc, void *data)
mc->desc = "Stellaris LM3S6965EVB";
mc->init = lm3s6965evb_init;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo lm3s6965evb_type = {

View file

@ -263,6 +263,7 @@ static void tosapda_machine_init(MachineClass *mc)
mc->desc = "Sharp SL-6000 (Tosa) PDA (PXA255)";
mc->init = tosa_init;
mc->block_default_type = IF_IDE;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("tosa", tosapda_machine_init)

View file

@ -403,6 +403,7 @@ static void versatilepb_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM Versatile/PB (ARM926EJ-S)";
mc->init = vpb_init;
mc->block_default_type = IF_SCSI;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo versatilepb_type = {
@ -418,6 +419,7 @@ static void versatileab_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM Versatile/AB (ARM926EJ-S)";
mc->init = vab_init;
mc->block_default_type = IF_SCSI;
mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo versatileab_type = {

View file

@ -752,6 +752,7 @@ static void vexpress_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM Versatile Express";
mc->init = vexpress_common_init;
mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
}
static void vexpress_a9_class_init(ObjectClass *oc, void *data)

View file

@ -326,6 +326,7 @@ static void zynq_machine_init(MachineClass *mc)
mc->init = zynq_init;
mc->max_cpus = 1;
mc->no_sdcard = 1;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("xilinx-zynq-a9", zynq_machine_init)

View file

@ -122,6 +122,7 @@ static void xlnx_ep108_machine_init(MachineClass *mc)
mc->init = xlnx_ep108_init;
mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("xlnx-ep108", xlnx_ep108_machine_init)
@ -132,6 +133,7 @@ static void xlnx_zcu102_machine_init(MachineClass *mc)
mc->init = xlnx_ep108_init;
mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("xlnx-zcu102", xlnx_zcu102_machine_init)

View file

@ -140,11 +140,6 @@ static void xlnx_zynqmp_init(Object *obj)
&error_abort);
}
object_property_add_link(obj, "ddr-ram", TYPE_MEMORY_REGION,
(Object **)&s->ddr_ram,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
object_initialize(&s->gic, sizeof(s->gic), gic_class_name());
qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
@ -433,6 +428,8 @@ static Property xlnx_zynqmp_props[] = {
DEFINE_PROP_STRING("boot-cpu", XlnxZynqMPState, boot_cpu),
DEFINE_PROP_BOOL("secure", XlnxZynqMPState, secure, false),
DEFINE_PROP_BOOL("has_rpu", XlnxZynqMPState, has_rpu, false),
DEFINE_PROP_LINK("ddr-ram", XlnxZynqMPState, ddr_ram, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_END_OF_LIST()
};

View file

@ -370,6 +370,7 @@ static void z2_machine_init(MachineClass *mc)
{
mc->desc = "Zipit Z2 (PXA27x)";
mc->init = z2_init;
mc->ignore_memory_transaction_failures = true;
}
DEFINE_MACHINE("z2", z2_machine_init)

View file

@ -562,18 +562,6 @@ static void xilinx_axidma_init(Object *obj)
XilinxAXIDMA *s = XILINX_AXI_DMA(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
(Object **)&s->tx_data_dev,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
object_property_add_link(obj, "axistream-control-connected",
TYPE_STREAM_SLAVE,
(Object **)&s->tx_control_dev,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
TYPE_XILINX_AXI_DMA_DATA_STREAM);
object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
@ -593,6 +581,10 @@ static void xilinx_axidma_init(Object *obj)
static Property axidma_properties[] = {
DEFINE_PROP_UINT32("freqhz", XilinxAXIDMA, freqhz, 50000000),
DEFINE_PROP_LINK("axistream-connected", XilinxAXIDMA,
tx_data_dev, TYPE_STREAM_SLAVE, StreamSlave *),
DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIDMA,
tx_control_dev, TYPE_STREAM_SLAVE, StreamSlave *),
DEFINE_PROP_END_OF_LIST(),
};

View file

@ -120,17 +120,6 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
qemu_add_vm_change_state_handler(vm_change_state_handler, s);
}
static void kvm_arm_its_init(Object *obj)
{
GICv3ITSState *s = KVM_ARM_ITS(obj);
object_property_add_link(obj, "parent-gicv3",
"kvm-arm-gicv3", (Object **)&s->gicv3,
object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
}
/**
* kvm_arm_its_pre_save - handles the saving of ITS registers.
* ITS tables are flushed into guest RAM separately and earlier,
@ -205,12 +194,19 @@ static void kvm_arm_its_post_load(GICv3ITSState *s)
GITS_CTLR, &s->ctlr, true, &error_abort);
}
static Property kvm_arm_its_props[] = {
DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "kvm-arm-gicv3",
GICv3State *),
DEFINE_PROP_END_OF_LIST(),
};
static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
dc->realize = kvm_arm_its_realize;
dc->props = kvm_arm_its_props;
icc->send_msi = kvm_its_send_msi;
icc->pre_save = kvm_arm_its_pre_save;
icc->post_load = kvm_arm_its_post_load;
@ -220,7 +216,6 @@ static const TypeInfo kvm_arm_its_info = {
.name = TYPE_KVM_ARM_ITS,
.parent = TYPE_ARM_GICV3_ITS_COMMON,
.instance_size = sizeof(GICv3ITSState),
.instance_init = kvm_arm_its_init,
.class_init = kvm_arm_its_class_init,
};

View file

@ -167,12 +167,12 @@ static inline int nvic_exec_prio(NVICState *s)
CPUARMState *env = &s->cpu->env;
int running;
if (env->v7m.faultmask) {
if (env->v7m.faultmask[env->v7m.secure]) {
running = -1;
} else if (env->v7m.primask) {
} else if (env->v7m.primask[env->v7m.secure]) {
running = 0;
} else if (env->v7m.basepri > 0) {
running = env->v7m.basepri & nvic_gprio_mask(s);
} else if (env->v7m.basepri[env->v7m.secure] > 0) {
running = env->v7m.basepri[env->v7m.secure] & nvic_gprio_mask(s);
} else {
running = NVIC_NOEXC_PRIO; /* lower than any possible priority */
}
@ -187,6 +187,13 @@ bool armv7m_nvic_can_take_pending_exception(void *opaque)
return nvic_exec_prio(s) > nvic_pending_prio(s);
}
int armv7m_nvic_raw_execution_priority(void *opaque)
{
NVICState *s = opaque;
return s->exception_prio;
}
/* caller must call nvic_irq_update() after this */
static void set_prio(NVICState *s, unsigned irq, uint8_t prio)
{
@ -396,7 +403,7 @@ static void set_irq_level(void *opaque, int n, int level)
}
}
static uint32_t nvic_readl(NVICState *s, uint32_t offset)
static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
{
ARMCPU *cpu = s->cpu;
uint32_t val;
@ -434,14 +441,19 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
/* ISRPREEMPT not implemented */
return val;
case 0xd08: /* Vector Table Offset. */
return cpu->env.v7m.vecbase;
return cpu->env.v7m.vecbase[attrs.secure];
case 0xd0c: /* Application Interrupt/Reset Control. */
return 0xfa050000 | (s->prigroup << 8);
case 0xd10: /* System Control. */
/* TODO: Implement SLEEPONEXIT. */
return 0;
case 0xd14: /* Configuration Control. */
return cpu->env.v7m.ccr;
/* The BFHFNMIGN bit is the only non-banked bit; we
* keep it in the non-secure copy of the register.
*/
val = cpu->env.v7m.ccr[attrs.secure];
val |= cpu->env.v7m.ccr[M_REG_NS] & R_V7M_CCR_BFHFNMIGN_MASK;
return val;
case 0xd24: /* System Handler Status. */
val = 0;
if (s->vectors[ARMV7M_EXCP_MEM].active) {
@ -488,13 +500,18 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
}
return val;
case 0xd28: /* Configurable Fault Status. */
return cpu->env.v7m.cfsr;
/* The BFSR bits [15:8] are shared between security states
* and we store them in the NS copy
*/
val = cpu->env.v7m.cfsr[attrs.secure];
val |= cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK;
return val;
case 0xd2c: /* Hard Fault Status. */
return cpu->env.v7m.hfsr;
case 0xd30: /* Debug Fault Status. */
return cpu->env.v7m.dfsr;
case 0xd34: /* MMFAR MemManage Fault Address */
return cpu->env.v7m.mmfar;
return cpu->env.v7m.mmfar[attrs.secure];
case 0xd38: /* Bus Fault Address. */
return cpu->env.v7m.bfar;
case 0xd3c: /* Aux Fault Status. */
@ -534,27 +551,58 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
return cpu->pmsav7_dregion << 8;
break;
case 0xd94: /* MPU_CTRL */
return cpu->env.v7m.mpu_ctrl;
return cpu->env.v7m.mpu_ctrl[attrs.secure];
case 0xd98: /* MPU_RNR */
return cpu->env.pmsav7.rnr;
return cpu->env.pmsav7.rnr[attrs.secure];
case 0xd9c: /* MPU_RBAR */
case 0xda4: /* MPU_RBAR_A1 */
case 0xdac: /* MPU_RBAR_A2 */
case 0xdb4: /* MPU_RBAR_A3 */
{
int region = cpu->env.pmsav7.rnr;
int region = cpu->env.pmsav7.rnr[attrs.secure];
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
/* PMSAv8M handling of the aliases is different from v7M:
* aliases A1, A2, A3 override the low two bits of the region
* number in MPU_RNR, and there is no 'region' field in the
* RBAR register.
*/
int aliasno = (offset - 0xd9c) / 8; /* 0..3 */
if (aliasno) {
region = deposit32(region, 0, 2, aliasno);
}
if (region >= cpu->pmsav7_dregion) {
return 0;
}
return cpu->env.pmsav8.rbar[attrs.secure][region];
}
if (region >= cpu->pmsav7_dregion) {
return 0;
}
return (cpu->env.pmsav7.drbar[region] & 0x1f) | (region & 0xf);
}
case 0xda0: /* MPU_RASR */
case 0xda8: /* MPU_RASR_A1 */
case 0xdb0: /* MPU_RASR_A2 */
case 0xdb8: /* MPU_RASR_A3 */
case 0xda0: /* MPU_RASR (v7M), MPU_RLAR (v8M) */
case 0xda8: /* MPU_RASR_A1 (v7M), MPU_RLAR_A1 (v8M) */
case 0xdb0: /* MPU_RASR_A2 (v7M), MPU_RLAR_A2 (v8M) */
case 0xdb8: /* MPU_RASR_A3 (v7M), MPU_RLAR_A3 (v8M) */
{
int region = cpu->env.pmsav7.rnr;
int region = cpu->env.pmsav7.rnr[attrs.secure];
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
/* PMSAv8M handling of the aliases is different from v7M:
* aliases A1, A2, A3 override the low two bits of the region
* number in MPU_RNR.
*/
int aliasno = (offset - 0xda0) / 8; /* 0..3 */
if (aliasno) {
region = deposit32(region, 0, 2, aliasno);
}
if (region >= cpu->pmsav7_dregion) {
return 0;
}
return cpu->env.pmsav8.rlar[attrs.secure][region];
}
if (region >= cpu->pmsav7_dregion) {
return 0;
@ -562,13 +610,25 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
return ((cpu->env.pmsav7.dracr[region] & 0xffff) << 16) |
(cpu->env.pmsav7.drsr[region] & 0xffff);
}
case 0xdc0: /* MPU_MAIR0 */
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
goto bad_offset;
}
return cpu->env.pmsav8.mair0[attrs.secure];
case 0xdc4: /* MPU_MAIR1 */
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
goto bad_offset;
}
return cpu->env.pmsav8.mair1[attrs.secure];
default:
bad_offset:
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
return 0;
}
}
static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
MemTxAttrs attrs)
{
ARMCPU *cpu = s->cpu;
@ -589,7 +649,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
}
break;
case 0xd08: /* Vector Table Offset. */
cpu->env.v7m.vecbase = value & 0xffffff80;
cpu->env.v7m.vecbase[attrs.secure] = value & 0xffffff80;
break;
case 0xd0c: /* Application Interrupt/Reset Control. */
if ((value >> 16) == 0x05fa) {
@ -623,7 +683,20 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
R_V7M_CCR_USERSETMPEND_MASK |
R_V7M_CCR_NONBASETHRDENA_MASK);
cpu->env.v7m.ccr = value;
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
/* v8M makes NONBASETHRDENA and STKALIGN be RES1 */
value |= R_V7M_CCR_NONBASETHRDENA_MASK
| R_V7M_CCR_STKALIGN_MASK;
}
if (attrs.secure) {
/* the BFHFNMIGN bit is not banked; keep that in the NS copy */
cpu->env.v7m.ccr[M_REG_NS] =
(cpu->env.v7m.ccr[M_REG_NS] & ~R_V7M_CCR_BFHFNMIGN_MASK)
| (value & R_V7M_CCR_BFHFNMIGN_MASK);
value &= ~R_V7M_CCR_BFHFNMIGN_MASK;
}
cpu->env.v7m.ccr[attrs.secure] = value;
break;
case 0xd24: /* System Handler Control. */
s->vectors[ARMV7M_EXCP_MEM].active = (value & (1 << 0)) != 0;
@ -643,7 +716,13 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
nvic_irq_update(s);
break;
case 0xd28: /* Configurable Fault Status. */
cpu->env.v7m.cfsr &= ~value; /* W1C */
cpu->env.v7m.cfsr[attrs.secure] &= ~value; /* W1C */
if (attrs.secure) {
/* The BFSR bits [15:8] are shared between security states
* and we store them in the NS copy.
*/
cpu->env.v7m.cfsr[M_REG_NS] &= ~(value & R_V7M_CFSR_BFSR_MASK);
}
break;
case 0xd2c: /* Hard Fault Status. */
cpu->env.v7m.hfsr &= ~value; /* W1C */
@ -652,7 +731,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
cpu->env.v7m.dfsr &= ~value; /* W1C */
break;
case 0xd34: /* Mem Manage Address. */
cpu->env.v7m.mmfar = value;
cpu->env.v7m.mmfar[attrs.secure] = value;
return;
case 0xd38: /* Bus Fault Address. */
cpu->env.v7m.bfar = value;
@ -670,9 +749,10 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
qemu_log_mask(LOG_GUEST_ERROR, "MPU_CTRL: HFNMIENA and !ENABLE is "
"UNPREDICTABLE\n");
}
cpu->env.v7m.mpu_ctrl = value & (R_V7M_MPU_CTRL_ENABLE_MASK |
R_V7M_MPU_CTRL_HFNMIENA_MASK |
R_V7M_MPU_CTRL_PRIVDEFENA_MASK);
cpu->env.v7m.mpu_ctrl[attrs.secure]
= value & (R_V7M_MPU_CTRL_ENABLE_MASK |
R_V7M_MPU_CTRL_HFNMIENA_MASK |
R_V7M_MPU_CTRL_PRIVDEFENA_MASK);
tlb_flush(CPU(cpu));
break;
case 0xd98: /* MPU_RNR */
@ -681,7 +761,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
PRIu32 "/%" PRIu32 "\n",
value, cpu->pmsav7_dregion);
} else {
cpu->env.pmsav7.rnr = value;
cpu->env.pmsav7.rnr[attrs.secure] = value;
}
break;
case 0xd9c: /* MPU_RBAR */
@ -691,6 +771,26 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
{
int region;
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
/* PMSAv8M handling of the aliases is different from v7M:
* aliases A1, A2, A3 override the low two bits of the region
* number in MPU_RNR, and there is no 'region' field in the
* RBAR register.
*/
int aliasno = (offset - 0xd9c) / 8; /* 0..3 */
region = cpu->env.pmsav7.rnr[attrs.secure];
if (aliasno) {
region = deposit32(region, 0, 2, aliasno);
}
if (region >= cpu->pmsav7_dregion) {
return;
}
cpu->env.pmsav8.rbar[attrs.secure][region] = value;
tlb_flush(CPU(cpu));
return;
}
if (value & (1 << 4)) {
/* VALID bit means use the region number specified in this
* value and also update MPU_RNR.REGION with that value.
@ -702,9 +802,9 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
region, cpu->pmsav7_dregion);
return;
}
cpu->env.pmsav7.rnr = region;
cpu->env.pmsav7.rnr[attrs.secure] = region;
} else {
region = cpu->env.pmsav7.rnr;
region = cpu->env.pmsav7.rnr[attrs.secure];
}
if (region >= cpu->pmsav7_dregion) {
@ -715,12 +815,31 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
tlb_flush(CPU(cpu));
break;
}
case 0xda0: /* MPU_RASR */
case 0xda8: /* MPU_RASR_A1 */
case 0xdb0: /* MPU_RASR_A2 */
case 0xdb8: /* MPU_RASR_A3 */
case 0xda0: /* MPU_RASR (v7M), MPU_RLAR (v8M) */
case 0xda8: /* MPU_RASR_A1 (v7M), MPU_RLAR_A1 (v8M) */
case 0xdb0: /* MPU_RASR_A2 (v7M), MPU_RLAR_A2 (v8M) */
case 0xdb8: /* MPU_RASR_A3 (v7M), MPU_RLAR_A3 (v8M) */
{
int region = cpu->env.pmsav7.rnr;
int region = cpu->env.pmsav7.rnr[attrs.secure];
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
/* PMSAv8M handling of the aliases is different from v7M:
* aliases A1, A2, A3 override the low two bits of the region
* number in MPU_RNR.
*/
int aliasno = (offset - 0xd9c) / 8; /* 0..3 */
region = cpu->env.pmsav7.rnr[attrs.secure];
if (aliasno) {
region = deposit32(region, 0, 2, aliasno);
}
if (region >= cpu->pmsav7_dregion) {
return;
}
cpu->env.pmsav8.rlar[attrs.secure][region] = value;
tlb_flush(CPU(cpu));
return;
}
if (region >= cpu->pmsav7_dregion) {
return;
@ -731,6 +850,30 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
tlb_flush(CPU(cpu));
break;
}
case 0xdc0: /* MPU_MAIR0 */
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
goto bad_offset;
}
if (cpu->pmsav7_dregion) {
/* Register is RES0 if no MPU regions are implemented */
cpu->env.pmsav8.mair0[attrs.secure] = value;
}
/* We don't need to do anything else because memory attributes
* only affect cacheability, and we don't implement caching.
*/
break;
case 0xdc4: /* MPU_MAIR1 */
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
goto bad_offset;
}
if (cpu->pmsav7_dregion) {
/* Register is RES0 if no MPU regions are implemented */
cpu->env.pmsav8.mair1[attrs.secure] = value;
}
/* We don't need to do anything else because memory attributes
* only affect cacheability, and we don't implement caching.
*/
break;
case 0xf00: /* Software Triggered Interrupt Register */
{
int excnum = (value & 0x1ff) + NVIC_FIRST_IRQ;
@ -740,17 +883,21 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
break;
}
default:
bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"NVIC: Bad write offset 0x%x\n", offset);
}
}
static bool nvic_user_access_ok(NVICState *s, hwaddr offset)
static bool nvic_user_access_ok(NVICState *s, hwaddr offset, MemTxAttrs attrs)
{
/* Return true if unprivileged access to this register is permitted. */
switch (offset) {
case 0xf00: /* STIR: accessible only if CCR.USERSETMPEND permits */
return s->cpu->env.v7m.ccr & R_V7M_CCR_USERSETMPEND_MASK;
/* For access via STIR_NS it is the NS CCR.USERSETMPEND that
* controls access even though the CPU is in Secure state (I_QDKX).
*/
return s->cpu->env.v7m.ccr[attrs.secure] & R_V7M_CCR_USERSETMPEND_MASK;
default:
/* All other user accesses cause a BusFault unconditionally */
return false;
@ -766,7 +913,7 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
unsigned i, startvec, end;
uint32_t val;
if (attrs.user && !nvic_user_access_ok(s, addr)) {
if (attrs.user && !nvic_user_access_ok(s, addr, attrs)) {
/* Generate BusFault for unprivileged accesses */
return MEMTX_ERROR;
}
@ -831,7 +978,7 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
break;
default:
if (size == 4) {
val = nvic_readl(s, offset);
val = nvic_readl(s, offset, attrs);
} else {
qemu_log_mask(LOG_GUEST_ERROR,
"NVIC: Bad read of size %d at offset 0x%x\n",
@ -856,7 +1003,7 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
trace_nvic_sysreg_write(addr, value, size);
if (attrs.user && !nvic_user_access_ok(s, addr)) {
if (attrs.user && !nvic_user_access_ok(s, addr, attrs)) {
/* Generate BusFault for unprivileged accesses */
return MEMTX_ERROR;
}
@ -912,7 +1059,7 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
return MEMTX_OK;
}
if (size == 4) {
nvic_writel(s, offset, value);
nvic_writel(s, offset, value, attrs);
return MEMTX_OK;
}
qemu_log_mask(LOG_GUEST_ERROR,
@ -927,6 +1074,47 @@ static const MemoryRegionOps nvic_sysreg_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
static MemTxResult nvic_sysreg_ns_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size,
MemTxAttrs attrs)
{
if (attrs.secure) {
/* S accesses to the alias act like NS accesses to the real region */
attrs.secure = 0;
return nvic_sysreg_write(opaque, addr, value, size, attrs);
} else {
/* NS attrs are RAZ/WI for privileged, and BusFault for user */
if (attrs.user) {
return MEMTX_ERROR;
}
return MEMTX_OK;
}
}
static MemTxResult nvic_sysreg_ns_read(void *opaque, hwaddr addr,
uint64_t *data, unsigned size,
MemTxAttrs attrs)
{
if (attrs.secure) {
/* S accesses to the alias act like NS accesses to the real region */
attrs.secure = 0;
return nvic_sysreg_read(opaque, addr, data, size, attrs);
} else {
/* NS attrs are RAZ/WI for privileged, and BusFault for user */
if (attrs.user) {
return MEMTX_ERROR;
}
*data = 0;
return MEMTX_OK;
}
}
static const MemoryRegionOps nvic_sysreg_ns_ops = {
.read_with_attrs = nvic_sysreg_ns_read,
.write_with_attrs = nvic_sysreg_ns_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static int nvic_post_load(void *opaque, int version_id)
{
NVICState *s = opaque;
@ -1028,6 +1216,7 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
NVICState *s = NVIC(dev);
SysBusDevice *systick_sbd;
Error *err = NULL;
int regionlen;
s->cpu = ARM_CPU(qemu_get_cpu(0));
assert(s->cpu);
@ -1060,8 +1249,23 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
* 0xd00..0xd3c - SCS registers
* 0xd40..0xeff - Reserved or Not implemented
* 0xf00 - STIR
*
* Some registers within this space are banked between security states.
* In v8M there is a second range 0xe002e000..0xe002efff which is the
* NonSecure alias SCS; secure accesses to this behave like NS accesses
* to the main SCS range, and non-secure accesses (including when
* the security extension is not implemented) are RAZ/WI.
* Note that both the main SCS range and the alias range are defined
* to be exempt from memory attribution (R_BLJT) and so the memory
* transaction attribute always matches the current CPU security
* state (attrs.secure == env->v7m.secure). In the nvic_sysreg_ns_ops
* wrappers we change attrs.secure to indicate the NS access; so
* generally code determining which banked register to use should
* use attrs.secure; code determining actual behaviour of the system
* should use env->v7m.secure.
*/
memory_region_init(&s->container, OBJECT(s), "nvic", 0x1000);
regionlen = arm_feature(&s->cpu->env, ARM_FEATURE_V8) ? 0x21000 : 0x1000;
memory_region_init(&s->container, OBJECT(s), "nvic", regionlen);
/* The system register region goes at the bottom of the priority
* stack as it covers the whole page.
*/
@ -1072,6 +1276,13 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
sysbus_mmio_get_region(systick_sbd, 0),
1);
if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) {
memory_region_init_io(&s->sysreg_ns_mem, OBJECT(s),
&nvic_sysreg_ns_ops, s,
"nvic_sysregs_ns", 0x1000);
memory_region_add_subregion(&s->container, 0x20000, &s->sysreg_ns_mem);
}
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->container);
}

View file

@ -989,18 +989,6 @@ static void xilinx_enet_init(Object *obj)
XilinxAXIEnet *s = XILINX_AXI_ENET(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
(Object **) &s->tx_data_dev,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
object_property_add_link(obj, "axistream-control-connected",
TYPE_STREAM_SLAVE,
(Object **) &s->tx_control_dev,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
TYPE_XILINX_AXI_ENET_DATA_STREAM);
object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
@ -1021,6 +1009,10 @@ static Property xilinx_enet_properties[] = {
DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000),
DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000),
DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf),
DEFINE_PROP_LINK("axistream-connected", XilinxAXIEnet,
tx_data_dev, TYPE_STREAM_SLAVE, StreamSlave *),
DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIEnet,
tx_control_dev, TYPE_STREAM_SLAVE, StreamSlave *),
DEFINE_PROP_END_OF_LIST(),
};

View file

@ -131,6 +131,16 @@ typedef struct {
* size than the target architecture's minimum. (Attempting to create
* such a CPU will fail.) Note that changing this is a migration
* compatibility break for the machine.
* @ignore_memory_transaction_failures:
* If this is flag is true then the CPU will ignore memory transaction
* failures which should cause the CPU to take an exception due to an
* access to an unassigned physical address; the transaction will instead
* return zero (for a read) or be ignored (for a write). This should be
* set only by legacy board models which rely on the old RAZ/WI behaviour
* for handling devices that QEMU does not yet model. New board models
* should instead use "unimplemented-device" for all memory ranges where
* the guest will attempt to probe for a device that QEMU doesn't
* implement and a stub device is required.
*/
struct MachineClass {
/*< private >*/
@ -171,6 +181,7 @@ struct MachineClass {
bool rom_file_has_mr;
int minimum_page_bits;
bool has_hotpluggable_cpus;
bool ignore_memory_transaction_failures;
int numa_mem_align_shift;
void (*numa_auto_assign_ram)(MachineClass *mc, NodeInfo *nodes,
int nb_nodes, ram_addr_t size);

View file

@ -50,6 +50,7 @@ typedef struct NVICState {
int exception_prio; /* group prio of the highest prio active exception */
MemoryRegion sysregmem;
MemoryRegion sysreg_ns_mem;
MemoryRegion container;
uint32_t num_irq;

View file

@ -312,6 +312,9 @@ struct qemu_work_item;
* @trace_dstate_delayed: Delayed changes to trace_dstate (includes all changes
* to @trace_dstate).
* @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask).
* @ignore_memory_transaction_failures: Cached copy of the MachineState
* flag of the same name: allows the board to suppress calling of the
* CPU do_transaction_failed hook function.
*
* State of one CPU core or thread.
*/
@ -398,6 +401,8 @@ struct CPUState {
*/
bool throttle_thread_scheduled;
bool ignore_memory_transaction_failures;
/* Note that this is accessed at the start of every TB via a negative
offset from AREG0. Leave this field at the end so as to make the
(absolute value) offset as small as possible. This reduces code
@ -864,7 +869,7 @@ static inline void cpu_transaction_failed(CPUState *cpu, hwaddr physaddr,
{
CPUClass *cc = CPU_GET_CLASS(cpu);
if (cc->do_transaction_failed) {
if (!cpu->ignore_memory_transaction_failures && cc->do_transaction_failed) {
cc->do_transaction_failed(cpu, physaddr, addr, size, access_type,
mmu_idx, attrs, response, retaddr);
}

View file

@ -29,6 +29,7 @@
#include "exec/cpu-common.h"
#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "trace-root.h"
@ -363,6 +364,21 @@ static void cpu_common_parse_features(const char *typename, char *features,
static void cpu_common_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cpu = CPU(dev);
Object *machine = qdev_get_machine();
/* qdev_get_machine() can return something that's not TYPE_MACHINE
* if this is one of the user-only emulators; in that case there's
* no need to check the ignore_memory_transaction_failures board flag.
*/
if (object_dynamic_cast(machine, TYPE_MACHINE)) {
ObjectClass *oc = object_get_class(machine);
MachineClass *mc = MACHINE_CLASS(oc);
if (mc) {
cpu->ignore_memory_transaction_failures =
mc->ignore_memory_transaction_failures;
}
}
if (dev->hotplugged) {
cpu_synchronize_post_init(cpu);

View file

@ -187,7 +187,6 @@ ERROR_WHITELIST = [
{'log':r"Device [\w.,-]+ can not be dynamically instantiated"},
{'log':r"Platform Bus: Can not fit MMIO region of size "},
# other more specific errors we will ignore:
{'device':'allwinner-a10', 'log':"Unsupported NIC model:"},
{'device':'.*-spapr-cpu-core', 'log':r"CPU core type should be"},
{'log':r"MSI(-X)? is not supported by interrupt controller"},
{'log':r"pxb-pcie? devices cannot reside on a PCIe? bus"},

View file

@ -185,11 +185,21 @@ static void arm_cpu_reset(CPUState *s)
uint32_t initial_pc; /* Loaded from 0x4 */
uint8_t *rom;
/* The reset value of this bit is IMPDEF, but ARM recommends
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
env->v7m.secure = true;
}
/* In v7M the reset value of this bit is IMPDEF, but ARM recommends
* that it resets to 1, so QEMU always does that rather than making
* it dependent on CPU model.
* it dependent on CPU model. In v8M it is RES1.
*/
env->v7m.ccr = R_V7M_CCR_STKALIGN_MASK;
env->v7m.ccr[M_REG_NS] = R_V7M_CCR_STKALIGN_MASK;
env->v7m.ccr[M_REG_S] = R_V7M_CCR_STKALIGN_MASK;
if (arm_feature(env, ARM_FEATURE_V8)) {
/* in v8M the NONBASETHRDENA bit [0] is RES1 */
env->v7m.ccr[M_REG_NS] |= R_V7M_CCR_NONBASETHRDENA_MASK;
env->v7m.ccr[M_REG_S] |= R_V7M_CCR_NONBASETHRDENA_MASK;
}
/* Unlike A/R profile, M profile defines the reset LR value */
env->regs[14] = 0xffffffff;
@ -228,17 +238,38 @@ static void arm_cpu_reset(CPUState *s)
env->vfp.xregs[ARM_VFP_FPEXC] = 0;
#endif
if (arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V7)) {
if (arm_feature(env, ARM_FEATURE_PMSA)) {
if (cpu->pmsav7_dregion > 0) {
memset(env->pmsav7.drbar, 0,
sizeof(*env->pmsav7.drbar) * cpu->pmsav7_dregion);
memset(env->pmsav7.drsr, 0,
sizeof(*env->pmsav7.drsr) * cpu->pmsav7_dregion);
memset(env->pmsav7.dracr, 0,
sizeof(*env->pmsav7.dracr) * cpu->pmsav7_dregion);
if (arm_feature(env, ARM_FEATURE_V8)) {
memset(env->pmsav8.rbar[M_REG_NS], 0,
sizeof(*env->pmsav8.rbar[M_REG_NS])
* cpu->pmsav7_dregion);
memset(env->pmsav8.rlar[M_REG_NS], 0,
sizeof(*env->pmsav8.rlar[M_REG_NS])
* cpu->pmsav7_dregion);
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
memset(env->pmsav8.rbar[M_REG_S], 0,
sizeof(*env->pmsav8.rbar[M_REG_S])
* cpu->pmsav7_dregion);
memset(env->pmsav8.rlar[M_REG_S], 0,
sizeof(*env->pmsav8.rlar[M_REG_S])
* cpu->pmsav7_dregion);
}
} else if (arm_feature(env, ARM_FEATURE_V7)) {
memset(env->pmsav7.drbar, 0,
sizeof(*env->pmsav7.drbar) * cpu->pmsav7_dregion);
memset(env->pmsav7.drsr, 0,
sizeof(*env->pmsav7.drsr) * cpu->pmsav7_dregion);
memset(env->pmsav7.dracr, 0,
sizeof(*env->pmsav7.dracr) * cpu->pmsav7_dregion);
}
}
env->pmsav7.rnr = 0;
env->pmsav7.rnr[M_REG_NS] = 0;
env->pmsav7.rnr[M_REG_S] = 0;
env->pmsav8.mair0[M_REG_NS] = 0;
env->pmsav8.mair0[M_REG_S] = 0;
env->pmsav8.mair1[M_REG_NS] = 0;
env->pmsav8.mair1[M_REG_S] = 0;
}
set_flush_to_zero(1, &env->vfp.standard_fp_status);
@ -681,6 +712,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
}
if (arm_feature(env, ARM_FEATURE_V6)) {
set_feature(env, ARM_FEATURE_V5);
set_feature(env, ARM_FEATURE_JAZELLE);
if (!arm_feature(env, ARM_FEATURE_M)) {
set_feature(env, ARM_FEATURE_AUXCR);
}
@ -809,9 +841,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
}
if (nr) {
env->pmsav7.drbar = g_new0(uint32_t, nr);
env->pmsav7.drsr = g_new0(uint32_t, nr);
env->pmsav7.dracr = g_new0(uint32_t, nr);
if (arm_feature(env, ARM_FEATURE_V8)) {
/* PMSAv8 */
env->pmsav8.rbar[M_REG_NS] = g_new0(uint32_t, nr);
env->pmsav8.rlar[M_REG_NS] = g_new0(uint32_t, nr);
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
env->pmsav8.rbar[M_REG_S] = g_new0(uint32_t, nr);
env->pmsav8.rlar[M_REG_S] = g_new0(uint32_t, nr);
}
} else {
env->pmsav7.drbar = g_new0(uint32_t, nr);
env->pmsav7.drsr = g_new0(uint32_t, nr);
env->pmsav7.dracr = g_new0(uint32_t, nr);
}
}
}
@ -825,22 +867,21 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
init_cpreg_list(cpu);
#ifndef CONFIG_USER_ONLY
if (cpu->has_el3) {
cs->num_ases = 2;
} else {
cs->num_ases = 1;
}
if (cpu->has_el3) {
if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) {
AddressSpace *as;
cs->num_ases = 2;
if (!cpu->secure_memory) {
cpu->secure_memory = cs->memory;
}
as = address_space_init_shareable(cpu->secure_memory,
"cpu-secure-memory");
cpu_address_space_init(cs, as, ARMASIdx_S);
} else {
cs->num_ases = 1;
}
cpu_address_space_init(cs,
address_space_init_shareable(cs->memory,
"cpu-memory"),
@ -887,6 +928,7 @@ static void arm926_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
set_feature(&cpu->env, ARM_FEATURE_JAZELLE);
cpu->midr = 0x41069265;
cpu->reset_fpsid = 0x41011090;
cpu->ctr = 0x1dd20d2;
@ -916,6 +958,7 @@ static void arm1026_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_AUXCR);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
set_feature(&cpu->env, ARM_FEATURE_JAZELLE);
cpu->midr = 0x4106a262;
cpu->reset_fpsid = 0x410110a0;
cpu->ctr = 0x1dd20d2;
@ -1667,6 +1710,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
#else
cc->do_interrupt = arm_cpu_do_interrupt;
cc->do_unaligned_access = arm_cpu_do_unaligned_access;
cc->do_transaction_failed = arm_cpu_do_transaction_failed;
cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
cc->asidx_from_attrs = arm_asidx_from_attrs;
cc->vmsd = &vmstate_arm_cpu;

View file

@ -66,11 +66,24 @@
#define ARMV7M_EXCP_MEM 4
#define ARMV7M_EXCP_BUS 5
#define ARMV7M_EXCP_USAGE 6
#define ARMV7M_EXCP_SECURE 7
#define ARMV7M_EXCP_SVC 11
#define ARMV7M_EXCP_DEBUG 12
#define ARMV7M_EXCP_PENDSV 14
#define ARMV7M_EXCP_SYSTICK 15
/* For M profile, some registers are banked secure vs non-secure;
* these are represented as a 2-element array where the first element
* is the non-secure copy and the second is the secure copy.
* When the CPU does not have implement the security extension then
* only the first element is used.
* This means that the copy for the current security state can be
* accessed via env->registerfield[env->v7m.secure] (whether the security
* extension is implemented or not).
*/
#define M_REG_NS 0
#define M_REG_S 1
/* ARM-specific interrupt pending bits. */
#define CPU_INTERRUPT_FIQ CPU_INTERRUPT_TGT_EXT_1
#define CPU_INTERRUPT_VIRQ CPU_INTERRUPT_TGT_EXT_2
@ -406,20 +419,34 @@ typedef struct CPUARMState {
} cp15;
struct {
/* M profile has up to 4 stack pointers:
* a Main Stack Pointer and a Process Stack Pointer for each
* of the Secure and Non-Secure states. (If the CPU doesn't support
* the security extension then it has only two SPs.)
* In QEMU we always store the currently active SP in regs[13],
* and the non-active SP for the current security state in
* v7m.other_sp. The stack pointers for the inactive security state
* are stored in other_ss_msp and other_ss_psp.
* switch_v7m_security_state() is responsible for rearranging them
* when we change security state.
*/
uint32_t other_sp;
uint32_t vecbase;
uint32_t basepri;
uint32_t control;
uint32_t ccr; /* Configuration and Control */
uint32_t cfsr; /* Configurable Fault Status */
uint32_t other_ss_msp;
uint32_t other_ss_psp;
uint32_t vecbase[2];
uint32_t basepri[2];
uint32_t control[2];
uint32_t ccr[2]; /* Configuration and Control */
uint32_t cfsr[2]; /* Configurable Fault Status */
uint32_t hfsr; /* HardFault Status */
uint32_t dfsr; /* Debug Fault Status Register */
uint32_t mmfar; /* MemManage Fault Address */
uint32_t mmfar[2]; /* MemManage Fault Address */
uint32_t bfar; /* BusFault Address */
unsigned mpu_ctrl; /* MPU_CTRL */
unsigned mpu_ctrl[2]; /* MPU_CTRL */
int exception;
uint32_t primask;
uint32_t faultmask;
uint32_t primask[2];
uint32_t faultmask[2];
uint32_t secure; /* Is CPU in Secure state? (not guest visible) */
} v7m;
/* Information associated with an exception about to be taken:
@ -519,9 +546,22 @@ typedef struct CPUARMState {
uint32_t *drbar;
uint32_t *drsr;
uint32_t *dracr;
uint32_t rnr;
uint32_t rnr[2];
} pmsav7;
/* PMSAv8 MPU */
struct {
/* The PMSAv8 implementation also shares some PMSAv7 config
* and state:
* pmsav7.rnr (region number register)
* pmsav7_dregion (number of configured regions)
*/
uint32_t *rbar[2];
uint32_t *rlar[2];
uint32_t mair0[2];
uint32_t mair1[2];
} pmsav8;
void *nvic;
const struct arm_boot_info *boot_info;
/* Store GICv3CPUState to access from this struct */
@ -1182,6 +1222,11 @@ FIELD(V7M_CFSR, NOCP, 16 + 3, 1)
FIELD(V7M_CFSR, UNALIGNED, 16 + 8, 1)
FIELD(V7M_CFSR, DIVBYZERO, 16 + 9, 1)
/* V7M CFSR bit masks covering all of the subregister bits */
FIELD(V7M_CFSR, MMFSR, 0, 8)
FIELD(V7M_CFSR, BFSR, 8, 8)
FIELD(V7M_CFSR, UFSR, 16, 16)
/* V7M HFSR bits */
FIELD(V7M_HFSR, VECTTBL, 1, 1)
FIELD(V7M_HFSR, FORCED, 30, 1)
@ -1250,6 +1295,8 @@ enum arm_features {
ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */
ARM_FEATURE_PMU, /* has PMU support */
ARM_FEATURE_VBAR, /* has cp15 VBAR */
ARM_FEATURE_M_SECURITY, /* M profile Security Extension */
ARM_FEATURE_JAZELLE, /* has (trivial) Jazelle implementation */
};
static inline int arm_feature(CPUARMState *env, int feature)
@ -1414,6 +1461,16 @@ void armv7m_nvic_acknowledge_irq(void *opaque);
* (Ignoring -1, this is the same as the RETTOBASE value before completion.)
*/
int armv7m_nvic_complete_irq(void *opaque, int irq);
/**
* armv7m_nvic_raw_execution_priority: return the raw execution priority
* @opaque: the NVIC
*
* Returns: the raw execution priority as defined by the v8M architecture.
* This is the execution priority minus the effects of AIRCR.PRIS,
* and minus any PRIMASK/FAULTMASK/BASEPRI priority boosting.
* (v8M ARM ARM I_PKLD.)
*/
int armv7m_nvic_raw_execution_priority(void *opaque);
/* Interface for defining coprocessor registers.
* Registers are defined in tables of arm_cp_reginfo structs
@ -1643,7 +1700,8 @@ static inline bool arm_v7m_is_handler_mode(CPUARMState *env)
static inline int arm_current_el(CPUARMState *env)
{
if (arm_feature(env, ARM_FEATURE_M)) {
return arm_v7m_is_handler_mode(env) || !(env->v7m.control & 1);
return arm_v7m_is_handler_mode(env) ||
!(env->v7m.control[env->v7m.secure] & 1);
}
if (is_a64(env)) {
@ -2087,6 +2145,10 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
* Execution priority negative (this is like privileged, but the
* MPU HFNMIENA bit means that it may have different access permission
* check results to normal privileged code, so can't share a TLB).
* If the CPU supports the v8M Security Extension then there are also:
* Secure User
* Secure Privileged
* Secure, execution priority negative
*
* The ARMMMUIdx and the mmu index value used by the core QEMU TLB code
* are not quite the same -- different CPU types (most notably M profile
@ -2124,6 +2186,9 @@ typedef enum ARMMMUIdx {
ARMMMUIdx_MUser = 0 | ARM_MMU_IDX_M,
ARMMMUIdx_MPriv = 1 | ARM_MMU_IDX_M,
ARMMMUIdx_MNegPri = 2 | ARM_MMU_IDX_M,
ARMMMUIdx_MSUser = 3 | ARM_MMU_IDX_M,
ARMMMUIdx_MSPriv = 4 | ARM_MMU_IDX_M,
ARMMMUIdx_MSNegPri = 5 | ARM_MMU_IDX_M,
/* Indexes below here don't have TLBs and are used only for AT system
* instructions or for the first stage of an S12 page table walk.
*/
@ -2145,6 +2210,9 @@ typedef enum ARMMMUIdxBit {
ARMMMUIdxBit_MUser = 1 << 0,
ARMMMUIdxBit_MPriv = 1 << 1,
ARMMMUIdxBit_MNegPri = 1 << 2,
ARMMMUIdxBit_MSUser = 1 << 3,
ARMMMUIdxBit_MSPriv = 1 << 4,
ARMMMUIdxBit_MSNegPri = 1 << 5,
} ARMMMUIdxBit;
#define MMU_USER_IDX 0
@ -2170,7 +2238,8 @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
case ARM_MMU_IDX_A:
return mmu_idx & 3;
case ARM_MMU_IDX_M:
return mmu_idx == ARMMMUIdx_MUser ? 0 : 1;
return (mmu_idx == ARMMMUIdx_MUser || mmu_idx == ARMMMUIdx_MSUser)
? 0 : 1;
default:
g_assert_not_reached();
}
@ -2188,8 +2257,12 @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
* we're in a HardFault or NMI handler.
*/
if ((env->v7m.exception > 0 && env->v7m.exception <= 3)
|| env->v7m.faultmask) {
return arm_to_core_mmu_idx(ARMMMUIdx_MNegPri);
|| env->v7m.faultmask[env->v7m.secure]) {
mmu_idx = ARMMMUIdx_MNegPri;
}
if (env->v7m.secure) {
mmu_idx += ARMMMUIdx_MSUser;
}
return arm_to_core_mmu_idx(mmu_idx);

View file

@ -2385,7 +2385,7 @@ static uint64_t pmsav7_read(CPUARMState *env, const ARMCPRegInfo *ri)
return 0;
}
u32p += env->pmsav7.rnr;
u32p += env->pmsav7.rnr[M_REG_NS];
return *u32p;
}
@ -2399,7 +2399,7 @@ static void pmsav7_write(CPUARMState *env, const ARMCPRegInfo *ri,
return;
}
u32p += env->pmsav7.rnr;
u32p += env->pmsav7.rnr[M_REG_NS];
tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */
*u32p = value;
}
@ -2442,7 +2442,7 @@ static const ARMCPRegInfo pmsav7_cp_reginfo[] = {
.resetfn = arm_cp_reset_ignore },
{ .name = "RGNR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 2, .opc2 = 0,
.access = PL1_RW,
.fieldoffset = offsetof(CPUARMState, pmsav7.rnr),
.fieldoffset = offsetof(CPUARMState, pmsav7.rnr[M_REG_NS]),
.writefn = pmsav7_rgnr_write,
.resetfn = arm_cp_reset_ignore },
REGINFO_SENTINEL
@ -5870,6 +5870,12 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
return 0;
}
void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
{
/* translate.c should never generate calls here in user-only mode */
g_assert_not_reached();
}
void switch_mode(CPUARMState *env, int mode)
{
ARMCPU *cpu = arm_env_get_cpu(env);
@ -6044,29 +6050,103 @@ static uint32_t v7m_pop(CPUARMState *env)
return val;
}
/* Return true if we're using the process stack pointer (not the MSP) */
static bool v7m_using_psp(CPUARMState *env)
{
/* Handler mode always uses the main stack; for thread mode
* the CONTROL.SPSEL bit determines the answer.
* Note that in v7M it is not possible to be in Handler mode with
* CONTROL.SPSEL non-zero, but in v8M it is, so we must check both.
*/
return !arm_v7m_is_handler_mode(env) &&
env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK;
}
/* Switch to V7M main or process stack pointer. */
static void switch_v7m_sp(CPUARMState *env, bool new_spsel)
{
uint32_t tmp;
bool old_spsel = env->v7m.control & R_V7M_CONTROL_SPSEL_MASK;
uint32_t old_control = env->v7m.control[env->v7m.secure];
bool old_spsel = old_control & R_V7M_CONTROL_SPSEL_MASK;
if (old_spsel != new_spsel) {
tmp = env->v7m.other_sp;
env->v7m.other_sp = env->regs[13];
env->regs[13] = tmp;
env->v7m.control = deposit32(env->v7m.control,
env->v7m.control[env->v7m.secure] = deposit32(old_control,
R_V7M_CONTROL_SPSEL_SHIFT,
R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
}
}
/* Switch M profile security state between NS and S */
static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
{
uint32_t new_ss_msp, new_ss_psp;
if (env->v7m.secure == new_secstate) {
return;
}
/* All the banked state is accessed by looking at env->v7m.secure
* except for the stack pointer; rearrange the SP appropriately.
*/
new_ss_msp = env->v7m.other_ss_msp;
new_ss_psp = env->v7m.other_ss_psp;
if (v7m_using_psp(env)) {
env->v7m.other_ss_psp = env->regs[13];
env->v7m.other_ss_msp = env->v7m.other_sp;
} else {
env->v7m.other_ss_msp = env->regs[13];
env->v7m.other_ss_psp = env->v7m.other_sp;
}
env->v7m.secure = new_secstate;
if (v7m_using_psp(env)) {
env->regs[13] = new_ss_psp;
env->v7m.other_sp = new_ss_msp;
} else {
env->regs[13] = new_ss_msp;
env->v7m.other_sp = new_ss_psp;
}
}
void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
{
/* Handle v7M BXNS:
* - if the return value is a magic value, do exception return (like BX)
* - otherwise bit 0 of the return value is the target security state
*/
if (dest >= 0xff000000) {
/* This is an exception return magic value; put it where
* do_v7m_exception_exit() expects and raise EXCEPTION_EXIT.
* Note that if we ever add gen_ss_advance() singlestep support to
* M profile this should count as an "instruction execution complete"
* event (compare gen_bx_excret_final_code()).
*/
env->regs[15] = dest & ~1;
env->thumb = dest & 1;
HELPER(exception_internal)(env, EXCP_EXCEPTION_EXIT);
/* notreached */
}
/* translate.c should have made BXNS UNDEF unless we're secure */
assert(env->v7m.secure);
switch_v7m_security_state(env, dest & 1);
env->thumb = 1;
env->regs[15] = dest & ~1;
}
static uint32_t arm_v7m_load_vector(ARMCPU *cpu)
{
CPUState *cs = CPU(cpu);
CPUARMState *env = &cpu->env;
MemTxResult result;
hwaddr vec = env->v7m.vecbase + env->v7m.exception * 4;
hwaddr vec = env->v7m.vecbase[env->v7m.secure] + env->v7m.exception * 4;
uint32_t addr;
addr = address_space_ldl(cs->as, vec,
@ -6112,7 +6192,8 @@ static void v7m_push_stack(ARMCPU *cpu)
uint32_t xpsr = xpsr_read(env);
/* Align stack pointer if the guest wants that */
if ((env->regs[13] & 4) && (env->v7m.ccr & R_V7M_CCR_STKALIGN_MASK)) {
if ((env->regs[13] & 4) &&
(env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) {
env->regs[13] -= 4;
xpsr |= XPSR_SPREALIGN;
}
@ -6166,8 +6247,20 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
}
if (env->v7m.exception != ARMV7M_EXCP_NMI) {
/* Auto-clear FAULTMASK on return from other than NMI */
env->v7m.faultmask = 0;
/* Auto-clear FAULTMASK on return from other than NMI.
* If the security extension is implemented then this only
* happens if the raw execution priority is >= 0; the
* value of the ES bit in the exception return value indicates
* which security state's faultmask to clear. (v8M ARM ARM R_KBNF.)
*/
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
int es = type & 1;
if (armv7m_nvic_raw_execution_priority(env->nvic) >= 0) {
env->v7m.faultmask[es] = 0;
}
} else {
env->v7m.faultmask[M_REG_NS] = 0;
}
}
switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception)) {
@ -6198,7 +6291,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
/* fall through */
case 9: /* Return to Thread using Main stack */
if (!rettobase &&
!(env->v7m.ccr & R_V7M_CCR_NONBASETHRDENA_MASK)) {
!(env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_NONBASETHRDENA_MASK)) {
ufault = true;
}
break;
@ -6210,7 +6303,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
/* Bad exception return: instead of popping the exception
* stack, directly take a usage fault on the current stack.
*/
env->v7m.cfsr |= R_V7M_CFSR_INVPC_MASK;
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
v7m_exception_taken(cpu, type | 0xf0000000);
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
@ -6252,7 +6345,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
if (return_to_handler != arm_v7m_is_handler_mode(env)) {
/* Take an INVPC UsageFault by pushing the stack again. */
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
env->v7m.cfsr |= R_V7M_CFSR_INVPC_MASK;
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
v7m_push_stack(cpu);
v7m_exception_taken(cpu, type | 0xf0000000);
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe: "
@ -6311,15 +6404,15 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
switch (cs->exception_index) {
case EXCP_UDEF:
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
env->v7m.cfsr |= R_V7M_CFSR_UNDEFINSTR_MASK;
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK;
break;
case EXCP_NOCP:
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
env->v7m.cfsr |= R_V7M_CFSR_NOCP_MASK;
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK;
break;
case EXCP_INVSTATE:
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
env->v7m.cfsr |= R_V7M_CFSR_INVSTATE_MASK;
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
break;
case EXCP_SWI:
/* The PC already points to the next instruction. */
@ -6335,11 +6428,11 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
case 0x8: /* External Abort */
switch (cs->exception_index) {
case EXCP_PREFETCH_ABORT:
env->v7m.cfsr |= R_V7M_CFSR_PRECISERR_MASK;
env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_PRECISERR_MASK;
qemu_log_mask(CPU_LOG_INT, "...with CFSR.PRECISERR\n");
break;
case EXCP_DATA_ABORT:
env->v7m.cfsr |=
env->v7m.cfsr[M_REG_NS] |=
(R_V7M_CFSR_IBUSERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
env->v7m.bfar = env->exception.vaddress;
qemu_log_mask(CPU_LOG_INT,
@ -6355,16 +6448,16 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
*/
switch (cs->exception_index) {
case EXCP_PREFETCH_ABORT:
env->v7m.cfsr |= R_V7M_CFSR_IACCVIOL_MASK;
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
break;
case EXCP_DATA_ABORT:
env->v7m.cfsr |=
env->v7m.cfsr[env->v7m.secure] |=
(R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK);
env->v7m.mmfar = env->exception.vaddress;
env->v7m.mmfar[env->v7m.secure] = env->exception.vaddress;
qemu_log_mask(CPU_LOG_INT,
"...with CFSR.DACCVIOL and MMFAR 0x%x\n",
env->v7m.mmfar);
env->v7m.mmfar[env->v7m.secure]);
break;
}
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
@ -6397,7 +6490,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
}
lr = 0xfffffff1;
if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) {
if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) {
lr |= 4;
}
if (!arm_v7m_is_handler_mode(env)) {
@ -7032,35 +7125,15 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
case ARMMMUIdx_MPriv:
case ARMMMUIdx_MNegPri:
case ARMMMUIdx_MUser:
case ARMMMUIdx_MSPriv:
case ARMMMUIdx_MSNegPri:
case ARMMMUIdx_MSUser:
return 1;
default:
g_assert_not_reached();
}
}
/* Return true if this address translation regime is secure */
static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
{
switch (mmu_idx) {
case ARMMMUIdx_S12NSE0:
case ARMMMUIdx_S12NSE1:
case ARMMMUIdx_S1NSE0:
case ARMMMUIdx_S1NSE1:
case ARMMMUIdx_S1E2:
case ARMMMUIdx_S2NS:
case ARMMMUIdx_MPriv:
case ARMMMUIdx_MNegPri:
case ARMMMUIdx_MUser:
return false;
case ARMMMUIdx_S1E3:
case ARMMMUIdx_S1SE0:
case ARMMMUIdx_S1SE1:
return true;
default:
g_assert_not_reached();
}
}
/* Return the SCTLR value which controls this address translation regime */
static inline uint32_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx)
{
@ -7072,11 +7145,12 @@ static inline bool regime_translation_disabled(CPUARMState *env,
ARMMMUIdx mmu_idx)
{
if (arm_feature(env, ARM_FEATURE_M)) {
switch (env->v7m.mpu_ctrl &
switch (env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)] &
(R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK)) {
case R_V7M_MPU_CTRL_ENABLE_MASK:
/* Enabled, but not for HardFault and NMI */
return mmu_idx == ARMMMUIdx_MNegPri;
return mmu_idx == ARMMMUIdx_MNegPri ||
mmu_idx == ARMMMUIdx_MSNegPri;
case R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK:
/* Enabled for all cases */
return false;
@ -8231,7 +8305,8 @@ static bool pmsav7_use_background_region(ARMCPU *cpu,
}
if (arm_feature(env, ARM_FEATURE_M)) {
return env->v7m.mpu_ctrl & R_V7M_MPU_CTRL_PRIVDEFENA_MASK;
return env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)]
& R_V7M_MPU_CTRL_PRIVDEFENA_MASK;
} else {
return regime_sctlr(env, mmu_idx) & SCTLR_BR;
}
@ -8411,6 +8486,112 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
return !(*prot & (1 << access_type));
}
static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, int *prot, uint32_t *fsr)
{
ARMCPU *cpu = arm_env_get_cpu(env);
bool is_user = regime_is_user(env, mmu_idx);
uint32_t secure = regime_is_secure(env, mmu_idx);
int n;
int matchregion = -1;
bool hit = false;
*phys_ptr = address;
*prot = 0;
/* Unlike the ARM ARM pseudocode, we don't need to check whether this
* was an exception vector read from the vector table (which is always
* done using the default system address map), because those accesses
* are done in arm_v7m_load_vector(), which always does a direct
* read using address_space_ldl(), rather than going via this function.
*/
if (regime_translation_disabled(env, mmu_idx)) { /* MPU disabled */
hit = true;
} else if (m_is_ppb_region(env, address)) {
hit = true;
} else if (pmsav7_use_background_region(cpu, mmu_idx, is_user)) {
hit = true;
} else {
for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) {
/* region search */
/* Note that the base address is bits [31:5] from the register
* with bits [4:0] all zeroes, but the limit address is bits
* [31:5] from the register with bits [4:0] all ones.
*/
uint32_t base = env->pmsav8.rbar[secure][n] & ~0x1f;
uint32_t limit = env->pmsav8.rlar[secure][n] | 0x1f;
if (!(env->pmsav8.rlar[secure][n] & 0x1)) {
/* Region disabled */
continue;
}
if (address < base || address > limit) {
continue;
}
if (hit) {
/* Multiple regions match -- always a failure (unlike
* PMSAv7 where highest-numbered-region wins)
*/
*fsr = 0x00d; /* permission fault */
return true;
}
matchregion = n;
hit = true;
if (base & ~TARGET_PAGE_MASK) {
qemu_log_mask(LOG_UNIMP,
"MPU_RBAR[%d]: No support for MPU region base"
"address of 0x%" PRIx32 ". Minimum alignment is "
"%d\n",
n, base, TARGET_PAGE_BITS);
continue;
}
if ((limit + 1) & ~TARGET_PAGE_MASK) {
qemu_log_mask(LOG_UNIMP,
"MPU_RBAR[%d]: No support for MPU region limit"
"address of 0x%" PRIx32 ". Minimum alignment is "
"%d\n",
n, limit, TARGET_PAGE_BITS);
continue;
}
}
}
if (!hit) {
/* background fault */
*fsr = 0;
return true;
}
if (matchregion == -1) {
/* hit using the background region */
get_phys_addr_pmsav7_default(env, mmu_idx, address, prot);
} else {
uint32_t ap = extract32(env->pmsav8.rbar[secure][matchregion], 1, 2);
uint32_t xn = extract32(env->pmsav8.rbar[secure][matchregion], 0, 1);
if (m_is_system_region(env, address)) {
/* System space is always execute never */
xn = 1;
}
*prot = simple_ap_to_rw_prot(env, mmu_idx, ap);
if (*prot && !xn) {
*prot |= PAGE_EXEC;
}
/* We don't need to look the attribute up in the MAIR0/MAIR1
* registers because that only tells us about cacheability.
*/
}
*fsr = 0x00d; /* Permission fault */
return !(*prot & (1 << access_type));
}
static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, int *prot, uint32_t *fsr)
@ -8580,7 +8761,11 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address,
bool ret;
*page_size = TARGET_PAGE_SIZE;
if (arm_feature(env, ARM_FEATURE_V7)) {
if (arm_feature(env, ARM_FEATURE_V8)) {
/* PMSAv8 */
ret = get_phys_addr_pmsav8(env, address, access_type, mmu_idx,
phys_ptr, prot, fsr);
} else if (arm_feature(env, ARM_FEATURE_V7)) {
/* PMSAv7 */
ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx,
phys_ptr, prot, fsr);
@ -8699,7 +8884,7 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
return xpsr_read(env) & mask;
break;
case 20: /* CONTROL */
return env->v7m.control;
return env->v7m.control[env->v7m.secure];
}
if (el == 0) {
@ -8708,18 +8893,18 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
switch (reg) {
case 8: /* MSP */
return (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) ?
return (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) ?
env->v7m.other_sp : env->regs[13];
case 9: /* PSP */
return (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) ?
return (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) ?
env->regs[13] : env->v7m.other_sp;
case 16: /* PRIMASK */
return env->v7m.primask;
return env->v7m.primask[env->v7m.secure];
case 17: /* BASEPRI */
case 18: /* BASEPRI_MAX */
return env->v7m.basepri;
return env->v7m.basepri[env->v7m.secure];
case 19: /* FAULTMASK */
return env->v7m.faultmask;
return env->v7m.faultmask[env->v7m.secure];
default:
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special"
" register %d\n", reg);
@ -8760,32 +8945,34 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
}
break;
case 8: /* MSP */
if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) {
if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) {
env->v7m.other_sp = val;
} else {
env->regs[13] = val;
}
break;
case 9: /* PSP */
if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) {
if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) {
env->regs[13] = val;
} else {
env->v7m.other_sp = val;
}
break;
case 16: /* PRIMASK */
env->v7m.primask = val & 1;
env->v7m.primask[env->v7m.secure] = val & 1;
break;
case 17: /* BASEPRI */
env->v7m.basepri = val & 0xff;
env->v7m.basepri[env->v7m.secure] = val & 0xff;
break;
case 18: /* BASEPRI_MAX */
val &= 0xff;
if (val != 0 && (val < env->v7m.basepri || env->v7m.basepri == 0))
env->v7m.basepri = val;
if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
|| env->v7m.basepri[env->v7m.secure] == 0)) {
env->v7m.basepri[env->v7m.secure] = val;
}
break;
case 19: /* FAULTMASK */
env->v7m.faultmask = val & 1;
env->v7m.faultmask[env->v7m.secure] = val & 1;
break;
case 20: /* CONTROL */
/* Writing to the SPSEL bit only has an effect if we are in
@ -8796,8 +8983,8 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
if (!arm_v7m_is_handler_mode(env)) {
switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
}
env->v7m.control &= ~R_V7M_CONTROL_NPRIV_MASK;
env->v7m.control |= val & R_V7M_CONTROL_NPRIV_MASK;
env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"

View file

@ -63,6 +63,8 @@ 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_2(v7m_bxns, void, env, 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)

View file

@ -472,6 +472,16 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
MMUAccessType access_type,
int mmu_idx, uintptr_t retaddr);
/* arm_cpu_do_transaction_failed: handle a memory system error response
* (eg "no device/memory present at address") by raising an external abort
* exception
*/
void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
vaddr addr, unsigned size,
MMUAccessType access_type,
int mmu_idx, MemTxAttrs attrs,
MemTxResult response, uintptr_t retaddr);
/* Call the EL change hook if one has been registered */
static inline void arm_call_el_change_hook(ARMCPU *cpu)
{
@ -480,4 +490,30 @@ static inline void arm_call_el_change_hook(ARMCPU *cpu)
}
}
/* Return true if this address translation regime is secure */
static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
{
switch (mmu_idx) {
case ARMMMUIdx_S12NSE0:
case ARMMMUIdx_S12NSE1:
case ARMMMUIdx_S1NSE0:
case ARMMMUIdx_S1NSE1:
case ARMMMUIdx_S1E2:
case ARMMMUIdx_S2NS:
case ARMMMUIdx_MPriv:
case ARMMMUIdx_MNegPri:
case ARMMMUIdx_MUser:
return false;
case ARMMMUIdx_S1E3:
case ARMMMUIdx_S1SE0:
case ARMMMUIdx_S1SE1:
case ARMMMUIdx_MSPriv:
case ARMMMUIdx_MSNegPri:
case ARMMMUIdx_MSUser:
return true;
default:
g_assert_not_reached();
}
}
#endif

View file

@ -102,8 +102,8 @@ static const VMStateDescription vmstate_m_faultmask_primask = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(env.v7m.faultmask, ARMCPU),
VMSTATE_UINT32(env.v7m.primask, ARMCPU),
VMSTATE_UINT32(env.v7m.faultmask[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.primask[M_REG_NS], ARMCPU),
VMSTATE_END_OF_LIST()
}
};
@ -114,16 +114,16 @@ static const VMStateDescription vmstate_m = {
.minimum_version_id = 4,
.needed = m_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT32(env.v7m.vecbase, ARMCPU),
VMSTATE_UINT32(env.v7m.basepri, ARMCPU),
VMSTATE_UINT32(env.v7m.control, ARMCPU),
VMSTATE_UINT32(env.v7m.ccr, ARMCPU),
VMSTATE_UINT32(env.v7m.cfsr, ARMCPU),
VMSTATE_UINT32(env.v7m.vecbase[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.basepri[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.control[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.ccr[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.cfsr[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.hfsr, ARMCPU),
VMSTATE_UINT32(env.v7m.dfsr, ARMCPU),
VMSTATE_UINT32(env.v7m.mmfar, ARMCPU),
VMSTATE_UINT32(env.v7m.mmfar[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.bfar, ARMCPU),
VMSTATE_UINT32(env.v7m.mpu_ctrl, ARMCPU),
VMSTATE_UINT32(env.v7m.mpu_ctrl[M_REG_NS], ARMCPU),
VMSTATE_INT32(env.v7m.exception, ARMCPU),
VMSTATE_END_OF_LIST()
},
@ -159,14 +159,15 @@ static bool pmsav7_needed(void *opaque)
CPUARMState *env = &cpu->env;
return arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V7);
arm_feature(env, ARM_FEATURE_V7) &&
!arm_feature(env, ARM_FEATURE_V8);
}
static bool pmsav7_rgnr_vmstate_validate(void *opaque, int version_id)
{
ARMCPU *cpu = opaque;
return cpu->env.pmsav7.rnr < cpu->pmsav7_dregion;
return cpu->env.pmsav7.rnr[M_REG_NS] < cpu->pmsav7_dregion;
}
static const VMStateDescription vmstate_pmsav7 = {
@ -204,7 +205,77 @@ static const VMStateDescription vmstate_pmsav7_rnr = {
.minimum_version_id = 1,
.needed = pmsav7_rnr_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT32(env.pmsav7.rnr, ARMCPU),
VMSTATE_UINT32(env.pmsav7.rnr[M_REG_NS], ARMCPU),
VMSTATE_END_OF_LIST()
}
};
static bool pmsav8_needed(void *opaque)
{
ARMCPU *cpu = opaque;
CPUARMState *env = &cpu->env;
return arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V8);
}
static const VMStateDescription vmstate_pmsav8 = {
.name = "cpu/pmsav8",
.version_id = 1,
.minimum_version_id = 1,
.needed = pmsav8_needed,
.fields = (VMStateField[]) {
VMSTATE_VARRAY_UINT32(env.pmsav8.rbar[M_REG_NS], ARMCPU, pmsav7_dregion,
0, vmstate_info_uint32, uint32_t),
VMSTATE_VARRAY_UINT32(env.pmsav8.rlar[M_REG_NS], ARMCPU, pmsav7_dregion,
0, vmstate_info_uint32, uint32_t),
VMSTATE_UINT32(env.pmsav8.mair0[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.pmsav8.mair1[M_REG_NS], ARMCPU),
VMSTATE_END_OF_LIST()
}
};
static bool s_rnr_vmstate_validate(void *opaque, int version_id)
{
ARMCPU *cpu = opaque;
return cpu->env.pmsav7.rnr[M_REG_S] < cpu->pmsav7_dregion;
}
static bool m_security_needed(void *opaque)
{
ARMCPU *cpu = opaque;
CPUARMState *env = &cpu->env;
return arm_feature(env, ARM_FEATURE_M_SECURITY);
}
static const VMStateDescription vmstate_m_security = {
.name = "cpu/m-security",
.version_id = 1,
.minimum_version_id = 1,
.needed = m_security_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT32(env.v7m.secure, ARMCPU),
VMSTATE_UINT32(env.v7m.other_ss_msp, ARMCPU),
VMSTATE_UINT32(env.v7m.other_ss_psp, ARMCPU),
VMSTATE_UINT32(env.v7m.basepri[M_REG_S], ARMCPU),
VMSTATE_UINT32(env.v7m.primask[M_REG_S], ARMCPU),
VMSTATE_UINT32(env.v7m.faultmask[M_REG_S], ARMCPU),
VMSTATE_UINT32(env.v7m.control[M_REG_S], ARMCPU),
VMSTATE_UINT32(env.v7m.vecbase[M_REG_S], ARMCPU),
VMSTATE_UINT32(env.pmsav8.mair0[M_REG_S], ARMCPU),
VMSTATE_UINT32(env.pmsav8.mair1[M_REG_S], ARMCPU),
VMSTATE_VARRAY_UINT32(env.pmsav8.rbar[M_REG_S], ARMCPU, pmsav7_dregion,
0, vmstate_info_uint32, uint32_t),
VMSTATE_VARRAY_UINT32(env.pmsav8.rlar[M_REG_S], ARMCPU, pmsav7_dregion,
0, vmstate_info_uint32, uint32_t),
VMSTATE_UINT32(env.pmsav7.rnr[M_REG_S], ARMCPU),
VMSTATE_VALIDATE("secure MPU_RNR is valid", s_rnr_vmstate_validate),
VMSTATE_UINT32(env.v7m.mpu_ctrl[M_REG_S], ARMCPU),
VMSTATE_UINT32(env.v7m.ccr[M_REG_S], ARMCPU),
VMSTATE_UINT32(env.v7m.mmfar[M_REG_S], ARMCPU),
VMSTATE_UINT32(env.v7m.cfsr[M_REG_S], ARMCPU),
VMSTATE_END_OF_LIST()
}
};
@ -225,9 +296,13 @@ static int get_cpsr(QEMUFile *f, void *opaque, size_t size,
* differences are that the T bit is not in the same place, the
* primask/faultmask info may be in the CPSR I and F bits, and
* we do not want the mode bits.
* We know that this cleanup happened before v8M, so there
* is no complication with banked primask/faultmask.
*/
uint32_t newval = val;
assert(!arm_feature(env, ARM_FEATURE_M_SECURITY));
newval &= (CPSR_NZCV | CPSR_Q | CPSR_IT | CPSR_GE);
if (val & CPSR_T) {
newval |= XPSR_T;
@ -238,10 +313,10 @@ static int get_cpsr(QEMUFile *f, void *opaque, size_t size,
* transferred using the vmstate_m_faultmask_primask subsection.
*/
if (val & CPSR_F) {
env->v7m.faultmask = 1;
env->v7m.faultmask[M_REG_NS] = 1;
}
if (val & CPSR_I) {
env->v7m.primask = 1;
env->v7m.primask[M_REG_NS] = 1;
}
val = newval;
}
@ -458,6 +533,8 @@ const VMStateDescription vmstate_arm_cpu = {
*/
&vmstate_pmsav7_rnr,
&vmstate_pmsav7,
&vmstate_pmsav8,
&vmstate_m_security,
NULL
}
};

View file

@ -229,6 +229,49 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
deliver_fault(cpu, vaddr, access_type, fsr, fsc, &fi);
}
/* arm_cpu_do_transaction_failed: handle a memory system error response
* (eg "no device/memory present at address") by raising an external abort
* exception
*/
void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
vaddr addr, unsigned size,
MMUAccessType access_type,
int mmu_idx, MemTxAttrs attrs,
MemTxResult response, uintptr_t retaddr)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
uint32_t fsr, fsc;
ARMMMUFaultInfo fi = {};
ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx);
if (retaddr) {
/* now we have a real cpu fault */
cpu_restore_state(cs, retaddr);
}
/* The EA bit in syndromes and fault status registers is an
* IMPDEF classification of external aborts. ARM implementations
* usually use this to indicate AXI bus Decode error (0) or
* Slave error (1); in QEMU we follow that.
*/
fi.ea = (response != MEMTX_DECODE_ERROR);
/* The fault status register format depends on whether we're using
* the LPAE long descriptor format, or the short descriptor format.
*/
if (arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) {
/* long descriptor form, STATUS 0b010000: synchronous ext abort */
fsr = (fi.ea << 12) | (1 << 9) | 0x10;
} else {
/* short descriptor form, FSR 0b01000 : synchronous ext abort */
fsr = (fi.ea << 12) | 0x8;
}
fsc = 0x10;
deliver_fault(cpu, addr, access_type, fsr, fsc, &fi);
}
#endif /* !defined(CONFIG_USER_ONLY) */
uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b)

View file

@ -41,7 +41,7 @@
#define ENABLE_ARCH_5 arm_dc_feature(s, ARM_FEATURE_V5)
/* currently all emulated v5 cores are also v5TE, so don't bother */
#define ENABLE_ARCH_5TE arm_dc_feature(s, ARM_FEATURE_V5)
#define ENABLE_ARCH_5J 0
#define ENABLE_ARCH_5J arm_dc_feature(s, ARM_FEATURE_JAZELLE)
#define ENABLE_ARCH_6 arm_dc_feature(s, ARM_FEATURE_V6)
#define ENABLE_ARCH_6K arm_dc_feature(s, ARM_FEATURE_V6K)
#define ENABLE_ARCH_6T2 arm_dc_feature(s, ARM_FEATURE_THUMB2)
@ -994,6 +994,25 @@ static inline void gen_bx_excret_final_code(DisasContext *s)
gen_exception_internal(EXCP_EXCEPTION_EXIT);
}
static inline void gen_bxns(DisasContext *s, int rm)
{
TCGv_i32 var = load_reg(s, rm);
/* The bxns helper may raise an EXCEPTION_EXIT exception, so in theory
* we need to sync state before calling it, but:
* - we don't need to do gen_set_pc_im() because the bxns helper will
* always set the PC itself
* - we don't need to do gen_set_condexec() because BXNS is UNPREDICTABLE
* unless it's outside an IT block or the last insn in an IT block,
* so we know that condexec == 0 (already set at the top of the TB)
* is correct in the non-UNPREDICTABLE cases, and we can choose
* "zeroes the IT bits" as our UNPREDICTABLE behaviour otherwise.
*/
gen_helper_v7m_bxns(cpu_env, var);
tcg_temp_free_i32(var);
s->base.is_jmp = DISAS_EXIT;
}
/* Variant of store_reg which uses branch&exchange logic when storing
to r15 in ARM architecture v7 and above. The source must be a temporary
and will be marked as dead. */
@ -11185,12 +11204,31 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
*/
bool link = insn & (1 << 7);
if (insn & 7) {
if (insn & 3) {
goto undef;
}
if (link) {
ARCH(5);
}
if ((insn & 4)) {
/* BXNS/BLXNS: only exists for v8M with the
* security extensions, and always UNDEF if NonSecure.
* We don't implement these in the user-only mode
* either (in theory you can use them from Secure User
* mode but they are too tied in to system emulation.)
*/
if (!s->v8m_secure || IS_USER_ONLY) {
goto undef;
}
if (link) {
/* BLXNS: not yet implemented */
goto undef;
} else {
gen_bxns(s, rm);
}
break;
}
/* BLX/BX */
tmp = load_reg(s, rm);
if (link) {
val = (uint32_t)s->pc | 1;
@ -11857,6 +11895,8 @@ static int arm_tr_init_disas_context(DisasContextBase *dcbase,
dc->vec_stride = ARM_TBFLAG_VECSTRIDE(dc->base.tb->flags);
dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(dc->base.tb->flags);
dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(dc->base.tb->flags);
dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
regime_is_secure(env, dc->mmu_idx);
dc->cp_regs = cpu->cp_regs;
dc->features = env->features;
@ -12288,24 +12328,30 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
if (arm_feature(env, ARM_FEATURE_M)) {
uint32_t xpsr = xpsr_read(env);
const char *mode;
const char *ns_status = "";
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
ns_status = env->v7m.secure ? "S " : "NS ";
}
if (xpsr & XPSR_EXCP) {
mode = "handler";
} else {
if (env->v7m.control & R_V7M_CONTROL_NPRIV_MASK) {
if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) {
mode = "unpriv-thread";
} else {
mode = "priv-thread";
}
}
cpu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s\n",
cpu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n",
xpsr,
xpsr & XPSR_N ? 'N' : '-',
xpsr & XPSR_Z ? 'Z' : '-',
xpsr & XPSR_C ? 'C' : '-',
xpsr & XPSR_V ? 'V' : '-',
xpsr & XPSR_T ? 'T' : 'A',
ns_status,
mode);
} else {
uint32_t psr = cpsr_read(env);

View file

@ -35,6 +35,7 @@ typedef struct DisasContext {
int vec_len;
int vec_stride;
bool v7m_handler_mode;
bool v8m_secure; /* true if v8M and we're in Secure mode */
/* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
* so that top level loop can generate correct syndrome information.
*/