aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-07-15 14:42:43 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-07-15 14:42:43 +0100
commit0dc6284710afa2342fbe3932f4a73c41204da8e9 (patch)
tree3fbe2604b708932aba655431f22b916af99a4808
parentb9404bf592e7ba74180e1a54ed7a266ec6ee67f2 (diff)
parent51c9122e92b776a3f16af0b9282f1dc5012e2a19 (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.c2
-rw-r--r--hw/core/machine.c1
-rw-r--r--hw/display/xlnx_dp.c15
-rw-r--r--hw/ssi/mss-spi.c8
-rw-r--r--hw/ssi/xilinx_spips.c43
-rw-r--r--hw/timer/pl031.c92
-rw-r--r--include/hw/timer/pl031.h2
-rw-r--r--target/arm/cpu.c16
-rw-r--r--target/arm/m_helper.c21
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;