diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-07-15 14:42:43 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-07-15 14:42:43 +0100 |
commit | 0dc6284710afa2342fbe3932f4a73c41204da8e9 (patch) | |
tree | 3fbe2604b708932aba655431f22b916af99a4808 | |
parent | b9404bf592e7ba74180e1a54ed7a266ec6ee67f2 (diff) | |
parent | 51c9122e92b776a3f16af0b9282f1dc5012e2a19 (diff) |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190715' into staging
target-arm queue:
* report ARMv8-A FP support for AArch32 -cpu max
* hw/ssi/xilinx_spips: Avoid AXI writes to the LQSPI linear memory
* hw/ssi/xilinx_spips: Avoid out-of-bound access to lqspi_buf[]
* hw/ssi/mss-spi: Avoid crash when reading empty RX FIFO
* hw/display/xlnx_dp: Avoid crash when reading empty RX FIFO
* hw/arm/virt: Fix non-secure flash mode
* pl031: Correctly migrate state when using -rtc clock=host
* fix regression that meant arm926 and arm1026 lost VFP
double-precision support
* v8M: NS BusFault on vector table fetch escalates to NS HardFault
# gpg: Signature made Mon 15 Jul 2019 14:41:25 BST
# 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]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20190715:
target/arm: NS BusFault on vector table fetch escalates to NS HardFault
target/arm: Set VFP-related MVFR0 fields for arm926 and arm1026
pl031: Correctly migrate state when using -rtc clock=host
hw/arm/virt: Fix non-secure flash mode
hw/display/xlnx_dp: Avoid crash when reading empty RX FIFO
hw/ssi/mss-spi: Avoid crash when reading empty RX FIFO
hw/ssi/xilinx_spips: Avoid out-of-bound access to lqspi_buf[]
hw/ssi/xilinx_spips: Avoid AXI writes to the LQSPI linear memory
hw/ssi/xilinx_spips: Convert lqspi_read() to read_with_attrs
target/arm: report ARMv8-A FP support for AArch32 -cpu max
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/arm/virt.c | 2 | ||||
-rw-r--r-- | hw/core/machine.c | 1 | ||||
-rw-r--r-- | hw/display/xlnx_dp.c | 15 | ||||
-rw-r--r-- | hw/ssi/mss-spi.c | 8 | ||||
-rw-r--r-- | hw/ssi/xilinx_spips.c | 43 | ||||
-rw-r--r-- | hw/timer/pl031.c | 92 | ||||
-rw-r--r-- | include/hw/timer/pl031.h | 2 | ||||
-rw-r--r-- | target/arm/cpu.c | 16 | ||||
-rw-r--r-- | target/arm/m_helper.c | 21 |
9 files changed, 174 insertions, 26 deletions
diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 0b5138cb22..d9496c9363 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1674,7 +1674,7 @@ static void machvirt_init(MachineState *machine) &machine->device_memory->mr); } - virt_flash_fdt(vms, sysmem, secure_sysmem); + virt_flash_fdt(vms, sysmem, secure_sysmem ?: sysmem); create_gic(vms, pic); diff --git a/hw/core/machine.c b/hw/core/machine.c index c4ead16010..c58a8e594e 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -35,6 +35,7 @@ GlobalProperty hw_compat_4_0[] = { { "virtio-gpu-pci", "edid", "false" }, { "virtio-device", "use-started", "false" }, { "virtio-balloon-device", "qemu-4-0-config-size", "true" }, + { "pl031", "migrate-tick-offset", "false" }, }; const size_t hw_compat_4_0_len = G_N_ELEMENTS(hw_compat_4_0); diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index cfd4c700b7..cc5b650df0 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -427,11 +427,18 @@ static uint8_t xlnx_dp_aux_pop_rx_fifo(XlnxDPState *s) uint8_t ret; if (fifo8_is_empty(&s->rx_fifo)) { - DPRINTF("rx_fifo underflow..\n"); - abort(); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Reading empty RX_FIFO\n", + __func__); + /* + * The datasheet is not clear about the reset value, it seems + * to be unspecified. We choose to return '0'. + */ + ret = 0; + } else { + ret = fifo8_pop(&s->rx_fifo); + DPRINTF("pop 0x%" PRIX8 " from rx_fifo.\n", ret); } - ret = fifo8_pop(&s->rx_fifo); - DPRINTF("pop 0x%" PRIX8 " from rx_fifo.\n", ret); return ret; } diff --git a/hw/ssi/mss-spi.c b/hw/ssi/mss-spi.c index 918b1f3e82..4c9da5d2b2 100644 --- a/hw/ssi/mss-spi.c +++ b/hw/ssi/mss-spi.c @@ -165,7 +165,13 @@ spi_read(void *opaque, hwaddr addr, unsigned int size) case R_SPI_RX: s->regs[R_SPI_STATUS] &= ~S_RXFIFOFUL; s->regs[R_SPI_STATUS] &= ~S_RXCHOVRF; - ret = fifo32_pop(&s->rx_fifo); + if (fifo32_is_empty(&s->rx_fifo)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Reading empty RX_FIFO\n", + __func__); + } else { + ret = fifo32_pop(&s->rx_fifo); + } if (fifo32_is_empty(&s->rx_fifo)) { s->regs[R_SPI_STATUS] |= S_RXFIFOEMP; } diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 8115bb6d46..b29e0a4a89 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -1202,28 +1202,47 @@ static void lqspi_load_cache(void *opaque, hwaddr addr) } } -static uint64_t -lqspi_read(void *opaque, hwaddr addr, unsigned int size) +static MemTxResult lqspi_read(void *opaque, hwaddr addr, uint64_t *value, + unsigned size, MemTxAttrs attrs) { - XilinxQSPIPS *q = opaque; - uint32_t ret; + XilinxQSPIPS *q = XILINX_QSPIPS(opaque); if (addr >= q->lqspi_cached_addr && addr <= q->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) { uint8_t *retp = &q->lqspi_buf[addr - q->lqspi_cached_addr]; - ret = cpu_to_le32(*(uint32_t *)retp); - DB_PRINT_L(1, "addr: %08x, data: %08x\n", (unsigned)addr, - (unsigned)ret); - return ret; - } else { - lqspi_load_cache(opaque, addr); - return lqspi_read(opaque, addr, size); + *value = cpu_to_le32(*(uint32_t *)retp); + DB_PRINT_L(1, "addr: %08" HWADDR_PRIx ", data: %08" PRIx64 "\n", + addr, *value); + return MEMTX_OK; } + + lqspi_load_cache(opaque, addr); + return lqspi_read(opaque, addr, value, size, attrs); +} + +static MemTxResult lqspi_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size, MemTxAttrs attrs) +{ + /* + * From UG1085, Chapter 24 (Quad-SPI controllers): + * - Writes are ignored + * - AXI writes generate an external AXI slave error (SLVERR) + */ + qemu_log_mask(LOG_GUEST_ERROR, "%s Unexpected %u-bit access to 0x%" PRIx64 + " (value: 0x%" PRIx64 "\n", + __func__, size << 3, offset, value); + + return MEMTX_ERROR; } static const MemoryRegionOps lqspi_ops = { - .read = lqspi_read, + .read_with_attrs = lqspi_read, + .write_with_attrs = lqspi_write, .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, .valid = { .min_access_size = 1, .max_access_size = 4 diff --git a/hw/timer/pl031.c b/hw/timer/pl031.c index 3378084f4a..1a7e2ee06b 100644 --- a/hw/timer/pl031.c +++ b/hw/timer/pl031.c @@ -199,29 +199,94 @@ static int pl031_pre_save(void *opaque) { PL031State *s = opaque; - /* tick_offset is base_time - rtc_clock base time. Instead, we want to - * store the base time relative to the QEMU_CLOCK_VIRTUAL for backwards-compatibility. */ + /* + * The PL031 device model code uses the tick_offset field, which is + * the offset between what the guest RTC should read and what the + * QEMU rtc_clock reads: + * guest_rtc = rtc_clock + tick_offset + * and so + * tick_offset = guest_rtc - rtc_clock + * + * We want to migrate this offset, which sounds straightforward. + * Unfortunately older versions of QEMU migrated a conversion of this + * offset into an offset from the vm_clock. (This was in turn an + * attempt to be compatible with even older QEMU versions, but it + * has incorrect behaviour if the rtc_clock is not the same as the + * vm_clock.) So we put the actual tick_offset into a migration + * subsection, and the backwards-compatible time-relative-to-vm_clock + * in the main migration state. + * + * Calculate base time relative to QEMU_CLOCK_VIRTUAL: + */ int64_t delta = qemu_clock_get_ns(rtc_clock) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->tick_offset_vmstate = s->tick_offset + delta / NANOSECONDS_PER_SECOND; return 0; } +static int pl031_pre_load(void *opaque) +{ + PL031State *s = opaque; + + s->tick_offset_migrated = false; + return 0; +} + static int pl031_post_load(void *opaque, int version_id) { PL031State *s = opaque; - int64_t delta = qemu_clock_get_ns(rtc_clock) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - s->tick_offset = s->tick_offset_vmstate - delta / NANOSECONDS_PER_SECOND; + /* + * If we got the tick_offset subsection, then we can just use + * the value in that. Otherwise the source is an older QEMU and + * has given us the offset from the vm_clock; convert it back to + * an offset from the rtc_clock. This will cause time to incorrectly + * go backwards compared to the host RTC, but this is unavoidable. + */ + + if (!s->tick_offset_migrated) { + int64_t delta = qemu_clock_get_ns(rtc_clock) - + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + s->tick_offset = s->tick_offset_vmstate - + delta / NANOSECONDS_PER_SECOND; + } pl031_set_alarm(s); return 0; } +static int pl031_tick_offset_post_load(void *opaque, int version_id) +{ + PL031State *s = opaque; + + s->tick_offset_migrated = true; + return 0; +} + +static bool pl031_tick_offset_needed(void *opaque) +{ + PL031State *s = opaque; + + return s->migrate_tick_offset; +} + +static const VMStateDescription vmstate_pl031_tick_offset = { + .name = "pl031/tick-offset", + .version_id = 1, + .minimum_version_id = 1, + .needed = pl031_tick_offset_needed, + .post_load = pl031_tick_offset_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(tick_offset, PL031State), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_pl031 = { .name = "pl031", .version_id = 1, .minimum_version_id = 1, .pre_save = pl031_pre_save, + .pre_load = pl031_pre_load, .post_load = pl031_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32(tick_offset_vmstate, PL031State), @@ -231,14 +296,33 @@ static const VMStateDescription vmstate_pl031 = { VMSTATE_UINT32(im, PL031State), VMSTATE_UINT32(is, PL031State), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription*[]) { + &vmstate_pl031_tick_offset, + NULL } }; +static Property pl031_properties[] = { + /* + * True to correctly migrate the tick offset of the RTC. False to + * obtain backward migration compatibility with older QEMU versions, + * at the expense of the guest RTC going backwards compared with the + * host RTC when the VM is saved/restored if using -rtc host. + * (Even if set to 'true' older QEMU can migrate forward to newer QEMU; + * 'false' also permits newer QEMU to migrate to older QEMU.) + */ + DEFINE_PROP_BOOL("migrate-tick-offset", + PL031State, migrate_tick_offset, true), + DEFINE_PROP_END_OF_LIST() +}; + static void pl031_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &vmstate_pl031; + dc->props = pl031_properties; } static const TypeInfo pl031_info = { diff --git a/include/hw/timer/pl031.h b/include/hw/timer/pl031.h index 8857c24ca5..8c3f555ee2 100644 --- a/include/hw/timer/pl031.h +++ b/include/hw/timer/pl031.h @@ -33,6 +33,8 @@ typedef struct PL031State { */ uint32_t tick_offset_vmstate; uint32_t tick_offset; + bool tick_offset_migrated; + bool migrate_tick_offset; uint32_t mr; uint32_t lr; diff --git a/target/arm/cpu.c b/target/arm/cpu.c index e75a64a25a..1959467fdc 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1666,6 +1666,12 @@ static void arm926_initfn(Object *obj) * set the field to indicate Jazelle support within QEMU. */ cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); + /* + * Similarly, we need to set MVFR0 fields to enable double precision + * and short vector support even though ARMv5 doesn't have this register. + */ + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); } static void arm946_initfn(Object *obj) @@ -1702,6 +1708,12 @@ static void arm1026_initfn(Object *obj) * set the field to indicate Jazelle support within QEMU. */ cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); + /* + * Similarly, we need to set MVFR0 fields to enable double precision + * and short vector support even though ARMv5 doesn't have this register. + */ + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1); { /* The 1026 had an IFAR at c6,c0,0,1 rather than the ARMv6 c6,c0,0,2 */ @@ -2452,6 +2464,10 @@ static void arm_max_initfn(Object *obj) t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); cpu->isar.id_isar6 = t; + t = cpu->isar.mvfr1; + t = FIELD_DP32(t, MVFR1, FPHP, 2); /* v8.0 FP support */ + cpu->isar.mvfr1 = t; + t = cpu->isar.mvfr2; t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 1867435db7..84609f446e 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -624,7 +624,11 @@ static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure, if (sattrs.ns) { attrs.secure = false; } else if (!targets_secure) { - /* NS access to S memory */ + /* + * NS access to S memory: the underlying exception which we escalate + * to HardFault is SecureFault, which always targets Secure. + */ + exc_secure = true; goto load_fail; } } @@ -632,6 +636,11 @@ static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure, vector_entry = address_space_ldl(arm_addressspace(cs, attrs), addr, attrs, &result); if (result != MEMTX_OK) { + /* + * Underlying exception is BusFault: its target security state + * depends on BFHFNMINS. + */ + exc_secure = !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK); goto load_fail; } *pvec = vector_entry; @@ -641,13 +650,17 @@ load_fail: /* * All vector table fetch fails are reported as HardFault, with * HFSR.VECTTBL and .FORCED set. (FORCED is set because - * technically the underlying exception is a MemManage or BusFault + * technically the underlying exception is a SecureFault or BusFault * that is escalated to HardFault.) This is a terminal exception, * so we will either take the HardFault immediately or else enter * lockup (the latter case is handled in armv7m_nvic_set_pending_derived()). + * The HardFault is Secure if BFHFNMINS is 0 (meaning that all HFs are + * secure); otherwise it targets the same security state as the + * underlying exception. */ - exc_secure = targets_secure || - !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK); + if (!(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) { + exc_secure = true; + } env->v7m.hfsr |= R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK; armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secure); return false; |