target-arm:

* new "unimplemented" device for stubbing out devices in a
    system model so accesses can be logged
  * stellaris: document the SoC memory map
  * arm: create instruction syndromes for AArch32 data aborts
  * arm: Correctly handle watchpoints for BE32 CPUs
  * Fix Thumb-1 BE32 execution and disassembly
  * arm: Add cfgend parameter for ARM CPU selection
  * sd: sdhci: check data length during dma_memory_read
  * aspeed: add a watchdog controller
  * integratorcp: adding vmstate for save/restore
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJYmh3zAAoJEDwlJe0UNgzeZF0P/0v1AomIyNLaJ8Xyr6/9Ia9L
 xn8jYsACWyT3AQ4BXdmaGXg24+wPVT4X36wzTNS50s4a3R4VWxaqu+9bxAKVtyfH
 Y1CIXIib5Gz9FyY1n5pvpj7b438h4QtNbgvb/0vJoECk2F99QjEQxX+XJlCGGAGi
 J8O/L2cfrzZUXLfRZQW1VfcIkgLvlGo1A489/MFYQuv+irzJckHmnY3LeqrRfKCB
 udYbaaAdtCiPQ/OlCzsDXucjOXBMqrGba+f3g+P4xmtDPYTlSvvOjFroR54v9xa8
 n8qLLelEiH8uhW3vl8aeEsdPMV3yrX2yz0HzMqhzXTajJJs8wxECtvYKWaSzosKP
 64pbSlHD8iwl1oHJ+ZOlwaCpAcaVnBLwz65VSB6EUxAGPpeFqp0q6uATc7t9dO3o
 PRAijt5IrNpKHehTmcZ1bAsO59KeCBFwMyGL8clX2jD1Vjj8zD9CrkCDL4tpJlsL
 uGHn9RyywsWcMGsjpP6JXo3uYMK1Wbozt0XRnWWex+wsW3qOdCHVGIhXyyDJBLMD
 +r+hc49//GA58GtdTDVsU/qI4NgLfVSp2qk4lKlYVu1kxp5azPs2OpRn44Hv6YID
 2VmepX4ug/pfJ0y2AHyYuJEO+auHKzunjDCrnrBqQEMrON2hmvqtHnS/G496+lIG
 146ctV+2sSPz2vxOvTwf
 =dbln
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20170207-1' into staging

target-arm:
 * new "unimplemented" device for stubbing out devices in a
   system model so accesses can be logged
 * stellaris: document the SoC memory map
 * arm: create instruction syndromes for AArch32 data aborts
 * arm: Correctly handle watchpoints for BE32 CPUs
 * Fix Thumb-1 BE32 execution and disassembly
 * arm: Add cfgend parameter for ARM CPU selection
 * sd: sdhci: check data length during dma_memory_read
 * aspeed: add a watchdog controller
 * integratorcp: adding vmstate for save/restore

# gpg: Signature made Tue 07 Feb 2017 19:20:19 GMT
# gpg:                using RSA key 0x3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>"
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20170207-1:
  stellaris: Use the 'unimplemented' device for parts we don't implement
  hw/misc: New "unimplemented" sysbus device
  stellaris: Document memory map and which SoC devices are unimplemented
  target/arm: A32, T32: Create Instruction Syndromes for Data Aborts
  target/arm: Abstract out pbit/wbit tests in ARM ldr/str decode
  arm: Correctly handle watchpoints for BE32 CPUs
  Fix Thumb-1 BE32 execution and disassembly.
  target/arm: Add cfgend parameter for ARM CPU selection.
  hw/arm/integratorcp: Support specifying features via -cpu
  sd: sdhci: check data length during dma_memory_read
  aspeed: add a watchdog controller
  wdt: Add Aspeed watchdog device model
  integratorcp: adding vmstate for save/restore

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-02-07 19:21:30 +00:00
commit f073cd3a2b
24 changed files with 801 additions and 70 deletions

View File

@ -190,6 +190,7 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
s.cpu = cpu;
s.info.read_memory_func = target_read_memory;
s.info.read_memory_inner_func = NULL;
s.info.buffer_vma = code;
s.info.buffer_length = size;
s.info.print_address_func = generic_print_address;

1
exec.c
View File

@ -2115,6 +2115,7 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
return;
}
vaddr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
vaddr = cc->adjust_watchpoint_address(cpu, vaddr, len);
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
if (cpu_watchpoint_address_matches(wp, vaddr, len)
&& (wp->flags & flags)) {

View File

@ -31,6 +31,7 @@
#define ASPEED_SOC_SCU_BASE 0x1E6E2000
#define ASPEED_SOC_SRAM_BASE 0x1E720000
#define ASPEED_SOC_TIMER_BASE 0x1E782000
#define ASPEED_SOC_WDT_BASE 0x1E785000
#define ASPEED_SOC_I2C_BASE 0x1E78A000
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
@ -170,6 +171,10 @@ static void aspeed_soc_init(Object *obj)
sc->info->silicon_rev);
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
"ram-size", &error_abort);
object_initialize(&s->wdt, sizeof(s->wdt), TYPE_ASPEED_WDT);
object_property_add_child(obj, "wdt", OBJECT(&s->wdt), NULL);
qdev_set_parent_bus(DEVICE(&s->wdt), sysbus_get_default());
}
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
@ -286,6 +291,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
/* Watch dog */
object_property_set_bool(OBJECT(&s->wdt), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, ASPEED_SOC_WDT_BASE);
}
static void aspeed_soc_class_init(ObjectClass *oc, void *data)

View File

