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 -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl0sgoUZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3m8UEAClHrOpyfFdOdlkjh6QTvvE dxsKVVtQ7hy0pH98LA9QrFwLq5e8N+RpJQfPipKgoQ1l/I/l1/1KV41R38mubcdB CcJTOX/BZuC8I9IHOX1oA9UJh9WMrEL/52lhYuzFD03mWPS28nUO8jRsM9pqYJ/3 KRNy20t0G13omq+BVPlj974J2SCHS2cJ67l3FPkxm1c+VR3MWPb2I3U30w9HRxCj 9so+QSw4cJ6lU5uJU/zXcsyFWR0h8p0lNZ6yfKtsm8mxqgKdNSKnNa7yLP+ODEBe GFDkOrTLrZcTU9Dw9IocRYBOZeFoRJdlkVVPeOju7eX8W4CdvKf2MxLaJu7uT+Qj CB3+kBJ1cCMDWW+JSlXuDRl9Uvk/a28AAT8LdWbjjKKcVZvGlONKb7o6vhsPPcjY YKTrbwac+D287f2RKrUv5aVcNr/9bd+bEpkqFBayz+hoJU1xfji+wiSOL1hbzWeD isuFrBphscAKdM7i7+Pn/wiL8jy428ZwVh7+SaR1WBqtOyk8BaC3vBPOlwacun94 US2WYVXuQRFfZPQSTf3ZWatcK4aelZJqlFZkGDtBfHyWRFOuG2HEKtA24BuU9mex U6e69gvNJfAKpaZ3bsNpAzW+1RGtn7ztVw0BkICPiiEMfc/ivGa9T0VJF9IEbMUY 2rAh/QP0g5rwla4hSa3AwQ== =1077 -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
0dc6284710
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue