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); DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = aw_a10_realize; 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 = { static const TypeInfo aw_a10_type_info = {

View file

@ -97,12 +97,6 @@ static void bitband_init(Object *obj)
BitBandState *s = BITBAND(obj); BitBandState *s = BITBAND(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(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, memory_region_init_io(&s->iomem, obj, &bitband_ops, s,
"bitband", 0x02000000); "bitband", 0x02000000);
sysbus_init_mmio(dev, &s->iomem); 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 */ /* 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); memory_region_init(&s->container, obj, "armv7m-container", UINT64_MAX);
object_initialize(&s->nvic, sizeof(s->nvic), TYPE_NVIC); 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[] = { static Property armv7m_properties[] = {
DEFINE_PROP_STRING("cpu-model", ARMv7MState, cpu_model), DEFINE_PROP_STRING("cpu-model", ARMv7MState, cpu_model),
DEFINE_PROP_LINK("memory", ARMv7MState, board_memory, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_END_OF_LIST(), 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[] = { static Property bitband_properties[] = {
DEFINE_PROP_UINT32("base", BitBandState, base, 0), DEFINE_PROP_UINT32("base", BitBandState, base, 0),
DEFINE_PROP_LINK("source-memory", BitBandState, source_memory,
TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_PROP_END_OF_LIST(), 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_floppy = 1;
mc->no_cdrom = 1; mc->no_cdrom = 1;
mc->no_parallel = 1; mc->no_parallel = 1;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo palmetto_bmc_type = { 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_floppy = 1;
mc->no_cdrom = 1; mc->no_cdrom = 1;
mc->no_parallel = 1; mc->no_parallel = 1;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo ast2500_evb_type = { 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_floppy = 1;
mc->no_cdrom = 1; mc->no_cdrom = 1;
mc->no_parallel = 1; mc->no_parallel = 1;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo romulus_bmc_type = { 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->desc = "Sharp SL-5500 (Collie) PDA (SA-1110)";
mc->init = collie_init; mc->init = collie_init;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("collie", collie_machine_init) DEFINE_MACHINE("collie", collie_machine_init)

View file

@ -86,6 +86,7 @@ static void cubieboard_machine_init(MachineClass *mc)
mc->init = cubieboard_init; mc->init = cubieboard_init;
mc->block_default_type = IF_IDE; mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1; mc->units_per_default_bus = 1;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("cubieboard", cubieboard_machine_init) 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->desc = "Canon PowerShot A1100 IS";
mc->init = &canon_a1100_init; mc->init = &canon_a1100_init;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("canon-a1100", canon_a1100_machine_init) 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->desc = "Samsung NURI board (Exynos4210)";
mc->init = nuri_init; mc->init = nuri_init;
mc->max_cpus = EXYNOS4210_NCPUS; mc->max_cpus = EXYNOS4210_NCPUS;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo nuri_type = { 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->desc = "Samsung SMDKC210 board (Exynos4210)";
mc->init = smdkc210_init; mc->init = smdkc210_init;
mc->max_cpus = EXYNOS4210_NCPUS; mc->max_cpus = EXYNOS4210_NCPUS;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo smdkc210_type = { 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->desc = "Gumstix Connex (PXA255)";
mc->init = connex_init; mc->init = connex_init;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo connex_type = { static const TypeInfo connex_type = {
@ -142,6 +143,7 @@ static void verdex_class_init(ObjectClass *oc, void *data)
mc->desc = "Gumstix Verdex (PXA270)"; mc->desc = "Gumstix Verdex (PXA270)";
mc->init = verdex_init; mc->init = verdex_init;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo verdex_type = { 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->block_default_type = IF_IDE;
mc->units_per_default_bus = 1; mc->units_per_default_bus = 1;
mc->max_cpus = 4; mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo highbank_type = { 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->block_default_type = IF_IDE;
mc->units_per_default_bus = 1; mc->units_per_default_bus = 1;
mc->max_cpus = 4; mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo midway_type = { 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->desc = "ARM i.MX25 PDK board (ARM926)";
mc->init = imx25_pdk_init; mc->init = imx25_pdk_init;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("imx25-pdk", imx25_pdk_machine_init) 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->desc = "ARM Integrator/CP (ARM926EJ-S)";
mc->init = integratorcp_init; mc->init = integratorcp_init;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("integratorcp", integratorcp_machine_init) 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->desc = "ARM KZM Emulation Baseboard (ARM1136)";
mc->init = kzm_init; mc->init = kzm_init;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("kzm", kzm_machine_init) 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->desc = "Mainstone II (PXA27x)";
mc->init = mainstone_init; mc->init = mainstone_init;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("mainstone", mainstone2_machine_init) 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->desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)";
mc->init = musicpal_init; mc->init = musicpal_init;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("musicpal", musicpal_machine_init) 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->desc = "Netduino 2 Machine";
mc->init = netduino2_init; mc->init = netduino2_init;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("netduino2", netduino2_machine_init) 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->desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)";
mc->init = n800_init; mc->init = n800_init;
mc->default_boot_order = ""; mc->default_boot_order = "";
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo n800_type = { 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->desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)";
mc->init = n810_init; mc->init = n810_init;
mc->default_boot_order = ""; mc->default_boot_order = "";
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo n810_type = { 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->desc = "Siemens SX1 (OMAP310) V2";
mc->init = sx1_init_v2; mc->init = sx1_init_v2;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo sx1_machine_v2_type = { 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->desc = "Siemens SX1 (OMAP310) V1";
mc->init = sx1_init_v1; mc->init = sx1_init_v1;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo sx1_machine_v1_type = { 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->desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)";
mc->init = palmte_init; mc->init = palmte_init;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("cheetah", palmte_machine_init) DEFINE_MACHINE("cheetah", palmte_machine_init)

View file

@ -168,5 +168,6 @@ static void raspi2_machine_init(MachineClass *mc)
mc->no_cdrom = 1; mc->no_cdrom = 1;
mc->max_cpus = BCM2836_NCPUS; mc->max_cpus = BCM2836_NCPUS;
mc->default_ram_size = 1024 * 1024 * 1024; mc->default_ram_size = 1024 * 1024 * 1024;
mc->ignore_memory_transaction_failures = true;
}; };
DEFINE_MACHINE("raspi2", raspi2_machine_init) 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->desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)";
mc->init = realview_eb_init; mc->init = realview_eb_init;
mc->block_default_type = IF_SCSI; mc->block_default_type = IF_SCSI;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo realview_eb_type = { 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->init = realview_eb_mpcore_init;
mc->block_default_type = IF_SCSI; mc->block_default_type = IF_SCSI;
mc->max_cpus = 4; mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo realview_eb_mpcore_type = { 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->desc = "ARM RealView Platform Baseboard for Cortex-A8";
mc->init = realview_pb_a8_init; mc->init = realview_pb_a8_init;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo realview_pb_a8_type = { 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->desc = "ARM RealView Platform Baseboard Explore for Cortex-A9";
mc->init = realview_pbx_a9_init; mc->init = realview_pbx_a9_init;
mc->max_cpus = 4; mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo realview_pbx_a9_type = { 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->desc = "Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)";
mc->init = sabrelite_init; mc->init = sabrelite_init;
mc->max_cpus = FSL_IMX6_NUM_CPUS; mc->max_cpus = FSL_IMX6_NUM_CPUS;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("sabrelite", sabrelite_machine_init) 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->desc = "Sharp SL-C1000 (Akita) PDA (PXA270)";
mc->init = akita_init; mc->init = akita_init;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo akitapda_type = { 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->desc = "Sharp SL-C3000 (Spitz) PDA (PXA270)";
mc->init = spitz_init; mc->init = spitz_init;
mc->block_default_type = IF_IDE; mc->block_default_type = IF_IDE;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo spitzpda_type = { 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->desc = "Sharp SL-C3100 (Borzoi) PDA (PXA270)";
mc->init = borzoi_init; mc->init = borzoi_init;
mc->block_default_type = IF_IDE; mc->block_default_type = IF_IDE;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo borzoipda_type = { 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->desc = "Sharp SL-C3200 (Terrier) PDA (PXA270)";
mc->init = terrier_init; mc->init = terrier_init;
mc->block_default_type = IF_IDE; mc->block_default_type = IF_IDE;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo terrierpda_type = { 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->desc = "Stellaris LM3S811EVB";
mc->init = lm3s811evb_init; mc->init = lm3s811evb_init;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo lm3s811evb_type = { static const TypeInfo lm3s811evb_type = {
@ -1467,6 +1468,7 @@ static void lm3s6965evb_class_init(ObjectClass *oc, void *data)
mc->desc = "Stellaris LM3S6965EVB"; mc->desc = "Stellaris LM3S6965EVB";
mc->init = lm3s6965evb_init; mc->init = lm3s6965evb_init;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo lm3s6965evb_type = { 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->desc = "Sharp SL-6000 (Tosa) PDA (PXA255)";
mc->init = tosa_init; mc->init = tosa_init;
mc->block_default_type = IF_IDE; mc->block_default_type = IF_IDE;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("tosa", tosapda_machine_init) 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->desc = "ARM Versatile/PB (ARM926EJ-S)";
mc->init = vpb_init; mc->init = vpb_init;
mc->block_default_type = IF_SCSI; mc->block_default_type = IF_SCSI;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo versatilepb_type = { 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->desc = "ARM Versatile/AB (ARM926EJ-S)";
mc->init = vab_init; mc->init = vab_init;
mc->block_default_type = IF_SCSI; mc->block_default_type = IF_SCSI;
mc->ignore_memory_transaction_failures = true;
} }
static const TypeInfo versatileab_type = { 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->desc = "ARM Versatile Express";
mc->init = vexpress_common_init; mc->init = vexpress_common_init;
mc->max_cpus = 4; mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
} }
static void vexpress_a9_class_init(ObjectClass *oc, void *data) 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->init = zynq_init;
mc->max_cpus = 1; mc->max_cpus = 1;
mc->no_sdcard = 1; mc->no_sdcard = 1;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("xilinx-zynq-a9", zynq_machine_init) 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->init = xlnx_ep108_init;
mc->block_default_type = IF_IDE; mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1; mc->units_per_default_bus = 1;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("xlnx-ep108", xlnx_ep108_machine_init) 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->init = xlnx_ep108_init;
mc->block_default_type = IF_IDE; mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1; mc->units_per_default_bus = 1;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("xlnx-zcu102", xlnx_zcu102_machine_init) DEFINE_MACHINE("xlnx-zcu102", xlnx_zcu102_machine_init)

View file

@ -140,11 +140,6 @@ static void xlnx_zynqmp_init(Object *obj)
&error_abort); &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()); object_initialize(&s->gic, sizeof(s->gic), gic_class_name());
qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default()); 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_STRING("boot-cpu", XlnxZynqMPState, boot_cpu),
DEFINE_PROP_BOOL("secure", XlnxZynqMPState, secure, false), DEFINE_PROP_BOOL("secure", XlnxZynqMPState, secure, false),
DEFINE_PROP_BOOL("has_rpu", XlnxZynqMPState, has_rpu, 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() DEFINE_PROP_END_OF_LIST()
}; };

View file

@ -370,6 +370,7 @@ static void z2_machine_init(MachineClass *mc)
{ {
mc->desc = "Zipit Z2 (PXA27x)"; mc->desc = "Zipit Z2 (PXA27x)";
mc->init = z2_init; mc->init = z2_init;
mc->ignore_memory_transaction_failures = true;
} }
DEFINE_MACHINE("z2", z2_machine_init) 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); XilinxAXIDMA *s = XILINX_AXI_DMA(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(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), object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
TYPE_XILINX_AXI_DMA_DATA_STREAM); TYPE_XILINX_AXI_DMA_DATA_STREAM);
object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev), 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[] = { static Property axidma_properties[] = {
DEFINE_PROP_UINT32("freqhz", XilinxAXIDMA, freqhz, 50000000), 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(), 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); 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. * kvm_arm_its_pre_save - handles the saving of ITS registers.
* ITS tables are flushed into guest RAM separately and earlier, * 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); 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) static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass); GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
dc->realize = kvm_arm_its_realize; dc->realize = kvm_arm_its_realize;
dc->props = kvm_arm_its_props;
icc->send_msi = kvm_its_send_msi; icc->send_msi = kvm_its_send_msi;
icc->pre_save = kvm_arm_its_pre_save; icc->pre_save = kvm_arm_its_pre_save;
icc->post_load = kvm_arm_its_post_load; icc->post_load = kvm_arm_its_post_load;
@ -220,7 +216,6 @@ static const TypeInfo kvm_arm_its_info = {
.name = TYPE_KVM_ARM_ITS, .name = TYPE_KVM_ARM_ITS,
.parent = TYPE_ARM_GICV3_ITS_COMMON, .parent = TYPE_ARM_GICV3_ITS_COMMON,
.instance_size = sizeof(GICv3ITSState), .instance_size = sizeof(GICv3ITSState),
.instance_init = kvm_arm_its_init,
.class_init = kvm_arm_its_class_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; CPUARMState *env = &s->cpu->env;
int running; int running;
if (env->v7m.faultmask) { if (env->v7m.faultmask[env->v7m.secure]) {
running = -1; running = -1;
} else if (env->v7m.primask) { } else if (env->v7m.primask[env->v7m.secure]) {
running = 0; running = 0;
} else if (env->v7m.basepri > 0) { } else if (env->v7m.basepri[env->v7m.secure] > 0) {
running = env->v7m.basepri & nvic_gprio_mask(s); running = env->v7m.basepri[env->v7m.secure] & nvic_gprio_mask(s);
} else { } else {
running = NVIC_NOEXC_PRIO; /* lower than any possible priority */ 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); 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 */ /* caller must call nvic_irq_update() after this */
static void set_prio(NVICState *s, unsigned irq, uint8_t prio) 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; ARMCPU *cpu = s->cpu;
uint32_t val; uint32_t val;
@ -434,14 +441,19 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
/* ISRPREEMPT not implemented */ /* ISRPREEMPT not implemented */
return val; return val;
case 0xd08: /* Vector Table Offset. */ case 0xd08: /* Vector Table Offset. */
return cpu->env.v7m.vecbase; return cpu->env.v7m.vecbase[attrs.secure];
case 0xd0c: /* Application Interrupt/Reset Control. */ case 0xd0c: /* Application Interrupt/Reset Control. */
return 0xfa050000 | (s->prigroup << 8); return 0xfa050000 | (s->prigroup << 8);
case 0xd10: /* System Control. */ case 0xd10: /* System Control. */
/* TODO: Implement SLEEPONEXIT. */ /* TODO: Implement SLEEPONEXIT. */
return 0; return 0;
case 0xd14: /* Configuration Control. */ 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. */ case 0xd24: /* System Handler Status. */
val = 0; val = 0;
if (s->vectors[ARMV7M_EXCP_MEM].active) { if (s->vectors[ARMV7M_EXCP_MEM].active) {
@ -488,13 +500,18 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
} }
return val; return val;
case 0xd28: /* Configurable Fault Status. */ 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. */ case 0xd2c: /* Hard Fault Status. */
return cpu->env.v7m.hfsr; return cpu->env.v7m.hfsr;
case 0xd30: /* Debug Fault Status. */ case 0xd30: /* Debug Fault Status. */
return cpu->env.v7m.dfsr; return cpu->env.v7m.dfsr;
case 0xd34: /* MMFAR MemManage Fault Address */ case 0xd34: /* MMFAR MemManage Fault Address */
return cpu->env.v7m.mmfar; return cpu->env.v7m.mmfar[attrs.secure];
case 0xd38: /* Bus Fault Address. */ case 0xd38: /* Bus Fault Address. */
return cpu->env.v7m.bfar; return cpu->env.v7m.bfar;
case 0xd3c: /* Aux Fault Status. */ case 0xd3c: /* Aux Fault Status. */
@ -534,27 +551,58 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
return cpu->pmsav7_dregion << 8; return cpu->pmsav7_dregion << 8;
break; break;
case 0xd94: /* MPU_CTRL */ case 0xd94: /* MPU_CTRL */
return cpu->env.v7m.mpu_ctrl; return cpu->env.v7m.mpu_ctrl[attrs.secure];
case 0xd98: /* MPU_RNR */ case 0xd98: /* MPU_RNR */
return cpu->env.pmsav7.rnr; return cpu->env.pmsav7.rnr[attrs.secure];
case 0xd9c: /* MPU_RBAR */ case 0xd9c: /* MPU_RBAR */
case 0xda4: /* MPU_RBAR_A1 */ case 0xda4: /* MPU_RBAR_A1 */
case 0xdac: /* MPU_RBAR_A2 */ case 0xdac: /* MPU_RBAR_A2 */
case 0xdb4: /* MPU_RBAR_A3 */ 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) { if (region >= cpu->pmsav7_dregion) {
return 0; return 0;
} }
return (cpu->env.pmsav7.drbar[region] & 0x1f) | (region & 0xf); return (cpu->env.pmsav7.drbar[region] & 0x1f) | (region & 0xf);
} }
case 0xda0: /* MPU_RASR */ case 0xda0: /* MPU_RASR (v7M), MPU_RLAR (v8M) */
case 0xda8: /* MPU_RASR_A1 */ case 0xda8: /* MPU_RASR_A1 (v7M), MPU_RLAR_A1 (v8M) */
case 0xdb0: /* MPU_RASR_A2 */ case 0xdb0: /* MPU_RASR_A2 (v7M), MPU_RLAR_A2 (v8M) */
case 0xdb8: /* MPU_RASR_A3 */ 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) { if (region >= cpu->pmsav7_dregion) {
return 0; return 0;
@ -562,13 +610,25 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
return ((cpu->env.pmsav7.dracr[region] & 0xffff) << 16) | return ((cpu->env.pmsav7.dracr[region] & 0xffff) << 16) |
(cpu->env.pmsav7.drsr[region] & 0xffff); (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: default:
bad_offset:
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset); qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
return 0; 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; ARMCPU *cpu = s->cpu;
@ -589,7 +649,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
} }
break; break;
case 0xd08: /* Vector Table Offset. */ case 0xd08: /* Vector Table Offset. */
cpu->env.v7m.vecbase = value & 0xffffff80; cpu->env.v7m.vecbase[attrs.secure] = value & 0xffffff80;
break; break;
case 0xd0c: /* Application Interrupt/Reset Control. */ case 0xd0c: /* Application Interrupt/Reset Control. */
if ((value >> 16) == 0x05fa) { 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_USERSETMPEND_MASK |
R_V7M_CCR_NONBASETHRDENA_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; break;
case 0xd24: /* System Handler Control. */ case 0xd24: /* System Handler Control. */
s->vectors[ARMV7M_EXCP_MEM].active = (value & (1 << 0)) != 0; 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); nvic_irq_update(s);
break; break;
case 0xd28: /* Configurable Fault Status. */ 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; break;
case 0xd2c: /* Hard Fault Status. */ case 0xd2c: /* Hard Fault Status. */
cpu->env.v7m.hfsr &= ~value; /* W1C */ 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 */ cpu->env.v7m.dfsr &= ~value; /* W1C */
break; break;
case 0xd34: /* Mem Manage Address. */ case 0xd34: /* Mem Manage Address. */
cpu->env.v7m.mmfar = value; cpu->env.v7m.mmfar[attrs.secure] = value;
return; return;
case 0xd38: /* Bus Fault Address. */ case 0xd38: /* Bus Fault Address. */
cpu->env.v7m.bfar = value; cpu->env.v7m.bfar = value;
@ -670,7 +749,8 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
qemu_log_mask(LOG_GUEST_ERROR, "MPU_CTRL: HFNMIENA and !ENABLE is " qemu_log_mask(LOG_GUEST_ERROR, "MPU_CTRL: HFNMIENA and !ENABLE is "
"UNPREDICTABLE\n"); "UNPREDICTABLE\n");
} }
cpu->env.v7m.mpu_ctrl = value & (R_V7M_MPU_CTRL_ENABLE_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_HFNMIENA_MASK |
R_V7M_MPU_CTRL_PRIVDEFENA_MASK); R_V7M_MPU_CTRL_PRIVDEFENA_MASK);
tlb_flush(CPU(cpu)); tlb_flush(CPU(cpu));
@ -681,7 +761,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
PRIu32 "/%" PRIu32 "\n", PRIu32 "/%" PRIu32 "\n",
value, cpu->pmsav7_dregion); value, cpu->pmsav7_dregion);
} else { } else {
cpu->env.pmsav7.rnr = value; cpu->env.pmsav7.rnr[attrs.secure] = value;
} }
break; break;
case 0xd9c: /* MPU_RBAR */ case 0xd9c: /* MPU_RBAR */
@ -691,6 +771,26 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
{ {
int region; 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)) { if (value & (1 << 4)) {
/* VALID bit means use the region number specified in this /* VALID bit means use the region number specified in this
* value and also update MPU_RNR.REGION with that value. * 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); region, cpu->pmsav7_dregion);
return; return;
} }
cpu->env.pmsav7.rnr = region; cpu->env.pmsav7.rnr[attrs.secure] = region;
} else { } else {
region = cpu->env.pmsav7.rnr; region = cpu->env.pmsav7.rnr[attrs.secure];
} }
if (region >= cpu->pmsav7_dregion) { 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)); tlb_flush(CPU(cpu));
break; break;
} }
case 0xda0: /* MPU_RASR */ case 0xda0: /* MPU_RASR (v7M), MPU_RLAR (v8M) */
case 0xda8: /* MPU_RASR_A1 */ case 0xda8: /* MPU_RASR_A1 (v7M), MPU_RLAR_A1 (v8M) */
case 0xdb0: /* MPU_RASR_A2 */ case 0xdb0: /* MPU_RASR_A2 (v7M), MPU_RLAR_A2 (v8M) */
case 0xdb8: /* MPU_RASR_A3 */ 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) { if (region >= cpu->pmsav7_dregion) {
return; return;
@ -731,6 +850,30 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
tlb_flush(CPU(cpu)); tlb_flush(CPU(cpu));
break; 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 */ case 0xf00: /* Software Triggered Interrupt Register */
{ {
int excnum = (value & 0x1ff) + NVIC_FIRST_IRQ; int excnum = (value & 0x1ff) + NVIC_FIRST_IRQ;
@ -740,17 +883,21 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
break; break;
} }
default: default:
bad_offset:
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,
"NVIC: Bad write offset 0x%x\n", offset); "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. */ /* Return true if unprivileged access to this register is permitted. */
switch (offset) { switch (offset) {
case 0xf00: /* STIR: accessible only if CCR.USERSETMPEND permits */ 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: default:
/* All other user accesses cause a BusFault unconditionally */ /* All other user accesses cause a BusFault unconditionally */
return false; return false;
@ -766,7 +913,7 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
unsigned i, startvec, end; unsigned i, startvec, end;
uint32_t val; 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 */ /* Generate BusFault for unprivileged accesses */
return MEMTX_ERROR; return MEMTX_ERROR;
} }
@ -831,7 +978,7 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
break; break;
default: default:
if (size == 4) { if (size == 4) {
val = nvic_readl(s, offset); val = nvic_readl(s, offset, attrs);
} else { } else {
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,
"NVIC: Bad read of size %d at offset 0x%x\n", "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); 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 */ /* Generate BusFault for unprivileged accesses */
return MEMTX_ERROR; return MEMTX_ERROR;
} }
@ -912,7 +1059,7 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
return MEMTX_OK; return MEMTX_OK;
} }
if (size == 4) { if (size == 4) {
nvic_writel(s, offset, value); nvic_writel(s, offset, value, attrs);
return MEMTX_OK; return MEMTX_OK;
} }
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,
@ -927,6 +1074,47 @@ static const MemoryRegionOps nvic_sysreg_ops = {
.endianness = DEVICE_NATIVE_ENDIAN, .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) static int nvic_post_load(void *opaque, int version_id)
{ {
NVICState *s = opaque; NVICState *s = opaque;
@ -1028,6 +1216,7 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
NVICState *s = NVIC(dev); NVICState *s = NVIC(dev);
SysBusDevice *systick_sbd; SysBusDevice *systick_sbd;
Error *err = NULL; Error *err = NULL;
int regionlen;
s->cpu = ARM_CPU(qemu_get_cpu(0)); s->cpu = ARM_CPU(qemu_get_cpu(0));
assert(s->cpu); assert(s->cpu);
@ -1060,8 +1249,23 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
* 0xd00..0xd3c - SCS registers * 0xd00..0xd3c - SCS registers
* 0xd40..0xeff - Reserved or Not implemented * 0xd40..0xeff - Reserved or Not implemented
* 0xf00 - STIR * 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 /* The system register region goes at the bottom of the priority
* stack as it covers the whole page. * 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), sysbus_mmio_get_region(systick_sbd, 0),
1); 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); 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); XilinxAXIEnet *s = XILINX_AXI_ENET(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(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), object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
TYPE_XILINX_AXI_ENET_DATA_STREAM); TYPE_XILINX_AXI_ENET_DATA_STREAM);
object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev), 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("rxmem", XilinxAXIEnet, c_rxmem, 0x1000),
DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000), DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000),
DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf), 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(), DEFINE_PROP_END_OF_LIST(),
}; };

View file

@ -131,6 +131,16 @@ typedef struct {
* size than the target architecture's minimum. (Attempting to create * size than the target architecture's minimum. (Attempting to create
* such a CPU will fail.) Note that changing this is a migration * such a CPU will fail.) Note that changing this is a migration
* compatibility break for the machine. * 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 { struct MachineClass {
/*< private >*/ /*< private >*/
@ -171,6 +181,7 @@ struct MachineClass {
bool rom_file_has_mr; bool rom_file_has_mr;
int minimum_page_bits; int minimum_page_bits;
bool has_hotpluggable_cpus; bool has_hotpluggable_cpus;
bool ignore_memory_transaction_failures;
int numa_mem_align_shift; int numa_mem_align_shift;
void (*numa_auto_assign_ram)(MachineClass *mc, NodeInfo *nodes, void (*numa_auto_assign_ram)(MachineClass *mc, NodeInfo *nodes,
int nb_nodes, ram_addr_t size); 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 */ int exception_prio; /* group prio of the highest prio active exception */
MemoryRegion sysregmem; MemoryRegion sysregmem;
MemoryRegion sysreg_ns_mem;
MemoryRegion container; MemoryRegion container;
uint32_t num_irq; 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 * @trace_dstate_delayed: Delayed changes to trace_dstate (includes all changes
* to @trace_dstate). * to @trace_dstate).
* @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask). * @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. * State of one CPU core or thread.
*/ */
@ -398,6 +401,8 @@ struct CPUState {
*/ */
bool throttle_thread_scheduled; bool throttle_thread_scheduled;
bool ignore_memory_transaction_failures;
/* Note that this is accessed at the start of every TB via a negative /* 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 offset from AREG0. Leave this field at the end so as to make the
(absolute value) offset as small as possible. This reduces code (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); 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, cc->do_transaction_failed(cpu, physaddr, addr, size, access_type,
mmu_idx, attrs, response, retaddr); mmu_idx, attrs, response, retaddr);
} }

View file

@ -29,6 +29,7 @@
#include "exec/cpu-common.h" #include "exec/cpu-common.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "trace-root.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) static void cpu_common_realizefn(DeviceState *dev, Error **errp)
{ {
CPUState *cpu = CPU(dev); 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) { if (dev->hotplugged) {
cpu_synchronize_post_init(cpu); cpu_synchronize_post_init(cpu);

View file

@ -187,7 +187,6 @@ ERROR_WHITELIST = [
{'log':r"Device [\w.,-]+ can not be dynamically instantiated"}, {'log':r"Device [\w.,-]+ can not be dynamically instantiated"},
{'log':r"Platform Bus: Can not fit MMIO region of size "}, {'log':r"Platform Bus: Can not fit MMIO region of size "},
# other more specific errors we will ignore: # 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"}, {'device':'.*-spapr-cpu-core', 'log':r"CPU core type should be"},
{'log':r"MSI(-X)? is not supported by interrupt controller"}, {'log':r"MSI(-X)? is not supported by interrupt controller"},
{'log':r"pxb-pcie? devices cannot reside on a PCIe? bus"}, {'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 */ uint32_t initial_pc; /* Loaded from 0x4 */
uint8_t *rom; 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 * 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 */ /* Unlike A/R profile, M profile defines the reset LR value */
env->regs[14] = 0xffffffff; env->regs[14] = 0xffffffff;
@ -228,9 +238,24 @@ static void arm_cpu_reset(CPUState *s)
env->vfp.xregs[ARM_VFP_FPEXC] = 0; env->vfp.xregs[ARM_VFP_FPEXC] = 0;
#endif #endif
if (arm_feature(env, ARM_FEATURE_PMSA) && if (arm_feature(env, ARM_FEATURE_PMSA)) {
arm_feature(env, ARM_FEATURE_V7)) {
if (cpu->pmsav7_dregion > 0) { if (cpu->pmsav7_dregion > 0) {
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, memset(env->pmsav7.drbar, 0,
sizeof(*env->pmsav7.drbar) * cpu->pmsav7_dregion); sizeof(*env->pmsav7.drbar) * cpu->pmsav7_dregion);
memset(env->pmsav7.drsr, 0, memset(env->pmsav7.drsr, 0,
@ -238,7 +263,13 @@ static void arm_cpu_reset(CPUState *s)
memset(env->pmsav7.dracr, 0, memset(env->pmsav7.dracr, 0,
sizeof(*env->pmsav7.dracr) * cpu->pmsav7_dregion); 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); 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)) { if (arm_feature(env, ARM_FEATURE_V6)) {
set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V5);
set_feature(env, ARM_FEATURE_JAZELLE);
if (!arm_feature(env, ARM_FEATURE_M)) { if (!arm_feature(env, ARM_FEATURE_M)) {
set_feature(env, ARM_FEATURE_AUXCR); set_feature(env, ARM_FEATURE_AUXCR);
} }
@ -809,11 +841,21 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
} }
if (nr) { if (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.drbar = g_new0(uint32_t, nr);
env->pmsav7.drsr = g_new0(uint32_t, nr); env->pmsav7.drsr = g_new0(uint32_t, nr);
env->pmsav7.dracr = g_new0(uint32_t, nr); env->pmsav7.dracr = g_new0(uint32_t, nr);
} }
} }
}
if (arm_feature(env, ARM_FEATURE_EL3)) { if (arm_feature(env, ARM_FEATURE_EL3)) {
set_feature(env, ARM_FEATURE_VBAR); set_feature(env, ARM_FEATURE_VBAR);
@ -825,22 +867,21 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
init_cpreg_list(cpu); init_cpreg_list(cpu);
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
if (cpu->has_el3) { if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) {
cs->num_ases = 2;
} else {
cs->num_ases = 1;
}
if (cpu->has_el3) {
AddressSpace *as; AddressSpace *as;
cs->num_ases = 2;
if (!cpu->secure_memory) { if (!cpu->secure_memory) {
cpu->secure_memory = cs->memory; cpu->secure_memory = cs->memory;
} }
as = address_space_init_shareable(cpu->secure_memory, as = address_space_init_shareable(cpu->secure_memory,
"cpu-secure-memory"); "cpu-secure-memory");
cpu_address_space_init(cs, as, ARMASIdx_S); cpu_address_space_init(cs, as, ARMASIdx_S);
} else {
cs->num_ases = 1;
} }
cpu_address_space_init(cs, cpu_address_space_init(cs,
address_space_init_shareable(cs->memory, address_space_init_shareable(cs->memory,
"cpu-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_VFP);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
set_feature(&cpu->env, ARM_FEATURE_JAZELLE);
cpu->midr = 0x41069265; cpu->midr = 0x41069265;
cpu->reset_fpsid = 0x41011090; cpu->reset_fpsid = 0x41011090;
cpu->ctr = 0x1dd20d2; 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_AUXCR);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
set_feature(&cpu->env, ARM_FEATURE_JAZELLE);
cpu->midr = 0x4106a262; cpu->midr = 0x4106a262;
cpu->reset_fpsid = 0x410110a0; cpu->reset_fpsid = 0x410110a0;
cpu->ctr = 0x1dd20d2; cpu->ctr = 0x1dd20d2;
@ -1667,6 +1710,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
#else #else
cc->do_interrupt = arm_cpu_do_interrupt; cc->do_interrupt = arm_cpu_do_interrupt;
cc->do_unaligned_access = arm_cpu_do_unaligned_access; 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->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
cc->asidx_from_attrs = arm_asidx_from_attrs; cc->asidx_from_attrs = arm_asidx_from_attrs;
cc->vmsd = &vmstate_arm_cpu; cc->vmsd = &vmstate_arm_cpu;

View file

@ -66,11 +66,24 @@
#define ARMV7M_EXCP_MEM 4 #define ARMV7M_EXCP_MEM 4
#define ARMV7M_EXCP_BUS 5 #define ARMV7M_EXCP_BUS 5
#define ARMV7M_EXCP_USAGE 6 #define ARMV7M_EXCP_USAGE 6
#define ARMV7M_EXCP_SECURE 7
#define ARMV7M_EXCP_SVC 11 #define ARMV7M_EXCP_SVC 11
#define ARMV7M_EXCP_DEBUG 12 #define ARMV7M_EXCP_DEBUG 12
#define ARMV7M_EXCP_PENDSV 14 #define ARMV7M_EXCP_PENDSV 14
#define ARMV7M_EXCP_SYSTICK 15 #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. */ /* ARM-specific interrupt pending bits. */
#define CPU_INTERRUPT_FIQ CPU_INTERRUPT_TGT_EXT_1 #define CPU_INTERRUPT_FIQ CPU_INTERRUPT_TGT_EXT_1
#define CPU_INTERRUPT_VIRQ CPU_INTERRUPT_TGT_EXT_2 #define CPU_INTERRUPT_VIRQ CPU_INTERRUPT_TGT_EXT_2
@ -406,20 +419,34 @@ typedef struct CPUARMState {
} cp15; } cp15;
struct { 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 other_sp;
uint32_t vecbase; uint32_t other_ss_msp;
uint32_t basepri; uint32_t other_ss_psp;
uint32_t control; uint32_t vecbase[2];
uint32_t ccr; /* Configuration and Control */ uint32_t basepri[2];
uint32_t cfsr; /* Configurable Fault Status */ 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 hfsr; /* HardFault Status */
uint32_t dfsr; /* Debug Fault Status Register */ 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 */ uint32_t bfar; /* BusFault Address */
unsigned mpu_ctrl; /* MPU_CTRL */ unsigned mpu_ctrl[2]; /* MPU_CTRL */
int exception; int exception;
uint32_t primask; uint32_t primask[2];
uint32_t faultmask; uint32_t faultmask[2];
uint32_t secure; /* Is CPU in Secure state? (not guest visible) */
} v7m; } v7m;
/* Information associated with an exception about to be taken: /* Information associated with an exception about to be taken:
@ -519,9 +546,22 @@ typedef struct CPUARMState {
uint32_t *drbar; uint32_t *drbar;
uint32_t *drsr; uint32_t *drsr;
uint32_t *dracr; uint32_t *dracr;
uint32_t rnr; uint32_t rnr[2];
} pmsav7; } 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; void *nvic;
const struct arm_boot_info *boot_info; const struct arm_boot_info *boot_info;
/* Store GICv3CPUState to access from this struct */ /* 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, UNALIGNED, 16 + 8, 1)
FIELD(V7M_CFSR, DIVBYZERO, 16 + 9, 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 */ /* V7M HFSR bits */
FIELD(V7M_HFSR, VECTTBL, 1, 1) FIELD(V7M_HFSR, VECTTBL, 1, 1)
FIELD(V7M_HFSR, FORCED, 30, 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_THUMB_DSP, /* DSP insns supported in the Thumb encodings */
ARM_FEATURE_PMU, /* has PMU support */ ARM_FEATURE_PMU, /* has PMU support */
ARM_FEATURE_VBAR, /* has cp15 VBAR */ 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) 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.) * (Ignoring -1, this is the same as the RETTOBASE value before completion.)
*/ */
int armv7m_nvic_complete_irq(void *opaque, int irq); 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. /* Interface for defining coprocessor registers.
* Registers are defined in tables of arm_cp_reginfo structs * 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) static inline int arm_current_el(CPUARMState *env)
{ {
if (arm_feature(env, ARM_FEATURE_M)) { 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)) { 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 * Execution priority negative (this is like privileged, but the
* MPU HFNMIENA bit means that it may have different access permission * MPU HFNMIENA bit means that it may have different access permission
* check results to normal privileged code, so can't share a TLB). * 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 * 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 * 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_MUser = 0 | ARM_MMU_IDX_M,
ARMMMUIdx_MPriv = 1 | ARM_MMU_IDX_M, ARMMMUIdx_MPriv = 1 | ARM_MMU_IDX_M,
ARMMMUIdx_MNegPri = 2 | 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 /* 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. * instructions or for the first stage of an S12 page table walk.
*/ */
@ -2145,6 +2210,9 @@ typedef enum ARMMMUIdxBit {
ARMMMUIdxBit_MUser = 1 << 0, ARMMMUIdxBit_MUser = 1 << 0,
ARMMMUIdxBit_MPriv = 1 << 1, ARMMMUIdxBit_MPriv = 1 << 1,
ARMMMUIdxBit_MNegPri = 1 << 2, ARMMMUIdxBit_MNegPri = 1 << 2,
ARMMMUIdxBit_MSUser = 1 << 3,
ARMMMUIdxBit_MSPriv = 1 << 4,
ARMMMUIdxBit_MSNegPri = 1 << 5,
} ARMMMUIdxBit; } ARMMMUIdxBit;
#define MMU_USER_IDX 0 #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: case ARM_MMU_IDX_A:
return mmu_idx & 3; return mmu_idx & 3;
case ARM_MMU_IDX_M: case ARM_MMU_IDX_M:
return mmu_idx == ARMMMUIdx_MUser ? 0 : 1; return (mmu_idx == ARMMMUIdx_MUser || mmu_idx == ARMMMUIdx_MSUser)
? 0 : 1;
default: default:
g_assert_not_reached(); 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. * we're in a HardFault or NMI handler.
*/ */
if ((env->v7m.exception > 0 && env->v7m.exception <= 3) if ((env->v7m.exception > 0 && env->v7m.exception <= 3)
|| env->v7m.faultmask) { || env->v7m.faultmask[env->v7m.secure]) {
return arm_to_core_mmu_idx(ARMMMUIdx_MNegPri); mmu_idx = ARMMMUIdx_MNegPri;
}
if (env->v7m.secure) {
mmu_idx += ARMMMUIdx_MSUser;
} }
return arm_to_core_mmu_idx(mmu_idx); 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; return 0;
} }
u32p += env->pmsav7.rnr; u32p += env->pmsav7.rnr[M_REG_NS];
return *u32p; return *u32p;
} }
@ -2399,7 +2399,7 @@ static void pmsav7_write(CPUARMState *env, const ARMCPRegInfo *ri,
return; return;
} }
u32p += env->pmsav7.rnr; u32p += env->pmsav7.rnr[M_REG_NS];
tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */
*u32p = value; *u32p = value;
} }
@ -2442,7 +2442,7 @@ static const ARMCPRegInfo pmsav7_cp_reginfo[] = {
.resetfn = arm_cp_reset_ignore }, .resetfn = arm_cp_reset_ignore },
{ .name = "RGNR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 2, .opc2 = 0, { .name = "RGNR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 2, .opc2 = 0,
.access = PL1_RW, .access = PL1_RW,
.fieldoffset = offsetof(CPUARMState, pmsav7.rnr), .fieldoffset = offsetof(CPUARMState, pmsav7.rnr[M_REG_NS]),
.writefn = pmsav7_rgnr_write, .writefn = pmsav7_rgnr_write,
.resetfn = arm_cp_reset_ignore }, .resetfn = arm_cp_reset_ignore },
REGINFO_SENTINEL REGINFO_SENTINEL
@ -5870,6 +5870,12 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
return 0; 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) void switch_mode(CPUARMState *env, int mode)
{ {
ARMCPU *cpu = arm_env_get_cpu(env); ARMCPU *cpu = arm_env_get_cpu(env);
@ -6044,29 +6050,103 @@ static uint32_t v7m_pop(CPUARMState *env)
return val; 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. */ /* Switch to V7M main or process stack pointer. */
static void switch_v7m_sp(CPUARMState *env, bool new_spsel) static void switch_v7m_sp(CPUARMState *env, bool new_spsel)
{ {
uint32_t tmp; 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) { if (old_spsel != new_spsel) {
tmp = env->v7m.other_sp; tmp = env->v7m.other_sp;
env->v7m.other_sp = env->regs[13]; env->v7m.other_sp = env->regs[13];
env->regs[13] = tmp; 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_SHIFT,
R_V7M_CONTROL_SPSEL_LENGTH, new_spsel); 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) static uint32_t arm_v7m_load_vector(ARMCPU *cpu)
{ {
CPUState *cs = CPU(cpu); CPUState *cs = CPU(cpu);
CPUARMState *env = &cpu->env; CPUARMState *env = &cpu->env;
MemTxResult result; 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; uint32_t addr;
addr = address_space_ldl(cs->as, vec, addr = address_space_ldl(cs->as, vec,
@ -6112,7 +6192,8 @@ static void v7m_push_stack(ARMCPU *cpu)
uint32_t xpsr = xpsr_read(env); uint32_t xpsr = xpsr_read(env);
/* Align stack pointer if the guest wants that */ /* 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; env->regs[13] -= 4;
xpsr |= XPSR_SPREALIGN; xpsr |= XPSR_SPREALIGN;
} }
@ -6166,8 +6247,20 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
} }
if (env->v7m.exception != ARMV7M_EXCP_NMI) { if (env->v7m.exception != ARMV7M_EXCP_NMI) {
/* Auto-clear FAULTMASK on return from other than NMI */ /* Auto-clear FAULTMASK on return from other than NMI.
env->v7m.faultmask = 0; * 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)) { switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception)) {
@ -6198,7 +6291,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
/* fall through */ /* fall through */
case 9: /* Return to Thread using Main stack */ case 9: /* Return to Thread using Main stack */
if (!rettobase && if (!rettobase &&
!(env->v7m.ccr & R_V7M_CCR_NONBASETHRDENA_MASK)) { !(env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_NONBASETHRDENA_MASK)) {
ufault = true; ufault = true;
} }
break; break;
@ -6210,7 +6303,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
/* Bad exception return: instead of popping the exception /* Bad exception return: instead of popping the exception
* stack, directly take a usage fault on the current stack. * 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); armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
v7m_exception_taken(cpu, type | 0xf0000000); v7m_exception_taken(cpu, type | 0xf0000000);
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing " 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)) { if (return_to_handler != arm_v7m_is_handler_mode(env)) {
/* Take an INVPC UsageFault by pushing the stack again. */ /* Take an INVPC UsageFault by pushing the stack again. */
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); 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_push_stack(cpu);
v7m_exception_taken(cpu, type | 0xf0000000); v7m_exception_taken(cpu, type | 0xf0000000);
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe: " 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) { switch (cs->exception_index) {
case EXCP_UDEF: case EXCP_UDEF:
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); 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; break;
case EXCP_NOCP: case EXCP_NOCP:
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); 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; break;
case EXCP_INVSTATE: case EXCP_INVSTATE:
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); 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; break;
case EXCP_SWI: case EXCP_SWI:
/* The PC already points to the next instruction. */ /* The PC already points to the next instruction. */
@ -6335,11 +6428,11 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
case 0x8: /* External Abort */ case 0x8: /* External Abort */
switch (cs->exception_index) { switch (cs->exception_index) {
case EXCP_PREFETCH_ABORT: 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"); qemu_log_mask(CPU_LOG_INT, "...with CFSR.PRECISERR\n");
break; break;
case EXCP_DATA_ABORT: case EXCP_DATA_ABORT:
env->v7m.cfsr |= env->v7m.cfsr[M_REG_NS] |=
(R_V7M_CFSR_IBUSERR_MASK | R_V7M_CFSR_BFARVALID_MASK); (R_V7M_CFSR_IBUSERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
env->v7m.bfar = env->exception.vaddress; env->v7m.bfar = env->exception.vaddress;
qemu_log_mask(CPU_LOG_INT, qemu_log_mask(CPU_LOG_INT,
@ -6355,16 +6448,16 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
*/ */
switch (cs->exception_index) { switch (cs->exception_index) {
case EXCP_PREFETCH_ABORT: 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"); qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
break; break;
case EXCP_DATA_ABORT: case EXCP_DATA_ABORT:
env->v7m.cfsr |= env->v7m.cfsr[env->v7m.secure] |=
(R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK); (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, qemu_log_mask(CPU_LOG_INT,
"...with CFSR.DACCVIOL and MMFAR 0x%x\n", "...with CFSR.DACCVIOL and MMFAR 0x%x\n",
env->v7m.mmfar); env->v7m.mmfar[env->v7m.secure]);
break; break;
} }
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM); armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
@ -6397,7 +6490,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
} }
lr = 0xfffffff1; 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; lr |= 4;
} }
if (!arm_v7m_is_handler_mode(env)) { 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_MPriv:
case ARMMMUIdx_MNegPri: case ARMMMUIdx_MNegPri:
case ARMMMUIdx_MUser: case ARMMMUIdx_MUser:
case ARMMMUIdx_MSPriv:
case ARMMMUIdx_MSNegPri:
case ARMMMUIdx_MSUser:
return 1; return 1;
default: default:
g_assert_not_reached(); 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 */ /* Return the SCTLR value which controls this address translation regime */
static inline uint32_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx) 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) ARMMMUIdx mmu_idx)
{ {
if (arm_feature(env, ARM_FEATURE_M)) { 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)) { (R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK)) {
case R_V7M_MPU_CTRL_ENABLE_MASK: case R_V7M_MPU_CTRL_ENABLE_MASK:
/* Enabled, but not for HardFault and NMI */ /* 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: case R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK:
/* Enabled for all cases */ /* Enabled for all cases */
return false; return false;
@ -8231,7 +8305,8 @@ static bool pmsav7_use_background_region(ARMCPU *cpu,
} }
if (arm_feature(env, ARM_FEATURE_M)) { 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 { } else {
return regime_sctlr(env, mmu_idx) & SCTLR_BR; 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)); 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, static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address,
MMUAccessType access_type, ARMMMUIdx mmu_idx, MMUAccessType access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, int *prot, uint32_t *fsr) hwaddr *phys_ptr, int *prot, uint32_t *fsr)
@ -8580,7 +8761,11 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address,
bool ret; bool ret;
*page_size = TARGET_PAGE_SIZE; *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 */ /* PMSAv7 */
ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx, ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx,
phys_ptr, prot, fsr); phys_ptr, prot, fsr);
@ -8699,7 +8884,7 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
return xpsr_read(env) & mask; return xpsr_read(env) & mask;
break; break;
case 20: /* CONTROL */ case 20: /* CONTROL */
return env->v7m.control; return env->v7m.control[env->v7m.secure];
} }
if (el == 0) { if (el == 0) {
@ -8708,18 +8893,18 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
switch (reg) { switch (reg) {
case 8: /* MSP */ 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]; env->v7m.other_sp : env->regs[13];
case 9: /* PSP */ 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; env->regs[13] : env->v7m.other_sp;
case 16: /* PRIMASK */ case 16: /* PRIMASK */
return env->v7m.primask; return env->v7m.primask[env->v7m.secure];
case 17: /* BASEPRI */ case 17: /* BASEPRI */
case 18: /* BASEPRI_MAX */ case 18: /* BASEPRI_MAX */
return env->v7m.basepri; return env->v7m.basepri[env->v7m.secure];
case 19: /* FAULTMASK */ case 19: /* FAULTMASK */
return env->v7m.faultmask; return env->v7m.faultmask[env->v7m.secure];
default: default:
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special" qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special"
" register %d\n", reg); " register %d\n", reg);
@ -8760,32 +8945,34 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
} }
break; break;
case 8: /* MSP */ 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; env->v7m.other_sp = val;
} else { } else {
env->regs[13] = val; env->regs[13] = val;
} }
break; break;
case 9: /* PSP */ 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; env->regs[13] = val;
} else { } else {
env->v7m.other_sp = val; env->v7m.other_sp = val;
} }
break; break;
case 16: /* PRIMASK */ case 16: /* PRIMASK */
env->v7m.primask = val & 1; env->v7m.primask[env->v7m.secure] = val & 1;
break; break;
case 17: /* BASEPRI */ case 17: /* BASEPRI */
env->v7m.basepri = val & 0xff; env->v7m.basepri[env->v7m.secure] = val & 0xff;
break; break;
case 18: /* BASEPRI_MAX */ case 18: /* BASEPRI_MAX */
val &= 0xff; val &= 0xff;
if (val != 0 && (val < env->v7m.basepri || env->v7m.basepri == 0)) if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
env->v7m.basepri = val; || env->v7m.basepri[env->v7m.secure] == 0)) {
env->v7m.basepri[env->v7m.secure] = val;
}
break; break;
case 19: /* FAULTMASK */ case 19: /* FAULTMASK */
env->v7m.faultmask = val & 1; env->v7m.faultmask[env->v7m.secure] = val & 1;
break; break;
case 20: /* CONTROL */ case 20: /* CONTROL */
/* Writing to the SPSEL bit only has an effect if we are in /* 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)) { if (!arm_v7m_is_handler_mode(env)) {
switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0); switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
} }
env->v7m.control &= ~R_V7M_CONTROL_NPRIV_MASK; env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
env->v7m.control |= val & R_V7M_CONTROL_NPRIV_MASK; env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
break; break;
default: default:
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special" 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_3(v7m_msr, void, env, i32, i32)
DEF_HELPER_2(v7m_mrs, i32, env, 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_4(access_check_cp_reg, void, env, ptr, i32, i32)
DEF_HELPER_3(set_cp_reg, void, env, ptr, i32) DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
DEF_HELPER_2(get_cp_reg, i32, env, ptr) 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, MMUAccessType access_type,
int mmu_idx, uintptr_t retaddr); 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 */ /* Call the EL change hook if one has been registered */
static inline void arm_call_el_change_hook(ARMCPU *cpu) 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 #endif