@ -53,6 +53,26 @@ static uint8_t integrator_spd[128] = {
0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
};
static const VMStateDescription vmstate_integratorcm = {
.name = "integratorcm",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(cm_osc, IntegratorCMState),
VMSTATE_UINT32(cm_ctrl, IntegratorCMState),
VMSTATE_UINT32(cm_lock, IntegratorCMState),
VMSTATE_UINT32(cm_auxosc, IntegratorCMState),
VMSTATE_UINT32(cm_sdram, IntegratorCMState),
VMSTATE_UINT32(cm_init, IntegratorCMState),
VMSTATE_UINT32(cm_flags, IntegratorCMState),
VMSTATE_UINT32(cm_nvflags, IntegratorCMState),
VMSTATE_UINT32(int_level, IntegratorCMState),
VMSTATE_UINT32(irq_enabled, IntegratorCMState),
VMSTATE_UINT32(fiq_enabled, IntegratorCMState),
VMSTATE_END_OF_LIST()
}
};
static uint64_t integratorcm_read(void *opaque, hwaddr offset,
unsigned size)
{
@ -309,6 +329,18 @@ typedef struct icp_pic_state {
qemu_irq parent_fiq;
} icp_pic_state;
static const VMStateDescription vmstate_icp_pic = {
.name = "icp_pic",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(level, icp_pic_state),
VMSTATE_UINT32(irq_enabled, icp_pic_state),
VMSTATE_UINT32(fiq_enabled, icp_pic_state),
VMSTATE_END_OF_LIST()
}
};
static void icp_pic_update(icp_pic_state *s)
{
uint32_t flags;
@ -438,6 +470,16 @@ typedef struct ICPCtrlRegsState {
#define ICP_INTREG_WPROT (1 << 0)
#define ICP_INTREG_CARDIN (1 << 3)
static const VMStateDescription vmstate_icp_control = {
.name = "icp_control",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(intreg_state, ICPCtrlRegsState),
VMSTATE_END_OF_LIST()
}
};
static uint64_t icp_control_read(void *opaque, hwaddr offset,
unsigned size)
{
@ -535,27 +577,42 @@ static void integratorcp_init(MachineState *machine)
const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
const char *initrd_filename = machine->initrd_filename;
char **cpustr;
ObjectClass *cpu_oc;
CPUClass *cc;
Object *cpuobj;
ARMCPU *cpu;
const char *typename;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
qemu_irq pic[32];
DeviceState *dev, *sic, *icp;
int i;
Error *err = NULL;
if (!cpu_model) {
cpu_model = "arm926";
}
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
cpustr = g_strsplit(cpu_model, ",", 2);
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
if (!cpu_oc) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
typename = object_class_get_name(cpu_oc);
cpuobj = object_new(object_class_get_name(cpu_oc));
cc = CPU_CLASS(cpu_oc);
cc->parse_features(typename, cpustr[1], &err);
g_strfreev(cpustr);
if (err) {
error_report_err(err);
exit(1);
}
cpuobj = object_new(typename);
/* By default ARM1176 CPUs have EL3 enabled. This board does not
* currently support EL3 so the CPU EL3 property is disabled before
@ -640,6 +697,21 @@ static void core_class_init(ObjectClass *klass, void *data)
dc->props = core_properties;
dc->realize = integratorcm_realize;
dc->vmsd = &vmstate_integratorcm;
}
static void icp_pic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_icp_pic;
}
static void icp_control_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_icp_control;
}
static const TypeInfo core_info = {
@ -655,6 +727,7 @@ static const TypeInfo icp_pic_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(icp_pic_state),
.instance_init = icp_pic_init,
.class_init = icp_pic_class_init,
};
static const TypeInfo icp_ctrl_regs_info = {
@ -662,6 +735,7 @@ static const TypeInfo icp_ctrl_regs_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ICPCtrlRegsState),
.instance_init = icp_control_init,
.class_init = icp_control_class_init,
};
static void integratorcp_register_types(void)

View File

@ -21,6 +21,7 @@
#include "exec/address-spaces.h"
#include "sysemu/sysemu.h"
#include "hw/char/pl011.h"
#include "hw/misc/unimp.h"
#define GPIO_A 0
#define GPIO_B 1
@ -1220,6 +1221,40 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
0x40024000, 0x40025000, 0x40026000};
static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
/* Memory map of SoC devices, from
* Stellaris LM3S6965 Microcontroller Data Sheet (rev I)
* http://www.ti.com/lit/ds/symlink/lm3s6965.pdf
*
* 40000000 wdtimer (unimplemented)
* 40002000 i2c (unimplemented)
* 40004000 GPIO
* 40005000 GPIO
* 40006000 GPIO
* 40007000 GPIO
* 40008000 SSI
* 4000c000 UART
* 4000d000 UART
* 4000e000 UART
* 40020000 i2c
* 40021000 i2c (unimplemented)
* 40024000 GPIO
* 40025000 GPIO
* 40026000 GPIO
* 40028000 PWM (unimplemented)
* 4002c000 QEI (unimplemented)
* 4002d000 QEI (unimplemented)
* 40030000 gptimer
* 40031000 gptimer
* 40032000 gptimer
* 40033000 gptimer
* 40038000 ADC
* 4003c000 analogue comparator (unimplemented)
* 40048000 ethernet
* 400fc000 hibernation module (unimplemented)
* 400fd000 flash memory control (unimplemented)
* 400fe000 system control
*/
DeviceState *gpio_dev[7], *nvic;
qemu_irq gpio_in[7][8];
qemu_irq gpio_out[7][8];
@ -1370,6 +1405,19 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
}
}
}
/* Add dummy regions for the devices we don't implement yet,
* so guest accesses don't cause unlogged crashes.
*/
create_unimplemented_device("wdtimer", 0x40000000, 0x1000);
create_unimplemented_device("i2c-0", 0x40002000, 0x1000);
create_unimplemented_device("i2c-2", 0x40021000, 0x1000);
create_unimplemented_device("PWM", 0x40028000, 0x1000);
create_unimplemented_device("QEI-0", 0x4002c000, 0x1000);
create_unimplemented_device("QEI-1", 0x4002d000, 0x1000);
create_unimplemented_device("analogue-comparator", 0x4003c000, 0x1000);
create_unimplemented_device("hibernation", 0x400fc000, 0x1000);
create_unimplemented_device("flash-control", 0x400fd000, 0x1000);
}
/* FIXME: Figure out how to generate these from stellaris_boards. */

View File

@ -6,6 +6,8 @@ common-obj-$(CONFIG_SGA) += sga.o
common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o
common-obj-y += unimp.o
obj-$(CONFIG_VMPORT) += vmport.o
# ARM devices

107
hw/misc/unimp.c Normal file
View File

@ -0,0 +1,107 @@
/* "Unimplemented" device
*
* This is a dummy device which accepts and logs all accesses.
* It's useful for stubbing out regions of an SoC or board
* map which correspond to devices that have not yet been
* implemented. This is often sufficient to placate initial
* guest device driver probing such that the system will
* come up.
*
* Copyright Linaro Limited, 2017
* Written by Peter Maydell
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/misc/unimp.h"
#include "qemu/log.h"
#include "qapi/error.h"
#define UNIMPLEMENTED_DEVICE(obj) \
OBJECT_CHECK(UnimplementedDeviceState, (obj), TYPE_UNIMPLEMENTED_DEVICE)
typedef struct {
SysBusDevice parent_obj;
MemoryRegion iomem;
char *name;
uint64_t size;
} UnimplementedDeviceState;
static uint64_t unimp_read(void *opaque, hwaddr offset, unsigned size)
{
UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque);
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
"(size %d, offset 0x%" HWADDR_PRIx ")\n",
s->name, size, offset);
return 0;
}
static void unimp_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque);
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
"(size %d, value 0x%" PRIx64
", offset 0x%" HWADDR_PRIx ")\n",
s->name, size, value, offset);
}
static const MemoryRegionOps unimp_ops = {
.read = unimp_read,
.write = unimp_write,
.impl.min_access_size = 1,
.impl.max_access_size = 8,
.valid.min_access_size = 1,
.valid.max_access_size = 8,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void unimp_realize(DeviceState *dev, Error **errp)
{
UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(dev);
if (s->size == 0) {
error_setg(errp, "property 'size' not specified or zero");
return;
}
if (s->name == NULL) {
error_setg(errp, "property 'name' not specified");
return;
}
memory_region_init_io(&s->iomem, OBJECT(s), &unimp_ops, s,
s->name, s->size);
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
}
static Property unimp_properties[] = {
DEFINE_PROP_UINT64("size", UnimplementedDeviceState, size, 0),
DEFINE_PROP_STRING("name", UnimplementedDeviceState, name),
DEFINE_PROP_END_OF_LIST(),
};
static void unimp_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = unimp_realize;
dc->props = unimp_properties;
}
static const TypeInfo unimp_info = {
.name = TYPE_UNIMPLEMENTED_DEVICE,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(UnimplementedDeviceState),
.class_init = unimp_class_init,
};
static void unimp_register_types(void)
{
type_register_static(&unimp_info);
}
type_init(unimp_register_types)

View File

@ -536,7 +536,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
boundary_count -= block_size - begin;
}
dma_memory_read(&address_space_memory, s->sdmasysad,
&s->fifo_buffer[begin], s->data_count);
&s->fifo_buffer[begin], s->data_count - begin);
s->sdmasysad += s->data_count - begin;
if (s->data_count == block_size) {
for (n = 0; n < block_size; n++) {

View File

@ -2,3 +2,4 @@ common-obj-y += watchdog.o
common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o
common-obj-$(CONFIG_ASPEED_SOC) += wdt_aspeed.o

225
hw/watchdog/wdt_aspeed.c Normal file
View File

@ -0,0 +1,225 @@
/*
* ASPEED Watchdog Controller
*
* Copyright (C) 2016-2017 IBM Corp.
*
* This code is licensed under the GPL version 2 or later. See the
* COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "sysemu/watchdog.h"
#include "hw/sysbus.h"
#include "qemu/timer.h"
#include "hw/watchdog/wdt_aspeed.h"
#define WDT_STATUS (0x00 / 4)
#define WDT_RELOAD_VALUE (0x04 / 4)
#define WDT_RESTART (0x08 / 4)
#define WDT_CTRL (0x0C / 4)
#define WDT_CTRL_RESET_MODE_SOC (0x00 << 5)
#define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5)
#define WDT_CTRL_1MHZ_CLK BIT(4)
#define WDT_CTRL_WDT_EXT BIT(3)
#define WDT_CTRL_WDT_INTR BIT(2)
#define WDT_CTRL_RESET_SYSTEM BIT(1)
#define WDT_CTRL_ENABLE BIT(0)
#define WDT_TIMEOUT_STATUS (0x10 / 4)
#define WDT_TIMEOUT_CLEAR (0x14 / 4)
#define WDT_RESET_WDITH (0x18 / 4)
#define WDT_RESTART_MAGIC 0x4755
static bool aspeed_wdt_is_enabled(const AspeedWDTState *s)
{
return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE;
}
static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size)
{
AspeedWDTState *s = ASPEED_WDT(opaque);
offset >>= 2;
switch (offset) {
case WDT_STATUS:
return s->regs[WDT_STATUS];
case WDT_RELOAD_VALUE:
return s->regs[WDT_RELOAD_VALUE];
case WDT_RESTART:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: read from write-only reg at offset 0x%"
HWADDR_PRIx "\n", __func__, offset);
return 0;
case WDT_CTRL:
return s->regs[WDT_CTRL];
case WDT_TIMEOUT_STATUS:
case WDT_TIMEOUT_CLEAR:
case WDT_RESET_WDITH:
qemu_log_mask(LOG_UNIMP,
"%s: uninmplemented read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return 0;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return 0;
}
}
static void aspeed_wdt_reload(AspeedWDTState *s, bool pclk)
{
uint32_t reload;
if (pclk) {
reload = muldiv64(s->regs[WDT_RELOAD_VALUE], NANOSECONDS_PER_SECOND,
s->pclk_freq);
} else {
reload = s->regs[WDT_RELOAD_VALUE] * 1000;
}
if (aspeed_wdt_is_enabled(s)) {
timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + reload);
}
}
static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size)
{
AspeedWDTState *s = ASPEED_WDT(opaque);
bool enable = data & WDT_CTRL_ENABLE;
offset >>= 2;
switch (offset) {
case WDT_STATUS:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: write to read-only reg at offset 0x%"
HWADDR_PRIx "\n", __func__, offset);
break;
case WDT_RELOAD_VALUE:
s->regs[WDT_RELOAD_VALUE] = data;
break;
case WDT_RESTART:
if ((data & 0xFFFF) == WDT_RESTART_MAGIC) {
s->regs[WDT_STATUS] = s->regs[WDT_RELOAD_VALUE];
aspeed_wdt_reload(s, !(data & WDT_CTRL_1MHZ_CLK));
}
break;
case WDT_CTRL:
if (enable && !aspeed_wdt_is_enabled(s)) {
s->regs[WDT_CTRL] = data;
aspeed_wdt_reload(s, !(data & WDT_CTRL_1MHZ_CLK));
} else if (!enable && aspeed_wdt_is_enabled(s)) {
s->regs[WDT_CTRL] = data;
timer_del(s->timer);
}
break;
case WDT_TIMEOUT_STATUS:
case WDT_TIMEOUT_CLEAR:
case WDT_RESET_WDITH:
qemu_log_mask(LOG_UNIMP,
"%s: uninmplemented write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
}
return;
}
static WatchdogTimerModel model = {
.wdt_name = TYPE_ASPEED_WDT,
.wdt_description = "Aspeed watchdog device",
};
static const VMStateDescription vmstate_aspeed_wdt = {
.name = "vmstate_aspeed_wdt",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_TIMER_PTR(timer, AspeedWDTState),
VMSTATE_UINT32_ARRAY(regs, AspeedWDTState, ASPEED_WDT_REGS_MAX),
VMSTATE_END_OF_LIST()
}
};
static const MemoryRegionOps aspeed_wdt_ops = {
.read = aspeed_wdt_read,
.write = aspeed_wdt_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid.min_access_size = 4,
.valid.max_access_size = 4,
.valid.unaligned = false,
};
static void aspeed_wdt_reset(DeviceState *dev)
{
AspeedWDTState *s = ASPEED_WDT(dev);
s->regs[WDT_STATUS] = 0x3EF1480;
s->regs[WDT_RELOAD_VALUE] = 0x03EF1480;
s->regs[WDT_RESTART] = 0;
s->regs[WDT_CTRL] = 0;
timer_del(s->timer);
}
static void aspeed_wdt_timer_expired(void *dev)
{
AspeedWDTState *s = ASPEED_WDT(dev);
qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
watchdog_perform_action();
timer_del(s->timer);
}
#define PCLK_HZ 24000000
static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedWDTState *s = ASPEED_WDT(dev);
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev);
/* FIXME: This setting should be derived from the SCU hw strapping
* register SCU70
*/
s->pclk_freq = PCLK_HZ;
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_wdt_ops, s,
TYPE_ASPEED_WDT, ASPEED_WDT_REGS_MAX * 4);
sysbus_init_mmio(sbd, &s->iomem);
}
static void aspeed_wdt_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_wdt_realize;
dc->reset = aspeed_wdt_reset;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->vmsd = &vmstate_aspeed_wdt;
}
static const TypeInfo aspeed_wdt_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.name = TYPE_ASPEED_WDT,
.instance_size = sizeof(AspeedWDTState),
.class_init = aspeed_wdt_class_init,
};
static void wdt_aspeed_register_types(void)
{
watchdog_add_model(&model);
type_register_static(&aspeed_wdt_info);
}
type_init(wdt_aspeed_register_types)

View File

@ -295,6 +295,7 @@ typedef struct disassemble_info {
The bottom 16 bits are for the internal use of the disassembler. */
unsigned long flags;
#define INSN_HAS_RELOC 0x80000000
#define INSN_ARM_BE32 0x00010000
PTR private_data;
/* Function used to get bytes to disassemble. MEMADDR is the
@ -306,6 +307,12 @@ typedef struct disassemble_info {
(bfd_vma memaddr, bfd_byte *myaddr, int length,
struct disassemble_info *info);
/* A place to stash the real read_memory_func if read_memory_func wants to
do some funky address arithmetic or similar (e.g. for ARM BE32 mode). */
int (*read_memory_inner_func)
(bfd_vma memaddr, bfd_byte *myaddr, int length,
struct disassemble_info *info);
/* Function which should be called if we get an error that we can't
recover from. STATUS is the errno value from read_memory_func and
MEMADDR is the address that we were trying to read. INFO is a

View File

@ -19,6 +19,7 @@
#include "hw/timer/aspeed_timer.h"
#include "hw/i2c/aspeed_i2c.h"
#include "hw/ssi/aspeed_smc.h"
#include "hw/watchdog/wdt_aspeed.h"
#define ASPEED_SPIS_NUM 2
@ -37,6 +38,7 @@ typedef struct AspeedSoCState {
AspeedSMCState fmc;
AspeedSMCState spi[ASPEED_SPIS_NUM];
AspeedSDMCState sdmc;
AspeedWDTState wdt;
} AspeedSoCState;
#define TYPE_ASPEED_SOC "aspeed-soc"

39
include/hw/misc/unimp.h Normal file
View File

@ -0,0 +1,39 @@
/*
* "Unimplemented" device
*
* Copyright Linaro Limited, 2017
* Written by Peter Maydell
*/
#ifndef HW_MISC_UNIMP_H
#define HW_MISC_UNIMP_H
#define TYPE_UNIMPLEMENTED_DEVICE "unimplemented-device"
/**
* create_unimplemented_device: create and map a dummy device
* @name: name of the device for debug logging
* @base: base address of the device's MMIO region
* @size: size of the device's MMIO region
*
* This utility function creates and maps an instance of unimplemented-device,
* which is a dummy device which simply logs all guest accesses to
* it via the qemu_log LOG_UNIMP debug log.
* The device is mapped at priority -1000, which means that you can
* use it to cover a large region and then map other devices on top of it
* if necessary.
*/
static inline void create_unimplemented_device(const char *name,
hwaddr base,
hwaddr size)
{
DeviceState *dev = qdev_create(NULL, TYPE_UNIMPLEMENTED_DEVICE);
qdev_prop_set_string(dev, "name", name);
qdev_prop_set_uint64(dev, "size", size);
qdev_init_nofail(dev);
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(dev), 0, base, -1000);
}
#endif

