mirror of https://github.com/xemu-project/xemu.git
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:
commit
ef475b5dd1
|
@ -118,6 +118,8 @@ static void aw_a10_class_init(ObjectClass *oc, void *data)
|
|||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = aw_a10_realize;
|
||||
/* Reason: Uses serial_hds in realize and nd_table in instance_init */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo aw_a10_type_info = {
|
||||
|
|
|
@ -97,12 +97,6 @@ static void bitband_init(Object *obj)
|
|||
BitBandState *s = BITBAND(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
object_property_add_link(obj, "source-memory",
|
||||
TYPE_MEMORY_REGION,
|
||||
(Object **)&s->source_memory,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
memory_region_init_io(&s->iomem, obj, &bitband_ops, s,
|
||||
"bitband", 0x02000000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
@ -138,12 +132,6 @@ static void armv7m_instance_init(Object *obj)
|
|||
|
||||
/* Can't init the cpu here, we don't yet know which model to use */
|
||||
|
||||
object_property_add_link(obj, "memory",
|
||||
TYPE_MEMORY_REGION,
|
||||
(Object **)&s->board_memory,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
memory_region_init(&s->container, obj, "armv7m-container", UINT64_MAX);
|
||||
|
||||
object_initialize(&s->nvic, sizeof(s->nvic), TYPE_NVIC);
|
||||
|
@ -254,6 +242,8 @@ static void armv7m_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
static Property armv7m_properties[] = {
|
||||
DEFINE_PROP_STRING("cpu-model", ARMv7MState, cpu_model),
|
||||
DEFINE_PROP_LINK("memory", ARMv7MState, board_memory, TYPE_MEMORY_REGION,
|
||||
MemoryRegion *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@ -349,6 +339,8 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size)
|
|||
|
||||
static Property bitband_properties[] = {
|
||||
DEFINE_PROP_UINT32("base", BitBandState, base, 0),
|
||||
DEFINE_PROP_LINK("source-memory", BitBandState, source_memory,
|
||||
TYPE_MEMORY_REGION, MemoryRegion *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
|
|
@ -270,6 +270,7 @@ static void palmetto_bmc_class_init(ObjectClass *oc, void *data)
|
|||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_parallel = 1;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo palmetto_bmc_type = {
|
||||
|
@ -302,6 +303,7 @@ static void ast2500_evb_class_init(ObjectClass *oc, void *data)
|
|||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_parallel = 1;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo ast2500_evb_type = {
|
||||
|
@ -326,6 +328,7 @@ static void romulus_bmc_class_init(ObjectClass *oc, void *data)
|
|||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_parallel = 1;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo romulus_bmc_type = {
|
||||
|
|
|
@ -64,6 +64,7 @@ static void collie_machine_init(MachineClass *mc)
|
|||
{
|
||||
mc->desc = "Sharp SL-5500 (Collie) PDA (SA-1110)";
|
||||
mc->init = collie_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("collie", collie_machine_init)
|
||||
|
|
|
@ -86,6 +86,7 @@ static void cubieboard_machine_init(MachineClass *mc)
|
|||
mc->init = cubieboard_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->units_per_default_bus = 1;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("cubieboard", cubieboard_machine_init)
|
||||
|
|
|
@ -155,6 +155,7 @@ static void canon_a1100_machine_init(MachineClass *mc)
|
|||
{
|
||||
mc->desc = "Canon PowerShot A1100 IS";
|
||||
mc->init = &canon_a1100_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("canon-a1100", canon_a1100_machine_init)
|
||||
|
|
|
@ -189,6 +189,7 @@ static void nuri_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "Samsung NURI board (Exynos4210)";
|
||||
mc->init = nuri_init;
|
||||
mc->max_cpus = EXYNOS4210_NCPUS;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo nuri_type = {
|
||||
|
@ -204,6 +205,7 @@ static void smdkc210_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "Samsung SMDKC210 board (Exynos4210)";
|
||||
mc->init = smdkc210_init;
|
||||
mc->max_cpus = EXYNOS4210_NCPUS;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo smdkc210_type = {
|
||||
|
|
|
@ -128,6 +128,7 @@ static void connex_class_init(ObjectClass *oc, void *data)
|
|||
|
||||
mc->desc = "Gumstix Connex (PXA255)";
|
||||
mc->init = connex_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo connex_type = {
|
||||
|
@ -142,6 +143,7 @@ static void verdex_class_init(ObjectClass *oc, void *data)
|
|||
|
||||
mc->desc = "Gumstix Verdex (PXA270)";
|
||||
mc->init = verdex_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo verdex_type = {
|
||||
|
|
|
@ -413,6 +413,7 @@ static void highbank_class_init(ObjectClass *oc, void *data)
|
|||
mc->block_default_type = IF_IDE;
|
||||
mc->units_per_default_bus = 1;
|
||||
mc->max_cpus = 4;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo highbank_type = {
|
||||
|
@ -430,6 +431,7 @@ static void midway_class_init(ObjectClass *oc, void *data)
|
|||
mc->block_default_type = IF_IDE;
|
||||
mc->units_per_default_bus = 1;
|
||||
mc->max_cpus = 4;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo midway_type = {
|
||||
|
|
|
@ -148,6 +148,7 @@ static void imx25_pdk_machine_init(MachineClass *mc)
|
|||
{
|
||||
mc->desc = "ARM i.MX25 PDK board (ARM926)";
|
||||
mc->init = imx25_pdk_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("imx25-pdk", imx25_pdk_machine_init)
|
||||
|
|
|
@ -681,6 +681,7 @@ static void integratorcp_machine_init(MachineClass *mc)
|
|||
{
|
||||
mc->desc = "ARM Integrator/CP (ARM926EJ-S)";
|
||||
mc->init = integratorcp_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("integratorcp", integratorcp_machine_init)
|
||||
|
|
|
@ -142,6 +142,7 @@ static void kzm_machine_init(MachineClass *mc)
|
|||
{
|
||||
mc->desc = "ARM KZM Emulation Baseboard (ARM1136)";
|
||||
mc->init = kzm_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("kzm", kzm_machine_init)
|
||||
|
|
|
@ -196,6 +196,7 @@ static void mainstone2_machine_init(MachineClass *mc)
|
|||
{
|
||||
mc->desc = "Mainstone II (PXA27x)";
|
||||
mc->init = mainstone_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("mainstone", mainstone2_machine_init)
|
||||
|
|
|
@ -1718,6 +1718,7 @@ static void musicpal_machine_init(MachineClass *mc)
|
|||
{
|
||||
mc->desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)";
|
||||
mc->init = musicpal_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("musicpal", musicpal_machine_init)
|
||||
|
|
|
@ -45,6 +45,7 @@ static void netduino2_machine_init(MachineClass *mc)
|
|||
{
|
||||
mc->desc = "Netduino 2 Machine";
|
||||
mc->init = netduino2_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("netduino2", netduino2_machine_init)
|
||||
|
|
|
@ -1425,6 +1425,7 @@ static void n800_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)";
|
||||
mc->init = n800_init;
|
||||
mc->default_boot_order = "";
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo n800_type = {
|
||||
|
@ -1440,6 +1441,7 @@ static void n810_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)";
|
||||
mc->init = n810_init;
|
||||
mc->default_boot_order = "";
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo n810_type = {
|
||||
|
|
|
@ -223,6 +223,7 @@ static void sx1_machine_v2_class_init(ObjectClass *oc, void *data)
|
|||
|
||||
mc->desc = "Siemens SX1 (OMAP310) V2";
|
||||
mc->init = sx1_init_v2;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo sx1_machine_v2_type = {
|
||||
|
@ -237,6 +238,7 @@ static void sx1_machine_v1_class_init(ObjectClass *oc, void *data)
|
|||
|
||||
mc->desc = "Siemens SX1 (OMAP310) V1";
|
||||
mc->init = sx1_init_v1;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo sx1_machine_v1_type = {
|
||||
|
|
|
@ -274,6 +274,7 @@ static void palmte_machine_init(MachineClass *mc)
|
|||
{
|
||||
mc->desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)";
|
||||
mc->init = palmte_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("cheetah", palmte_machine_init)
|
||||
|
|
|
@ -168,5 +168,6 @@ static void raspi2_machine_init(MachineClass *mc)
|
|||
mc->no_cdrom = 1;
|
||||
mc->max_cpus = BCM2836_NCPUS;
|
||||
mc->default_ram_size = 1024 * 1024 * 1024;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
};
|
||||
DEFINE_MACHINE("raspi2", raspi2_machine_init)
|
||||
|
|
|
@ -398,6 +398,7 @@ static void realview_eb_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)";
|
||||
mc->init = realview_eb_init;
|
||||
mc->block_default_type = IF_SCSI;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo realview_eb_type = {
|
||||
|
@ -414,6 +415,7 @@ static void realview_eb_mpcore_class_init(ObjectClass *oc, void *data)
|
|||
mc->init = realview_eb_mpcore_init;
|
||||
mc->block_default_type = IF_SCSI;
|
||||
mc->max_cpus = 4;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo realview_eb_mpcore_type = {
|
||||
|
@ -428,6 +430,7 @@ static void realview_pb_a8_class_init(ObjectClass *oc, void *data)
|
|||
|
||||
mc->desc = "ARM RealView Platform Baseboard for Cortex-A8";
|
||||
mc->init = realview_pb_a8_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo realview_pb_a8_type = {
|
||||
|
@ -443,6 +446,7 @@ static void realview_pbx_a9_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "ARM RealView Platform Baseboard Explore for Cortex-A9";
|
||||
mc->init = realview_pbx_a9_init;
|
||||
mc->max_cpus = 4;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo realview_pbx_a9_type = {
|
||||
|
|
|
@ -122,6 +122,7 @@ static void sabrelite_machine_init(MachineClass *mc)
|
|||
mc->desc = "Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)";
|
||||
mc->init = sabrelite_init;
|
||||
mc->max_cpus = FSL_IMX6_NUM_CPUS;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("sabrelite", sabrelite_machine_init)
|
||||
|
|
|
@ -983,6 +983,7 @@ static void akitapda_class_init(ObjectClass *oc, void *data)
|
|||
|
||||
mc->desc = "Sharp SL-C1000 (Akita) PDA (PXA270)";
|
||||
mc->init = akita_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo akitapda_type = {
|
||||
|
@ -998,6 +999,7 @@ static void spitzpda_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "Sharp SL-C3000 (Spitz) PDA (PXA270)";
|
||||
mc->init = spitz_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo spitzpda_type = {
|
||||
|
@ -1013,6 +1015,7 @@ static void borzoipda_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "Sharp SL-C3100 (Borzoi) PDA (PXA270)";
|
||||
mc->init = borzoi_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo borzoipda_type = {
|
||||
|
@ -1028,6 +1031,7 @@ static void terrierpda_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "Sharp SL-C3200 (Terrier) PDA (PXA270)";
|
||||
mc->init = terrier_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo terrierpda_type = {
|
||||
|
|
|
@ -1453,6 +1453,7 @@ static void lm3s811evb_class_init(ObjectClass *oc, void *data)
|
|||
|
||||
mc->desc = "Stellaris LM3S811EVB";
|
||||
mc->init = lm3s811evb_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo lm3s811evb_type = {
|
||||
|
@ -1467,6 +1468,7 @@ static void lm3s6965evb_class_init(ObjectClass *oc, void *data)
|
|||
|
||||
mc->desc = "Stellaris LM3S6965EVB";
|
||||
mc->init = lm3s6965evb_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo lm3s6965evb_type = {
|
||||
|
|
|
@ -263,6 +263,7 @@ static void tosapda_machine_init(MachineClass *mc)
|
|||
mc->desc = "Sharp SL-6000 (Tosa) PDA (PXA255)";
|
||||
mc->init = tosa_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("tosa", tosapda_machine_init)
|
||||
|
|
|
@ -403,6 +403,7 @@ static void versatilepb_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "ARM Versatile/PB (ARM926EJ-S)";
|
||||
mc->init = vpb_init;
|
||||
mc->block_default_type = IF_SCSI;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo versatilepb_type = {
|
||||
|
@ -418,6 +419,7 @@ static void versatileab_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "ARM Versatile/AB (ARM926EJ-S)";
|
||||
mc->init = vab_init;
|
||||
mc->block_default_type = IF_SCSI;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo versatileab_type = {
|
||||
|
|
|
@ -752,6 +752,7 @@ static void vexpress_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "ARM Versatile Express";
|
||||
mc->init = vexpress_common_init;
|
||||
mc->max_cpus = 4;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static void vexpress_a9_class_init(ObjectClass *oc, void *data)
|
||||
|
|
|
@ -326,6 +326,7 @@ static void zynq_machine_init(MachineClass *mc)
|
|||
mc->init = zynq_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->no_sdcard = 1;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("xilinx-zynq-a9", zynq_machine_init)
|
||||
|
|
|
@ -122,6 +122,7 @@ static void xlnx_ep108_machine_init(MachineClass *mc)
|
|||
mc->init = xlnx_ep108_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->units_per_default_bus = 1;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("xlnx-ep108", xlnx_ep108_machine_init)
|
||||
|
@ -132,6 +133,7 @@ static void xlnx_zcu102_machine_init(MachineClass *mc)
|
|||
mc->init = xlnx_ep108_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->units_per_default_bus = 1;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("xlnx-zcu102", xlnx_zcu102_machine_init)
|
||||
|
|
|
@ -140,11 +140,6 @@ static void xlnx_zynqmp_init(Object *obj)
|
|||
&error_abort);
|
||||
}
|
||||
|
||||
object_property_add_link(obj, "ddr-ram", TYPE_MEMORY_REGION,
|
||||
(Object **)&s->ddr_ram,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
|
||||
|
||||
object_initialize(&s->gic, sizeof(s->gic), gic_class_name());
|
||||
qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
|
||||
|
||||
|
@ -433,6 +428,8 @@ static Property xlnx_zynqmp_props[] = {
|
|||
DEFINE_PROP_STRING("boot-cpu", XlnxZynqMPState, boot_cpu),
|
||||
DEFINE_PROP_BOOL("secure", XlnxZynqMPState, secure, false),
|
||||
DEFINE_PROP_BOOL("has_rpu", XlnxZynqMPState, has_rpu, false),
|
||||
DEFINE_PROP_LINK("ddr-ram", XlnxZynqMPState, ddr_ram, TYPE_MEMORY_REGION,
|
||||
MemoryRegion *),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
|
|
|
@ -370,6 +370,7 @@ static void z2_machine_init(MachineClass *mc)
|
|||
{
|
||||
mc->desc = "Zipit Z2 (PXA27x)";
|
||||
mc->init = z2_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("z2", z2_machine_init)
|
||||
|
|
|
@ -562,18 +562,6 @@ static void xilinx_axidma_init(Object *obj)
|
|||
XilinxAXIDMA *s = XILINX_AXI_DMA(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
|
||||
(Object **)&s->tx_data_dev,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
object_property_add_link(obj, "axistream-control-connected",
|
||||
TYPE_STREAM_SLAVE,
|
||||
(Object **)&s->tx_control_dev,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
|
||||
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
|
||||
TYPE_XILINX_AXI_DMA_DATA_STREAM);
|
||||
object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
|
||||
|
@ -593,6 +581,10 @@ static void xilinx_axidma_init(Object *obj)
|
|||
|
||||
static Property axidma_properties[] = {
|
||||
DEFINE_PROP_UINT32("freqhz", XilinxAXIDMA, freqhz, 50000000),
|
||||
DEFINE_PROP_LINK("axistream-connected", XilinxAXIDMA,
|
||||
tx_data_dev, TYPE_STREAM_SLAVE, StreamSlave *),
|
||||
DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIDMA,
|
||||
tx_control_dev, TYPE_STREAM_SLAVE, StreamSlave *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
|
|
@ -120,17 +120,6 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
|
|||
qemu_add_vm_change_state_handler(vm_change_state_handler, s);
|
||||
}
|
||||
|
||||
static void kvm_arm_its_init(Object *obj)
|
||||
{
|
||||
GICv3ITSState *s = KVM_ARM_ITS(obj);
|
||||
|
||||
object_property_add_link(obj, "parent-gicv3",
|
||||
"kvm-arm-gicv3", (Object **)&s->gicv3,
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_arm_its_pre_save - handles the saving of ITS registers.
|
||||
* ITS tables are flushed into guest RAM separately and earlier,
|
||||
|
@ -205,12 +194,19 @@ static void kvm_arm_its_post_load(GICv3ITSState *s)
|
|||
GITS_CTLR, &s->ctlr, true, &error_abort);
|
||||
}
|
||||
|
||||
static Property kvm_arm_its_props[] = {
|
||||
DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "kvm-arm-gicv3",
|
||||
GICv3State *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
|
||||
|
||||
dc->realize = kvm_arm_its_realize;
|
||||
dc->props = kvm_arm_its_props;
|
||||
icc->send_msi = kvm_its_send_msi;
|
||||
icc->pre_save = kvm_arm_its_pre_save;
|
||||
icc->post_load = kvm_arm_its_post_load;
|
||||
|
@ -220,7 +216,6 @@ static const TypeInfo kvm_arm_its_info = {
|
|||
.name = TYPE_KVM_ARM_ITS,
|
||||
.parent = TYPE_ARM_GICV3_ITS_COMMON,
|
||||
.instance_size = sizeof(GICv3ITSState),
|
||||
.instance_init = kvm_arm_its_init,
|
||||
.class_init = kvm_arm_its_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -167,12 +167,12 @@ static inline int nvic_exec_prio(NVICState *s)
|
|||
CPUARMState *env = &s->cpu->env;
|
||||
int running;
|
||||
|
||||
if (env->v7m.faultmask) {
|
||||
if (env->v7m.faultmask[env->v7m.secure]) {
|
||||
running = -1;
|
||||
} else if (env->v7m.primask) {
|
||||
} else if (env->v7m.primask[env->v7m.secure]) {
|
||||
running = 0;
|
||||
} else if (env->v7m.basepri > 0) {
|
||||
running = env->v7m.basepri & nvic_gprio_mask(s);
|
||||
} else if (env->v7m.basepri[env->v7m.secure] > 0) {
|
||||
running = env->v7m.basepri[env->v7m.secure] & nvic_gprio_mask(s);
|
||||
} else {
|
||||
running = NVIC_NOEXC_PRIO; /* lower than any possible priority */
|
||||
}
|
||||
|
@ -187,6 +187,13 @@ bool armv7m_nvic_can_take_pending_exception(void *opaque)
|
|||
return nvic_exec_prio(s) > nvic_pending_prio(s);
|
||||
}
|
||||
|
||||
int armv7m_nvic_raw_execution_priority(void *opaque)
|
||||
{
|
||||
NVICState *s = opaque;
|
||||
|
||||
return s->exception_prio;
|
||||
}
|
||||
|
||||
/* caller must call nvic_irq_update() after this */
|
||||
static void set_prio(NVICState *s, unsigned irq, uint8_t prio)
|
||||
{
|
||||
|
@ -396,7 +403,7 @@ static void set_irq_level(void *opaque, int n, int level)
|
|||
}
|
||||
}
|
||||
|
||||
static uint32_t nvic_readl(NVICState *s, uint32_t offset)
|
||||
static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
|
||||
{
|
||||
ARMCPU *cpu = s->cpu;
|
||||
uint32_t val;
|
||||
|
@ -434,14 +441,19 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
|
|||
/* ISRPREEMPT not implemented */
|
||||
return val;
|
||||
case 0xd08: /* Vector Table Offset. */
|
||||
return cpu->env.v7m.vecbase;
|
||||
return cpu->env.v7m.vecbase[attrs.secure];
|
||||
case 0xd0c: /* Application Interrupt/Reset Control. */
|
||||
return 0xfa050000 | (s->prigroup << 8);
|
||||
case 0xd10: /* System Control. */
|
||||
/* TODO: Implement SLEEPONEXIT. */
|
||||
return 0;
|
||||
case 0xd14: /* Configuration Control. */
|
||||
return cpu->env.v7m.ccr;
|
||||
/* The BFHFNMIGN bit is the only non-banked bit; we
|
||||
* keep it in the non-secure copy of the register.
|
||||
*/
|
||||
val = cpu->env.v7m.ccr[attrs.secure];
|
||||
val |= cpu->env.v7m.ccr[M_REG_NS] & R_V7M_CCR_BFHFNMIGN_MASK;
|
||||
return val;
|
||||
case 0xd24: /* System Handler Status. */
|
||||
val = 0;
|
||||
if (s->vectors[ARMV7M_EXCP_MEM].active) {
|
||||
|
@ -488,13 +500,18 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
|
|||
}
|
||||
return val;
|
||||
case 0xd28: /* Configurable Fault Status. */
|
||||
return cpu->env.v7m.cfsr;
|
||||
/* The BFSR bits [15:8] are shared between security states
|
||||
* and we store them in the NS copy
|
||||
*/
|
||||
val = cpu->env.v7m.cfsr[attrs.secure];
|
||||
val |= cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK;
|
||||
return val;
|
||||
case 0xd2c: /* Hard Fault Status. */
|
||||
return cpu->env.v7m.hfsr;
|
||||
case 0xd30: /* Debug Fault Status. */
|
||||
return cpu->env.v7m.dfsr;
|
||||
case 0xd34: /* MMFAR MemManage Fault Address */
|
||||
return cpu->env.v7m.mmfar;
|
||||
return cpu->env.v7m.mmfar[attrs.secure];
|
||||
case 0xd38: /* Bus Fault Address. */
|
||||
return cpu->env.v7m.bfar;
|
||||
case 0xd3c: /* Aux Fault Status. */
|
||||
|
@ -534,27 +551,58 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
|
|||
return cpu->pmsav7_dregion << 8;
|
||||
break;
|
||||
case 0xd94: /* MPU_CTRL */
|
||||
return cpu->env.v7m.mpu_ctrl;
|
||||
return cpu->env.v7m.mpu_ctrl[attrs.secure];
|
||||
case 0xd98: /* MPU_RNR */
|
||||
return cpu->env.pmsav7.rnr;
|
||||
return cpu->env.pmsav7.rnr[attrs.secure];
|
||||
case 0xd9c: /* MPU_RBAR */
|
||||
case 0xda4: /* MPU_RBAR_A1 */
|
||||
case 0xdac: /* MPU_RBAR_A2 */
|
||||
case 0xdb4: /* MPU_RBAR_A3 */
|
||||
{
|
||||
int region = cpu->env.pmsav7.rnr;
|
||||
int region = cpu->env.pmsav7.rnr[attrs.secure];
|
||||
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
/* PMSAv8M handling of the aliases is different from v7M:
|
||||
* aliases A1, A2, A3 override the low two bits of the region
|
||||
* number in MPU_RNR, and there is no 'region' field in the
|
||||
* RBAR register.
|
||||
*/
|
||||
int aliasno = (offset - 0xd9c) / 8; /* 0..3 */
|
||||
if (aliasno) {
|
||||
region = deposit32(region, 0, 2, aliasno);
|
||||
}
|
||||
if (region >= cpu->pmsav7_dregion) {
|
||||
return 0;
|
||||
}
|
||||
return cpu->env.pmsav8.rbar[attrs.secure][region];
|
||||
}
|
||||
|
||||
if (region >= cpu->pmsav7_dregion) {
|
||||
return 0;
|
||||
}
|
||||
return (cpu->env.pmsav7.drbar[region] & 0x1f) | (region & 0xf);
|
||||
}
|
||||
case 0xda0: /* MPU_RASR */
|
||||
case 0xda8: /* MPU_RASR_A1 */
|
||||
case 0xdb0: /* MPU_RASR_A2 */
|
||||
case 0xdb8: /* MPU_RASR_A3 */
|
||||
case 0xda0: /* MPU_RASR (v7M), MPU_RLAR (v8M) */
|
||||
case 0xda8: /* MPU_RASR_A1 (v7M), MPU_RLAR_A1 (v8M) */
|
||||
case 0xdb0: /* MPU_RASR_A2 (v7M), MPU_RLAR_A2 (v8M) */
|
||||
case 0xdb8: /* MPU_RASR_A3 (v7M), MPU_RLAR_A3 (v8M) */
|
||||
{
|
||||
int region = cpu->env.pmsav7.rnr;
|
||||
int region = cpu->env.pmsav7.rnr[attrs.secure];
|
||||
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
/* PMSAv8M handling of the aliases is different from v7M:
|
||||
* aliases A1, A2, A3 override the low two bits of the region
|
||||
* number in MPU_RNR.
|
||||
*/
|
||||
int aliasno = (offset - 0xda0) / 8; /* 0..3 */
|
||||
if (aliasno) {
|
||||
region = deposit32(region, 0, 2, aliasno);
|
||||
}
|
||||
if (region >= cpu->pmsav7_dregion) {
|
||||
return 0;
|
||||
}
|
||||
return cpu->env.pmsav8.rlar[attrs.secure][region];
|
||||
}
|
||||
|
||||
if (region >= cpu->pmsav7_dregion) {
|
||||
return 0;
|
||||
|
@ -562,13 +610,25 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
|
|||
return ((cpu->env.pmsav7.dracr[region] & 0xffff) << 16) |
|
||||
(cpu->env.pmsav7.drsr[region] & 0xffff);
|
||||
}
|
||||
case 0xdc0: /* MPU_MAIR0 */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
return cpu->env.pmsav8.mair0[attrs.secure];
|
||||
case 0xdc4: /* MPU_MAIR1 */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
return cpu->env.pmsav8.mair1[attrs.secure];
|
||||
default:
|
||||
bad_offset:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
||||
static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
ARMCPU *cpu = s->cpu;
|
||||
|
||||
|
@ -589,7 +649,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
|||
}
|
||||
break;
|
||||
case 0xd08: /* Vector Table Offset. */
|
||||
cpu->env.v7m.vecbase = value & 0xffffff80;
|
||||
cpu->env.v7m.vecbase[attrs.secure] = value & 0xffffff80;
|
||||
break;
|
||||
case 0xd0c: /* Application Interrupt/Reset Control. */
|
||||
if ((value >> 16) == 0x05fa) {
|
||||
|
@ -623,7 +683,20 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
|||
R_V7M_CCR_USERSETMPEND_MASK |
|
||||
R_V7M_CCR_NONBASETHRDENA_MASK);
|
||||
|
||||
cpu->env.v7m.ccr = value;
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
/* v8M makes NONBASETHRDENA and STKALIGN be RES1 */
|
||||
value |= R_V7M_CCR_NONBASETHRDENA_MASK
|
||||
| R_V7M_CCR_STKALIGN_MASK;
|
||||
}
|
||||
if (attrs.secure) {
|
||||
/* the BFHFNMIGN bit is not banked; keep that in the NS copy */
|
||||
cpu->env.v7m.ccr[M_REG_NS] =
|
||||
(cpu->env.v7m.ccr[M_REG_NS] & ~R_V7M_CCR_BFHFNMIGN_MASK)
|
||||
| (value & R_V7M_CCR_BFHFNMIGN_MASK);
|
||||
value &= ~R_V7M_CCR_BFHFNMIGN_MASK;
|
||||
}
|
||||
|
||||
cpu->env.v7m.ccr[attrs.secure] = value;
|
||||
break;
|
||||
case 0xd24: /* System Handler Control. */
|
||||
s->vectors[ARMV7M_EXCP_MEM].active = (value & (1 << 0)) != 0;
|
||||
|
@ -643,7 +716,13 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
|||
nvic_irq_update(s);
|
||||
break;
|
||||
case 0xd28: /* Configurable Fault Status. */
|
||||
cpu->env.v7m.cfsr &= ~value; /* W1C */
|
||||
cpu->env.v7m.cfsr[attrs.secure] &= ~value; /* W1C */
|
||||
if (attrs.secure) {
|
||||
/* The BFSR bits [15:8] are shared between security states
|
||||
* and we store them in the NS copy.
|
||||
*/
|
||||
cpu->env.v7m.cfsr[M_REG_NS] &= ~(value & R_V7M_CFSR_BFSR_MASK);
|
||||
}
|
||||
break;
|
||||
case 0xd2c: /* Hard Fault Status. */
|
||||
cpu->env.v7m.hfsr &= ~value; /* W1C */
|
||||
|
@ -652,7 +731,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
|||
cpu->env.v7m.dfsr &= ~value; /* W1C */
|
||||
break;
|
||||
case 0xd34: /* Mem Manage Address. */
|
||||
cpu->env.v7m.mmfar = value;
|
||||
cpu->env.v7m.mmfar[attrs.secure] = value;
|
||||
return;
|
||||
case 0xd38: /* Bus Fault Address. */
|
||||
cpu->env.v7m.bfar = value;
|
||||
|
@ -670,9 +749,10 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
|||
qemu_log_mask(LOG_GUEST_ERROR, "MPU_CTRL: HFNMIENA and !ENABLE is "
|
||||
"UNPREDICTABLE\n");
|
||||
}
|
||||
cpu->env.v7m.mpu_ctrl = value & (R_V7M_MPU_CTRL_ENABLE_MASK |
|
||||
R_V7M_MPU_CTRL_HFNMIENA_MASK |
|
||||
R_V7M_MPU_CTRL_PRIVDEFENA_MASK);
|
||||
cpu->env.v7m.mpu_ctrl[attrs.secure]
|
||||
= value & (R_V7M_MPU_CTRL_ENABLE_MASK |
|
||||
R_V7M_MPU_CTRL_HFNMIENA_MASK |
|
||||
R_V7M_MPU_CTRL_PRIVDEFENA_MASK);
|
||||
tlb_flush(CPU(cpu));
|
||||
break;
|
||||
case 0xd98: /* MPU_RNR */
|
||||
|
@ -681,7 +761,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
|||
PRIu32 "/%" PRIu32 "\n",
|
||||
value, cpu->pmsav7_dregion);
|
||||
} else {
|
||||
cpu->env.pmsav7.rnr = value;
|
||||
cpu->env.pmsav7.rnr[attrs.secure] = value;
|
||||
}
|
||||
break;
|
||||
case 0xd9c: /* MPU_RBAR */
|
||||
|
@ -691,6 +771,26 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
|||
{
|
||||
int region;
|
||||
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
/* PMSAv8M handling of the aliases is different from v7M:
|
||||
* aliases A1, A2, A3 override the low two bits of the region
|
||||
* number in MPU_RNR, and there is no 'region' field in the
|
||||
* RBAR register.
|
||||
*/
|
||||
int aliasno = (offset - 0xd9c) / 8; /* 0..3 */
|
||||
|
||||
region = cpu->env.pmsav7.rnr[attrs.secure];
|
||||
if (aliasno) {
|
||||
region = deposit32(region, 0, 2, aliasno);
|
||||
}
|
||||
if (region >= cpu->pmsav7_dregion) {
|
||||
return;
|
||||
}
|
||||
cpu->env.pmsav8.rbar[attrs.secure][region] = value;
|
||||
tlb_flush(CPU(cpu));
|
||||
return;
|
||||
}
|
||||
|
||||
if (value & (1 << 4)) {
|
||||
/* VALID bit means use the region number specified in this
|
||||
* value and also update MPU_RNR.REGION with that value.
|
||||
|
@ -702,9 +802,9 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
|||
region, cpu->pmsav7_dregion);
|
||||
return;
|
||||
}
|
||||
cpu->env.pmsav7.rnr = region;
|
||||
cpu->env.pmsav7.rnr[attrs.secure] = region;
|
||||
} else {
|
||||
region = cpu->env.pmsav7.rnr;
|
||||
region = cpu->env.pmsav7.rnr[attrs.secure];
|
||||
}
|
||||
|
||||
if (region >= cpu->pmsav7_dregion) {
|
||||
|
@ -715,12 +815,31 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
|||
tlb_flush(CPU(cpu));
|
||||
break;
|
||||
}
|
||||
case 0xda0: /* MPU_RASR */
|
||||
case 0xda8: /* MPU_RASR_A1 */
|
||||
case 0xdb0: /* MPU_RASR_A2 */
|
||||
case 0xdb8: /* MPU_RASR_A3 */
|
||||
case 0xda0: /* MPU_RASR (v7M), MPU_RLAR (v8M) */
|
||||
case 0xda8: /* MPU_RASR_A1 (v7M), MPU_RLAR_A1 (v8M) */
|
||||
case 0xdb0: /* MPU_RASR_A2 (v7M), MPU_RLAR_A2 (v8M) */
|
||||
case 0xdb8: /* MPU_RASR_A3 (v7M), MPU_RLAR_A3 (v8M) */
|
||||
{
|
||||
int region = cpu->env.pmsav7.rnr;
|
||||
int region = cpu->env.pmsav7.rnr[attrs.secure];
|
||||
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
/* PMSAv8M handling of the aliases is different from v7M:
|
||||
* aliases A1, A2, A3 override the low two bits of the region
|
||||
* number in MPU_RNR.
|
||||
*/
|
||||
int aliasno = (offset - 0xd9c) / 8; /* 0..3 */
|
||||
|
||||
region = cpu->env.pmsav7.rnr[attrs.secure];
|
||||
if (aliasno) {
|
||||
region = deposit32(region, 0, 2, aliasno);
|
||||
}
|
||||
if (region >= cpu->pmsav7_dregion) {
|
||||
return;
|
||||
}
|
||||
cpu->env.pmsav8.rlar[attrs.secure][region] = value;
|
||||
tlb_flush(CPU(cpu));
|
||||
return;
|
||||
}
|
||||
|
||||
if (region >= cpu->pmsav7_dregion) {
|
||||
return;
|
||||
|
@ -731,6 +850,30 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
|||
tlb_flush(CPU(cpu));
|
||||
break;
|
||||
}
|
||||
case 0xdc0: /* MPU_MAIR0 */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (cpu->pmsav7_dregion) {
|
||||
/* Register is RES0 if no MPU regions are implemented */
|
||||
cpu->env.pmsav8.mair0[attrs.secure] = value;
|
||||
}
|
||||
/* We don't need to do anything else because memory attributes
|
||||
* only affect cacheability, and we don't implement caching.
|
||||
*/
|
||||
break;
|
||||
case 0xdc4: /* MPU_MAIR1 */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (cpu->pmsav7_dregion) {
|
||||
/* Register is RES0 if no MPU regions are implemented */
|
||||
cpu->env.pmsav8.mair1[attrs.secure] = value;
|
||||
}
|
||||
/* We don't need to do anything else because memory attributes
|
||||
* only affect cacheability, and we don't implement caching.
|
||||
*/
|
||||
break;
|
||||
case 0xf00: /* Software Triggered Interrupt Register */
|
||||
{
|
||||
int excnum = (value & 0x1ff) + NVIC_FIRST_IRQ;
|
||||
|
@ -740,17 +883,21 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
|||
break;
|
||||
}
|
||||
default:
|
||||
bad_offset:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"NVIC: Bad write offset 0x%x\n", offset);
|
||||
}
|
||||
}
|
||||
|
||||
static bool nvic_user_access_ok(NVICState *s, hwaddr offset)
|
||||
static bool nvic_user_access_ok(NVICState *s, hwaddr offset, MemTxAttrs attrs)
|
||||
{
|
||||
/* Return true if unprivileged access to this register is permitted. */
|
||||
switch (offset) {
|
||||
case 0xf00: /* STIR: accessible only if CCR.USERSETMPEND permits */
|
||||
return s->cpu->env.v7m.ccr & R_V7M_CCR_USERSETMPEND_MASK;
|
||||
/* For access via STIR_NS it is the NS CCR.USERSETMPEND that
|
||||
* controls access even though the CPU is in Secure state (I_QDKX).
|
||||
*/
|
||||
return s->cpu->env.v7m.ccr[attrs.secure] & R_V7M_CCR_USERSETMPEND_MASK;
|
||||
default:
|
||||
/* All other user accesses cause a BusFault unconditionally */
|
||||
return false;
|
||||
|
@ -766,7 +913,7 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
|
|||
unsigned i, startvec, end;
|
||||
uint32_t val;
|
||||
|
||||
if (attrs.user && !nvic_user_access_ok(s, addr)) {
|
||||
if (attrs.user && !nvic_user_access_ok(s, addr, attrs)) {
|
||||
/* Generate BusFault for unprivileged accesses */
|
||||
return MEMTX_ERROR;
|
||||
}
|
||||
|
@ -831,7 +978,7 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr,
|
|||
break;
|
||||
default:
|
||||
if (size == 4) {
|
||||
val = nvic_readl(s, offset);
|
||||
val = nvic_readl(s, offset, attrs);
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"NVIC: Bad read of size %d at offset 0x%x\n",
|
||||
|
@ -856,7 +1003,7 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
|
|||
|
||||
trace_nvic_sysreg_write(addr, value, size);
|
||||
|
||||
if (attrs.user && !nvic_user_access_ok(s, addr)) {
|
||||
if (attrs.user && !nvic_user_access_ok(s, addr, attrs)) {
|
||||
/* Generate BusFault for unprivileged accesses */
|
||||
return MEMTX_ERROR;
|
||||
}
|
||||
|
@ -912,7 +1059,7 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
|
|||
return MEMTX_OK;
|
||||
}
|
||||
if (size == 4) {
|
||||
nvic_writel(s, offset, value);
|
||||
nvic_writel(s, offset, value, attrs);
|
||||
return MEMTX_OK;
|
||||
}
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
|
@ -927,6 +1074,47 @@ static const MemoryRegionOps nvic_sysreg_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static MemTxResult nvic_sysreg_ns_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
if (attrs.secure) {
|
||||
/* S accesses to the alias act like NS accesses to the real region */
|
||||
attrs.secure = 0;
|
||||
return nvic_sysreg_write(opaque, addr, value, size, attrs);
|
||||
} else {
|
||||
/* NS attrs are RAZ/WI for privileged, and BusFault for user */
|
||||
if (attrs.user) {
|
||||
return MEMTX_ERROR;
|
||||
}
|
||||
return MEMTX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static MemTxResult nvic_sysreg_ns_read(void *opaque, hwaddr addr,
|
||||
uint64_t *data, unsigned size,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
if (attrs.secure) {
|
||||
/* S accesses to the alias act like NS accesses to the real region */
|
||||
attrs.secure = 0;
|
||||
return nvic_sysreg_read(opaque, addr, data, size, attrs);
|
||||
} else {
|
||||
/* NS attrs are RAZ/WI for privileged, and BusFault for user */
|
||||
if (attrs.user) {
|
||||
return MEMTX_ERROR;
|
||||
}
|
||||
*data = 0;
|
||||
return MEMTX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps nvic_sysreg_ns_ops = {
|
||||
.read_with_attrs = nvic_sysreg_ns_read,
|
||||
.write_with_attrs = nvic_sysreg_ns_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int nvic_post_load(void *opaque, int version_id)
|
||||
{
|
||||
NVICState *s = opaque;
|
||||
|
@ -1028,6 +1216,7 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
|
|||
NVICState *s = NVIC(dev);
|
||||
SysBusDevice *systick_sbd;
|
||||
Error *err = NULL;
|
||||
int regionlen;
|
||||
|
||||
s->cpu = ARM_CPU(qemu_get_cpu(0));
|
||||
assert(s->cpu);
|
||||
|
@ -1060,8 +1249,23 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
|
|||
* 0xd00..0xd3c - SCS registers
|
||||
* 0xd40..0xeff - Reserved or Not implemented
|
||||
* 0xf00 - STIR
|
||||
*
|
||||
* Some registers within this space are banked between security states.
|
||||
* In v8M there is a second range 0xe002e000..0xe002efff which is the
|
||||
* NonSecure alias SCS; secure accesses to this behave like NS accesses
|
||||
* to the main SCS range, and non-secure accesses (including when
|
||||
* the security extension is not implemented) are RAZ/WI.
|
||||
* Note that both the main SCS range and the alias range are defined
|
||||
* to be exempt from memory attribution (R_BLJT) and so the memory
|
||||
* transaction attribute always matches the current CPU security
|
||||
* state (attrs.secure == env->v7m.secure). In the nvic_sysreg_ns_ops
|
||||
* wrappers we change attrs.secure to indicate the NS access; so
|
||||
* generally code determining which banked register to use should
|
||||
* use attrs.secure; code determining actual behaviour of the system
|
||||
* should use env->v7m.secure.
|
||||
*/
|
||||
memory_region_init(&s->container, OBJECT(s), "nvic", 0x1000);
|
||||
regionlen = arm_feature(&s->cpu->env, ARM_FEATURE_V8) ? 0x21000 : 0x1000;
|
||||
memory_region_init(&s->container, OBJECT(s), "nvic", regionlen);
|
||||
/* The system register region goes at the bottom of the priority
|
||||
* stack as it covers the whole page.
|
||||
*/
|
||||
|
@ -1072,6 +1276,13 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_mmio_get_region(systick_sbd, 0),
|
||||
1);
|
||||
|
||||
if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) {
|
||||
memory_region_init_io(&s->sysreg_ns_mem, OBJECT(s),
|
||||
&nvic_sysreg_ns_ops, s,
|
||||
"nvic_sysregs_ns", 0x1000);
|
||||
memory_region_add_subregion(&s->container, 0x20000, &s->sysreg_ns_mem);
|
||||
}
|
||||
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->container);
|
||||
}
|
||||
|
||||
|
|
|
@ -989,18 +989,6 @@ static void xilinx_enet_init(Object *obj)
|
|||
XilinxAXIEnet *s = XILINX_AXI_ENET(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
|
||||
(Object **) &s->tx_data_dev,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
object_property_add_link(obj, "axistream-control-connected",
|
||||
TYPE_STREAM_SLAVE,
|
||||
(Object **) &s->tx_control_dev,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
|
||||
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
|
||||
TYPE_XILINX_AXI_ENET_DATA_STREAM);
|
||||
object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
|
||||
|
@ -1021,6 +1009,10 @@ static Property xilinx_enet_properties[] = {
|
|||
DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000),
|
||||
DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000),
|
||||
DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf),
|
||||
DEFINE_PROP_LINK("axistream-connected", XilinxAXIEnet,
|
||||
tx_data_dev, TYPE_STREAM_SLAVE, StreamSlave *),
|
||||
DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIEnet,
|
||||
tx_control_dev, TYPE_STREAM_SLAVE, StreamSlave *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
|
|
@ -131,6 +131,16 @@ typedef struct {
|
|||
* size than the target architecture's minimum. (Attempting to create
|
||||
* such a CPU will fail.) Note that changing this is a migration
|
||||
* compatibility break for the machine.
|
||||
* @ignore_memory_transaction_failures:
|
||||
* If this is flag is true then the CPU will ignore memory transaction
|
||||
* failures which should cause the CPU to take an exception due to an
|
||||
* access to an unassigned physical address; the transaction will instead
|
||||
* return zero (for a read) or be ignored (for a write). This should be
|
||||
* set only by legacy board models which rely on the old RAZ/WI behaviour
|
||||
* for handling devices that QEMU does not yet model. New board models
|
||||
* should instead use "unimplemented-device" for all memory ranges where
|
||||
* the guest will attempt to probe for a device that QEMU doesn't
|
||||
* implement and a stub device is required.
|
||||
*/
|
||||
struct MachineClass {
|
||||
/*< private >*/
|
||||
|
@ -171,6 +181,7 @@ struct MachineClass {
|
|||
bool rom_file_has_mr;
|
||||
int minimum_page_bits;
|
||||
bool has_hotpluggable_cpus;
|
||||
bool ignore_memory_transaction_failures;
|
||||
int numa_mem_align_shift;
|
||||
void (*numa_auto_assign_ram)(MachineClass *mc, NodeInfo *nodes,
|
||||
int nb_nodes, ram_addr_t size);
|
||||
|
|
|
@ -50,6 +50,7 @@ typedef struct NVICState {
|
|||
int exception_prio; /* group prio of the highest prio active exception */
|
||||
|
||||
MemoryRegion sysregmem;
|
||||
MemoryRegion sysreg_ns_mem;
|
||||
MemoryRegion container;
|
||||
|
||||
uint32_t num_irq;
|
||||
|
|
|
@ -312,6 +312,9 @@ struct qemu_work_item;
|
|||
* @trace_dstate_delayed: Delayed changes to trace_dstate (includes all changes
|
||||
* to @trace_dstate).
|
||||
* @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask).
|
||||
* @ignore_memory_transaction_failures: Cached copy of the MachineState
|
||||
* flag of the same name: allows the board to suppress calling of the
|
||||
* CPU do_transaction_failed hook function.
|
||||
*
|
||||
* State of one CPU core or thread.
|
||||
*/
|
||||
|
@ -398,6 +401,8 @@ struct CPUState {
|
|||
*/
|
||||
bool throttle_thread_scheduled;
|
||||
|
||||
bool ignore_memory_transaction_failures;
|
||||
|
||||
/* Note that this is accessed at the start of every TB via a negative
|
||||
offset from AREG0. Leave this field at the end so as to make the
|
||||
(absolute value) offset as small as possible. This reduces code
|
||||
|
@ -864,7 +869,7 @@ static inline void cpu_transaction_failed(CPUState *cpu, hwaddr physaddr,
|
|||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
if (cc->do_transaction_failed) {
|
||||
if (!cpu->ignore_memory_transaction_failures && cc->do_transaction_failed) {
|
||||
cc->do_transaction_failed(cpu, physaddr, addr, size, access_type,
|
||||
mmu_idx, attrs, response, retaddr);
|
||||
}
|
||||
|
|
16
qom/cpu.c
16
qom/cpu.c
|
@ -29,6 +29,7 @@
|
|||
#include "exec/cpu-common.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "trace-root.h"
|
||||
|
||||
|
@ -363,6 +364,21 @@ static void cpu_common_parse_features(const char *typename, char *features,
|
|||
static void cpu_common_realizefn(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUState *cpu = CPU(dev);
|
||||
Object *machine = qdev_get_machine();
|
||||
|
||||
/* qdev_get_machine() can return something that's not TYPE_MACHINE
|
||||
* if this is one of the user-only emulators; in that case there's
|
||||
* no need to check the ignore_memory_transaction_failures board flag.
|
||||
*/
|
||||
if (object_dynamic_cast(machine, TYPE_MACHINE)) {
|
||||
ObjectClass *oc = object_get_class(machine);
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
if (mc) {
|
||||
cpu->ignore_memory_transaction_failures =
|
||||
mc->ignore_memory_transaction_failures;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->hotplugged) {
|
||||
cpu_synchronize_post_init(cpu);
|
||||
|
|
|
@ -187,7 +187,6 @@ ERROR_WHITELIST = [
|
|||
{'log':r"Device [\w.,-]+ can not be dynamically instantiated"},
|
||||
{'log':r"Platform Bus: Can not fit MMIO region of size "},
|
||||
# other more specific errors we will ignore:
|
||||
{'device':'allwinner-a10', 'log':"Unsupported NIC model:"},
|
||||
{'device':'.*-spapr-cpu-core', 'log':r"CPU core type should be"},
|
||||
{'log':r"MSI(-X)? is not supported by interrupt controller"},
|
||||
{'log':r"pxb-pcie? devices cannot reside on a PCIe? bus"},
|
||||
|
|
|
@ -185,11 +185,21 @@ static void arm_cpu_reset(CPUState *s)
|
|||
uint32_t initial_pc; /* Loaded from 0x4 */
|
||||
uint8_t *rom;
|
||||
|
||||
/* The reset value of this bit is IMPDEF, but ARM recommends
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
env->v7m.secure = true;
|
||||
}
|
||||
|
||||
/* In v7M the reset value of this bit is IMPDEF, but ARM recommends
|
||||
* that it resets to 1, so QEMU always does that rather than making
|
||||
* it dependent on CPU model.
|
||||
* it dependent on CPU model. In v8M it is RES1.
|
||||
*/
|
||||
env->v7m.ccr = R_V7M_CCR_STKALIGN_MASK;
|
||||
env->v7m.ccr[M_REG_NS] = R_V7M_CCR_STKALIGN_MASK;
|
||||
env->v7m.ccr[M_REG_S] = R_V7M_CCR_STKALIGN_MASK;
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
/* in v8M the NONBASETHRDENA bit [0] is RES1 */
|
||||
env->v7m.ccr[M_REG_NS] |= R_V7M_CCR_NONBASETHRDENA_MASK;
|
||||
env->v7m.ccr[M_REG_S] |= R_V7M_CCR_NONBASETHRDENA_MASK;
|
||||
}
|
||||
|
||||
/* Unlike A/R profile, M profile defines the reset LR value */
|
||||
env->regs[14] = 0xffffffff;
|
||||
|
@ -228,17 +238,38 @@ static void arm_cpu_reset(CPUState *s)
|
|||
env->vfp.xregs[ARM_VFP_FPEXC] = 0;
|
||||
#endif
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_PMSA) &&
|
||||
arm_feature(env, ARM_FEATURE_V7)) {
|
||||
if (arm_feature(env, ARM_FEATURE_PMSA)) {
|
||||
if (cpu->pmsav7_dregion > 0) {
|
||||
memset(env->pmsav7.drbar, 0,
|
||||
sizeof(*env->pmsav7.drbar) * cpu->pmsav7_dregion);
|
||||
memset(env->pmsav7.drsr, 0,
|
||||
sizeof(*env->pmsav7.drsr) * cpu->pmsav7_dregion);
|
||||
memset(env->pmsav7.dracr, 0,
|
||||
sizeof(*env->pmsav7.dracr) * cpu->pmsav7_dregion);
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
memset(env->pmsav8.rbar[M_REG_NS], 0,
|
||||
sizeof(*env->pmsav8.rbar[M_REG_NS])
|
||||
* cpu->pmsav7_dregion);
|
||||
memset(env->pmsav8.rlar[M_REG_NS], 0,
|
||||
sizeof(*env->pmsav8.rlar[M_REG_NS])
|
||||
* cpu->pmsav7_dregion);
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
memset(env->pmsav8.rbar[M_REG_S], 0,
|
||||
sizeof(*env->pmsav8.rbar[M_REG_S])
|
||||
* cpu->pmsav7_dregion);
|
||||
memset(env->pmsav8.rlar[M_REG_S], 0,
|
||||
sizeof(*env->pmsav8.rlar[M_REG_S])
|
||||
* cpu->pmsav7_dregion);
|
||||
}
|
||||
} else if (arm_feature(env, ARM_FEATURE_V7)) {
|
||||
memset(env->pmsav7.drbar, 0,
|
||||
sizeof(*env->pmsav7.drbar) * cpu->pmsav7_dregion);
|
||||
memset(env->pmsav7.drsr, 0,
|
||||
sizeof(*env->pmsav7.drsr) * cpu->pmsav7_dregion);
|
||||
memset(env->pmsav7.dracr, 0,
|
||||
sizeof(*env->pmsav7.dracr) * cpu->pmsav7_dregion);
|
||||
}
|
||||
}
|
||||
env->pmsav7.rnr = 0;
|
||||
env->pmsav7.rnr[M_REG_NS] = 0;
|
||||
env->pmsav7.rnr[M_REG_S] = 0;
|
||||
env->pmsav8.mair0[M_REG_NS] = 0;
|
||||
env->pmsav8.mair0[M_REG_S] = 0;
|
||||
env->pmsav8.mair1[M_REG_NS] = 0;
|
||||
env->pmsav8.mair1[M_REG_S] = 0;
|
||||
}
|
||||
|
||||
set_flush_to_zero(1, &env->vfp.standard_fp_status);
|
||||
|
@ -681,6 +712,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
|||
}
|
||||
if (arm_feature(env, ARM_FEATURE_V6)) {
|
||||
set_feature(env, ARM_FEATURE_V5);
|
||||
set_feature(env, ARM_FEATURE_JAZELLE);
|
||||
if (!arm_feature(env, ARM_FEATURE_M)) {
|
||||
set_feature(env, ARM_FEATURE_AUXCR);
|
||||
}
|
||||
|
@ -809,9 +841,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
|||
}
|
||||
|
||||
if (nr) {
|
||||
env->pmsav7.drbar = g_new0(uint32_t, nr);
|
||||
env->pmsav7.drsr = g_new0(uint32_t, nr);
|
||||
env->pmsav7.dracr = g_new0(uint32_t, nr);
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
/* PMSAv8 */
|
||||
env->pmsav8.rbar[M_REG_NS] = g_new0(uint32_t, nr);
|
||||
env->pmsav8.rlar[M_REG_NS] = g_new0(uint32_t, nr);
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
env->pmsav8.rbar[M_REG_S] = g_new0(uint32_t, nr);
|
||||
env->pmsav8.rlar[M_REG_S] = g_new0(uint32_t, nr);
|
||||
}
|
||||
} else {
|
||||
env->pmsav7.drbar = g_new0(uint32_t, nr);
|
||||
env->pmsav7.drsr = g_new0(uint32_t, nr);
|
||||
env->pmsav7.dracr = g_new0(uint32_t, nr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -825,22 +867,21 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
|||
init_cpreg_list(cpu);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu->has_el3) {
|
||||
cs->num_ases = 2;
|
||||
} else {
|
||||
cs->num_ases = 1;
|
||||
}
|
||||
|
||||
if (cpu->has_el3) {
|
||||
if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
AddressSpace *as;
|
||||
|
||||
cs->num_ases = 2;
|
||||
|
||||
if (!cpu->secure_memory) {
|
||||
cpu->secure_memory = cs->memory;
|
||||
}
|
||||
as = address_space_init_shareable(cpu->secure_memory,
|
||||
"cpu-secure-memory");
|
||||
cpu_address_space_init(cs, as, ARMASIdx_S);
|
||||
} else {
|
||||
cs->num_ases = 1;
|
||||
}
|
||||
|
||||
cpu_address_space_init(cs,
|
||||
address_space_init_shareable(cs->memory,
|
||||
"cpu-memory"),
|
||||
|
@ -887,6 +928,7 @@ static void arm926_initfn(Object *obj)
|
|||
set_feature(&cpu->env, ARM_FEATURE_VFP);
|
||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
|
||||
set_feature(&cpu->env, ARM_FEATURE_JAZELLE);
|
||||
cpu->midr = 0x41069265;
|
||||
cpu->reset_fpsid = 0x41011090;
|
||||
cpu->ctr = 0x1dd20d2;
|
||||
|
@ -916,6 +958,7 @@ static void arm1026_initfn(Object *obj)
|
|||
set_feature(&cpu->env, ARM_FEATURE_AUXCR);
|
||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
|
||||
set_feature(&cpu->env, ARM_FEATURE_JAZELLE);
|
||||
cpu->midr = 0x4106a262;
|
||||
cpu->reset_fpsid = 0x410110a0;
|
||||
cpu->ctr = 0x1dd20d2;
|
||||
|
@ -1667,6 +1710,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
|
|||
#else
|
||||
cc->do_interrupt = arm_cpu_do_interrupt;
|
||||
cc->do_unaligned_access = arm_cpu_do_unaligned_access;
|
||||
cc->do_transaction_failed = arm_cpu_do_transaction_failed;
|
||||
cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
|
||||
cc->asidx_from_attrs = arm_asidx_from_attrs;
|
||||
cc->vmsd = &vmstate_arm_cpu;
|
||||
|
|
101
target/arm/cpu.h
101
target/arm/cpu.h
|
@ -66,11 +66,24 @@
|
|||
#define ARMV7M_EXCP_MEM 4
|
||||
#define ARMV7M_EXCP_BUS 5
|
||||
#define ARMV7M_EXCP_USAGE 6
|
||||
#define ARMV7M_EXCP_SECURE 7
|
||||
#define ARMV7M_EXCP_SVC 11
|
||||
#define ARMV7M_EXCP_DEBUG 12
|
||||
#define ARMV7M_EXCP_PENDSV 14
|
||||
#define ARMV7M_EXCP_SYSTICK 15
|
||||
|
||||
/* For M profile, some registers are banked secure vs non-secure;
|
||||
* these are represented as a 2-element array where the first element
|
||||
* is the non-secure copy and the second is the secure copy.
|
||||
* When the CPU does not have implement the security extension then
|
||||
* only the first element is used.
|
||||
* This means that the copy for the current security state can be
|
||||
* accessed via env->registerfield[env->v7m.secure] (whether the security
|
||||
* extension is implemented or not).
|
||||
*/
|
||||
#define M_REG_NS 0
|
||||
#define M_REG_S 1
|
||||
|
||||
/* ARM-specific interrupt pending bits. */
|
||||
#define CPU_INTERRUPT_FIQ CPU_INTERRUPT_TGT_EXT_1
|
||||
#define CPU_INTERRUPT_VIRQ CPU_INTERRUPT_TGT_EXT_2
|
||||
|
@ -406,20 +419,34 @@ typedef struct CPUARMState {
|
|||
} cp15;
|
||||
|
||||
struct {
|
||||
/* M profile has up to 4 stack pointers:
|
||||
* a Main Stack Pointer and a Process Stack Pointer for each
|
||||
* of the Secure and Non-Secure states. (If the CPU doesn't support
|
||||
* the security extension then it has only two SPs.)
|
||||
* In QEMU we always store the currently active SP in regs[13],
|
||||
* and the non-active SP for the current security state in
|
||||
* v7m.other_sp. The stack pointers for the inactive security state
|
||||
* are stored in other_ss_msp and other_ss_psp.
|
||||
* switch_v7m_security_state() is responsible for rearranging them
|
||||
* when we change security state.
|
||||
*/
|
||||
uint32_t other_sp;
|
||||
uint32_t vecbase;
|
||||
uint32_t basepri;
|
||||
uint32_t control;
|
||||
uint32_t ccr; /* Configuration and Control */
|
||||
uint32_t cfsr; /* Configurable Fault Status */
|
||||
uint32_t other_ss_msp;
|
||||
uint32_t other_ss_psp;
|
||||
uint32_t vecbase[2];
|
||||
uint32_t basepri[2];
|
||||
uint32_t control[2];
|
||||
uint32_t ccr[2]; /* Configuration and Control */
|
||||
uint32_t cfsr[2]; /* Configurable Fault Status */
|
||||
uint32_t hfsr; /* HardFault Status */
|
||||
uint32_t dfsr; /* Debug Fault Status Register */
|
||||
uint32_t mmfar; /* MemManage Fault Address */
|
||||
uint32_t mmfar[2]; /* MemManage Fault Address */
|
||||
uint32_t bfar; /* BusFault Address */
|
||||
unsigned mpu_ctrl; /* MPU_CTRL */
|
||||
unsigned mpu_ctrl[2]; /* MPU_CTRL */
|
||||
int exception;
|
||||
uint32_t primask;
|
||||
uint32_t faultmask;
|
||||
uint32_t primask[2];
|
||||
uint32_t faultmask[2];
|
||||
uint32_t secure; /* Is CPU in Secure state? (not guest visible) */
|
||||
} v7m;
|
||||
|
||||
/* Information associated with an exception about to be taken:
|
||||
|
@ -519,9 +546,22 @@ typedef struct CPUARMState {
|
|||
uint32_t *drbar;
|
||||
uint32_t *drsr;
|
||||
uint32_t *dracr;
|
||||
uint32_t rnr;
|
||||
uint32_t rnr[2];
|
||||
} pmsav7;
|
||||
|
||||
/* PMSAv8 MPU */
|
||||
struct {
|
||||
/* The PMSAv8 implementation also shares some PMSAv7 config
|
||||
* and state:
|
||||
* pmsav7.rnr (region number register)
|
||||
* pmsav7_dregion (number of configured regions)
|
||||
*/
|
||||
uint32_t *rbar[2];
|
||||
uint32_t *rlar[2];
|
||||
uint32_t mair0[2];
|
||||
uint32_t mair1[2];
|
||||
} pmsav8;
|
||||
|
||||
void *nvic;
|
||||
const struct arm_boot_info *boot_info;
|
||||
/* Store GICv3CPUState to access from this struct */
|
||||
|
@ -1182,6 +1222,11 @@ FIELD(V7M_CFSR, NOCP, 16 + 3, 1)
|
|||
FIELD(V7M_CFSR, UNALIGNED, 16 + 8, 1)
|
||||
FIELD(V7M_CFSR, DIVBYZERO, 16 + 9, 1)
|
||||
|
||||
/* V7M CFSR bit masks covering all of the subregister bits */
|
||||
FIELD(V7M_CFSR, MMFSR, 0, 8)
|
||||
FIELD(V7M_CFSR, BFSR, 8, 8)
|
||||
FIELD(V7M_CFSR, UFSR, 16, 16)
|
||||
|
||||
/* V7M HFSR bits */
|
||||
FIELD(V7M_HFSR, VECTTBL, 1, 1)
|
||||
FIELD(V7M_HFSR, FORCED, 30, 1)
|
||||
|
@ -1250,6 +1295,8 @@ enum arm_features {
|
|||
ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */
|
||||
ARM_FEATURE_PMU, /* has PMU support */
|
||||
ARM_FEATURE_VBAR, /* has cp15 VBAR */
|
||||
ARM_FEATURE_M_SECURITY, /* M profile Security Extension */
|
||||
ARM_FEATURE_JAZELLE, /* has (trivial) Jazelle implementation */
|
||||
};
|
||||
|
||||
static inline int arm_feature(CPUARMState *env, int feature)
|
||||
|
@ -1414,6 +1461,16 @@ void armv7m_nvic_acknowledge_irq(void *opaque);
|
|||
* (Ignoring -1, this is the same as the RETTOBASE value before completion.)
|
||||
*/
|
||||
int armv7m_nvic_complete_irq(void *opaque, int irq);
|
||||
/**
|
||||
* armv7m_nvic_raw_execution_priority: return the raw execution priority
|
||||
* @opaque: the NVIC
|
||||
*
|
||||
* Returns: the raw execution priority as defined by the v8M architecture.
|
||||
* This is the execution priority minus the effects of AIRCR.PRIS,
|
||||
* and minus any PRIMASK/FAULTMASK/BASEPRI priority boosting.
|
||||
* (v8M ARM ARM I_PKLD.)
|
||||
*/
|
||||
int armv7m_nvic_raw_execution_priority(void *opaque);
|
||||
|
||||
/* Interface for defining coprocessor registers.
|
||||
* Registers are defined in tables of arm_cp_reginfo structs
|
||||
|
@ -1643,7 +1700,8 @@ static inline bool arm_v7m_is_handler_mode(CPUARMState *env)
|
|||
static inline int arm_current_el(CPUARMState *env)
|
||||
{
|
||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
return arm_v7m_is_handler_mode(env) || !(env->v7m.control & 1);
|
||||
return arm_v7m_is_handler_mode(env) ||
|
||||
!(env->v7m.control[env->v7m.secure] & 1);
|
||||
}
|
||||
|
||||
if (is_a64(env)) {
|
||||
|
@ -2087,6 +2145,10 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
|
|||
* Execution priority negative (this is like privileged, but the
|
||||
* MPU HFNMIENA bit means that it may have different access permission
|
||||
* check results to normal privileged code, so can't share a TLB).
|
||||
* If the CPU supports the v8M Security Extension then there are also:
|
||||
* Secure User
|
||||
* Secure Privileged
|
||||
* Secure, execution priority negative
|
||||
*
|
||||
* The ARMMMUIdx and the mmu index value used by the core QEMU TLB code
|
||||
* are not quite the same -- different CPU types (most notably M profile
|
||||
|
@ -2124,6 +2186,9 @@ typedef enum ARMMMUIdx {
|
|||
ARMMMUIdx_MUser = 0 | ARM_MMU_IDX_M,
|
||||
ARMMMUIdx_MPriv = 1 | ARM_MMU_IDX_M,
|
||||
ARMMMUIdx_MNegPri = 2 | ARM_MMU_IDX_M,
|
||||
ARMMMUIdx_MSUser = 3 | ARM_MMU_IDX_M,
|
||||
ARMMMUIdx_MSPriv = 4 | ARM_MMU_IDX_M,
|
||||
ARMMMUIdx_MSNegPri = 5 | ARM_MMU_IDX_M,
|
||||
/* Indexes below here don't have TLBs and are used only for AT system
|
||||
* instructions or for the first stage of an S12 page table walk.
|
||||
*/
|
||||
|
@ -2145,6 +2210,9 @@ typedef enum ARMMMUIdxBit {
|
|||
ARMMMUIdxBit_MUser = 1 << 0,
|
||||
ARMMMUIdxBit_MPriv = 1 << 1,
|
||||
ARMMMUIdxBit_MNegPri = 1 << 2,
|
||||
ARMMMUIdxBit_MSUser = 1 << 3,
|
||||
ARMMMUIdxBit_MSPriv = 1 << 4,
|
||||
ARMMMUIdxBit_MSNegPri = 1 << 5,
|
||||
} ARMMMUIdxBit;
|
||||
|
||||
#define MMU_USER_IDX 0
|
||||
|
@ -2170,7 +2238,8 @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
|
|||
case ARM_MMU_IDX_A:
|
||||
return mmu_idx & 3;
|
||||
case ARM_MMU_IDX_M:
|
||||
return mmu_idx == ARMMMUIdx_MUser ? 0 : 1;
|
||||
return (mmu_idx == ARMMMUIdx_MUser || mmu_idx == ARMMMUIdx_MSUser)
|
||||
? 0 : 1;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
@ -2188,8 +2257,12 @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
|
|||
* we're in a HardFault or NMI handler.
|
||||
*/
|
||||
if ((env->v7m.exception > 0 && env->v7m.exception <= 3)
|
||||
|| env->v7m.faultmask) {
|
||||
return arm_to_core_mmu_idx(ARMMMUIdx_MNegPri);
|
||||
|| env->v7m.faultmask[env->v7m.secure]) {
|
||||
mmu_idx = ARMMMUIdx_MNegPri;
|
||||
}
|
||||
|
||||
if (env->v7m.secure) {
|
||||
mmu_idx += ARMMMUIdx_MSUser;
|
||||
}
|
||||
|
||||
return arm_to_core_mmu_idx(mmu_idx);
|
||||
|
|
|
@ -2385,7 +2385,7 @@ static uint64_t pmsav7_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
return 0;
|
||||
}
|
||||
|
||||
u32p += env->pmsav7.rnr;
|
||||
u32p += env->pmsav7.rnr[M_REG_NS];
|
||||
return *u32p;
|
||||
}
|
||||
|
||||
|
@ -2399,7 +2399,7 @@ static void pmsav7_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
return;
|
||||
}
|
||||
|
||||
u32p += env->pmsav7.rnr;
|
||||
u32p += env->pmsav7.rnr[M_REG_NS];
|
||||
tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */
|
||||
*u32p = value;
|
||||
}
|
||||
|
@ -2442,7 +2442,7 @@ static const ARMCPRegInfo pmsav7_cp_reginfo[] = {
|
|||
.resetfn = arm_cp_reset_ignore },
|
||||
{ .name = "RGNR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 2, .opc2 = 0,
|
||||
.access = PL1_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, pmsav7.rnr),
|
||||
.fieldoffset = offsetof(CPUARMState, pmsav7.rnr[M_REG_NS]),
|
||||
.writefn = pmsav7_rgnr_write,
|
||||
.resetfn = arm_cp_reset_ignore },
|
||||
REGINFO_SENTINEL
|
||||
|
@ -5870,6 +5870,12 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
|
||||
{
|
||||
/* translate.c should never generate calls here in user-only mode */
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
void switch_mode(CPUARMState *env, int mode)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
|
@ -6044,29 +6050,103 @@ static uint32_t v7m_pop(CPUARMState *env)
|
|||
return val;
|
||||
}
|
||||
|
||||
/* Return true if we're using the process stack pointer (not the MSP) */
|
||||
static bool v7m_using_psp(CPUARMState *env)
|
||||
{
|
||||
/* Handler mode always uses the main stack; for thread mode
|
||||
* the CONTROL.SPSEL bit determines the answer.
|
||||
* Note that in v7M it is not possible to be in Handler mode with
|
||||
* CONTROL.SPSEL non-zero, but in v8M it is, so we must check both.
|
||||
*/
|
||||
return !arm_v7m_is_handler_mode(env) &&
|
||||
env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK;
|
||||
}
|
||||
|
||||
/* Switch to V7M main or process stack pointer. */
|
||||
static void switch_v7m_sp(CPUARMState *env, bool new_spsel)
|
||||
{
|
||||
uint32_t tmp;
|
||||
bool old_spsel = env->v7m.control & R_V7M_CONTROL_SPSEL_MASK;
|
||||
uint32_t old_control = env->v7m.control[env->v7m.secure];
|
||||
bool old_spsel = old_control & R_V7M_CONTROL_SPSEL_MASK;
|
||||
|
||||
if (old_spsel != new_spsel) {
|
||||
tmp = env->v7m.other_sp;
|
||||
env->v7m.other_sp = env->regs[13];
|
||||
env->regs[13] = tmp;
|
||||
|
||||
env->v7m.control = deposit32(env->v7m.control,
|
||||
env->v7m.control[env->v7m.secure] = deposit32(old_control,
|
||||
R_V7M_CONTROL_SPSEL_SHIFT,
|
||||
R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
|
||||
}
|
||||
}
|
||||
|
||||
/* Switch M profile security state between NS and S */
|
||||
static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
|
||||
{
|
||||
uint32_t new_ss_msp, new_ss_psp;
|
||||
|
||||
if (env->v7m.secure == new_secstate) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* All the banked state is accessed by looking at env->v7m.secure
|
||||
* except for the stack pointer; rearrange the SP appropriately.
|
||||
*/
|
||||
new_ss_msp = env->v7m.other_ss_msp;
|
||||
new_ss_psp = env->v7m.other_ss_psp;
|
||||
|
||||
if (v7m_using_psp(env)) {
|
||||
env->v7m.other_ss_psp = env->regs[13];
|
||||
env->v7m.other_ss_msp = env->v7m.other_sp;
|
||||
} else {
|
||||
env->v7m.other_ss_msp = env->regs[13];
|
||||
env->v7m.other_ss_psp = env->v7m.other_sp;
|
||||
}
|
||||
|
||||
env->v7m.secure = new_secstate;
|
||||
|
||||
if (v7m_using_psp(env)) {
|
||||
env->regs[13] = new_ss_psp;
|
||||
env->v7m.other_sp = new_ss_msp;
|
||||
} else {
|
||||
env->regs[13] = new_ss_msp;
|
||||
env->v7m.other_sp = new_ss_psp;
|
||||
}
|
||||
}
|
||||
|
||||
void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
|
||||
{
|
||||
/* Handle v7M BXNS:
|
||||
* - if the return value is a magic value, do exception return (like BX)
|
||||
* - otherwise bit 0 of the return value is the target security state
|
||||
*/
|
||||
if (dest >= 0xff000000) {
|
||||
/* This is an exception return magic value; put it where
|
||||
* do_v7m_exception_exit() expects and raise EXCEPTION_EXIT.
|
||||
* Note that if we ever add gen_ss_advance() singlestep support to
|
||||
* M profile this should count as an "instruction execution complete"
|
||||
* event (compare gen_bx_excret_final_code()).
|
||||
*/
|
||||
env->regs[15] = dest & ~1;
|
||||
env->thumb = dest & 1;
|
||||
HELPER(exception_internal)(env, EXCP_EXCEPTION_EXIT);
|
||||
/* notreached */
|
||||
}
|
||||
|
||||
/* translate.c should have made BXNS UNDEF unless we're secure */
|
||||
assert(env->v7m.secure);
|
||||
|
||||
switch_v7m_security_state(env, dest & 1);
|
||||
env->thumb = 1;
|
||||
env->regs[15] = dest & ~1;
|
||||
}
|
||||
|
||||
static uint32_t arm_v7m_load_vector(ARMCPU *cpu)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUARMState *env = &cpu->env;
|
||||
MemTxResult result;
|
||||
hwaddr vec = env->v7m.vecbase + env->v7m.exception * 4;
|
||||
hwaddr vec = env->v7m.vecbase[env->v7m.secure] + env->v7m.exception * 4;
|
||||
uint32_t addr;
|
||||
|
||||
addr = address_space_ldl(cs->as, vec,
|
||||
|
@ -6112,7 +6192,8 @@ static void v7m_push_stack(ARMCPU *cpu)
|
|||
uint32_t xpsr = xpsr_read(env);
|
||||
|
||||
/* Align stack pointer if the guest wants that */
|
||||
if ((env->regs[13] & 4) && (env->v7m.ccr & R_V7M_CCR_STKALIGN_MASK)) {
|
||||
if ((env->regs[13] & 4) &&
|
||||
(env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) {
|
||||
env->regs[13] -= 4;
|
||||
xpsr |= XPSR_SPREALIGN;
|
||||
}
|
||||
|
@ -6166,8 +6247,20 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
}
|
||||
|
||||
if (env->v7m.exception != ARMV7M_EXCP_NMI) {
|
||||
/* Auto-clear FAULTMASK on return from other than NMI */
|
||||
env->v7m.faultmask = 0;
|
||||
/* Auto-clear FAULTMASK on return from other than NMI.
|
||||
* If the security extension is implemented then this only
|
||||
* happens if the raw execution priority is >= 0; the
|
||||
* value of the ES bit in the exception return value indicates
|
||||
* which security state's faultmask to clear. (v8M ARM ARM R_KBNF.)
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
int es = type & 1;
|
||||
if (armv7m_nvic_raw_execution_priority(env->nvic) >= 0) {
|
||||
env->v7m.faultmask[es] = 0;
|
||||
}
|
||||
} else {
|
||||
env->v7m.faultmask[M_REG_NS] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception)) {
|
||||
|
@ -6198,7 +6291,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
/* fall through */
|
||||
case 9: /* Return to Thread using Main stack */
|
||||
if (!rettobase &&
|
||||
!(env->v7m.ccr & R_V7M_CCR_NONBASETHRDENA_MASK)) {
|
||||
!(env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_NONBASETHRDENA_MASK)) {
|
||||
ufault = true;
|
||||
}
|
||||
break;
|
||||
|
@ -6210,7 +6303,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
/* Bad exception return: instead of popping the exception
|
||||
* stack, directly take a usage fault on the current stack.
|
||||
*/
|
||||
env->v7m.cfsr |= R_V7M_CFSR_INVPC_MASK;
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||
v7m_exception_taken(cpu, type | 0xf0000000);
|
||||
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
|
||||
|
@ -6252,7 +6345,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
if (return_to_handler != arm_v7m_is_handler_mode(env)) {
|
||||
/* Take an INVPC UsageFault by pushing the stack again. */
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||
env->v7m.cfsr |= R_V7M_CFSR_INVPC_MASK;
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
|
||||
v7m_push_stack(cpu);
|
||||
v7m_exception_taken(cpu, type | 0xf0000000);
|
||||
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe: "
|
||||
|
@ -6311,15 +6404,15 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
switch (cs->exception_index) {
|
||||
case EXCP_UDEF:
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||
env->v7m.cfsr |= R_V7M_CFSR_UNDEFINSTR_MASK;
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK;
|
||||
break;
|
||||
case EXCP_NOCP:
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||
env->v7m.cfsr |= R_V7M_CFSR_NOCP_MASK;
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK;
|
||||
break;
|
||||
case EXCP_INVSTATE:
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||
env->v7m.cfsr |= R_V7M_CFSR_INVSTATE_MASK;
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
|
||||
break;
|
||||
case EXCP_SWI:
|
||||
/* The PC already points to the next instruction. */
|
||||
|
@ -6335,11 +6428,11 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
case 0x8: /* External Abort */
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
env->v7m.cfsr |= R_V7M_CFSR_PRECISERR_MASK;
|
||||
env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_PRECISERR_MASK;
|
||||
qemu_log_mask(CPU_LOG_INT, "...with CFSR.PRECISERR\n");
|
||||
break;
|
||||
case EXCP_DATA_ABORT:
|
||||
env->v7m.cfsr |=
|
||||
env->v7m.cfsr[M_REG_NS] |=
|
||||
(R_V7M_CFSR_IBUSERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
|
||||
env->v7m.bfar = env->exception.vaddress;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
|
@ -6355,16 +6448,16 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
*/
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
env->v7m.cfsr |= R_V7M_CFSR_IACCVIOL_MASK;
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
|
||||
qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
|
||||
break;
|
||||
case EXCP_DATA_ABORT:
|
||||
env->v7m.cfsr |=
|
||||
env->v7m.cfsr[env->v7m.secure] |=
|
||||
(R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK);
|
||||
env->v7m.mmfar = env->exception.vaddress;
|
||||
env->v7m.mmfar[env->v7m.secure] = env->exception.vaddress;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...with CFSR.DACCVIOL and MMFAR 0x%x\n",
|
||||
env->v7m.mmfar);
|
||||
env->v7m.mmfar[env->v7m.secure]);
|
||||
break;
|
||||
}
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
|
||||
|
@ -6397,7 +6490,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
}
|
||||
|
||||
lr = 0xfffffff1;
|
||||
if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) {
|
||||
if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) {
|
||||
lr |= 4;
|
||||
}
|
||||
if (!arm_v7m_is_handler_mode(env)) {
|
||||
|
@ -7032,35 +7125,15 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
|
|||
case ARMMMUIdx_MPriv:
|
||||
case ARMMMUIdx_MNegPri:
|
||||
case ARMMMUIdx_MUser:
|
||||
case ARMMMUIdx_MSPriv:
|
||||
case ARMMMUIdx_MSNegPri:
|
||||
case ARMMMUIdx_MSUser:
|
||||
return 1;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true if this address translation regime is secure */
|
||||
static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
switch (mmu_idx) {
|
||||
case ARMMMUIdx_S12NSE0:
|
||||
case ARMMMUIdx_S12NSE1:
|
||||
case ARMMMUIdx_S1NSE0:
|
||||
case ARMMMUIdx_S1NSE1:
|
||||
case ARMMMUIdx_S1E2:
|
||||
case ARMMMUIdx_S2NS:
|
||||
case ARMMMUIdx_MPriv:
|
||||
case ARMMMUIdx_MNegPri:
|
||||
case ARMMMUIdx_MUser:
|
||||
return false;
|
||||
case ARMMMUIdx_S1E3:
|
||||
case ARMMMUIdx_S1SE0:
|
||||
case ARMMMUIdx_S1SE1:
|
||||
return true;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the SCTLR value which controls this address translation regime */
|
||||
static inline uint32_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
|
@ -7072,11 +7145,12 @@ static inline bool regime_translation_disabled(CPUARMState *env,
|
|||
ARMMMUIdx mmu_idx)
|
||||
{
|
||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
switch (env->v7m.mpu_ctrl &
|
||||
switch (env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)] &
|
||||
(R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK)) {
|
||||
case R_V7M_MPU_CTRL_ENABLE_MASK:
|
||||
/* Enabled, but not for HardFault and NMI */
|
||||
return mmu_idx == ARMMMUIdx_MNegPri;
|
||||
return mmu_idx == ARMMMUIdx_MNegPri ||
|
||||
mmu_idx == ARMMMUIdx_MSNegPri;
|
||||
case R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK:
|
||||
/* Enabled for all cases */
|
||||
return false;
|
||||
|
@ -8231,7 +8305,8 @@ static bool pmsav7_use_background_region(ARMCPU *cpu,
|
|||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
return env->v7m.mpu_ctrl & R_V7M_MPU_CTRL_PRIVDEFENA_MASK;
|
||||
return env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)]
|
||||
& R_V7M_MPU_CTRL_PRIVDEFENA_MASK;
|
||||
} else {
|
||||
return regime_sctlr(env, mmu_idx) & SCTLR_BR;
|
||||
}
|
||||
|
@ -8411,6 +8486,112 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
|
|||
return !(*prot & (1 << access_type));
|
||||
}
|
||||
|
||||
static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address,
|
||||
MMUAccessType access_type, ARMMMUIdx mmu_idx,
|
||||
hwaddr *phys_ptr, int *prot, uint32_t *fsr)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
bool is_user = regime_is_user(env, mmu_idx);
|
||||
uint32_t secure = regime_is_secure(env, mmu_idx);
|
||||
int n;
|
||||
int matchregion = -1;
|
||||
bool hit = false;
|
||||
|
||||
*phys_ptr = address;
|
||||
*prot = 0;
|
||||
|
||||
/* Unlike the ARM ARM pseudocode, we don't need to check whether this
|
||||
* was an exception vector read from the vector table (which is always
|
||||
* done using the default system address map), because those accesses
|
||||
* are done in arm_v7m_load_vector(), which always does a direct
|
||||
* read using address_space_ldl(), rather than going via this function.
|
||||
*/
|
||||
if (regime_translation_disabled(env, mmu_idx)) { /* MPU disabled */
|
||||
hit = true;
|
||||
} else if (m_is_ppb_region(env, address)) {
|
||||
hit = true;
|
||||
} else if (pmsav7_use_background_region(cpu, mmu_idx, is_user)) {
|
||||
hit = true;
|
||||
} else {
|
||||
for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) {
|
||||
/* region search */
|
||||
/* Note that the base address is bits [31:5] from the register
|
||||
* with bits [4:0] all zeroes, but the limit address is bits
|
||||
* [31:5] from the register with bits [4:0] all ones.
|
||||
*/
|
||||
uint32_t base = env->pmsav8.rbar[secure][n] & ~0x1f;
|
||||
uint32_t limit = env->pmsav8.rlar[secure][n] | 0x1f;
|
||||
|
||||
if (!(env->pmsav8.rlar[secure][n] & 0x1)) {
|
||||
/* Region disabled */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (address < base || address > limit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hit) {
|
||||
/* Multiple regions match -- always a failure (unlike
|
||||
* PMSAv7 where highest-numbered-region wins)
|
||||
*/
|
||||
*fsr = 0x00d; /* permission fault */
|
||||
return true;
|
||||
}
|
||||
|
||||
matchregion = n;
|
||||
hit = true;
|
||||
|
||||
if (base & ~TARGET_PAGE_MASK) {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"MPU_RBAR[%d]: No support for MPU region base"
|
||||
"address of 0x%" PRIx32 ". Minimum alignment is "
|
||||
"%d\n",
|
||||
n, base, TARGET_PAGE_BITS);
|
||||
continue;
|
||||
}
|
||||
if ((limit + 1) & ~TARGET_PAGE_MASK) {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"MPU_RBAR[%d]: No support for MPU region limit"
|
||||
"address of 0x%" PRIx32 ". Minimum alignment is "
|
||||
"%d\n",
|
||||
n, limit, TARGET_PAGE_BITS);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hit) {
|
||||
/* background fault */
|
||||
*fsr = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (matchregion == -1) {
|
||||
/* hit using the background region */
|
||||
get_phys_addr_pmsav7_default(env, mmu_idx, address, prot);
|
||||
} else {
|
||||
uint32_t ap = extract32(env->pmsav8.rbar[secure][matchregion], 1, 2);
|
||||
uint32_t xn = extract32(env->pmsav8.rbar[secure][matchregion], 0, 1);
|
||||
|
||||
if (m_is_system_region(env, address)) {
|
||||
/* System space is always execute never */
|
||||
xn = 1;
|
||||
}
|
||||
|
||||
*prot = simple_ap_to_rw_prot(env, mmu_idx, ap);
|
||||
if (*prot && !xn) {
|
||||
*prot |= PAGE_EXEC;
|
||||
}
|
||||
/* We don't need to look the attribute up in the MAIR0/MAIR1
|
||||
* registers because that only tells us about cacheability.
|
||||
*/
|
||||
}
|
||||
|
||||
*fsr = 0x00d; /* Permission fault */
|
||||
return !(*prot & (1 << access_type));
|
||||
}
|
||||
|
||||
static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address,
|
||||
MMUAccessType access_type, ARMMMUIdx mmu_idx,
|
||||
hwaddr *phys_ptr, int *prot, uint32_t *fsr)
|
||||
|
@ -8580,7 +8761,11 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address,
|
|||
bool ret;
|
||||
*page_size = TARGET_PAGE_SIZE;
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_V7)) {
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
/* PMSAv8 */
|
||||
ret = get_phys_addr_pmsav8(env, address, access_type, mmu_idx,
|
||||
phys_ptr, prot, fsr);
|
||||
} else if (arm_feature(env, ARM_FEATURE_V7)) {
|
||||
/* PMSAv7 */
|
||||
ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx,
|
||||
phys_ptr, prot, fsr);
|
||||
|
@ -8699,7 +8884,7 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
|||
return xpsr_read(env) & mask;
|
||||
break;
|
||||
case 20: /* CONTROL */
|
||||
return env->v7m.control;
|
||||
return env->v7m.control[env->v7m.secure];
|
||||
}
|
||||
|
||||
if (el == 0) {
|
||||
|
@ -8708,18 +8893,18 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
|||
|
||||
switch (reg) {
|
||||
case 8: /* MSP */
|
||||
return (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) ?
|
||||
return (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) ?
|
||||
env->v7m.other_sp : env->regs[13];
|
||||
case 9: /* PSP */
|
||||
return (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) ?
|
||||
return (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) ?
|
||||
env->regs[13] : env->v7m.other_sp;
|
||||
case 16: /* PRIMASK */
|
||||
return env->v7m.primask;
|
||||
return env->v7m.primask[env->v7m.secure];
|
||||
case 17: /* BASEPRI */
|
||||
case 18: /* BASEPRI_MAX */
|
||||
return env->v7m.basepri;
|
||||
return env->v7m.basepri[env->v7m.secure];
|
||||
case 19: /* FAULTMASK */
|
||||
return env->v7m.faultmask;
|
||||
return env->v7m.faultmask[env->v7m.secure];
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special"
|
||||
" register %d\n", reg);
|
||||
|
@ -8760,32 +8945,34 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
|
|||
}
|
||||
break;
|
||||
case 8: /* MSP */
|
||||
if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) {
|
||||
if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) {
|
||||
env->v7m.other_sp = val;
|
||||
} else {
|
||||
env->regs[13] = val;
|
||||
}
|
||||
break;
|
||||
case 9: /* PSP */
|
||||
if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) {
|
||||
if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) {
|
||||
env->regs[13] = val;
|
||||
} else {
|
||||
env->v7m.other_sp = val;
|
||||
}
|
||||
break;
|
||||
case 16: /* PRIMASK */
|
||||
env->v7m.primask = val & 1;
|
||||
env->v7m.primask[env->v7m.secure] = val & 1;
|
||||
break;
|
||||
case 17: /* BASEPRI */
|
||||
env->v7m.basepri = val & 0xff;
|
||||
env->v7m.basepri[env->v7m.secure] = val & 0xff;
|
||||
break;
|
||||
case 18: /* BASEPRI_MAX */
|
||||
val &= 0xff;
|
||||
if (val != 0 && (val < env->v7m.basepri || env->v7m.basepri == 0))
|
||||
env->v7m.basepri = val;
|
||||
if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
|
||||
|| env->v7m.basepri[env->v7m.secure] == 0)) {
|
||||
env->v7m.basepri[env->v7m.secure] = val;
|
||||
}
|
||||
break;
|
||||
case 19: /* FAULTMASK */
|
||||
env->v7m.faultmask = val & 1;
|
||||
env->v7m.faultmask[env->v7m.secure] = val & 1;
|
||||
break;
|
||||
case 20: /* CONTROL */
|
||||
/* Writing to the SPSEL bit only has an effect if we are in
|
||||
|
@ -8796,8 +8983,8 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
|
|||
if (!arm_v7m_is_handler_mode(env)) {
|
||||
switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
|
||||
}
|
||||
env->v7m.control &= ~R_V7M_CONTROL_NPRIV_MASK;
|
||||
env->v7m.control |= val & R_V7M_CONTROL_NPRIV_MASK;
|
||||
env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
|
||||
env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"
|
||||
|
|
|
@ -63,6 +63,8 @@ DEF_HELPER_1(cpsr_read, i32, env)
|
|||
DEF_HELPER_3(v7m_msr, void, env, i32, i32)
|
||||
DEF_HELPER_2(v7m_mrs, i32, env, i32)
|
||||
|
||||
DEF_HELPER_2(v7m_bxns, void, env, i32)
|
||||
|
||||
DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32)
|
||||
DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
|
||||
DEF_HELPER_2(get_cp_reg, i32, env, ptr)
|
||||
|
|
|
@ -472,6 +472,16 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
|
|||
MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr);
|
||||
|
||||
/* arm_cpu_do_transaction_failed: handle a memory system error response
|
||||
* (eg "no device/memory present at address") by raising an external abort
|
||||
* exception
|
||||
*/
|
||||
void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
vaddr addr, unsigned size,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, MemTxAttrs attrs,
|
||||
MemTxResult response, uintptr_t retaddr);
|
||||
|
||||
/* Call the EL change hook if one has been registered */
|
||||
static inline void arm_call_el_change_hook(ARMCPU *cpu)
|
||||
{
|
||||
|
@ -480,4 +490,30 @@ static inline void arm_call_el_change_hook(ARMCPU *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
/* Return true if this address translation regime is secure */
|
||||
static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
switch (mmu_idx) {
|
||||
case ARMMMUIdx_S12NSE0:
|
||||
case ARMMMUIdx_S12NSE1:
|
||||
case ARMMMUIdx_S1NSE0:
|
||||
case ARMMMUIdx_S1NSE1:
|
||||
case ARMMMUIdx_S1E2:
|
||||
case ARMMMUIdx_S2NS:
|
||||
case ARMMMUIdx_MPriv:
|
||||
case ARMMMUIdx_MNegPri:
|
||||
case ARMMMUIdx_MUser:
|
||||
return false;
|
||||
case ARMMMUIdx_S1E3:
|
||||
case ARMMMUIdx_S1SE0:
|
||||
case ARMMMUIdx_S1SE1:
|
||||
case ARMMMUIdx_MSPriv:
|
||||
case ARMMMUIdx_MSNegPri:
|
||||
case ARMMMUIdx_MSUser:
|
||||
return true;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -102,8 +102,8 @@ static const VMStateDescription vmstate_m_faultmask_primask = {
|
|||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(env.v7m.faultmask, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.primask, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.faultmask[M_REG_NS], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.primask[M_REG_NS], ARMCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -114,16 +114,16 @@ static const VMStateDescription vmstate_m = {
|
|||
.minimum_version_id = 4,
|
||||
.needed = m_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(env.v7m.vecbase, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.basepri, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.control, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.ccr, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.cfsr, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.vecbase[M_REG_NS], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.basepri[M_REG_NS], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.control[M_REG_NS], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.ccr[M_REG_NS], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.cfsr[M_REG_NS], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.hfsr, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.dfsr, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.mmfar, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.mmfar[M_REG_NS], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.bfar, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.mpu_ctrl, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.mpu_ctrl[M_REG_NS], ARMCPU),
|
||||
VMSTATE_INT32(env.v7m.exception, ARMCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
|
@ -159,14 +159,15 @@ static bool pmsav7_needed(void *opaque)
|
|||
CPUARMState *env = &cpu->env;
|
||||
|
||||
return arm_feature(env, ARM_FEATURE_PMSA) &&
|
||||
arm_feature(env, ARM_FEATURE_V7);
|
||||
arm_feature(env, ARM_FEATURE_V7) &&
|
||||
!arm_feature(env, ARM_FEATURE_V8);
|
||||
}
|
||||
|
||||
static bool pmsav7_rgnr_vmstate_validate(void *opaque, int version_id)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
|
||||
return cpu->env.pmsav7.rnr < cpu->pmsav7_dregion;
|
||||
return cpu->env.pmsav7.rnr[M_REG_NS] < cpu->pmsav7_dregion;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pmsav7 = {
|
||||
|
@ -204,7 +205,77 @@ static const VMStateDescription vmstate_pmsav7_rnr = {
|
|||
.minimum_version_id = 1,
|
||||
.needed = pmsav7_rnr_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(env.pmsav7.rnr, ARMCPU),
|
||||
VMSTATE_UINT32(env.pmsav7.rnr[M_REG_NS], ARMCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static bool pmsav8_needed(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
CPUARMState *env = &cpu->env;
|
||||
|
||||
return arm_feature(env, ARM_FEATURE_PMSA) &&
|
||||
arm_feature(env, ARM_FEATURE_V8);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pmsav8 = {
|
||||
.name = "cpu/pmsav8",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = pmsav8_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VARRAY_UINT32(env.pmsav8.rbar[M_REG_NS], ARMCPU, pmsav7_dregion,
|
||||
0, vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_VARRAY_UINT32(env.pmsav8.rlar[M_REG_NS], ARMCPU, pmsav7_dregion,
|
||||
0, vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_UINT32(env.pmsav8.mair0[M_REG_NS], ARMCPU),
|
||||
VMSTATE_UINT32(env.pmsav8.mair1[M_REG_NS], ARMCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static bool s_rnr_vmstate_validate(void *opaque, int version_id)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
|
||||
return cpu->env.pmsav7.rnr[M_REG_S] < cpu->pmsav7_dregion;
|
||||
}
|
||||
|
||||
static bool m_security_needed(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
CPUARMState *env = &cpu->env;
|
||||
|
||||
return arm_feature(env, ARM_FEATURE_M_SECURITY);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_m_security = {
|
||||
.name = "cpu/m-security",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = m_security_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(env.v7m.secure, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.other_ss_msp, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.other_ss_psp, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.basepri[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.primask[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.faultmask[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.control[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.vecbase[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.pmsav8.mair0[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.pmsav8.mair1[M_REG_S], ARMCPU),
|
||||
VMSTATE_VARRAY_UINT32(env.pmsav8.rbar[M_REG_S], ARMCPU, pmsav7_dregion,
|
||||
0, vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_VARRAY_UINT32(env.pmsav8.rlar[M_REG_S], ARMCPU, pmsav7_dregion,
|
||||
0, vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_UINT32(env.pmsav7.rnr[M_REG_S], ARMCPU),
|
||||
VMSTATE_VALIDATE("secure MPU_RNR is valid", s_rnr_vmstate_validate),
|
||||
VMSTATE_UINT32(env.v7m.mpu_ctrl[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.ccr[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.mmfar[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.cfsr[M_REG_S], ARMCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -225,9 +296,13 @@ static int get_cpsr(QEMUFile *f, void *opaque, size_t size,
|
|||
* differences are that the T bit is not in the same place, the
|
||||
* primask/faultmask info may be in the CPSR I and F bits, and
|
||||
* we do not want the mode bits.
|
||||
* We know that this cleanup happened before v8M, so there
|
||||
* is no complication with banked primask/faultmask.
|
||||
*/
|
||||
uint32_t newval = val;
|
||||
|
||||
assert(!arm_feature(env, ARM_FEATURE_M_SECURITY));
|
||||
|
||||
newval &= (CPSR_NZCV | CPSR_Q | CPSR_IT | CPSR_GE);
|
||||
if (val & CPSR_T) {
|
||||
newval |= XPSR_T;
|
||||
|
@ -238,10 +313,10 @@ static int get_cpsr(QEMUFile *f, void *opaque, size_t size,
|
|||
* transferred using the vmstate_m_faultmask_primask subsection.
|
||||
*/
|
||||
if (val & CPSR_F) {
|
||||
env->v7m.faultmask = 1;
|
||||
env->v7m.faultmask[M_REG_NS] = 1;
|
||||
}
|
||||
if (val & CPSR_I) {
|
||||
env->v7m.primask = 1;
|
||||
env->v7m.primask[M_REG_NS] = 1;
|
||||
}
|
||||
val = newval;
|
||||
}
|
||||
|
@ -458,6 +533,8 @@ const VMStateDescription vmstate_arm_cpu = {
|
|||
*/
|
||||
&vmstate_pmsav7_rnr,
|
||||
&vmstate_pmsav7,
|
||||
&vmstate_pmsav8,
|
||||
&vmstate_m_security,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
|
|
@ -229,6 +229,49 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
|
|||
deliver_fault(cpu, vaddr, access_type, fsr, fsc, &fi);
|
||||
}
|
||||
|
||||
/* arm_cpu_do_transaction_failed: handle a memory system error response
|
||||
* (eg "no device/memory present at address") by raising an external abort
|
||||
* exception
|
||||
*/
|
||||
void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
vaddr addr, unsigned size,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, MemTxAttrs attrs,
|
||||
MemTxResult response, uintptr_t retaddr)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
CPUARMState *env = &cpu->env;
|
||||
uint32_t fsr, fsc;
|
||||
ARMMMUFaultInfo fi = {};
|
||||
ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx);
|
||||
|
||||
if (retaddr) {
|
||||
/* now we have a real cpu fault */
|
||||
cpu_restore_state(cs, retaddr);
|
||||
}
|
||||
|
||||
/* The EA bit in syndromes and fault status registers is an
|
||||
* IMPDEF classification of external aborts. ARM implementations
|
||||
* usually use this to indicate AXI bus Decode error (0) or
|
||||
* Slave error (1); in QEMU we follow that.
|
||||
*/
|
||||
fi.ea = (response != MEMTX_DECODE_ERROR);
|
||||
|
||||
/* The fault status register format depends on whether we're using
|
||||
* the LPAE long descriptor format, or the short descriptor format.
|
||||
*/
|
||||
if (arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) {
|
||||
/* long descriptor form, STATUS 0b010000: synchronous ext abort */
|
||||
fsr = (fi.ea << 12) | (1 << 9) | 0x10;
|
||||
} else {
|
||||
/* short descriptor form, FSR 0b01000 : synchronous ext abort */
|
||||
fsr = (fi.ea << 12) | 0x8;
|
||||
}
|
||||
fsc = 0x10;
|
||||
|
||||
deliver_fault(cpu, addr, access_type, fsr, fsc, &fi);
|
||||
}
|
||||
|
||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
||||
|
||||
uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b)
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#define ENABLE_ARCH_5 arm_dc_feature(s, ARM_FEATURE_V5)
|
||||
/* currently all emulated v5 cores are also v5TE, so don't bother */
|
||||
#define ENABLE_ARCH_5TE arm_dc_feature(s, ARM_FEATURE_V5)
|
||||
#define ENABLE_ARCH_5J 0
|
||||
#define ENABLE_ARCH_5J arm_dc_feature(s, ARM_FEATURE_JAZELLE)
|
||||
#define ENABLE_ARCH_6 arm_dc_feature(s, ARM_FEATURE_V6)
|
||||
#define ENABLE_ARCH_6K arm_dc_feature(s, ARM_FEATURE_V6K)
|
||||
#define ENABLE_ARCH_6T2 arm_dc_feature(s, ARM_FEATURE_THUMB2)
|
||||
|
@ -994,6 +994,25 @@ static inline void gen_bx_excret_final_code(DisasContext *s)
|
|||
gen_exception_internal(EXCP_EXCEPTION_EXIT);
|
||||
}
|
||||
|
||||
static inline void gen_bxns(DisasContext *s, int rm)
|
||||
{
|
||||
TCGv_i32 var = load_reg(s, rm);
|
||||
|
||||
/* The bxns helper may raise an EXCEPTION_EXIT exception, so in theory
|
||||
* we need to sync state before calling it, but:
|
||||
* - we don't need to do gen_set_pc_im() because the bxns helper will
|
||||
* always set the PC itself
|
||||
* - we don't need to do gen_set_condexec() because BXNS is UNPREDICTABLE
|
||||
* unless it's outside an IT block or the last insn in an IT block,
|
||||
* so we know that condexec == 0 (already set at the top of the TB)
|
||||
* is correct in the non-UNPREDICTABLE cases, and we can choose
|
||||
* "zeroes the IT bits" as our UNPREDICTABLE behaviour otherwise.
|
||||
*/
|
||||
gen_helper_v7m_bxns(cpu_env, var);
|
||||
tcg_temp_free_i32(var);
|
||||
s->base.is_jmp = DISAS_EXIT;
|
||||
}
|
||||
|
||||
/* Variant of store_reg which uses branch&exchange logic when storing
|
||||
to r15 in ARM architecture v7 and above. The source must be a temporary
|
||||
and will be marked as dead. */
|
||||
|
@ -11185,12 +11204,31 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
|||
*/
|
||||
bool link = insn & (1 << 7);
|
||||
|
||||
if (insn & 7) {
|
||||
if (insn & 3) {
|
||||
goto undef;
|
||||
}
|
||||
if (link) {
|
||||
ARCH(5);
|
||||
}
|
||||
if ((insn & 4)) {
|
||||
/* BXNS/BLXNS: only exists for v8M with the
|
||||
* security extensions, and always UNDEF if NonSecure.
|
||||
* We don't implement these in the user-only mode
|
||||
* either (in theory you can use them from Secure User
|
||||
* mode but they are too tied in to system emulation.)
|
||||
*/
|
||||
if (!s->v8m_secure || IS_USER_ONLY) {
|
||||
goto undef;
|
||||
}
|
||||
if (link) {
|
||||
/* BLXNS: not yet implemented */
|
||||
goto undef;
|
||||
} else {
|
||||
gen_bxns(s, rm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* BLX/BX */
|
||||
tmp = load_reg(s, rm);
|
||||
if (link) {
|
||||
val = (uint32_t)s->pc | 1;
|
||||
|
@ -11857,6 +11895,8 @@ static int arm_tr_init_disas_context(DisasContextBase *dcbase,
|
|||
dc->vec_stride = ARM_TBFLAG_VECSTRIDE(dc->base.tb->flags);
|
||||
dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(dc->base.tb->flags);
|
||||
dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(dc->base.tb->flags);
|
||||
dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
|
||||
regime_is_secure(env, dc->mmu_idx);
|
||||
dc->cp_regs = cpu->cp_regs;
|
||||
dc->features = env->features;
|
||||
|
||||
|
@ -12288,24 +12328,30 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
|
|||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
uint32_t xpsr = xpsr_read(env);
|
||||
const char *mode;
|
||||
const char *ns_status = "";
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
ns_status = env->v7m.secure ? "S " : "NS ";
|
||||
}
|
||||
|
||||
if (xpsr & XPSR_EXCP) {
|
||||
mode = "handler";
|
||||
} else {
|
||||
if (env->v7m.control & R_V7M_CONTROL_NPRIV_MASK) {
|
||||
if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) {
|
||||
mode = "unpriv-thread";
|
||||
} else {
|
||||
mode = "priv-thread";
|
||||
}
|
||||
}
|
||||
|
||||
cpu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s\n",
|
||||
cpu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n",
|
||||
xpsr,
|
||||
xpsr & XPSR_N ? 'N' : '-',
|
||||
xpsr & XPSR_Z ? 'Z' : '-',
|
||||
xpsr & XPSR_C ? 'C' : '-',
|
||||
xpsr & XPSR_V ? 'V' : '-',
|
||||
xpsr & XPSR_T ? 'T' : 'A',
|
||||
ns_status,
|
||||
mode);
|
||||
} else {
|
||||
uint32_t psr = cpsr_read(env);
|
||||
|
|
|
@ -35,6 +35,7 @@ typedef struct DisasContext {
|
|||
int vec_len;
|
||||
int vec_stride;
|
||||
bool v7m_handler_mode;
|
||||
bool v8m_secure; /* true if v8M and we're in Secure mode */
|
||||
/* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
|
||||
* so that top level loop can generate correct syndrome information.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue