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----- 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>
This commit is contained in:
commit
d8d20b38ec
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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'))
|
||||
|
221
hw/ssi/npcm_pspi.c
Normal file
221
hw/ssi/npcm_pspi.c
Normal file
@ -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);
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
53
include/hw/ssi/npcm_pspi.h
Normal file
53
include/hw/ssi/npcm_pspi.h
Normal file
@ -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 */
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -120,6 +120,104 @@ enum {
|
||||
ARM_CP_SME = 1 << 19,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
@ -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"
|
||||
|
228
target/arm/cpu.h
228
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)
|
||||
{
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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'))
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
if (g_str_equal(qtest_get_arch(), "aarch64")) {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
out:
|
||||
return g_test_run();
|
||||
}
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user