View File

@ -0,0 +1,32 @@
/*
* ASPEED Watchdog Controller
*
* Copyright (C) 2016-2017 IBM Corp.
*
* This code is licensed under the GPL version 2 or later. See the
* COPYING file in the top-level directory.
*/
#ifndef ASPEED_WDT_H
#define ASPEED_WDT_H
#include "hw/sysbus.h"
#define TYPE_ASPEED_WDT "aspeed.wdt"
#define ASPEED_WDT(obj) \
OBJECT_CHECK(AspeedWDTState, (obj), TYPE_ASPEED_WDT)
#define ASPEED_WDT_REGS_MAX (0x20 / 4)
typedef struct AspeedWDTState {
/*< private >*/
SysBusDevice parent_obj;
QEMUTimer *timer;
/*< public >*/
MemoryRegion iomem;
uint32_t regs[ASPEED_WDT_REGS_MAX];
uint32_t pclk_freq;
} AspeedWDTState;
#endif /* ASPEED_WDT_H */

View File

@ -132,6 +132,8 @@ struct TranslationBlock;
* @cpu_exec_exit: Callback for cpu_exec cleanup.
* @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec.
* @disas_set_info: Setup architecture specific components of disassembly info
* @adjust_watchpoint_address: Perform a target-specific adjustment to an
* address before attempting to match it against watchpoints.
*
* Represents a CPU family or model.
*/
@ -195,6 +197,7 @@ typedef struct CPUClass {
bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
void (*disas_set_info)(CPUState *cpu, disassemble_info *info);
vaddr (*adjust_watchpoint_address)(CPUState *cpu, vaddr addr, int len);
} CPUClass;
#ifdef HOST_WORDS_BIGENDIAN

View File

@ -391,6 +391,11 @@ static int64_t cpu_common_get_arch_id(CPUState *cpu)
return cpu->cpu_index;
}
static vaddr cpu_adjust_watchpoint_address(CPUState *cpu, vaddr addr, int len)
{
return addr;
}
static void cpu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@ -415,6 +420,7 @@ static void cpu_class_init(ObjectClass *klass, void *data)
k->cpu_exec_enter = cpu_common_noop;
k->cpu_exec_exit = cpu_common_noop;
k->cpu_exec_interrupt = cpu_common_exec_interrupt;
k->adjust_watchpoint_address = cpu_adjust_watchpoint_address;
set_bit(DEVICE_CATEGORY_CPU, dc->categories);
dc->realize = cpu_common_realizefn;
dc->unrealize = cpu_common_unrealizefn;

View File

