aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2023-02-16 17:12:18 +0000
committerPeter Maydell <peter.maydell@linaro.org>2023-02-16 17:12:18 +0000
commitd8d20b38ec5875b98cfdae52c1f2132540cd65b5 (patch)
tree66aede6f7cf63aef48e3408563b3f5deddbe5d44
parent6dffbe36af79e26a4d23f94a9a1c1201de99c261 (diff)
parentcaf01d6a435d9f4a95aeae2f9fc6cb8b889b1fb8 (diff)
downloadqemu-d8d20b38ec5875b98cfdae52c1f2132540cd65b5.zip
qemu-d8d20b38ec5875b98cfdae52c1f2132540cd65b5.tar.gz
qemu-d8d20b38ec5875b98cfdae52c1f2132540cd65b5.tar.bz2
Merge tag 'pull-target-arm-20230216' of https://git.linaro.org/people/pmaydell/qemu-arm into staging
target-arm queue: * Some mostly M-profile-related code cleanups * avocado: Retire the boot_linux.py AArch64 TCG tests * hw/arm/smmuv3: Add GBPA register * arm/virt: don't try to spell out the accelerator * hw/arm: Attach PSPI module to NPCM7XX SoC * Some cleanup/refactoring patches aiming towards allowing building Arm targets without CONFIG_TCG # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmPuY50ZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3oKND/9Cy7/XlMBOq1vlEM/TG7eK # Jq582mUDsOqnebDZLEYheWe7wDzIHpoAZfCwOL1sLDbzjjglYXgQu7J3fQvuSofo # QJBKkJiiATHCQb3I+A7VITl0pyW3lcRy9zZ7E5O9WdbbBcKIC8dwTNyiTAEmKyL9 # ldYxfCZiMl+j+za3uNUxnlEd3oC15UZZfGAi++KjdfdFH6TxyGRhkiAI3iP4QD7s # aHo+9/TEyl1b9ApjXWymlgupwLeAOI3TwCq30lyBttxh9aU/hUkBttdc+oo+ymTH # EuOB4IM2O7jCjGMKAeg7jlYfgLJRradaOsY4g0K0VxD/wGRTp6Qehmt//mzYwYYb # izprDDb1UbJAH5OsFFPNevxQjJHfOOFYs+ObvadRgvLFTPuid8+1YNleknPxp7qm # jRC9/DYekqcxU2mlEwuPApFNhZBoxwnJhFEHfmO8SCqre4+QfDNbGhUxPuHORt6V # 0xLzaSC1L6RALLsDnhgYK/Iz8vA/2HmrcO+FC0TlIeKcGUV2xOMQB8+DRlsrzpEz # KzrjXyuLqUOIWN6iGThxOG72qPd94BKO3SHue7r4BCYpDdeHIbQUC67cBq6b1LZ4 # QDOoeHwuTo5GRnAYoc+lQ7HyEfGiWy38wApQihZ3EOndot6DN/AD8nRC2632Hidu # evQUClDbeXZDTv87AfIojg== # =M2nc # -----END PGP SIGNATURE----- # gpg: Signature made Thu 16 Feb 2023 17:10:53 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * tag 'pull-target-arm-20230216' of https://git.linaro.org/people/pmaydell/qemu-arm: (30 commits) tests/qtest: Restrict tpm-tis-devices-{swtpm}-test to CONFIG_TCG tests/qtest: arm-cpu-features: Match tests to required accelerators target/arm: Use "max" as default cpu for the virt machine with KVM tests/avocado: Tag TCG tests with accel:tcg tests/avocado: Skip tests that require a missing accelerator target/arm: Move cpregs code out of cpu.h target/arm: Move PC alignment check target/arm: wrap call to aarch64_sve_change_el in tcg_enabled() target/arm: wrap psci call with tcg_enabled target/arm: rename handle_semihosting to tcg_handle_semihosting hw/arm/smmu-common: Fix TTB1 handling hw/arm/smmu-common: Support 64-bit addresses hw/arm: Attach PSPI module to NPCM7XX SoC hw/ssi: Add Nuvoton PSPI Module MAINTAINERS: Add myself to maintainers and remove Havard arm/virt: don't try to spell out the accelerator hw/arm: Add missing XLNX_ZYNQMP_ARM -> USB_DWC3 Kconfig dependency hw/arm/smmuv3: Add GBPA register tests/avocado: retire the Aarch64 TCG tests from boot_linux.py target/arm: Declare CPU <-> NVIC helpers in 'hw/intc/armv7m_nvic.h' ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--MAINTAINERS8
-rw-r--r--docs/system/arm/nuvoton.rst2
-rw-r--r--hw/arm/Kconfig1
-rw-r--r--hw/arm/npcm7xx.c25
-rw-r--r--hw/arm/smmu-common.c4
-rw-r--r--hw/arm/smmuv3-internal.h7
-rw-r--r--hw/arm/smmuv3.c43
-rw-r--r--hw/arm/virt.c10
-rw-r--r--hw/intc/armv7m_nvic.c38
-rw-r--r--hw/ssi/meson.build2
-rw-r--r--hw/ssi/npcm_pspi.c221
-rw-r--r--hw/ssi/trace-events5
-rw-r--r--include/hw/arm/npcm7xx.h2
-rw-r--r--include/hw/arm/smmu-common.h2
-rw-r--r--include/hw/arm/smmuv3.h1
-rw-r--r--include/hw/intc/armv7m_nvic.h128
-rw-r--r--include/hw/ssi/npcm_pspi.h53
-rw-r--r--linux-user/arm/cpu_loop.c4
-rw-r--r--linux-user/user-internals.h2
-rw-r--r--target/arm/cpregs.h98
-rw-r--r--target/arm/cpu.c5
-rw-r--r--target/arm/cpu.h228
-rw-r--r--target/arm/cpu_tcg.c3
-rw-r--r--target/arm/helper.c31
-rw-r--r--target/arm/internals.h14
-rw-r--r--target/arm/m_helper.c86
-rw-r--r--target/arm/machine.c18
-rw-r--r--tests/avocado/avocado_qemu/__init__.py4
-rw-r--r--tests/avocado/boot_linux.py48
-rw-r--r--tests/avocado/boot_linux_console.py1
-rw-r--r--tests/avocado/machine_aarch64_virt.py63
-rw-r--r--tests/avocado/reverse_debugging.py8
-rw-r--r--tests/qtest/arm-cpu-features.c22
-rw-r--r--tests/qtest/meson.build4
34 files changed, 795 insertions, 396 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index fd54c1f..21595f0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -807,13 +807,13 @@ F: include/hw/net/mv88w8618_eth.h
F: docs/system/arm/musicpal.rst
Nuvoton NPCM7xx
-M: Havard Skinnemoen <hskinnemoen@google.com>
M: Tyrone Ting <kfting@nuvoton.com>
+M: Hao Wu <wuhaotsh@google.com>
L: qemu-arm@nongnu.org
S: Supported
-F: hw/*/npcm7xx*
-F: include/hw/*/npcm7xx*
-F: tests/qtest/npcm7xx*
+F: hw/*/npcm*
+F: include/hw/*/npcm*
+F: tests/qtest/npcm*
F: pc-bios/npcm7xx_bootrom.bin
F: roms/vbootrom
F: docs/system/arm/nuvoton.rst
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
index c38df32..0424cae 100644
--- a/docs/system/arm/nuvoton.rst
+++ b/docs/system/arm/nuvoton.rst
@@ -49,6 +49,7 @@ Supported devices
* SMBus controller (SMBF)
* Ethernet controller (EMC)
* Tachometer
+ * Peripheral SPI controller (PSPI)
Missing devices
---------------
@@ -64,7 +65,6 @@ Missing devices
* Ethernet controller (GMAC)
* USB device (USBD)
- * Peripheral SPI controller (PSPI)
* SD/MMC host
* PECI interface
* PCI and PCIe root complex and bridges
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 2d157de..b5aed4a 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -389,6 +389,7 @@ config XLNX_ZYNQMP_ARM
select XLNX_CSU_DMA
select XLNX_ZYNQMP
select XLNX_ZDMA
+ select USB_DWC3
config XLNX_VERSAL
bool
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index d85cc02..15ff21d 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -86,6 +86,8 @@ enum NPCM7xxInterrupt {
NPCM7XX_EMC1RX_IRQ = 15,
NPCM7XX_EMC1TX_IRQ,
NPCM7XX_MMC_IRQ = 26,
+ NPCM7XX_PSPI2_IRQ = 28,
+ NPCM7XX_PSPI1_IRQ = 31,
NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */
NPCM7XX_TIMER1_IRQ,
NPCM7XX_TIMER2_IRQ,
@@ -220,6 +222,12 @@ static const hwaddr npcm7xx_emc_addr[] = {
0xf0826000,
};
+/* Register base address for each PSPI Module */
+static const hwaddr npcm7xx_pspi_addr[] = {
+ 0xf0200000,
+ 0xf0201000,
+};
+
static const struct {
hwaddr regs_addr;
uint32_t unconnected_pins;
@@ -444,6 +452,10 @@ static void npcm7xx_init(Object *obj)
object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC);
}
+ for (i = 0; i < ARRAY_SIZE(s->pspi); i++) {
+ object_initialize_child(obj, "pspi[*]", &s->pspi[i], TYPE_NPCM_PSPI);
+ }
+
object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
}
@@ -715,6 +727,17 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0,
npcm7xx_irq(s, NPCM7XX_MMC_IRQ));
+ /* PSPI */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pspi_addr) != ARRAY_SIZE(s->pspi));
+ for (i = 0; i < ARRAY_SIZE(s->pspi); i++) {
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pspi[i]);
+ int irq = (i == 0) ? NPCM7XX_PSPI1_IRQ : NPCM7XX_PSPI2_IRQ;
+
+ sysbus_realize(sbd, &error_abort);
+ sysbus_mmio_map(sbd, 0, npcm7xx_pspi_addr[i]);
+ sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, irq));
+ }
+
create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB);
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
@@ -724,8 +747,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB);
create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB);
create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB);
- create_unimplemented_device("npcm7xx.pspi1", 0xf0200000, 4 * KiB);
- create_unimplemented_device("npcm7xx.pspi2", 0xf0201000, 4 * KiB);
create_unimplemented_device("npcm7xx.ahbpci", 0xf0400000, 1 * MiB);
create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB);
create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB);
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 733c964..0a5a60c 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -249,7 +249,7 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova)
/* there is a ttbr0 region and we are in it (high bits all zero) */
return &cfg->tt[0];
} else if (cfg->tt[1].tsz &&
- !extract64(iova, 64 - cfg->tt[1].tsz, cfg->tt[1].tsz - tbi_byte)) {
+ sextract64(iova, 64 - cfg->tt[1].tsz, cfg->tt[1].tsz - tbi_byte) == -1) {
/* there is a ttbr1 region and we are in it (high bits all one) */
return &cfg->tt[1];
} else if (!cfg->tt[0].tsz) {
@@ -439,7 +439,7 @@ static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn)
memory_region_init_iommu(&sdev->iommu, sizeof(sdev->iommu),
s->mrtypename,
- OBJECT(s), name, 1ULL << SMMU_MAX_VA_BITS);
+ OBJECT(s), name, UINT64_MAX);
address_space_init(&sdev->as,
MEMORY_REGION(&sdev->iommu), name);
trace_smmu_add_mr(name);
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index bce1618..e8f0ebf 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -79,6 +79,13 @@ REG32(CR0ACK, 0x24)
REG32(CR1, 0x28)
REG32(CR2, 0x2c)
REG32(STATUSR, 0x40)
+REG32(GBPA, 0x44)
+ FIELD(GBPA, ABORT, 20, 1)
+ FIELD(GBPA, UPDATE, 31, 1)
+
+/* Use incoming. */
+#define SMMU_GBPA_RESET_VAL 0x1000
+
REG32(IRQ_CTRL, 0x50)
FIELD(IRQ_CTRL, GERROR_IRQEN, 0, 1)
FIELD(IRQ_CTRL, PRI_IRQEN, 1, 1)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 955b89c..270c80b 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -285,6 +285,7 @@ static void smmuv3_init_regs(SMMUv3State *s)
s->gerror = 0;
s->gerrorn = 0;
s->statusr = 0;
+ s->gbpa = SMMU_GBPA_RESET_VAL;
}
static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
@@ -659,7 +660,11 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
qemu_mutex_lock(&s->mutex);
if (!smmu_enabled(s)) {
- status = SMMU_TRANS_DISABLE;
+ if (FIELD_EX32(s->gbpa, GBPA, ABORT)) {
+ status = SMMU_TRANS_ABORT;
+ } else {
+ status = SMMU_TRANS_DISABLE;
+ }
goto epilogue;
}
@@ -1170,6 +1175,16 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
case A_GERROR_IRQ_CFG2:
s->gerror_irq_cfg2 = data;
return MEMTX_OK;
+ case A_GBPA:
+ /*
+ * If UPDATE is not set, the write is ignored. This is the only
+ * permitted behavior in SMMUv3.2 and later.
+ */
+ if (data & R_GBPA_UPDATE_MASK) {
+ /* Ignore update bit as write is synchronous. */
+ s->gbpa = data & ~R_GBPA_UPDATE_MASK;
+ }
+ return MEMTX_OK;
case A_STRTAB_BASE: /* 64b */
s->strtab_base = deposit64(s->strtab_base, 0, 32, data);
return MEMTX_OK;
@@ -1318,6 +1333,9 @@ static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
case A_STATUSR:
*data = s->statusr;
return MEMTX_OK;
+ case A_GBPA:
+ *data = s->gbpa;
+ return MEMTX_OK;
case A_IRQ_CTRL:
case A_IRQ_CTRL_ACK:
*data = s->irq_ctrl;
@@ -1482,6 +1500,25 @@ static const VMStateDescription vmstate_smmuv3_queue = {
},
};
+static bool smmuv3_gbpa_needed(void *opaque)
+{
+ SMMUv3State *s = opaque;
+
+ /* Only migrate GBPA if it has different reset value. */
+ return s->gbpa != SMMU_GBPA_RESET_VAL;
+}
+
+static const VMStateDescription vmstate_gbpa = {
+ .name = "smmuv3/gbpa",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = smmuv3_gbpa_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(gbpa, SMMUv3State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_smmuv3 = {
.name = "smmuv3",
.version_id = 1,
@@ -1512,6 +1549,10 @@ static const VMStateDescription vmstate_smmuv3 = {
VMSTATE_END_OF_LIST(),
},
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_gbpa,
+ NULL
+ }
};
static void smmuv3_instance_init(Object *obj)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 75f2894..ac626b3 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2133,21 +2133,21 @@ static void machvirt_init(MachineState *machine)
if (vms->secure && (kvm_enabled() || hvf_enabled())) {
error_report("mach-virt: %s does not support providing "
"Security extensions (TrustZone) to the guest CPU",
- kvm_enabled() ? "KVM" : "HVF");
+ current_accel_name());
exit(1);
}
if (vms->virt && (kvm_enabled() || hvf_enabled())) {
error_report("mach-virt: %s does not support providing "
"Virtualization extensions to the guest CPU",
- kvm_enabled() ? "KVM" : "HVF");
+ current_accel_name());
exit(1);
}
if (vms->mte && (kvm_enabled() || hvf_enabled())) {
error_report("mach-virt: %s does not support providing "
"MTE to the guest CPU",
- kvm_enabled() ? "KVM" : "HVF");
+ current_accel_name());
exit(1);
}
@@ -3013,7 +3013,11 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
mc->minimum_page_bits = 12;
mc->possible_cpu_arch_ids = virt_possible_cpu_arch_ids;
mc->cpu_index_to_instance_props = virt_cpu_index_to_props;
+#ifdef CONFIG_TCG
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
+#else
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("max");
+#endif
mc->get_default_cpu_node_id = virt_get_default_cpu_node_id;
mc->kvm_type = virt_kvm_type;
assert(!mc->get_hotplug_handler);
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 1f77639..e545532 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -389,7 +389,7 @@ static inline int nvic_exec_prio(NVICState *s)
return MIN(running, s->exception_prio);
}
-bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure)
+bool armv7m_nvic_neg_prio_requested(NVICState *s, bool secure)
{
/* Return true if the requested execution priority is negative
* for the specified security state, ie that security state
@@ -399,8 +399,6 @@ bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure)
* mean we don't allow FAULTMASK_NS to actually make the execution
* priority negative). Compare pseudocode IsReqExcPriNeg().
*/
- NVICState *s = opaque;
-
if (s->cpu->env.v7m.faultmask[secure]) {
return true;
}
@@ -418,17 +416,13 @@ bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure)
return false;
}
-bool armv7m_nvic_can_take_pending_exception(void *opaque)
+bool armv7m_nvic_can_take_pending_exception(NVICState *s)
{
- NVICState *s = opaque;
-
return nvic_exec_prio(s) > nvic_pending_prio(s);
}
-int armv7m_nvic_raw_execution_priority(void *opaque)
+int armv7m_nvic_raw_execution_priority(NVICState *s)
{
- NVICState *s = opaque;
-
return s->exception_prio;
}
@@ -506,9 +500,8 @@ static void nvic_irq_update(NVICState *s)
* if @secure is true and @irq does not specify one of the fixed set
* of architecturally banked exceptions.
*/
-static void armv7m_nvic_clear_pending(void *opaque, int irq, bool secure)
+static void armv7m_nvic_clear_pending(NVICState *s, int irq, bool secure)
{
- NVICState *s = (NVICState *)opaque;
VecInfo *vec;
assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq);
@@ -666,17 +659,17 @@ static void do_armv7m_nvic_set_pending(void *opaque, int irq, bool secure,
}
}
-void armv7m_nvic_set_pending(void *opaque, int irq, bool secure)
+void armv7m_nvic_set_pending(NVICState *s, int irq, bool secure)
{
- do_armv7m_nvic_set_pending(opaque, irq, secure, false);
+ do_armv7m_nvic_set_pending(s, irq, secure, false);
}
-void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure)
+void armv7m_nvic_set_pending_derived(NVICState *s, int irq, bool secure)
{
- do_armv7m_nvic_set_pending(opaque, irq, secure, true);
+ do_armv7m_nvic_set_pending(s, irq, secure, true);
}
-void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure)
+void armv7m_nvic_set_pending_lazyfp(NVICState *s, int irq, bool secure)
{
/*
* Pend an exception during lazy FP stacking. This differs
@@ -684,7 +677,6 @@ void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure)
* whether we should escalate depends on the saved context
* in the FPCCR register, not on the current state of the CPU/NVIC.
*/
- NVICState *s = (NVICState *)opaque;
bool banked = exc_is_banked(irq);
VecInfo *vec;
bool targets_secure;
@@ -773,9 +765,8 @@ void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure)
}
/* Make pending IRQ active. */
-void armv7m_nvic_acknowledge_irq(void *opaque)
+void armv7m_nvic_acknowledge_irq(NVICState *s)
{
- NVICState *s = (NVICState *)opaque;
CPUARMState *env = &s->cpu->env;
const int pending = s->vectpending;
const int running = nvic_exec_prio(s);
@@ -814,10 +805,9 @@ static bool vectpending_targets_secure(NVICState *s)
exc_targets_secure(s, s->vectpending);
}
-void armv7m_nvic_get_pending_irq_info(void *opaque,
+void armv7m_nvic_get_pending_irq_info(NVICState *s,
int *pirq, bool *ptargets_secure)
{
- NVICState *s = (NVICState *)opaque;
const int pending = s->vectpending;
bool targets_secure;
@@ -831,9 +821,8 @@ void armv7m_nvic_get_pending_irq_info(void *opaque,
*pirq = pending;
}
-int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure)
+int armv7m_nvic_complete_irq(NVICState *s, int irq, bool secure)
{
- NVICState *s = (NVICState *)opaque;
VecInfo *vec = NULL;
int ret = 0;
@@ -915,7 +904,7 @@ int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure)
return ret;
}
-bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure)
+bool armv7m_nvic_get_ready_status(NVICState *s, int irq, bool secure)
{
/*
* Return whether an exception is "ready", i.e. it is enabled and is
@@ -926,7 +915,6 @@ bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure)
* for non-banked exceptions secure is always false; for banked exceptions
* it indicates which of the exceptions is required.
*/
- NVICState *s = (NVICState *)opaque;
bool banked = exc_is_banked(irq);
VecInfo *vec;
int running = nvic_exec_prio(s);
diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build
index 702aa5e..904a471 100644
--- a/hw/ssi/meson.build
+++ b/hw/ssi/meson.build
@@ -1,6 +1,6 @@
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_smc.c'))
softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-spi.c'))
-softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c'))
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c', 'npcm_pspi.c'))
softmmu_ss.add(when: 'CONFIG_PL022', if_true: files('pl022.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_SPI', if_true: files('sifive_spi.c'))
softmmu_ss.add(when: 'CONFIG_SSI', if_true: files('ssi.c'))
diff --git a/hw/ssi/npcm_pspi.c b/hw/ssi/npcm_pspi.c
new file mode 100644
index 0000000..3fb9350
--- /dev/null
+++ b/hw/ssi/npcm_pspi.c
@@ -0,0 +1,221 @@
+/*
+ * Nuvoton NPCM Peripheral SPI Module (PSPI)
+ *
+ * Copyright 2023 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/irq.h"
+#include "hw/registerfields.h"
+#include "hw/ssi/npcm_pspi.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/units.h"
+
+#include "trace.h"
+
+REG16(PSPI_DATA, 0x0)
+REG16(PSPI_CTL1, 0x2)
+ FIELD(PSPI_CTL1, SPIEN, 0, 1)
+ FIELD(PSPI_CTL1, MOD, 2, 1)
+ FIELD(PSPI_CTL1, EIR, 5, 1)
+ FIELD(PSPI_CTL1, EIW, 6, 1)
+ FIELD(PSPI_CTL1, SCM, 7, 1)
+ FIELD(PSPI_CTL1, SCIDL, 8, 1)
+ FIELD(PSPI_CTL1, SCDV, 9, 7)
+REG16(PSPI_STAT, 0x4)
+ FIELD(PSPI_STAT, BSY, 0, 1)
+ FIELD(PSPI_STAT, RBF, 1, 1)
+
+static void npcm_pspi_update_irq(NPCMPSPIState *s)
+{
+ int level = 0;
+
+ /* Only fire IRQ when the module is enabled. */
+ if (FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, SPIEN)) {
+ /* Update interrupt as BSY is cleared. */
+ if ((!FIELD_EX16(s->regs[R_PSPI_STAT], PSPI_STAT, BSY)) &&
+ FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, EIW)) {
+ level = 1;
+ }
+
+ /* Update interrupt as RBF is set. */
+ if (FIELD_EX16(s->regs[R_PSPI_STAT], PSPI_STAT, RBF) &&
+ FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, EIR)) {
+ level = 1;
+ }
+ }
+ qemu_set_irq(s->irq, level);
+}
+
+static uint16_t npcm_pspi_read_data(NPCMPSPIState *s)
+{
+ uint16_t value = s->regs[R_PSPI_DATA];
+
+ /* Clear stat bits as the value are read out. */
+ s->regs[R_PSPI_STAT] = 0;
+
+ return value;
+}
+
+static void npcm_pspi_write_data(NPCMPSPIState *s, uint16_t data)
+{
+ uint16_t value = 0;
+
+ if (FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, MOD)) {
+ value = ssi_transfer(s->spi, extract16(data, 8, 8)) << 8;
+ }
+ value |= ssi_transfer(s->spi, extract16(data, 0, 8));
+ s->regs[R_PSPI_DATA] = value;
+
+ /* Mark data as available */
+ s->regs[R_PSPI_STAT] = R_PSPI_STAT_BSY_MASK | R_PSPI_STAT_RBF_MASK;
+}
+
+/* Control register read handler. */
+static uint64_t npcm_pspi_ctrl_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ NPCMPSPIState *s = opaque;
+ uint16_t value;
+
+ switch (addr) {
+ case A_PSPI_DATA:
+ value = npcm_pspi_read_data(s);
+ break;
+
+ case A_PSPI_CTL1:
+ value = s->regs[R_PSPI_CTL1];
+ break;
+
+ case A_PSPI_STAT:
+ value = s->regs[R_PSPI_STAT];
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to invalid offset 0x%" PRIx64 "\n",
+ DEVICE(s)->canonical_path, addr);
+ return 0;
+ }
+ trace_npcm_pspi_ctrl_read(DEVICE(s)->canonical_path, addr, value);
+ npcm_pspi_update_irq(s);
+
+ return value;
+}
+
+/* Control register write handler. */
+static void npcm_pspi_ctrl_write(void *opaque, hwaddr addr, uint64_t v,
+ unsigned int size)
+{
+ NPCMPSPIState *s = opaque;
+ uint16_t value = v;
+
+ trace_npcm_pspi_ctrl_write(DEVICE(s)->canonical_path, addr, value);
+
+ switch (addr) {
+ case A_PSPI_DATA:
+ npcm_pspi_write_data(s, value);
+ break;
+
+ case A_PSPI_CTL1:
+ s->regs[R_PSPI_CTL1] = value;
+ break;
+
+ case A_PSPI_STAT:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to read-only register PSPI_STAT: 0x%08"
+ PRIx64 "\n", DEVICE(s)->canonical_path, v);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to invalid offset 0x%" PRIx64 "\n",
+ DEVICE(s)->canonical_path, addr);
+ return;
+ }
+ npcm_pspi_update_irq(s);
+}
+
+static const MemoryRegionOps npcm_pspi_ctrl_ops = {
+ .read = npcm_pspi_ctrl_read,
+ .write = npcm_pspi_ctrl_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 2,
+ .unaligned = false,
+ },
+ .impl = {
+ .min_access_size = 2,
+ .max_access_size = 2,
+ .unaligned = false,
+ },
+};
+
+static void npcm_pspi_enter_reset(Object *obj, ResetType type)
+{
+ NPCMPSPIState *s = NPCM_PSPI(obj);
+
+ trace_npcm_pspi_enter_reset(DEVICE(obj)->canonical_path, type);
+ memset(s->regs, 0, sizeof(s->regs));
+}
+
+static void npcm_pspi_realize(DeviceState *dev, Error **errp)
+{
+ NPCMPSPIState *s = NPCM_PSPI(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ Object *obj = OBJECT(dev);
+
+ s->spi = ssi_create_bus(dev, "pspi");
+ memory_region_init_io(&s->mmio, obj, &npcm_pspi_ctrl_ops, s,
+ "mmio", 4 * KiB);
+ sysbus_init_mmio(sbd, &s->mmio);
+ sysbus_init_irq(sbd, &s->irq);
+}
+
+static const VMStateDescription vmstate_npcm_pspi = {
+ .name = "npcm-pspi",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16_ARRAY(regs, NPCMPSPIState, NPCM_PSPI_NR_REGS),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+
+static void npcm_pspi_class_init(ObjectClass *klass, void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "NPCM Peripheral SPI Module";
+ dc->realize = npcm_pspi_realize;
+ dc->vmsd = &vmstate_npcm_pspi;
+ rc->phases.enter = npcm_pspi_enter_reset;
+}
+
+static const TypeInfo npcm_pspi_types[] = {
+ {
+ .name = TYPE_NPCM_PSPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NPCMPSPIState),
+ .class_init = npcm_pspi_class_init,
+ },
+};
+DEFINE_TYPES(npcm_pspi_types);
diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events
index c707d4a..2d5bd2b 100644
--- a/hw/ssi/trace-events
+++ b/hw/ssi/trace-events
@@ -21,6 +21,11 @@ npcm7xx_fiu_ctrl_write(const char *id, uint64_t addr, uint32_t data) "%s offset:
npcm7xx_fiu_flash_read(const char *id, int cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64
npcm7xx_fiu_flash_write(const char *id, unsigned cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64
+# npcm_pspi.c
+npcm_pspi_enter_reset(const char *id, int reset_type) "%s reset type: %d"
+npcm_pspi_ctrl_read(const char *id, uint64_t addr, uint16_t data) "%s offset: 0x%03" PRIx64 " value: 0x%04" PRIx16
+npcm_pspi_ctrl_write(const char *id, uint64_t addr, uint16_t data) "%s offset: 0x%03" PRIx64 " value: 0x%04" PRIx16
+
# ibex_spi_host.c
ibex_spi_host_reset(const char *msg) "%s"
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
index f1b7e4a..72c7722 100644
--- a/include/hw/arm/npcm7xx.h
+++ b/include/hw/arm/npcm7xx.h
@@ -32,6 +32,7 @@
#include "hw/nvram/npcm7xx_otp.h"
#include "hw/timer/npcm7xx_timer.h"
#include "hw/ssi/npcm7xx_fiu.h"
+#include "hw/ssi/npcm_pspi.h"
#include "hw/usb/hcd-ehci.h"
#include "hw/usb/hcd-ohci.h"
#include "target/arm/cpu.h"
@@ -104,6 +105,7 @@ struct NPCM7xxState {
NPCM7xxFIUState fiu[2];
NPCM7xxEMCState emc[2];
NPCM7xxSDHCIState mmc;
+ NPCMPSPIState pspi[2];
};
#define TYPE_NPCM7XX "npcm7xx"
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index c5683af..9fcff26 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -27,8 +27,6 @@
#define SMMU_PCI_DEVFN_MAX 256
#define SMMU_PCI_DEVFN(sid) (sid & 0xFF)
-#define SMMU_MAX_VA_BITS 48
-
/*
* Page table walk error types
*/
diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
index b6dd087..a0c0264 100644
--- a/include/hw/arm/smmuv3.h
+++ b/include/hw/arm/smmuv3.h
@@ -45,6 +45,7 @@ struct SMMUv3State {
uint32_t cr[3];
uint32_t cr0ack;
uint32_t statusr;
+ uint32_t gbpa;
uint32_t irq_ctrl;
uint32_t gerror;
uint32_t gerrorn;
diff --git a/include/hw/intc/armv7m_nvic.h b/include/hw/intc/armv7m_nvic.h
index 0180c7b..1ca262f 100644
--- a/include/hw/intc/armv7m_nvic.h
+++ b/include/hw/intc/armv7m_nvic.h
@@ -16,10 +16,7 @@
#include "qom/object.h"
#define TYPE_NVIC "armv7m_nvic"
-
-typedef struct NVICState NVICState;
-DECLARE_INSTANCE_CHECKER(NVICState, NVIC,
- TYPE_NVIC)
+OBJECT_DECLARE_SIMPLE_TYPE(NVICState, NVIC)
/* Highest permitted number of exceptions (architectural limit) */
#define NVIC_MAX_VECTORS 512
@@ -86,4 +83,127 @@ struct NVICState {
qemu_irq sysresetreq;
};
+/* Interface between CPU and Interrupt controller. */
+/**
+ * armv7m_nvic_set_pending: mark the specified exception as pending
+ * @s: the NVIC
+ * @irq: the exception number to mark pending
+ * @secure: false for non-banked exceptions or for the nonsecure
+ * version of a banked exception, true for the secure version of a banked
+ * exception.
+ *
+ * Marks the specified exception as pending. Note that we will assert()
+ * if @secure is true and @irq does not specify one of the fixed set
+ * of architecturally banked exceptions.
+ */
+void armv7m_nvic_set_pending(NVICState *s, int irq, bool secure);
+/**
+ * armv7m_nvic_set_pending_derived: mark this derived exception as pending
+ * @s: the NVIC
+ * @irq: the exception number to mark pending
+ * @secure: false for non-banked exceptions or for the nonsecure
+ * version of a banked exception, true for the secure version of a banked
+ * exception.
+ *
+ * Similar to armv7m_nvic_set_pending(), but specifically for derived
+ * exceptions (exceptions generated in the course of trying to take
+ * a different exception).
+ */
+void armv7m_nvic_set_pending_derived(NVICState *s, int irq, bool secure);
+/**
+ * armv7m_nvic_set_pending_lazyfp: mark this lazy FP exception as pending
+ * @s: the NVIC
+ * @irq: the exception number to mark pending
+ * @secure: false for non-banked exceptions or for the nonsecure
+ * version of a banked exception, true for the secure version of a banked
+ * exception.
+ *
+ * Similar to armv7m_nvic_set_pending(), but specifically for exceptions
+ * generated in the course of lazy stacking of FP registers.
+ */
+void armv7m_nvic_set_pending_lazyfp(NVICState *s, int irq, bool secure);
+/**
+ * armv7m_nvic_get_pending_irq_info: return highest priority pending
+ * exception, and whether it targets Secure state
+ * @s: the NVIC
+ * @pirq: set to pending exception number
+ * @ptargets_secure: set to whether pending exception targets Secure
+ *
+ * This function writes the number of the highest priority pending
+ * exception (the one which would be made active by
+ * armv7m_nvic_acknowledge_irq()) to @pirq, and sets @ptargets_secure
+ * to true if the current highest priority pending exception should
+ * be taken to Secure state, false for NS.
+ */
+void armv7m_nvic_get_pending_irq_info(NVICState *s, int *pirq,
+ bool *ptargets_secure);
+/**
+ * armv7m_nvic_acknowledge_irq: make highest priority pending exception active
+ * @s: the NVIC
+ *
+ * Move the current highest priority pending exception from the pending
+ * state to the active state, and update v7m.exception to indicate that
+ * it is the exception currently being handled.
+ */
+void armv7m_nvic_acknowledge_irq(NVICState *s);
+/**
+ * armv7m_nvic_complete_irq: complete specified interrupt or exception
+ * @s: the NVIC
+ * @irq: the exception number to complete
+ * @secure: true if this exception was secure
+ *
+ * Returns: -1 if the irq was not active
+ * 1 if completing this irq brought us back to base (no active irqs)
+ * 0 if there is still an irq active after this one was completed
+ * (Ignoring -1, this is the same as the RETTOBASE value before completion.)
+ */
+int armv7m_nvic_complete_irq(NVICState *s, int irq, bool secure);
+/**
+ * armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure)
+ * @s: the NVIC
+ * @irq: the exception number to mark pending
+ * @secure: false for non-banked exceptions or for the nonsecure
+ * version of a banked exception, true for the secure version of a banked
+ * exception.
+ *
+ * Return whether an exception is "ready", i.e. whether the exception is
+ * enabled and is configured at a priority which would allow it to
+ * interrupt the current execution priority. This controls whether the
+ * RDY bit for it in the FPCCR is set.
+ */
+bool armv7m_nvic_get_ready_status(NVICState *s, int irq, bool secure);
+/**
+ * armv7m_nvic_raw_execution_priority: return the raw execution priority
+ * @s: 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(NVICState *s);
+/**
+ * armv7m_nvic_neg_prio_requested: return true if the requested execution
+ * priority is negative for the specified security state.
+ * @s: the NVIC
+ * @secure: the security state to test
+ * This corresponds to the pseudocode IsReqExecPriNeg().
+ */
+#ifndef CONFIG_USER_ONLY
+bool armv7m_nvic_neg_prio_requested(NVICState *s, bool secure);
+#else
+static inline bool armv7m_nvic_neg_prio_requested(NVICState *s, bool secure)
+{
+ return false;
+}
+#endif
+#ifndef CONFIG_USER_ONLY
+bool armv7m_nvic_can_take_pending_exception(NVICState *s);
+#else
+static inline bool armv7m_nvic_can_take_pending_exception(NVICState *s)
+{
+ return true;
+}
+#endif
+
#endif
diff --git a/include/hw/ssi/npcm_pspi.h b/include/hw/ssi/npcm_pspi.h
new file mode 100644
index 0000000..37cc784
--- /dev/null
+++ b/include/hw/ssi/npcm_pspi.h
@@ -0,0 +1,53 @@
+/*
+ * Nuvoton Peripheral SPI Module
+ *
+ * Copyright 2023 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#ifndef NPCM_PSPI_H
+#define NPCM_PSPI_H
+
+#include "hw/ssi/ssi.h"
+#include "hw/sysbus.h"
+
+/*
+ * Number of registers in our device state structure. Don't change this without
+ * incrementing the version_id in the vmstate.
+ */
+#define NPCM_PSPI_NR_REGS 3
+
+/**
+ * NPCMPSPIState - Device state for one Flash Interface Unit.
+ * @parent: System bus device.
+ * @mmio: Memory region for register access.
+ * @spi: The SPI bus mastered by this controller.
+ * @regs: Register contents.
+ * @irq: The interrupt request queue for this module.
+ *
+ * Each PSPI has a shared bank of registers, and controls up to four chip
+ * selects. Each chip select has a dedicated memory region which may be used to
+ * read and write the flash connected to that chip select as if it were memory.
+ */
+typedef struct NPCMPSPIState {
+ SysBusDevice parent;
+
+ MemoryRegion mmio;
+
+ SSIBus *spi;
+ uint16_t regs[NPCM_PSPI_NR_REGS];
+ qemu_irq irq;
+} NPCMPSPIState;
+
+#define TYPE_NPCM_PSPI "npcm-pspi"
+OBJECT_DECLARE_SIMPLE_TYPE(NPCMPSPIState, NPCM_PSPI)
+
+#endif /* NPCM_PSPI_H */
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index c0790f3..a992423 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -356,7 +356,7 @@ void cpu_loop(CPUARMState *env)
break;
case EXCP_SWI:
{
- env->eabi = 1;
+ env->eabi = true;
/* system call */
if (env->thumb) {
/* Thumb is always EABI style with syscall number in r7 */
@@ -382,7 +382,7 @@ void cpu_loop(CPUARMState *env)
* > 0xfffff and are handled below as out-of-range.
*/
n ^= ARM_SYSCALL_BASE;
- env->eabi = 0;
+ env->eabi = false;
}
}
diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h
index 0280e76..3576da4 100644
--- a/linux-user/user-internals.h
+++ b/linux-user/user-internals.h
@@ -135,7 +135,7 @@ void print_termios(void *arg);
#ifdef TARGET_ARM
static inline int regpairs_aligned(CPUArchState *cpu_env, int num)
{
- return cpu_env->eabi == 1;
+ return cpu_env->eabi;
}
#elif defined(TARGET_MIPS) && defined(TARGET_ABI_MIPSO32)
static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 1; }
diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index efcf918..1ee64e9 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -121,6 +121,104 @@ enum {
};
/*
+ * Interface for defining coprocessor registers.
+ * Registers are defined in tables of arm_cp_reginfo structs
+ * which are passed to define_arm_cp_regs().
+ */
+
+/*
+ * When looking up a coprocessor register we look for it
+ * via an integer which encodes all of:
+ * coprocessor number
+ * Crn, Crm, opc1, opc2 fields
+ * 32 or 64 bit register (ie is it accessed via MRC/MCR
+ * or via MRRC/MCRR?)
+ * non-secure/secure bank (AArch32 only)
+ * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
+ * (In this case crn and opc2 should be zero.)
+ * For AArch64, there is no 32/64 bit size distinction;
+ * instead all registers have a 2 bit op0, 3 bit op1 and op2,
+ * and 4 bit CRn and CRm. The encoding patterns are chosen
+ * to be easy to convert to and from the KVM encodings, and also
+ * so that the hashtable can contain both AArch32 and AArch64
+ * registers (to allow for interprocessing where we might run
+ * 32 bit code on a 64 bit core).
+ */
+/*
+ * This bit is private to our hashtable cpreg; in KVM register
+ * IDs the AArch64/32 distinction is the KVM_REG_ARM/ARM64
+ * in the upper bits of the 64 bit ID.
+ */
+#define CP_REG_AA64_SHIFT 28
+#define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
+
+/*
+ * To enable banking of coprocessor registers depending on ns-bit we
+ * add a bit to distinguish between secure and non-secure cpregs in the
+ * hashtable.
+ */
+#define CP_REG_NS_SHIFT 29
+#define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT)
+
+#define ENCODE_CP_REG(cp, is64, ns, crn, crm, opc1, opc2) \
+ ((ns) << CP_REG_NS_SHIFT | ((cp) << 16) | ((is64) << 15) | \
+ ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
+
+#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
+ (CP_REG_AA64_MASK | \
+ ((cp) << CP_REG_ARM_COPROC_SHIFT) | \
+ ((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) | \
+ ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) | \
+ ((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) | \
+ ((crm) << CP_REG_ARM64_SYSREG_CRM_SHIFT) | \
+ ((op2) << CP_REG_ARM64_SYSREG_OP2_SHIFT))
+
+/*
+ * Convert a full 64 bit KVM register ID to the truncated 32 bit
+ * version used as a key for the coprocessor register hashtable
+ */
+static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
+{
+ uint32_t cpregid = kvmid;
+ if ((kvmid & CP_REG_ARCH_MASK) == CP_REG_ARM64) {
+ cpregid |= CP_REG_AA64_MASK;
+ } else {
+ if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) {
+ cpregid |= (1 << 15);
+ }
+
+ /*
+ * KVM is always non-secure so add the NS flag on AArch32 register
+ * entries.
+ */
+ cpregid |= 1 << CP_REG_NS_SHIFT;
+ }
+ return cpregid;
+}
+
+/*
+ * Convert a truncated 32 bit hashtable key into the full
+ * 64 bit KVM register ID.
+ */
+static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
+{
+ uint64_t kvmid;
+
+ if (cpregid & CP_REG_AA64_MASK) {
+ kvmid = cpregid & ~CP_REG_AA64_MASK;
+ kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM64;
+ } else {
+ kvmid = cpregid & ~(1 << 15);
+ if (cpregid & (1 << 15)) {
+ kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM;
+ } else {
+ kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM;
+ }
+ }
+ return kvmid;
+}
+
+/*
* Valid values for ARMCPRegInfo state field, indicating which of
* the AArch32 and AArch64 execution states this register is visible in.
* If the reginfo doesn't explicitly specify then it is AArch32 only.
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 5f63316..876ab8f 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -36,7 +36,10 @@
#if !defined(CONFIG_USER_ONLY)
#include "hw/loader.h"
#include "hw/boards.h"
-#endif
+#ifdef CONFIG_TCG
+#include "hw/intc/armv7m_nvic.h"
+#endif /* CONFIG_TCG */
+#endif /* !CONFIG_USER_ONLY */
#include "sysemu/tcg.h"
#include "sysemu/qtest.h"
#include "sysemu/hw_accel.h"
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 7bc97fe..12b1082 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -227,6 +227,8 @@ typedef struct CPUARMTBFlags {
typedef struct ARMMMUFaultInfo ARMMMUFaultInfo;
+typedef struct NVICState NVICState;
+
typedef struct CPUArchState {
/* Regs for current mode. */
uint32_t regs[16];
@@ -721,11 +723,6 @@ typedef struct CPUArchState {
ARMVectorReg zarray[ARM_MAX_VQ * 16];
#endif
-#if defined(CONFIG_USER_ONLY)
- /* For usermode syscall translation. */
- int eabi;
-#endif
-
struct CPUBreakpoint *cpu_breakpoint[16];
struct CPUWatchpoint *cpu_watchpoint[16];
@@ -772,10 +769,15 @@ typedef struct CPUArchState {
uint32_t ctrl;
} sau;
- void *nvic;
+#if !defined(CONFIG_USER_ONLY)
+ NVICState *nvic;
const struct arm_boot_info *boot_info;
/* Store GICv3CPUState to access from this struct */
void *gicv3state;
+#else /* CONFIG_USER_ONLY */
+ /* For usermode syscall translation. */
+ bool eabi;
+#endif /* CONFIG_USER_ONLY */
#ifdef TARGET_TAGGED_ADDRESSES
/* Linux syscall tagged address support */
@@ -2557,220 +2559,6 @@ void arm_cpu_list(void);
uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
uint32_t cur_el, bool secure);
-/* Interface between CPU and Interrupt controller. */
-#ifndef CONFIG_USER_ONLY
-bool armv7m_nvic_can_take_pending_exception(void *opaque);
-#else
-static inline bool armv7m_nvic_can_take_pending_exception(void *opaque)
-{
- return true;
-}
-#endif
-/**
- * armv7m_nvic_set_pending: mark the specified exception as pending
- * @opaque: the NVIC
- * @irq: the exception number to mark pending
- * @secure: false for non-banked exceptions or for the nonsecure
- * version of a banked exception, true for the secure version of a banked
- * exception.
- *
- * Marks the specified exception as pending. Note that we will assert()
- * if @secure is true and @irq does not specify one of the fixed set
- * of architecturally banked exceptions.
- */
-void armv7m_nvic_set_pending(void *opaque, int irq, bool secure);
-/**
- * armv7m_nvic_set_pending_derived: mark this derived exception as pending
- * @opaque: the NVIC
- * @irq: the exception number to mark pending
- * @secure: false for non-banked exceptions or for the nonsecure
- * version of a banked exception, true for the secure version of a banked
- * exception.
- *
- * Similar to armv7m_nvic_set_pending(), but specifically for derived
- * exceptions (exceptions generated in the course of trying to take
- * a different exception).
- */
-void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure);
-/**
- * armv7m_nvic_set_pending_lazyfp: mark this lazy FP exception as pending
- * @opaque: the NVIC
- * @irq: the exception number to mark pending
- * @secure: false for non-banked exceptions or for the nonsecure
- * version of a banked exception, true for the secure version of a banked
- * exception.
- *
- * Similar to armv7m_nvic_set_pending(), but specifically for exceptions
- * generated in the course of lazy stacking of FP registers.
- */
-void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure);
-/**
- * armv7m_nvic_get_pending_irq_info: return highest priority pending
- * exception, and whether it targets Secure state
- * @opaque: the NVIC
- * @pirq: set to pending exception number
- * @ptargets_secure: set to whether pending exception targets Secure
- *
- * This function writes the number of the highest priority pending
- * exception (the one which would be made active by
- * armv7m_nvic_acknowledge_irq()) to @pirq, and sets @ptargets_secure
- * to true if the current highest priority pending exception should
- * be taken to Secure state, false for NS.
- */
-void armv7m_nvic_get_pending_irq_info(void *opaque, int *pirq,
- bool *ptargets_secure);
-/**
- * armv7m_nvic_acknowledge_irq: make highest priority pending exception active
- * @opaque: the NVIC
- *
- * Move the current highest priority pending exception from the pending
- * state to the active state, and update v7m.exception to indicate that
- * it is the exception currently being handled.
- */
-void armv7m_nvic_acknowledge_irq(void *opaque);
-/**
- * armv7m_nvic_complete_irq: complete specified interrupt or exception
- * @opaque: the NVIC
- * @irq: the exception number to complete
- * @secure: true if this exception was secure
- *
- * Returns: -1 if the irq was not active
- * 1 if completing this irq brought us back to base (no active irqs)
- * 0 if there is still an irq active after this one was completed
- * (Ignoring -1, this is the same as the RETTOBASE value before completion.)
- */
-int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure);
-/**
- * armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure)
- * @opaque: the NVIC
- * @irq: the exception number to mark pending
- * @secure: false for non-banked exceptions or for the nonsecure
- * version of a banked exception, true for the secure version of a banked
- * exception.
- *
- * Return whether an exception is "ready", i.e. whether the exception is
- * enabled and is configured at a priority which would allow it to
- * interrupt the current execution priority. This controls whether the
- * RDY bit for it in the FPCCR is set.
- */
-bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure);
-/**
- * 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);
-/**
- * armv7m_nvic_neg_prio_requested: return true if the requested execution
- * priority is negative for the specified security state.
- * @opaque: the NVIC
- * @secure: the security state to test
- * This corresponds to the pseudocode IsReqExecPriNeg().
- */
-#ifndef CONFIG_USER_ONLY
-bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure);
-#else
-static inline bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure)
-{
- return false;
-}
-#endif
-
-/* Interface for defining coprocessor registers.
- * Registers are defined in tables of arm_cp_reginfo structs
- * which are passed to define_arm_cp_regs().
- */
-
-/* When looking up a coprocessor register we look for it
- * via an integer which encodes all of:
- * coprocessor number
- * Crn, Crm, opc1, opc2 fields
- * 32 or 64 bit register (ie is it accessed via MRC/MCR
- * or via MRRC/MCRR?)
- * non-secure/secure bank (AArch32 only)
- * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
- * (In this case crn and opc2 should be zero.)
- * For AArch64, there is no 32/64 bit size distinction;
- * instead all registers have a 2 bit op0, 3 bit op1 and op2,
- * and 4 bit CRn and CRm. The encoding patterns are chosen
- * to be easy to convert to and from the KVM encodings, and also
- * so that the hashtable can contain both AArch32 and AArch64
- * registers (to allow for interprocessing where we might run
- * 32 bit code on a 64 bit core).
- */
-/* This bit is private to our hashtable cpreg; in KVM register
- * IDs the AArch64/32 distinction is the KVM_REG_ARM/ARM64
- * in the upper bits of the 64 bit ID.
- */
-#define CP_REG_AA64_SHIFT 28
-#define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
-
-/* To enable banking of coprocessor registers depending on ns-bit we
- * add a bit to distinguish between secure and non-secure cpregs in the
- * hashtable.
- */
-#define CP_REG_NS_SHIFT 29
-#define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT)
-
-#define ENCODE_CP_REG(cp, is64, ns, crn, crm, opc1, opc2) \
- ((ns) << CP_REG_NS_SHIFT | ((cp) << 16) | ((is64) << 15) | \
- ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
-
-#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
- (CP_REG_AA64_MASK | \
- ((cp) << CP_REG_ARM_COPROC_SHIFT) | \
- ((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) | \
- ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) | \
- ((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) | \
- ((crm) << CP_REG_ARM64_SYSREG_CRM_SHIFT) | \
- ((op2) << CP_REG_ARM64_SYSREG_OP2_SHIFT))
-
-/* Convert a full 64 bit KVM register ID to the truncated 32 bit
- * version used as a key for the coprocessor register hashtable
- */
-static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
-{
- uint32_t cpregid = kvmid;
- if ((kvmid & CP_REG_ARCH_MASK) == CP_REG_ARM64) {
- cpregid |= CP_REG_AA64_MASK;
- } else {
- if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) {
- cpregid |= (1 << 15);
- }
-
- /* KVM is always non-secure so add the NS flag on AArch32 register
- * entries.
- */
- cpregid |= 1 << CP_REG_NS_SHIFT;
- }
- return cpregid;
-}
-
-/* Convert a truncated 32 bit hashtable key into the full
- * 64 bit KVM register ID.
- */
-static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
-{
- uint64_t kvmid;
-
- if (cpregid & CP_REG_AA64_MASK) {
- kvmid = cpregid & ~CP_REG_AA64_MASK;
- kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM64;
- } else {
- kvmid = cpregid & ~(1 << 15);
- if (cpregid & (1 << 15)) {
- kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM;
- } else {
- kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM;
- }
- }
- return kvmid;
-}
-
/* Return the highest implemented Exception Level */
static inline int arm_highest_el(CPUARMState *env)
{
diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
index ccde508..df0c45e 100644
--- a/target/arm/cpu_tcg.c
+++ b/target/arm/cpu_tcg.c
@@ -19,6 +19,9 @@
#include "hw/boards.h"
#endif
#include "cpregs.h"
+#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG)
+#include "hw/intc/armv7m_nvic.h"
+#endif
/* Share AArch32 -cpu max features with AArch64. */
diff --git a/target/arm/helper.c b/target/arm/helper.c
index c62ed05..07d4100 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -22,6 +22,7 @@
#include "hw/irq.h"
#include "sysemu/cpu-timers.h"
#include "sysemu/kvm.h"
+#include "sysemu/tcg.h"
#include "qapi/qapi-commands-machine-target.h"
#include "qapi/error.h"
#include "qemu/guest-random.h"
@@ -7021,6 +7022,7 @@ static void define_pmu_regs(ARMCPU *cpu)
}
}
+#ifndef CONFIG_USER_ONLY
/*
* We don't know until after realize whether there's a GICv3
* attached, and that is what registers the gicv3 sysregs.
@@ -7038,7 +7040,6 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri)
return pfr1;
}
-#ifndef CONFIG_USER_ONLY
static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
ARMCPU *cpu = env_archcpu(env);
@@ -7998,8 +7999,16 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 1,
.access = PL1_R, .type = ARM_CP_NO_RAW,
.accessfn = access_aa32_tid3,
+#ifdef CONFIG_USER_ONLY
+ .type = ARM_CP_CONST,
+ .resetvalue = cpu->isar.id_pfr1,
+#else
+ .type = ARM_CP_NO_RAW,
+ .accessfn = access_aa32_tid3,
.readfn = id_pfr1_read,
- .writefn = arm_cp_write_ignore },
+ .writefn = arm_cp_write_ignore
+#endif
+ },
{ .name = "ID_DFR0", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 2,
.access = PL1_R, .type = ARM_CP_CONST,
@@ -10818,11 +10827,13 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
unsigned int cur_el = arm_current_el(env);
int rt;
- /*
- * Note that new_el can never be 0. If cur_el is 0, then
- * el0_a64 is is_a64(), else el0_a64 is ignored.
- */
- aarch64_sve_change_el(env, cur_el, new_el, is_a64(env));
+ if (tcg_enabled()) {
+ /*
+ * Note that new_el can never be 0. If cur_el is 0, then
+ * el0_a64 is is_a64(), else el0_a64 is ignored.
+ */
+ aarch64_sve_change_el(env, cur_el, new_el, is_a64(env));
+ }
if (cur_el < new_el) {
/*
@@ -11006,7 +11017,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
* trapped to the hypervisor in KVM.
*/
#ifdef CONFIG_TCG
-static void handle_semihosting(CPUState *cs)
+static void tcg_handle_semihosting(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@@ -11055,7 +11066,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
env->exception.syndrome);
}
- if (arm_is_psci_call(cpu, cs->exception_index)) {
+ if (tcg_enabled() && arm_is_psci_call(cpu, cs->exception_index)) {
arm_handle_psci_call(cpu);
qemu_log_mask(CPU_LOG_INT, "...handled as PSCI call\n");
return;
@@ -11068,7 +11079,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
*/
#ifdef CONFIG_TCG
if (cs->exception_index == EXCP_SEMIHOST) {
- handle_semihosting(cs);
+ tcg_handle_semihosting(cs);
return;
}
#endif
diff --git a/target/arm/internals.h b/target/arm/internals.h
index e1e018d..759b70c 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -597,20 +597,6 @@ static inline ARMMMUIdx core_to_aa64_mmu_idx(int mmu_idx)
int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx);
-/*
- * Return the MMU index for a v7M CPU with all relevant information
- * manually specified.
- */
-ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env,
- bool secstate, bool priv, bool negpri);
-
-/*
- * Return the MMU index for a v7M CPU in the specified security and
- * privilege state.
- */
-ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
- bool secstate, bool priv);
-
/* Return the MMU index for a v7M CPU in the specified security state */
ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate);
diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c
index e7e746e..f94e87e 100644
--- a/target/arm/m_helper.c
+++ b/target/arm/m_helper.c
@@ -18,6 +18,9 @@
#include "exec/cpu_ldst.h"
#include "semihosting/common-semi.h"
#endif
+#if !defined(CONFIG_USER_ONLY)
+#include "hw/intc/armv7m_nvic.h"
+#endif
static void v7m_msr_xpsr(CPUARMState *env, uint32_t mask,
uint32_t reg, uint32_t val)
@@ -150,7 +153,49 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
return 0;
}
-#else
+ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
+{
+ return ARMMMUIdx_MUser;
+}
+
+#else /* !CONFIG_USER_ONLY */
+
+static ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env,
+ bool secstate, bool priv, bool negpri)
+{
+ ARMMMUIdx mmu_idx = ARM_MMU_IDX_M;
+
+ if (priv) {
+ mmu_idx |= ARM_MMU_IDX_M_PRIV;
+ }
+
+ if (negpri) {
+ mmu_idx |= ARM_MMU_IDX_M_NEGPRI;
+ }
+
+ if (secstate) {
+ mmu_idx |= ARM_MMU_IDX_M_S;
+ }
+
+ return mmu_idx;
+}
+
+static ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
+ bool secstate, bool priv)
+{
+ bool negpri = armv7m_nvic_neg_prio_requested(env->nvic, secstate);
+
+ return arm_v7m_mmu_idx_all(env, secstate, priv, negpri);
+}
+
+/* Return the MMU index for a v7M CPU in the specified security state */
+ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
+{
+ bool priv = arm_v7m_is_handler_mode(env) ||
+ !(env->v7m.control[secstate] & 1);
+
+ return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv);
+}
/*
* What kind of stack write are we doing? This affects how exceptions
@@ -973,7 +1018,7 @@ static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr,
* that we will need later in order to do lazy FP reg stacking.
*/
bool is_secure = env->v7m.secure;
- void *nvic = env->nvic;
+ NVICState *nvic = env->nvic;
/*
* Some bits are unbanked and live always in fpccr[M_REG_S]; some bits
* are banked and we want to update the bit in the bank for the
@@ -2855,40 +2900,3 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
}
#endif /* !CONFIG_USER_ONLY */
-
-ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env,
- bool secstate, bool priv, bool negpri)
-{
- ARMMMUIdx mmu_idx = ARM_MMU_IDX_M;
-
- if (priv) {
- mmu_idx |= ARM_MMU_IDX_M_PRIV;
- }
-
- if (negpri) {
- mmu_idx |= ARM_MMU_IDX_M_NEGPRI;
- }
-
- if (secstate) {
- mmu_idx |= ARM_MMU_IDX_M_S;
- }
-
- return mmu_idx;
-}
-
-ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
- bool secstate, bool priv)
-{
- bool negpri = armv7m_nvic_neg_prio_requested(env->nvic, secstate);
-
- return arm_v7m_mmu_idx_all(env, secstate, priv, negpri);
-}
-
-/* Return the MMU index for a v7M CPU in the specified security state */
-ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
-{
- bool priv = arm_v7m_is_handler_mode(env) ||
- !(env->v7m.control[secstate] & 1);
-
- return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv);
-}
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 5f26152..b4c3850 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -839,6 +839,15 @@ static int cpu_post_load(void *opaque, int version_id)
}
}
+ /*
+ * Misaligned thumb pc is architecturally impossible. Fail the
+ * incoming migration. For TCG it would trigger the assert in
+ * thumb_tr_translate_insn().
+ */
+ if (!is_a64(env) && env->thumb && (env->regs[15] & 1)) {
+ return -1;
+ }
+
hw_breakpoint_update_all(cpu);
hw_watchpoint_update_all(cpu);
@@ -856,15 +865,6 @@ static int cpu_post_load(void *opaque, int version_id)
}
}
- /*
- * Misaligned thumb pc is architecturally impossible.
- * We have an assert in thumb_tr_translate_insn to verify this.
- * Fail an incoming migrate to avoid this assert.
- */
- if (!is_a64(env) && env->thumb && (env->regs[15] & 1)) {
- return -1;
- }
-
if (!kvm_enabled()) {
pmu_op_finish(&cpu->env);
}
diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py
index 25a5468..a313e88 100644
--- a/tests/avocado/avocado_qemu/__init__.py
+++ b/tests/avocado/avocado_qemu/__init__.py
@@ -274,6 +274,10 @@ class QemuSystemTest(QemuBaseTest):
super().setUp('qemu-system-')
+ accel_required = self._get_unique_tag_val('accel')
+ if accel_required:
+ self.require_accelerator(accel_required)
+
self.machine = self.params.get('machine',
default=self._get_unique_tag_val('machine'))
diff --git a/tests/avocado/boot_linux.py b/tests/avocado/boot_linux.py
index b3e58fa..fe0bb18 100644
--- a/tests/avocado/boot_linux.py
+++ b/tests/avocado/boot_linux.py
@@ -58,52 +58,16 @@ class BootLinuxX8664(LinuxTest):
self.launch_and_wait(set_up_ssh_connection=False)
-# For Aarch64 we only boot KVM tests in CI as the TCG tests are very
-# heavyweight. There are lighter weight distros which we use in the
-# machine_aarch64_virt.py tests.
+# For Aarch64 we only boot KVM tests in CI as booting the current
+# Fedora OS in TCG tests is very heavyweight. There are lighter weight
+# distros which we use in the machine_aarch64_virt.py tests.
class BootLinuxAarch64(LinuxTest):
"""
:avocado: tags=arch:aarch64
:avocado: tags=machine:virt
- :avocado: tags=machine:gic-version=2
"""
timeout = 720
- def add_common_args(self):
- self.vm.add_args('-bios',
- os.path.join(BUILD_DIR, 'pc-bios',
- 'edk2-aarch64-code.fd'))
- self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
- self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom')
-
- @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab')
- def test_fedora_cloud_tcg_gicv2(self):
- """
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:max
- :avocado: tags=device:gicv2
- """
- self.require_accelerator("tcg")
- self.vm.add_args("-accel", "tcg")
- self.vm.add_args("-cpu", "max,lpa2=off")
- self.vm.add_args("-machine", "virt,gic-version=2")
- self.add_common_args()
- self.launch_and_wait(set_up_ssh_connection=False)
-
- @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab')
- def test_fedora_cloud_tcg_gicv3(self):
- """
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:max
- :avocado: tags=device:gicv3
- """
- self.require_accelerator("tcg")
- self.vm.add_args("-accel", "tcg")
- self.vm.add_args("-cpu", "max,lpa2=off")
- self.vm.add_args("-machine", "virt,gic-version=3")
- self.add_common_args()
- self.launch_and_wait(set_up_ssh_connection=False)
-
def test_virt_kvm(self):
"""
:avocado: tags=accel:kvm
@@ -112,7 +76,11 @@ class BootLinuxAarch64(LinuxTest):
self.require_accelerator("kvm")
self.vm.add_args("-accel", "kvm")
self.vm.add_args("-machine", "virt,gic-version=host")
- self.add_common_args()
+ self.vm.add_args('-bios',
+ os.path.join(BUILD_DIR, 'pc-bios',
+ 'edk2-aarch64-code.fd'))
+ self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
+ self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom')
self.launch_and_wait(set_up_ssh_connection=False)
diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py
index be60f8c..574609b 100644
--- a/tests/avocado/boot_linux_console.py
+++ b/tests/avocado/boot_linux_console.py
@@ -997,6 +997,7 @@ class BootLinuxConsole(LinuxKernelTest):
def test_aarch64_raspi3_atf(self):
"""
+ :avocado: tags=accel:tcg
:avocado: tags=arch:aarch64
:avocado: tags=machine:raspi3b
:avocado: tags=cpu:cortex-a53
diff --git a/tests/avocado/machine_aarch64_virt.py b/tests/avocado/machine_aarch64_virt.py
index c2b2ba2..25dab8d 100644
--- a/tests/avocado/machine_aarch64_virt.py
+++ b/tests/avocado/machine_aarch64_virt.py
@@ -10,11 +10,14 @@
import time
import os
+import logging
from avocado_qemu import QemuSystemTest
from avocado_qemu import wait_for_console_pattern
from avocado_qemu import exec_command
from avocado_qemu import BUILD_DIR
+from avocado.utils import process
+from avocado.utils.path import find_command
class Aarch64VirtMachine(QemuSystemTest):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
@@ -65,16 +68,15 @@ class Aarch64VirtMachine(QemuSystemTest):
self.wait_for_console_pattern('Welcome to Alpine Linux 3.16')
- def test_aarch64_virt(self):
+ def common_aarch64_virt(self, machine):
"""
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:max
+ Common code to launch basic virt machine with kernel+initrd
+ and a scratch disk.
"""
+ logger = logging.getLogger('aarch64_virt')
+
kernel_url = ('https://fileserver.linaro.org/s/'
'z6B2ARM7DQT3HWN/download')
-
kernel_hash = 'ed11daab50c151dde0e1e9c9cb8b2d9bd3215347'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
@@ -83,13 +85,62 @@ class Aarch64VirtMachine(QemuSystemTest):
'console=ttyAMA0')
self.require_accelerator("tcg")
self.vm.add_args('-cpu', 'max,pauth-impdef=on',
+ '-machine', machine,
'-accel', 'tcg',
'-kernel', kernel_path,
'-append', kernel_command_line)
+
+ # A RNG offers an easy way to generate a few IRQs
+ self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
+ self.vm.add_args('-object',
+ 'rng-random,id=rng0,filename=/dev/urandom')
+
+ # Also add a scratch block device
+ logger.info('creating scratch qcow2 image')
+ image_path = os.path.join(self.workdir, 'scratch.qcow2')
+ qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
+ if not os.path.exists(qemu_img):
+ qemu_img = find_command('qemu-img', False)
+ if qemu_img is False:
+ self.cancel('Could not find "qemu-img", which is required to '
+ 'create the temporary qcow2 image')
+ cmd = '%s create -f qcow2 %s 8M' % (qemu_img, image_path)
+ process.run(cmd)
+
+ # Add the device
+ self.vm.add_args('-blockdev',
+ f"driver=qcow2,file.driver=file,file.filename={image_path},node-name=scratch")
+ self.vm.add_args('-device',
+ 'virtio-blk-device,drive=scratch')
+
self.vm.launch()
self.wait_for_console_pattern('Welcome to Buildroot')
time.sleep(0.1)
exec_command(self, 'root')
time.sleep(0.1)
+ exec_command(self, 'dd if=/dev/hwrng of=/dev/vda bs=512 count=4')
+ time.sleep(0.1)
+ exec_command(self, 'md5sum /dev/vda')
+ time.sleep(0.1)
+ exec_command(self, 'cat /proc/interrupts')
+ time.sleep(0.1)
exec_command(self, 'cat /proc/self/maps')
time.sleep(0.1)
+
+ def test_aarch64_virt_gicv3(self):
+ """
+ :avocado: tags=arch:aarch64
+ :avocado: tags=machine:virt
+ :avocado: tags=accel:tcg
+ :avocado: tags=cpu:max
+ """
+ self.common_aarch64_virt("virt,gic_version=3")
+
+ def test_aarch64_virt_gicv2(self):
+ """
+ :avocado: tags=arch:aarch64
+ :avocado: tags=machine:virt
+ :avocado: tags=accel:tcg
+ :avocado: tags=cpu:max
+ """
+ self.common_aarch64_virt("virt,gic-version=2")
diff --git a/tests/avocado/reverse_debugging.py b/tests/avocado/reverse_debugging.py
index d2921e7..680c314 100644
--- a/tests/avocado/reverse_debugging.py
+++ b/tests/avocado/reverse_debugging.py
@@ -173,6 +173,10 @@ class ReverseDebugging(LinuxKernelTest):
vm.shutdown()
class ReverseDebugging_X86_64(ReverseDebugging):
+ """
+ :avocado: tags=accel:tcg
+ """
+
REG_PC = 0x10
REG_CS = 0x12
def get_pc(self, g):
@@ -190,6 +194,10 @@ class ReverseDebugging_X86_64(ReverseDebugging):
self.reverse_debugging()
class ReverseDebugging_AArch64(ReverseDebugging):
+ """
+ :avocado: tags=accel:tcg
+ """
+
REG_PC = 32
# unidentified gitlab timeout problem
diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c
index 8691802..1cb0813 100644
--- a/tests/qtest/arm-cpu-features.c
+++ b/tests/qtest/arm-cpu-features.c
@@ -21,7 +21,7 @@
#define SVE_MAX_VQ 16
#define MACHINE "-machine virt,gic-version=max -accel tcg "
-#define MACHINE_KVM "-machine virt,gic-version=max -accel kvm -accel tcg "
+#define MACHINE_KVM "-machine virt,gic-version=max -accel kvm "
#define QUERY_HEAD "{ 'execute': 'query-cpu-model-expansion', " \
" 'arguments': { 'type': 'full', "
#define QUERY_TAIL "}}"
@@ -607,31 +607,39 @@ int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
- qtest_add_data_func("/arm/query-cpu-model-expansion",
- NULL, test_query_cpu_model_expansion);
+ if (qtest_has_accel("tcg")) {
+ qtest_add_data_func("/arm/query-cpu-model-expansion",
+ NULL, test_query_cpu_model_expansion);
+ }
+
+ if (!g_str_equal(qtest_get_arch(), "aarch64")) {
+ goto out;
+ }
/*
* For now we only run KVM specific tests with AArch64 QEMU in
* order avoid attempting to run an AArch32 QEMU with KVM on
* AArch64 hosts. That won't work and isn't easy to detect.
*/
- if (g_str_equal(qtest_get_arch(), "aarch64") && qtest_has_accel("kvm")) {
+ if (qtest_has_accel("kvm")) {
/*
* This tests target the 'host' CPU type, so register it only if
* KVM is available.
*/
qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
NULL, test_query_cpu_model_expansion_kvm);
+
+ qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
+ NULL, sve_tests_sve_off_kvm);
}
- if (g_str_equal(qtest_get_arch(), "aarch64")) {
+ if (qtest_has_accel("tcg")) {
qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8",
NULL, sve_tests_sve_max_vq_8);
qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off",
NULL, sve_tests_sve_off);
- qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
- NULL, sve_tests_sve_off_kvm);
}
+out:
return g_test_run();
}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 222e189..29a4efb 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -208,8 +208,8 @@ qtests_arm = \
# TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional
qtests_aarch64 = \
(cpu != 'arm' and unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
- (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-test'] : []) + \
- (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) + \
+ (config_all.has_key('CONFIG_TCG') and config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? \
+ ['tpm-tis-device-test', 'tpm-tis-device-swtpm-test'] : []) + \
(config_all_devices.has_key('CONFIG_XLNX_ZYNQMP_ARM') ? ['xlnx-can-test', 'fuzz-xlnx-dp-test'] : []) + \
(config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test'] : []) + \
['arm-cpu-features',