diff options
44 files changed, 429 insertions, 145 deletions
diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index cec87e3743..d8b102fa0a 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -14,6 +14,7 @@ AST2400 SoC based machines : - ``palmetto-bmc`` OpenPOWER Palmetto POWER8 BMC - ``quanta-q71l-bmc`` OpenBMC Quanta BMC +- ``supermicrox11-bmc`` Supermicro X11 BMC AST2500 SoC based machines : @@ -21,12 +22,16 @@ AST2500 SoC based machines : - ``romulus-bmc`` OpenPOWER Romulus POWER9 BMC - ``witherspoon-bmc`` OpenPOWER Witherspoon POWER9 BMC - ``sonorapass-bmc`` OCP SonoraPass BMC -- ``swift-bmc`` OpenPOWER Swift BMC POWER9 +- ``swift-bmc`` OpenPOWER Swift BMC POWER9 (to be removed in v7.0) +- ``fp5280g2-bmc`` Inspur FP5280G2 BMC +- ``g220a-bmc`` Bytedance G220A BMC AST2600 SoC based machines : - ``ast2600-evb`` Aspeed AST2600 Evaluation board (Cortex-A7) - ``tacoma-bmc`` OpenPOWER Witherspoon POWER9 AST2600 BMC +- ``rainier-bmc`` IBM Rainier POWER10 BMC +- ``fuji-bmc`` Facebook Fuji BMC Supported devices ----------------- @@ -51,13 +56,13 @@ Supported devices * Front LEDs (PCA9552 on I2C bus) * LPC Peripheral Controller (a subset of subdevices are supported) * Hash/Crypto Engine (HACE) - Hash support only. TODO: HMAC and RSA + * ADC Missing devices --------------- * Coprocessor support - * ADC (out of tree implementation) * PWM and Fan Controller * Slave GPIO Controller * Super I/O Controller @@ -73,16 +78,25 @@ Missing devices Boot options ------------ -The Aspeed machines can be started using the ``-kernel`` option to -load a Linux kernel or from a firmware. Images can be downloaded from -the OpenBMC jenkins : +The Aspeed machines can be started using the ``-kernel`` and ``-dtb`` options +to load a Linux kernel or from a firmware. Images can be downloaded from the +OpenBMC jenkins : - https://jenkins.openbmc.org/job/ci-openbmc/lastSuccessfulBuild/distro=ubuntu,label=docker-builder + https://jenkins.openbmc.org/job/ci-openbmc/lastSuccessfulBuild/ or directly from the OpenBMC GitHub release repository : https://github.com/openbmc/openbmc/releases +To boot a kernel directly from a Linux build tree: + +.. code-block:: bash + + $ qemu-system-arm -M ast2600-evb -nographic \ + -kernel arch/arm/boot/zImage \ + -dtb arch/arm/boot/dts/aspeed-ast2600-evb.dtb \ + -initrd rootfs.cpio + The image should be attached as an MTD drive. Run : .. code-block:: bash diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 2d37d29f02..e652590943 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -27,6 +27,7 @@ config ARM_VIRT select DIMM select ACPI_HW_REDUCED select ACPI_APEI + select ACPI_VIOT config CHEETAH bool diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 74ad397b1f..399f8e837c 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/error-report.h" #include "qapi/error.h" diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c index b771a3d8b7..4093af09cb 100644 --- a/hw/arm/digic_boards.c +++ b/hw/arm/digic_boards.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "hw/boards.h" #include "qemu/error-report.h" diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index c3cb315dbc..4210894d81 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qapi/error.h" #include "hw/sysbus.h" diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index dec7d16ae5..aff8c87042 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -24,7 +24,6 @@ #include "hw/qdev-core.h" #include "hw/qdev-properties.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" #include "sysemu/blockdev.h" diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 358714bd3e..dd944553f7 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qapi/error.h" #include "qemu/error-report.h" diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index 0019b7f478..c07947d9f8 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" #include "hw/arm/stm32f405_soc.h" diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 58481c0762..3e6d63c7f9 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -23,7 +23,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "cpu.h" #include "hw/sysbus.h" diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 674f902652..d0f4867fdf 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -55,6 +55,7 @@ #include "kvm_arm.h" #include "migration/vmstate.h" #include "hw/acpi/ghes.h" +#include "hw/acpi/viot.h" #define ARM_SPI_BASE 32 @@ -1011,6 +1012,12 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) } #endif + if (vms->iommu == VIRT_IOMMU_VIRTIO) { + acpi_add_table(table_offsets, tables_blob); + build_viot(ms, tables_blob, tables->linker, vms->virtio_iommu_bdf, + vms->oem_id, vms->oem_table_id); + } + /* XSDT is pointed to by RSDP */ xsdt = tables_blob->len; build_xsdt(tables_blob, tables->linker, table_offsets, vms->oem_id, diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 30da05dfe0..6bce595aba 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -29,7 +29,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" #include "qemu/option.h" @@ -2494,6 +2493,11 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, hwaddr db_start = 0, db_end = 0; char *resv_prop_str; + if (vms->iommu != VIRT_IOMMU_NONE) { + error_setg(errp, "virt machine does not support multiple IOMMUs"); + return; + } + switch (vms->msi_controller) { case VIRT_MSI_CTRL_NONE: return; @@ -2513,8 +2517,9 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, db_start, db_end, VIRTIO_IOMMU_RESV_MEM_T_MSI); - qdev_prop_set_uint32(dev, "len-reserved-regions", 1); - qdev_prop_set_string(dev, "reserved-regions[0]", resv_prop_str); + object_property_set_uint(OBJECT(dev), "len-reserved-regions", 1, errp); + object_property_set_str(OBJECT(dev), "reserved-regions[0]", + resv_prop_str, errp); g_free(resv_prop_str); } } @@ -2614,16 +2619,10 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, MachineClass *mc = MACHINE_GET_CLASS(machine); if (device_is_dynamic_sysbus(mc, dev) || - (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) { + object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || + object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) { return HOTPLUG_HANDLER(machine); } - if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) { - VirtMachineState *vms = VIRT_MACHINE(machine); - - if (!vms->bootinfo.firmware_loaded || !virt_is_acpi_enabled(vms)) { - return HOTPLUG_HANDLER(machine); - } - } return NULL; } diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c index 8df0832424..fde67f4f03 100644 --- a/hw/char/stm32f2xx_usart.c +++ b/hw/char/stm32f2xx_usart.c @@ -103,10 +103,11 @@ static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr, return retvalue; case USART_DR: DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr); + retvalue = s->usart_dr & 0x3FF; s->usart_sr &= ~USART_SR_RXNE; qemu_chr_fe_accept_input(&s->chr); qemu_set_irq(s->irq, 0); - return s->usart_dr & 0x3FF; + return retvalue; case USART_BRR: return s->usart_brr; case USART_CR1: diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index 78aed93c45..010ded7eae 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -25,6 +25,11 @@ config APIC select MSI_NONBROKEN select I8259 +config ARM_GIC_TCG + bool + default y + depends on ARM_GIC && TCG + config ARM_GIC_KVM bool default y diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c index 9f5f815db9..715df5421d 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c @@ -1,5 +1,5 @@ /* - * ARM Generic Interrupt Controller v3 + * ARM Generic Interrupt Controller v3 (emulation) * * Copyright (c) 2015 Huawei. * Copyright (c) 2016 Linaro Limited diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 85fc369e55..d7e03d0cab 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -1,5 +1,5 @@ /* - * ARM Generic Interrupt Controller v3 + * ARM Generic Interrupt Controller v3 (emulation) * * Copyright (c) 2016 Linaro Limited * Written by Peter Maydell @@ -21,14 +21,6 @@ #include "hw/irq.h" #include "cpu.h" -void gicv3_set_gicv3state(CPUState *cpu, GICv3CPUState *s) -{ - ARMCPU *arm_cpu = ARM_CPU(cpu); - CPUARMState *env = &arm_cpu->env; - - env->gicv3state = (void *)s; -}; - static GICv3CPUState *icc_cs_from_env(CPUARMState *env) { return env->gicv3state; diff --git a/hw/intc/arm_gicv3_cpuif_common.c b/hw/intc/arm_gicv3_cpuif_common.c new file mode 100644 index 0000000000..ff1239f65d --- /dev/null +++ b/hw/intc/arm_gicv3_cpuif_common.c @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * ARM Generic Interrupt Controller v3 + * + * Copyright (c) 2016 Linaro Limited + * Written by Peter Maydell + * + * This code is licensed under the GPL, version 2 or (at your option) + * any later version. + */ + +#include "qemu/osdep.h" +#include "gicv3_internal.h" +#include "cpu.h" + +void gicv3_set_gicv3state(CPUState *cpu, GICv3CPUState *s) +{ + ARMCPU *arm_cpu = ARM_CPU(cpu); + CPUARMState *env = &arm_cpu->env; + + env->gicv3state = (void *)s; +}; diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index c929a9cb5c..b99e63d58f 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -274,21 +274,36 @@ static bool process_its_cmd(GICv3ITSState *s, uint64_t value, uint32_t offset, if (res != MEMTX_OK) { return result; } + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid command attributes: " + "invalid dte: %"PRIx64" for %d (MEM_TX: %d)\n", + __func__, dte, devid, res); + return result; } - if ((devid > s->dt.maxids.max_devids) || !dte_valid || !ite_valid || - !cte_valid || (eventid > max_eventid)) { + + /* + * In this implementation, in case of guest errors we ignore the + * command and move onto the next command in the queue. + */ + if (devid > s->dt.maxids.max_devids) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid command attributes " - "devid %d or eventid %d or invalid dte %d or" - "invalid cte %d or invalid ite %d\n", - __func__, devid, eventid, dte_valid, cte_valid, - ite_valid); - /* - * in this implementation, in case of error - * we ignore this command and move onto the next - * command in the queue - */ + "%s: invalid command attributes: devid %d>%d", + __func__, devid, s->dt.maxids.max_devids); + + } else if (!dte_valid || !ite_valid || !cte_valid) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid command attributes: " + "dte: %s, ite: %s, cte: %s\n", + __func__, + dte_valid ? "valid" : "invalid", + ite_valid ? "valid" : "invalid", + cte_valid ? "valid" : "invalid"); + } else if (eventid > max_eventid) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid command attributes: eventid %d > %d\n", + __func__, eventid, max_eventid); } else { /* * Current implementation only supports rdbase == procnum diff --git a/hw/intc/meson.build b/hw/intc/meson.build index c89d2ca180..70080bc161 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -3,12 +3,14 @@ softmmu_ss.add(when: 'CONFIG_ARM_GIC', if_true: files( 'arm_gic.c', 'arm_gic_common.c', 'arm_gicv2m.c', - 'arm_gicv3.c', 'arm_gicv3_common.c', - 'arm_gicv3_dist.c', 'arm_gicv3_its_common.c', - 'arm_gicv3_redist.c', +)) +softmmu_ss.add(when: 'CONFIG_ARM_GIC_TCG', if_true: files( + 'arm_gicv3.c', + 'arm_gicv3_dist.c', 'arm_gicv3_its.c', + 'arm_gicv3_redist.c', )) softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c')) softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c')) @@ -25,7 +27,8 @@ softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_PMU', if_true: files('xlnx-pmu-iomod-in specific_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c')) specific_ss.add(when: 'CONFIG_APIC', if_true: files('apic.c', 'apic_common.c')) -specific_ss.add(when: 'CONFIG_ARM_GIC', if_true: files('arm_gicv3_cpuif.c')) +specific_ss.add(when: 'CONFIG_ARM_GIC', if_true: files('arm_gicv3_cpuif_common.c')) +specific_ss.add(when: 'CONFIG_ARM_GIC_TCG', if_true: files('arm_gicv3_cpuif.c')) specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c')) specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'TARGET_AARCH64'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c')) specific_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c')) diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c index 7c892f820f..545b2b7410 100644 --- a/hw/net/npcm7xx_emc.c +++ b/hw/net/npcm7xx_emc.c @@ -284,6 +284,12 @@ static void emc_halt_rx(NPCM7xxEMCState *emc, uint32_t mista_flag) emc_set_mista(emc, mista_flag); } +static void emc_enable_rx_and_flush(NPCM7xxEMCState *emc) +{ + emc->rx_active = true; + qemu_flush_queued_packets(qemu_get_queue(emc->nic)); +} + static void emc_set_next_tx_descriptor(NPCM7xxEMCState *emc, const NPCM7xxEMCTxDesc *tx_desc, uint32_t desc_addr) @@ -581,13 +587,6 @@ static ssize_t emc_receive(NetClientState *nc, const uint8_t *buf, size_t len1) return len; } -static void emc_try_receive_next_packet(NPCM7xxEMCState *emc) -{ - if (emc_can_receive(qemu_get_queue(emc->nic))) { - qemu_flush_queued_packets(qemu_get_queue(emc->nic)); - } -} - static uint64_t npcm7xx_emc_read(void *opaque, hwaddr offset, unsigned size) { NPCM7xxEMCState *emc = opaque; @@ -703,7 +702,7 @@ static void npcm7xx_emc_write(void *opaque, hwaddr offset, emc->regs[REG_MGSTA] |= REG_MGSTA_RXHA; } if (value & REG_MCMDR_RXON) { - emc->rx_active = true; + emc_enable_rx_and_flush(emc); } else { emc_halt_rx(emc, 0); } @@ -739,8 +738,7 @@ static void npcm7xx_emc_write(void *opaque, hwaddr offset, break; case REG_RSDR: if (emc->regs[REG_MCMDR] & REG_MCMDR_RXON) { - emc->rx_active = true; - emc_try_receive_next_packet(emc); + emc_enable_rx_and_flush(emc); } break; case REG_MIIDA: diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c index a160ae6b41..6a1df7fe50 100644 --- a/hw/virtio/virtio-iommu-pci.c +++ b/hw/virtio/virtio-iommu-pci.c @@ -48,16 +48,8 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) VirtIOIOMMU *s = VIRTIO_IOMMU(vdev); if (!qdev_get_machine_hotplug_handler(DEVICE(vpci_dev))) { - MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); - - error_setg(errp, - "%s machine fails to create iommu-map device tree bindings", - mc->name); - error_append_hint(errp, - "Check your machine implements a hotplug handler " - "for the virtio-iommu-pci device\n"); - error_append_hint(errp, "Check the guest is booted without FW or with " - "-no-acpi\n"); + error_setg(errp, "Check your machine implements a hotplug handler " + "for the virtio-iommu-pci device"); return; } for (int i = 0; i < s->nb_reserved_regions; i++) { diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h index 4d9c732d4b..efcbd926fd 100644 --- a/include/hw/i386/microvm.h +++ b/include/hw/i386/microvm.h @@ -18,7 +18,6 @@ #ifndef HW_I386_MICROVM_H #define HW_I386_MICROVM_H -#include "qemu-common.h" #include "exec/hwaddr.h" #include "qemu/notify.h" diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index bb1cfb8896..a145a30370 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -17,7 +17,6 @@ #ifndef HW_I386_X86_H #define HW_I386_X86_H -#include "qemu-common.h" #include "exec/hwaddr.h" #include "qemu/notify.h" diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index 97e0728b67..f9f3473288 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -113,27 +113,35 @@ void cpu_loop(CPUARMState *env) break; case EXCP_PREFETCH_ABORT: case EXCP_DATA_ABORT: - /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */ ec = syn_get_ec(env->exception.syndrome); - assert(ec == EC_DATAABORT || ec == EC_INSNABORT); - - /* Both EC have the same format for FSC, or close enough. */ - fsc = extract32(env->exception.syndrome, 0, 6); - switch (fsc) { - case 0x04 ... 0x07: /* Translation fault, level {0-3} */ - si_signo = TARGET_SIGSEGV; - si_code = TARGET_SEGV_MAPERR; + switch (ec) { + case EC_DATAABORT: + case EC_INSNABORT: + /* Both EC have the same format for FSC, or close enough. */ + fsc = extract32(env->exception.syndrome, 0, 6); + switch (fsc) { + case 0x04 ... 0x07: /* Translation fault, level {0-3} */ + si_signo = TARGET_SIGSEGV; + si_code = TARGET_SEGV_MAPERR; + break; + case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */ + case 0x0d ... 0x0f: /* Permission fault, level {1-3} */ + si_signo = TARGET_SIGSEGV; + si_code = TARGET_SEGV_ACCERR; + break; + case 0x11: /* Synchronous Tag Check Fault */ + si_signo = TARGET_SIGSEGV; + si_code = TARGET_SEGV_MTESERR; + break; + case 0x21: /* Alignment fault */ + si_signo = TARGET_SIGBUS; + si_code = TARGET_BUS_ADRALN; + break; + default: + g_assert_not_reached(); + } break; - case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */ - case 0x0d ... 0x0f: /* Permission fault, level {1-3} */ - si_signo = TARGET_SIGSEGV; - si_code = TARGET_SEGV_ACCERR; - break; - case 0x11: /* Synchronous Tag Check Fault */ - si_signo = TARGET_SIGSEGV; - si_code = TARGET_SEGV_MTESERR; - break; - case 0x21: /* Alignment fault */ + case EC_PCALIGNMENT: si_signo = TARGET_SIGBUS; si_code = TARGET_BUS_ADRALN; break; diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c index 6b24cbaba9..e47f8348d5 100644 --- a/linux-user/hexagon/cpu_loop.c +++ b/linux-user/hexagon/cpu_loop.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu-common.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index 2983e36dd3..32f3caec23 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -220,6 +220,7 @@ bool arm_debug_check_breakpoint(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; + target_ulong pc; int n; /* @@ -231,6 +232,28 @@ bool arm_debug_check_breakpoint(CPUState *cs) return false; } + /* + * Single-step exceptions have priority over breakpoint exceptions. + * If single-step state is active-pending, suppress the bp. + */ + if (arm_singlestep_active(env) && !(env->pstate & PSTATE_SS)) { + return false; + } + + /* + * PC alignment faults have priority over breakpoint exceptions. + */ + pc = is_a64(env) ? env->pc : env->regs[15]; + if ((is_a64(env) || !env->thumb) && (pc & 3) != 0) { + return false; + } + + /* + * Instruction aborts have priority over breakpoint exceptions. + * TODO: We would need to look up the page for PC and verify that + * it is present and executable. + */ + for (n = 0; n < ARRAY_SIZE(env->cpu_breakpoint); n++) { if (bp_wp_matches(cpu, n, false)) { return true; diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index 134da0d0ae..ca1de47511 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -77,8 +77,13 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) tmp = ldl_p(mem_buf); - /* Mask out low bit of PC to workaround gdb bugs. This will probably - cause problems if we ever implement the Jazelle DBX extensions. */ + /* + * Mask out low bits of PC to workaround gdb bugs. + * This avoids an assert in thumb_tr_translate_insn, because it is + * architecturally impossible to misalign the pc. + * This will probably cause problems if we ever implement the + * Jazelle DBX extensions. + */ if (n == 15) { tmp &= ~1; } diff --git a/target/arm/helper.c b/target/arm/helper.c index 9b317899a6..db837d53bd 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4519,18 +4519,18 @@ static uint64_t tlbi_aa64_range_get_length(CPUARMState *env, uint64_t exponent; uint64_t length; - num = extract64(value, 39, 4); + num = extract64(value, 39, 5); scale = extract64(value, 44, 2); page_size_granule = extract64(value, 46, 2); - page_shift = page_size_granule * 2 + 12; - if (page_size_granule == 0) { qemu_log_mask(LOG_GUEST_ERROR, "Invalid page size granule %d\n", page_size_granule); return 0; } + page_shift = (page_size_granule - 1) * 2 + 12; + exponent = (5 * scale) + 1; length = (num + 1) << (exponent + page_shift); diff --git a/target/arm/helper.h b/target/arm/helper.h index 448a86edfd..b463d9343b 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -47,6 +47,7 @@ DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE, DEF_HELPER_2(exception_internal, void, env, i32) DEF_HELPER_4(exception_with_syndrome, void, env, i32, i32, i32) DEF_HELPER_2(exception_bkpt_insn, void, env, i32) +DEF_HELPER_2(exception_pc_alignment, noreturn, env, tl) DEF_HELPER_1(setend, void, env) DEF_HELPER_2(wfi, void, env, i32) DEF_HELPER_1(wfe, void, env) diff --git a/target/arm/machine.c b/target/arm/machine.c index c74d8c3f4b..135d2420b5 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -794,6 +794,16 @@ static int cpu_post_load(void *opaque, int version_id) return -1; } } + + /* + * 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/target/arm/syndrome.h b/target/arm/syndrome.h index f30f4130a2..8cde8e7243 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -282,4 +282,9 @@ static inline uint32_t syn_illegalstate(void) return (EC_ILLEGALSTATE << ARM_EL_EC_SHIFT) | ARM_EL_IL; } +static inline uint32_t syn_pcalignment(void) +{ + return (EC_PCALIGNMENT << ARM_EL_EC_SHIFT) | ARM_EL_IL; +} + #endif /* TARGET_ARM_SYNDROME_H */ diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c index 12a934e924..b79004e0cc 100644 --- a/target/arm/tlb_helper.c +++ b/target/arm/tlb_helper.c @@ -9,6 +9,7 @@ #include "cpu.h" #include "internals.h" #include "exec/exec-all.h" +#include "exec/helper-proto.h" static inline uint32_t merge_syn_data_abort(uint32_t template_syn, unsigned int target_el, @@ -49,25 +50,11 @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn, return syn; } -static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr, - MMUAccessType access_type, - int mmu_idx, ARMMMUFaultInfo *fi) +static uint32_t compute_fsr_fsc(CPUARMState *env, ARMMMUFaultInfo *fi, + int target_el, int mmu_idx, uint32_t *ret_fsc) { - CPUARMState *env = &cpu->env; - int target_el; - bool same_el; - uint32_t syn, exc, fsr, fsc; ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx); - - target_el = exception_target_el(env); - if (fi->stage2) { - target_el = 2; - env->cp15.hpfar_el2 = extract64(fi->s2addr, 12, 47) << 4; - if (arm_is_secure_below_el3(env) && fi->s1ns) { - env->cp15.hpfar_el2 |= HPFAR_NS; - } - } - same_el = (arm_current_el(env) == target_el); + uint32_t fsr, fsc; if (target_el == 2 || arm_el_is_aa64(env, target_el) || arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) { @@ -88,6 +75,31 @@ static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr, fsc = 0x3f; } + *ret_fsc = fsc; + return fsr; +} + +static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr, + MMUAccessType access_type, + int mmu_idx, ARMMMUFaultInfo *fi) +{ + CPUARMState *env = &cpu->env; + int target_el; + bool same_el; + uint32_t syn, exc, fsr, fsc; + + target_el = exception_target_el(env); + if (fi->stage2) { + target_el = 2; + env->cp15.hpfar_el2 = extract64(fi->s2addr, 12, 47) << 4; + if (arm_is_secure_below_el3(env) && fi->s1ns) { + env->cp15.hpfar_el2 |= HPFAR_NS; + } + } + same_el = (arm_current_el(env) == target_el); + + fsr = compute_fsr_fsc(env, fi, target_el, mmu_idx, &fsc); + if (access_type == MMU_INST_FETCH) { syn = syn_insn_abort(same_el, fi->ea, fi->s1ptw, fsc); exc = EXCP_PREFETCH_ABORT; @@ -123,6 +135,23 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi); } +void helper_exception_pc_alignment(CPUARMState *env, target_ulong pc) +{ + ARMMMUFaultInfo fi = { .type = ARMFault_Alignment }; + int target_el = exception_target_el(env); + int mmu_idx = cpu_mmu_index(env, true); + uint32_t fsc; + + env->exception.vaddress = pc; + + /* + * Note that the fsc is not applicable to this exception, + * since any syndrome is pcalignment not insn_abort. + */ + env->exception.fsr = compute_fsr_fsc(env, &fi, target_el, mmu_idx, &fsc); + raise_exception(env, EXCP_PREFETCH_ABORT, syn_pcalignment(), target_el); +} + #if !defined(CONFIG_USER_ONLY) /* diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index cec672f229..130a9ff8d5 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14750,8 +14750,10 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *s = container_of(dcbase, DisasContext, base); CPUARMState *env = cpu->env_ptr; + uint64_t pc = s->base.pc_next; uint32_t insn; + /* Singlestep exceptions have the highest priority. */ if (s->ss_active && !s->pstate_ss) { /* Singlestep state is Active-pending. * If we're in this state at the start of a TB then either @@ -14766,13 +14768,28 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) assert(s->base.num_insns == 1); gen_swstep_exception(s, 0, 0); s->base.is_jmp = DISAS_NORETURN; + s->base.pc_next = pc + 4; return; } - s->pc_curr = s->base.pc_next; - insn = arm_ldl_code(env, &s->base, s->base.pc_next, s->sctlr_b); + if (pc & 3) { + /* + * PC alignment fault. This has priority over the instruction abort + * that we would receive from a translation fault via arm_ldl_code. + * This should only be possible after an indirect branch, at the + * start of the TB. + */ + assert(s->base.num_insns == 1); + gen_helper_exception_pc_alignment(cpu_env, tcg_constant_tl(pc)); + s->base.is_jmp = DISAS_NORETURN; + s->base.pc_next = QEMU_ALIGN_UP(pc, 4); + return; + } + + s->pc_curr = pc; + insn = arm_ldl_code(env, &s->base, pc, s->sctlr_b); s->insn = insn; - s->base.pc_next += 4; + s->base.pc_next = pc + 4; s->fp_access_checked = false; s->sve_access_checked = false; diff --git a/target/arm/translate.c b/target/arm/translate.c index 98f5925928..0a3840d227 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -9502,7 +9502,7 @@ static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) dc->insn_start = tcg_last_op(); } -static bool arm_pre_translate_insn(DisasContext *dc) +static bool arm_check_kernelpage(DisasContext *dc) { #ifdef CONFIG_USER_ONLY /* Intercept jump to the magic kernel page. */ @@ -9514,7 +9514,11 @@ static bool arm_pre_translate_insn(DisasContext *dc) return true; } #endif + return false; +} +static bool arm_check_ss_active(DisasContext *dc) +{ if (dc->ss_active && !dc->pstate_ss) { /* Singlestep state is Active-pending. * If we're in this state at the start of a TB then either @@ -9548,17 +9552,38 @@ static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); CPUARMState *env = cpu->env_ptr; + uint32_t pc = dc->base.pc_next; unsigned int insn; - if (arm_pre_translate_insn(dc)) { - dc->base.pc_next += 4; + /* Singlestep exceptions have the highest priority. */ + if (arm_check_ss_active(dc)) { + dc->base.pc_next = pc + 4; return; } - dc->pc_curr = dc->base.pc_next; - insn = arm_ldl_code(env, &dc->base, dc->base.pc_next, dc->sctlr_b); + if (pc & 3) { + /* + * PC alignment fault. This has priority over the instruction abort + * that we would receive from a translation fault via arm_ldl_code + * (or the execution of the kernelpage entrypoint). This should only + * be possible after an indirect branch, at the start of the TB. + */ + assert(dc->base.num_insns == 1); + gen_helper_exception_pc_alignment(cpu_env, tcg_constant_tl(pc)); + dc->base.is_jmp = DISAS_NORETURN; + dc->base.pc_next = QEMU_ALIGN_UP(pc, 4); + return; + } + + if (arm_check_kernelpage(dc)) { + dc->base.pc_next = pc + 4; + return; + } + + dc->pc_curr = pc; + insn = arm_ldl_code(env, &dc->base, pc, dc->sctlr_b); dc->insn = insn; - dc->base.pc_next += 4; + dc->base.pc_next = pc + 4; disas_arm_insn(dc, insn); arm_post_translate_insn(dc); @@ -9617,25 +9642,28 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); CPUARMState *env = cpu->env_ptr; + uint32_t pc = dc->base.pc_next; uint32_t insn; bool is_16bit; - if (arm_pre_translate_insn(dc)) { - dc->base.pc_next += 2; + /* Misaligned thumb PC is architecturally impossible. */ + assert((dc->base.pc_next & 1) == 0); + + if (arm_check_ss_active(dc) || arm_check_kernelpage(dc)) { + dc->base.pc_next = pc + 2; return; } - dc->pc_curr = dc->base.pc_next; - insn = arm_lduw_code(env, &dc->base, dc->base.pc_next, dc->sctlr_b); + dc->pc_curr = pc; + insn = arm_lduw_code(env, &dc->base, pc, dc->sctlr_b); is_16bit = thumb_insn_is_16bit(dc, dc->base.pc_next, insn); - dc->base.pc_next += 2; + pc += 2; if (!is_16bit) { - uint32_t insn2 = arm_lduw_code(env, &dc->base, dc->base.pc_next, - dc->sctlr_b); - + uint32_t insn2 = arm_lduw_code(env, &dc->base, pc, dc->sctlr_b); insn = insn << 16 | insn2; - dc->base.pc_next += 2; + pc += 2; } + dc->base.pc_next = pc; dc->insn = insn; if (dc->pstate_il) { diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index de121d950f..58a0d3870b 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -23,7 +23,6 @@ typedef struct CPUHexagonState CPUHexagonState; #include "fpu/softfloat-types.h" -#include "qemu-common.h" #include "exec/cpu-defs.h" #include "hex_regs.h" #include "mmvec/mmvec.h" diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index e9e1451540..05f9336c9b 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -3519,9 +3519,6 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, case 0x171: /* shift xmm, im */ case 0x172: case 0x173: - if (b1 >= 2) { - goto unknown_op; - } val = x86_ldub_code(env, s); if (is_xmm) { tcg_gen_movi_tl(s->T0, val); @@ -3540,6 +3537,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, offsetof(CPUX86State, mmx_t0.MMX_L(1))); op1_offset = offsetof(CPUX86State,mmx_t0); } + assert(b1 < 2); sse_fn_epp = sse_op_table2[((b - 1) & 3) * 8 + (((modrm >> 3)) & 7)][b1]; if (!sse_fn_epp) { @@ -3770,10 +3768,8 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, rm = modrm & 7; reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; - if (b1 >= 2) { - goto unknown_op; - } + assert(b1 < 2); sse_fn_epp = sse_op_table6[b].op[b1]; if (!sse_fn_epp) { goto unknown_op; @@ -4200,10 +4196,8 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, rm = modrm & 7; reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; - if (b1 >= 2) { - goto unknown_op; - } + assert(b1 < 2); sse_fn_eppi = sse_op_table7[b].op[b1]; if (!sse_fn_eppi) { goto unknown_op; diff --git a/target/rx/cpu.h b/target/rx/cpu.h index 4ac71aec37..657db84ef0 100644 --- a/target/rx/cpu.h +++ b/target/rx/cpu.h @@ -20,7 +20,6 @@ #define RX_CPU_H #include "qemu/bitops.h" -#include "qemu-common.h" #include "hw/registerfields.h" #include "cpu-qom.h" diff --git a/tests/data/acpi/q35/DSDT.viot b/tests/data/acpi/q35/DSDT.viot Binary files differnew file mode 100644 index 0000000000..1c3b4da5cb --- /dev/null +++ b/tests/data/acpi/q35/DSDT.viot diff --git a/tests/data/acpi/q35/VIOT.viot b/tests/data/acpi/q35/VIOT.viot Binary files differnew file mode 100644 index 0000000000..9b179266cc --- /dev/null +++ b/tests/data/acpi/q35/VIOT.viot diff --git a/tests/data/acpi/virt/VIOT b/tests/data/acpi/virt/VIOT Binary files differnew file mode 100644 index 0000000000..921f40d88c --- /dev/null +++ b/tests/data/acpi/virt/VIOT diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 258874167e..58df53b15b 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1465,6 +1465,42 @@ static void test_acpi_virt_tcg(void) free_test_data(&data); } +static void test_acpi_q35_viot(void) +{ + test_data data = { + .machine = MACHINE_Q35, + .variant = ".viot", + }; + + /* + * To keep things interesting, two buses bypass the IOMMU. + * VIOT should only describes the other two buses. + */ + test_acpi_one("-machine default_bus_bypass_iommu=on " + "-device virtio-iommu-pci " + "-device pxb-pcie,bus_nr=0x10,id=pcie.100,bus=pcie.0 " + "-device pxb-pcie,bus_nr=0x20,id=pcie.200,bus=pcie.0,bypass_iommu=on " + "-device pxb-pcie,bus_nr=0x30,id=pcie.300,bus=pcie.0", + &data); + free_test_data(&data); +} + +static void test_acpi_virt_viot(void) +{ + test_data data = { + .machine = "virt", + .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", + .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", + .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", + .ram_start = 0x40000000ULL, + .scan_len = 128ULL * 1024 * 1024, + }; + + test_acpi_one("-cpu cortex-a57 " + "-device virtio-iommu-pci", &data); + free_test_data(&data); +} + static void test_oem_fields(test_data *data) { int i; @@ -1639,6 +1675,7 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/kvm/xapic", test_acpi_q35_kvm_xapic); qtest_add_func("acpi/q35/kvm/dmar", test_acpi_q35_kvm_dmar); } + qtest_add_func("acpi/q35/viot", test_acpi_q35_viot); } else if (strcmp(arch, "aarch64") == 0) { if (has_tcg) { qtest_add_func("acpi/virt", test_acpi_virt_tcg); @@ -1646,6 +1683,7 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp); qtest_add_func("acpi/virt/pxb", test_acpi_virt_tcg_pxb); qtest_add_func("acpi/virt/oem-fields", test_acpi_oem_fields_virt); + qtest_add_func("acpi/virt/viot", test_acpi_virt_viot); } } ret = g_test_run(); diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index 2c05c90d17..1d967901bd 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -8,8 +8,8 @@ VPATH += $(ARM_SRC) AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64 VPATH += $(AARCH64_SRC) -# Float-convert Tests -AARCH64_TESTS=fcvt +# Base architecture tests +AARCH64_TESTS=fcvt pcalign-a64 fcvt: LDFLAGS+=-lm diff --git a/tests/tcg/aarch64/pcalign-a64.c b/tests/tcg/aarch64/pcalign-a64.c new file mode 100644 index 0000000000..6b9277f919 --- /dev/null +++ b/tests/tcg/aarch64/pcalign-a64.c @@ -0,0 +1,37 @@ +/* Test PC misalignment exception */ + +#include <assert.h> +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> + +static void *expected; + +static void sigbus(int sig, siginfo_t *info, void *vuc) +{ + assert(info->si_code == BUS_ADRALN); + assert(info->si_addr == expected); + exit(EXIT_SUCCESS); +} + +int main() +{ + void *tmp; + + struct sigaction sa = { + .sa_sigaction = sigbus, + .sa_flags = SA_SIGINFO + }; + + if (sigaction(SIGBUS, &sa, NULL) < 0) { + perror("sigaction"); + return EXIT_FAILURE; + } + + asm volatile("adr %0, 1f + 1\n\t" + "str %0, %1\n\t" + "br %0\n" + "1:" + : "=&r"(tmp), "=m"(expected)); + abort(); +} diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target index 5ab59ed6ce..f509d823d4 100644 --- a/tests/tcg/arm/Makefile.target +++ b/tests/tcg/arm/Makefile.target @@ -29,6 +29,10 @@ run-fcvt: fcvt $(call run-test,fcvt,$(QEMU) $<,"$< on $(TARGET_NAME)") $(call diff-out,fcvt,$(ARM_SRC)/fcvt.ref) +# PC alignment test +ARM_TESTS += pcalign-a32 +pcalign-a32: CFLAGS+=-marm + ifeq ($(CONFIG_ARM_COMPATIBLE_SEMIHOSTING),y) # Semihosting smoke test for linux-user diff --git a/tests/tcg/arm/pcalign-a32.c b/tests/tcg/arm/pcalign-a32.c new file mode 100644 index 0000000000..3c9c8cc97b --- /dev/null +++ b/tests/tcg/arm/pcalign-a32.c @@ -0,0 +1,46 @@ +/* Test PC misalignment exception */ + +#ifdef __thumb__ +#error "This test must be compiled for ARM" +#endif + +#include <assert.h> +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> + +static void *expected; + +static void sigbus(int sig, siginfo_t *info, void *vuc) +{ + assert(info->si_code == BUS_ADRALN); + assert(info->si_addr == expected); + exit(EXIT_SUCCESS); +} + +int main() +{ + void *tmp; + + struct sigaction sa = { + .sa_sigaction = sigbus, + .sa_flags = SA_SIGINFO + }; + + if (sigaction(SIGBUS, &sa, NULL) < 0) { + perror("sigaction"); + return EXIT_FAILURE; + } + + asm volatile("adr %0, 1f + 2\n\t" + "str %0, %1\n\t" + "bx %0\n" + "1:" + : "=&r"(tmp), "=m"(expected)); + + /* + * From v8, it is CONSTRAINED UNPREDICTABLE whether BXWritePC aligns + * the address or not. If so, we can legitimately fall through. + */ + return EXIT_SUCCESS; +} |