@ -39,7 +39,15 @@ static inline uint32_t arm_ldl_code(CPUARMState *env, target_ulong addr,
static inline uint16_t arm_lduw_code(CPUARMState *env, target_ulong addr,
bool sctlr_b)
{
uint16_t insn = cpu_lduw_code(env, addr);
uint16_t insn;
#ifndef CONFIG_USER_ONLY
/* In big-endian (BE32) mode, adjacent Thumb instructions have been swapped
within each word. Undo that now. */
if (sctlr_b) {
addr ^= 2;
}
#endif
insn = cpu_lduw_code(env, addr);
if (bswap_code(sctlr_b)) {
return bswap16(insn);
}

View File

@ -446,6 +446,21 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info)
return print_insn_arm(pc | 1, info);
}
static int arm_read_memory_func(bfd_vma memaddr, bfd_byte *b,
int length, struct disassemble_info *info)
{
assert(info->read_memory_inner_func);
assert((info->flags & INSN_ARM_BE32) == 0 || length == 2 || length == 4);
if ((info->flags & INSN_ARM_BE32) != 0 && length == 2) {
assert(info->endian == BFD_ENDIAN_LITTLE);
return info->read_memory_inner_func(memaddr ^ 2, (bfd_byte *)b, 2,
info);
} else {
return info->read_memory_inner_func(memaddr, b, length, info);
}
}
static void arm_disas_set_info(CPUState *cpu, disassemble_info *info)
{
ARMCPU *ac = ARM_CPU(cpu);
@ -471,6 +486,14 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info)
info->endian = BFD_ENDIAN_BIG;
#endif
}
if (info->read_memory_inner_func == NULL) {
info->read_memory_inner_func = info->read_memory_func;
info->read_memory_func = arm_read_memory_func;
}
info->flags &= ~INSN_ARM_BE32;
if (arm_sctlr_b(env)) {
info->flags |= INSN_ARM_BE32;
}
}
static void arm_cpu_initfn(Object *obj)
@ -541,6 +564,9 @@ static Property arm_cpu_has_el2_property =
static Property arm_cpu_has_el3_property =
DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
static Property arm_cpu_cfgend_property =
DEFINE_PROP_BOOL("cfgend", ARMCPU, cfgend, false);
/* use property name "pmu" to match other archs and virt tools */
static Property arm_cpu_has_pmu_property =
DEFINE_PROP_BOOL("pmu", ARMCPU, has_pmu, true);
@ -608,6 +634,8 @@ static void arm_cpu_post_init(Object *obj)
}
}
qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property,
&error_abort);
}
static void arm_cpu_finalizefn(Object *obj)
@ -728,6 +756,14 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
cpu->reset_sctlr |= (1 << 13);
}
if (cpu->cfgend) {
if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
cpu->reset_sctlr |= SCTLR_EE;
} else {
cpu->reset_sctlr |= SCTLR_B;
}
}
if (!cpu->has_el3) {
/* If the has_el3 CPU property is disabled then we need to disable the
* feature.
@ -1639,6 +1675,9 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_stop_before_watchpoint = true;
cc->debug_excp_handler = arm_debug_excp_handler;
cc->debug_check_watchpoint = arm_debug_check_watchpoint;
#if !defined(CONFIG_USER_ONLY)
cc->adjust_watchpoint_address = arm_adjust_watchpoint_address;
#endif
cc->disas_set_info = arm_disas_set_info;
}

View File

@ -676,6 +676,13 @@ struct ARMCPU {
int gic_vpribits; /* number of virtual priority bits */
int gic_vprebits; /* number of virtual preemption bits */
/* Whether the cfgend input is high (i.e. this CPU should reset into
* big-endian mode). This setting isn't used directly: instead it modifies
* the reset_sctlr value to have SCTLR_B or SCTLR_EE set, depending on the
* architecture version.
*/
bool cfgend;
ARMELChangeHook *el_change_hook;
void *el_change_hook_opaque;
};

View File

@ -444,6 +444,11 @@ void hw_breakpoint_update_all(ARMCPU *cpu);
/* Callback function for checking if a watchpoint should trigger. */
bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp);
/* Adjust addresses (in BE32 mode) before testing against watchpoint
* addresses.
*/
vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len);
/* Callback function for when a watchpoint or breakpoint triggers. */
void arm_debug_excp_handler(CPUState *cs);

View File