View file

@ -102,8 +102,8 @@ static const VMStateDescription vmstate_m_faultmask_primask = {
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(env.v7m.faultmask, ARMCPU), VMSTATE_UINT32(env.v7m.faultmask[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.primask, ARMCPU), VMSTATE_UINT32(env.v7m.primask[M_REG_NS], ARMCPU),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
} }
}; };
@ -114,16 +114,16 @@ static const VMStateDescription vmstate_m = {
.minimum_version_id = 4, .minimum_version_id = 4,
.needed = m_needed, .needed = m_needed,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(env.v7m.vecbase, ARMCPU), VMSTATE_UINT32(env.v7m.vecbase[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.basepri, ARMCPU), VMSTATE_UINT32(env.v7m.basepri[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.control, ARMCPU), VMSTATE_UINT32(env.v7m.control[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.ccr, ARMCPU), VMSTATE_UINT32(env.v7m.ccr[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.cfsr, ARMCPU), VMSTATE_UINT32(env.v7m.cfsr[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.v7m.hfsr, ARMCPU), VMSTATE_UINT32(env.v7m.hfsr, ARMCPU),
VMSTATE_UINT32(env.v7m.dfsr, 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.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_INT32(env.v7m.exception, ARMCPU),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },
@ -159,14 +159,15 @@ static bool pmsav7_needed(void *opaque)
CPUARMState *env = &cpu->env; CPUARMState *env = &cpu->env;
return arm_feature(env, ARM_FEATURE_PMSA) && 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) static bool pmsav7_rgnr_vmstate_validate(void *opaque, int version_id)
{ {
ARMCPU *cpu = opaque; 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 = { static const VMStateDescription vmstate_pmsav7 = {
@ -204,7 +205,77 @@ static const VMStateDescription vmstate_pmsav7_rnr = {
.minimum_version_id = 1, .minimum_version_id = 1,
.needed = pmsav7_rnr_needed, .needed = pmsav7_rnr_needed,
.fields = (VMStateField[]) { .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() 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 * 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 * primask/faultmask info may be in the CPSR I and F bits, and
* we do not want the mode bits. * 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; uint32_t newval = val;
assert(!arm_feature(env, ARM_FEATURE_M_SECURITY));
newval &= (CPSR_NZCV | CPSR_Q | CPSR_IT | CPSR_GE); newval &= (CPSR_NZCV | CPSR_Q | CPSR_IT | CPSR_GE);
if (val & CPSR_T) { if (val & CPSR_T) {
newval |= XPSR_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. * transferred using the vmstate_m_faultmask_primask subsection.
*/ */
if (val & CPSR_F) { if (val & CPSR_F) {
env->v7m.faultmask = 1; env->v7m.faultmask[M_REG_NS] = 1;
} }
if (val & CPSR_I) { if (val & CPSR_I) {
env->v7m.primask = 1; env->v7m.primask[M_REG_NS] = 1;
} }
val = newval; val = newval;
} }
@ -458,6 +533,8 @@ const VMStateDescription vmstate_arm_cpu = {
*/ */
&vmstate_pmsav7_rnr, &vmstate_pmsav7_rnr,
&vmstate_pmsav7, &vmstate_pmsav7,
&vmstate_pmsav8,
&vmstate_m_security,
NULL 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); 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) */ #endif /* !defined(CONFIG_USER_ONLY) */
uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b) 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) #define ENABLE_ARCH_5 arm_dc_feature(s, ARM_FEATURE_V5)
/* currently all emulated v5 cores are also v5TE, so don't bother */ /* 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_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_6 arm_dc_feature(s, ARM_FEATURE_V6)
#define ENABLE_ARCH_6K arm_dc_feature(s, ARM_FEATURE_V6K) #define ENABLE_ARCH_6K arm_dc_feature(s, ARM_FEATURE_V6K)
#define ENABLE_ARCH_6T2 arm_dc_feature(s, ARM_FEATURE_THUMB2) #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); 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 /* 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 to r15 in ARM architecture v7 and above. The source must be a temporary
and will be marked as dead. */ and will be marked as dead. */
@ -11185,12 +11204,31 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
*/ */
bool link = insn & (1 << 7); bool link = insn & (1 << 7);
if (insn & 7) { if (insn & 3) {
goto undef; goto undef;
} }
if (link) { if (link) {
ARCH(5); 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); tmp = load_reg(s, rm);
if (link) { if (link) {
val = (uint32_t)s->pc | 1; 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->vec_stride = ARM_TBFLAG_VECSTRIDE(dc->base.tb->flags);
dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(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->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->cp_regs = cpu->cp_regs;
dc->features = env->features; 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)) { if (arm_feature(env, ARM_FEATURE_M)) {
uint32_t xpsr = xpsr_read(env); uint32_t xpsr = xpsr_read(env);
const char *mode; 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) { if (xpsr & XPSR_EXCP) {
mode = "handler"; mode = "handler";
} else { } 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"; mode = "unpriv-thread";
} else { } else {
mode = "priv-thread"; 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 & XPSR_N ? 'N' : '-', xpsr & XPSR_N ? 'N' : '-',
xpsr & XPSR_Z ? 'Z' : '-', xpsr & XPSR_Z ? 'Z' : '-',
xpsr & XPSR_C ? 'C' : '-', xpsr & XPSR_C ? 'C' : '-',
xpsr & XPSR_V ? 'V' : '-', xpsr & XPSR_V ? 'V' : '-',
xpsr & XPSR_T ? 'T' : 'A', xpsr & XPSR_T ? 'T' : 'A',
ns_status,
mode); mode);
} else { } else {
uint32_t psr = cpsr_read(env); uint32_t psr = cpsr_read(env);

View file

@ -35,6 +35,7 @@ typedef struct DisasContext {
int vec_len; int vec_len;
int vec_stride; int vec_stride;
bool v7m_handler_mode; 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 /* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
* so that top level loop can generate correct syndrome information. * so that top level loop can generate correct syndrome information.
*/ */