@ -1225,6 +1225,28 @@ bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
return check_watchpoints(cpu);
}
vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
/* In BE32 system mode, target memory is stored byteswapped (on a
* little-endian host system), and by the time we reach here (via an
* opcode helper) the addresses of subword accesses have been adjusted
* to account for that, which means that watchpoints will not match.
* Undo the adjustment here.
*/
if (arm_sctlr_b(env)) {
if (len == 1) {
addr ^= 3;
} else if (len == 2) {
addr ^= 2;
}
}
return addr;
}
void arm_debug_excp_handler(CPUState *cs)
{
/* Called by core code when a watchpoint or breakpoint fires;

View File

@ -379,20 +379,6 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
}
}
static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
{
/* We don't need to save all of the syndrome so we mask and shift
* out uneeded bits to help the sleb128 encoder do a better job.
*/
syn &= ARM_INSN_START_WORD2_MASK;
syn >>= ARM_INSN_START_WORD2_SHIFT;
/* We check and clear insn_start_idx to catch multiple updates. */
assert(s->insn_start_idx != 0);
tcg_set_insn_param(s->insn_start_idx, 2, syn);
s->insn_start_idx = 0;
}
static void unallocated_encoding(DisasContext *s)
{
/* Unallocated and reserved encodings are uncategorized */

View File

@ -102,6 +102,49 @@ void arm_translate_init(void)
a64_translate_init();
}
/* Flags for the disas_set_da_iss info argument:
* lower bits hold the Rt register number, higher bits are flags.
*/
typedef enum ISSInfo {
ISSNone = 0,
ISSRegMask = 0x1f,
ISSInvalid = (1 << 5),
ISSIsAcqRel = (1 << 6),
ISSIsWrite = (1 << 7),
ISSIs16Bit = (1 << 8),
} ISSInfo;
/* Save the syndrome information for a Data Abort */
static void disas_set_da_iss(DisasContext *s, TCGMemOp memop, ISSInfo issinfo)
{
uint32_t syn;
int sas = memop & MO_SIZE;
bool sse = memop & MO_SIGN;
bool is_acqrel = issinfo & ISSIsAcqRel;
bool is_write = issinfo & ISSIsWrite;
bool is_16bit = issinfo & ISSIs16Bit;
int srt = issinfo & ISSRegMask;
if (issinfo & ISSInvalid) {
/* Some callsites want to conditionally provide ISS info,
* eg "only if this was not a writeback"
*/
return;
}
if (srt == 15) {
/* For AArch32, insns where the src/dest is R15 never generate
* ISS information. Catching that here saves checking at all
* the call sites.
*/
return;
}
syn = syn_data_abort_with_iss(0, sas, sse, srt, 0, is_acqrel,
0, 0, 0, is_write, 0, is_16bit);
disas_set_insn_syndrome(s, syn);
}
static inline ARMMMUIdx get_a32_user_mem_index(DisasContext *s)
{
/* Return the mmu_idx to use for A32/T32 "unprivileged load/store"
@ -933,6 +976,14 @@ static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \
TCGv_i32 a32, int index) \
{ \
gen_aa32_ld_i32(s, val, a32, index, OPC | s->be_data); \
} \
static inline void gen_aa32_ld##SUFF##_iss(DisasContext *s, \
TCGv_i32 val, \
TCGv_i32 a32, int index, \
ISSInfo issinfo) \
{ \
gen_aa32_ld##SUFF(s, val, a32, index); \
disas_set_da_iss(s, OPC, issinfo); \
}
#define DO_GEN_ST(SUFF, OPC) \
@ -940,6 +991,14 @@ static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \
TCGv_i32 a32, int index) \
{ \
gen_aa32_st_i32(s, val, a32, index, OPC | s->be_data); \
} \
static inline void gen_aa32_st##SUFF##_iss(DisasContext *s, \
TCGv_i32 val, \
TCGv_i32 a32, int index, \
ISSInfo issinfo) \
{ \
gen_aa32_st##SUFF(s, val, a32, index); \
disas_set_da_iss(s, OPC, issinfo | ISSIsWrite); \
}
static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val)
@ -8682,16 +8741,19 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
tmp = tcg_temp_new_i32();
switch (op1) {
case 0: /* lda */
gen_aa32_ld32u(s, tmp, addr,
get_mem_index(s));
gen_aa32_ld32u_iss(s, tmp, addr,
get_mem_index(s),
rd | ISSIsAcqRel);
break;
case 2: /* ldab */
gen_aa32_ld8u(s, tmp, addr,
get_mem_index(s));
gen_aa32_ld8u_iss(s, tmp, addr,
get_mem_index(s),
rd | ISSIsAcqRel);
break;
case 3: /* ldah */
gen_aa32_ld16u(s, tmp, addr,
get_mem_index(s));
gen_aa32_ld16u_iss(s, tmp, addr,
get_mem_index(s),
rd | ISSIsAcqRel);
break;
default:
abort();
@ -8702,16 +8764,19 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
tmp = load_reg(s, rm);
switch (op1) {
case 0: /* stl */
gen_aa32_st32(s, tmp, addr,
get_mem_index(s));
gen_aa32_st32_iss(s, tmp, addr,
get_mem_index(s),
rm | ISSIsAcqRel);
break;
case 2: /* stlb */
gen_aa32_st8(s, tmp, addr,
get_mem_index(s));
gen_aa32_st8_iss(s, tmp, addr,
get_mem_index(s),
rm | ISSIsAcqRel);
break;
case 3: /* stlh */
gen_aa32_st16(s, tmp, addr,
get_mem_index(s));
gen_aa32_st16_iss(s, tmp, addr,
get_mem_index(s),
rm | ISSIsAcqRel);
break;
default:
abort();
@ -8782,11 +8847,18 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
} else {
int address_offset;
bool load = insn & (1 << 20);
bool wbit = insn & (1 << 21);
bool pbit = insn & (1 << 24);
bool doubleword = false;
ISSInfo issinfo;
/* Misc load/store */
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
/* ISS not valid if writeback */
issinfo = (pbit & !wbit) ? rd : ISSInvalid;
if (!load && (sh & 2)) {
/* doubleword */
ARCH(5TE);
@ -8799,8 +8871,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
}
addr = load_reg(s, rn);
if (insn & (1 << 24))
if (pbit) {
gen_add_datah_offset(s, insn, 0, addr);
}
address_offset = 0;
if (doubleword) {
@ -8829,30 +8902,33 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
tmp = tcg_temp_new_i32();
switch (sh) {
case 1:
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s),
issinfo);
break;
case 2:
gen_aa32_ld8s(s, tmp, addr, get_mem_index(s));
gen_aa32_ld8s_iss(s, tmp, addr, get_mem_index(s),
issinfo);
break;
default:
case 3:
gen_aa32_ld16s(s, tmp, addr, get_mem_index(s));
gen_aa32_ld16s_iss(s, tmp, addr, get_mem_index(s),
issinfo);
break;
}
} else {
/* store */
tmp = load_reg(s, rd);
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), issinfo);
tcg_temp_free_i32(tmp);
}
/* Perform base writeback before the loaded value to
ensure correct behavior with overlapping index registers.
ldrd with base writeback is undefined if the
destination and index registers overlap. */
if (!(insn & (1 << 24))) {
if (!pbit) {
gen_add_datah_offset(s, insn, address_offset, addr);
store_reg(s, rn, addr);
} else if (insn & (1 << 21)) {
} else if (wbit) {
if (address_offset)
tcg_gen_addi_i32(addr, addr, address_offset);
store_reg(s, rn, addr);
@ -9195,17 +9271,17 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
/* load */
tmp = tcg_temp_new_i32();
if (insn & (1 << 22)) {
gen_aa32_ld8u(s, tmp, tmp2, i);
gen_aa32_ld8u_iss(s, tmp, tmp2, i, rd);
} else {
gen_aa32_ld32u(s, tmp, tmp2, i);
gen_aa32_ld32u_iss(s, tmp, tmp2, i, rd);
}
} else {
/* store */
tmp = load_reg(s, rd);
if (insn & (1 << 22)) {
gen_aa32_st8(s, tmp, tmp2, i);
gen_aa32_st8_iss(s, tmp, tmp2, i, rd);
} else {
gen_aa32_st32(s, tmp, tmp2, i);
gen_aa32_st32_iss(s, tmp, tmp2, i, rd);
}
tcg_temp_free_i32(tmp);
}
@ -9666,13 +9742,16 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
tmp = tcg_temp_new_i32();
switch (op) {
case 0: /* ldab */
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s),
rs | ISSIsAcqRel);
break;
case 1: /* ldah */
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s),
rs | ISSIsAcqRel);
break;
case 2: /* lda */
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s),
rs | ISSIsAcqRel);
break;
default:
abort();
@ -9682,13 +9761,16 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
tmp = load_reg(s, rs);
switch (op) {
case 0: /* stlb */
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s),
rs | ISSIsAcqRel);
break;
case 1: /* stlh */
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s),
rs | ISSIsAcqRel);
break;
case 2: /* stl */
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s),
rs | ISSIsAcqRel);
break;
default:
abort();
@ -10634,6 +10716,8 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
int postinc = 0;
int writeback = 0;
int memidx;
ISSInfo issinfo;
if ((insn & 0x01100000) == 0x01000000) {
if (disas_neon_ls_insn(s, insn)) {
goto illegal_op;
@ -10737,24 +10821,27 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
}
}
}
issinfo = writeback ? ISSInvalid : rs;
if (insn & (1 << 20)) {
/* Load. */
tmp = tcg_temp_new_i32();
switch (op) {
case 0:
gen_aa32_ld8u(s, tmp, addr, memidx);
gen_aa32_ld8u_iss(s, tmp, addr, memidx, issinfo);
break;
case 4:
gen_aa32_ld8s(s, tmp, addr, memidx);
gen_aa32_ld8s_iss(s, tmp, addr, memidx, issinfo);
break;
case 1:
gen_aa32_ld16u(s, tmp, addr, memidx);
gen_aa32_ld16u_iss(s, tmp, addr, memidx, issinfo);
break;
case 5:
gen_aa32_ld16s(s, tmp, addr, memidx);
gen_aa32_ld16s_iss(s, tmp, addr, memidx, issinfo);
break;
case 2:
gen_aa32_ld32u(s, tmp, addr, memidx);
gen_aa32_ld32u_iss(s, tmp, addr, memidx, issinfo);
break;
default:
tcg_temp_free_i32(tmp);
@ -10771,13 +10858,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
tmp = load_reg(s, rs);
switch (op) {
case 0:
gen_aa32_st8(s, tmp, addr, memidx);
gen_aa32_st8_iss(s, tmp, addr, memidx, issinfo);
break;
case 1:
gen_aa32_st16(s, tmp, addr, memidx);
gen_aa32_st16_iss(s, tmp, addr, memidx, issinfo);
break;
case 2:
gen_aa32_st32(s, tmp, addr, memidx);
gen_aa32_st32_iss(s, tmp, addr, memidx, issinfo);
break;
default:
tcg_temp_free_i32(tmp);
@ -10914,7 +11001,8 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
addr = tcg_temp_new_i32();
tcg_gen_movi_i32(addr, val);
tmp = tcg_temp_new_i32();
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s),
rd | ISSIs16Bit);
tcg_temp_free_i32(addr);
store_reg(s, rd, tmp);
break;
@ -11117,28 +11205,28 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
switch (op) {
case 0: /* str */
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
break;
case 1: /* strh */
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
break;
case 2: /* strb */
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
break;
case 3: /* ldrsb */
gen_aa32_ld8s(s, tmp, addr, get_mem_index(s));
gen_aa32_ld8s_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
break;
case 4: /* ldr */
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
break;
case 5: /* ldrh */
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
break;
case 6: /* ldrb */
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
break;
case 7: /* ldrsh */
gen_aa32_ld16s(s, tmp, addr, get_mem_index(s));
gen_aa32_ld16s_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
break;
}
if (op >= 3) { /* load */
@ -11182,12 +11270,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
if (insn & (1 << 11)) {
/* load */
tmp = tcg_temp_new_i32();
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
store_reg(s, rd, tmp);
} else {
/* store */
tmp = load_reg(s, rd);
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
tcg_temp_free_i32(tmp);
}
tcg_temp_free_i32(addr);
@ -11204,12 +11292,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
if (insn & (1 << 11)) {
/* load */
tmp = tcg_temp_new_i32();
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
store_reg(s, rd, tmp);
} else {
/* store */
tmp = load_reg(s, rd);
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
tcg_temp_free_i32(tmp);
}
tcg_temp_free_i32(addr);
@ -11225,12 +11313,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
if (insn & (1 << 11)) {
/* load */
tmp = tcg_temp_new_i32();
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
store_reg(s, rd, tmp);
} else {
/* store */
tmp = load_reg(s, rd);
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
tcg_temp_free_i32(tmp);
}
tcg_temp_free_i32(addr);
@ -11712,6 +11800,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
store_cpu_field(tmp, condexec_bits);
}
do {
dc->insn_start_idx = tcg_op_buf_count();
tcg_gen_insn_start(dc->pc,
(dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
0);

View File

@ -104,6 +104,20 @@ static inline int default_exception_el(DisasContext *s)
? 3 : MAX(1, s->current_el);
}
static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
{
/* We don't need to save all of the syndrome so we mask and shift
* out unneeded bits to help the sleb128 encoder do a better job.
*/
syn &= ARM_INSN_START_WORD2_MASK;
syn >>= ARM_INSN_START_WORD2_SHIFT;
/* We check and clear insn_start_idx to catch multiple updates. */
assert(s->insn_start_idx != 0);
tcg_set_insn_param(s->insn_start_idx, 2, syn);
s->insn_start_idx = 0;
}
/* target-specific extra values for is_jmp */
/* These instructions trap after executing, so the A32/T32 decoder must
* defer them until after the conditional execution state has been updated.