target-arm queue:

* Handle "extended small page" descriptors correctly
  * Use extended address bits from supersection short descriptors
  * Update interrupt status for all cores in gic_update
  * Fix off-by-one in exynos4210_fimd bit-swap code
  * Remove stray unused 'pending_exception' field
  * Add Cortex-A53 KVM support
  * Fix reset value of REVIDR
  * Add AArch32 MIDR aliases for ARMv8 cores
  * MAINTAINERS update for ARM ACPI code
  * Trust the kernel's value of MPIDR if we're using KVM
  * Various pxa2xx device updates to avoid old APIs
  * Mark pxa2xx copro registers as ARM_CP_IO so -icount works
  * Correctly UNDEF Thumb2 DSP insns on Cortex-M3
  * Initial work towards implementing PMSAv7
  * Fix a reset order bug introduced recently
  * Correct "preferred return address" for cpreg access exceptions
  * Add ACPI SPCR table for the virt board
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJVfwkmAAoJEDwlJe0UNgzeEs0P/jxgYWPOJeSms0VWIKYC/NqZ
 p8v3nT2B/U85Pa/MyJawGNfWsbBl9QrtgOVQmBucKp1RL73bwGDrxYM3UJ1vrCtw
 KIC1Oy7c8ujwmbqc7eWxQbSni5Z6khRrCsiXOAQDKlYPDoOO01YRQHFkcNMK/CoK
 MlSEaaQqlX15s2yJKnFKAn5W1MsweZ7UWNa1ZZ8rJRJvdE/9kGPW2G8Sbfn/MQ1z
 hy74lCyA1zejz4aVgrt7Yybl/Gs3OXEBAstlUwLrv+sNFaivBIaIOgdLJRG8+PA6
 VKQ9cOA+oO2Aa2EeAiEKuTR+6CdWh1UOUuNobNIibAPYOxeODNOmq7YaiguVietb
 7SmQ1zsIEaFTgg22apDl/sCP5/BgOX5kwz2cDkbv/bKdnfO7itcM858LJ+/7JAHL
 hg1MXM303IPZIky3+JhOT06wGuCdmr4SyDuRTM2j/e5Pn/u3emWS6ylNObSxoRtX
 nIaktkxTumH7rp++PQ4DzdqAUWYAwHqoP7iKEf5DTqGydhD3XbUFIDgwXorsHVR3
 xW19SqLlVoGjuvAa20ahAuxcQO3ifdEc8HuKIS1zOmTVaM+rNskt4fDvmmm7CTJe
 XJAzsLfZA0mTuLNLg9ZItCtiBCHBrE2X9VSN2VPUooTTVr7AUWzYY2pl784VML15
 0jd6k+oxGi0waZ4xor1H
 =m0HJ
 -----END PGP SIGNATURE-----

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

target-arm queue:
 * Handle "extended small page" descriptors correctly
 * Use extended address bits from supersection short descriptors
 * Update interrupt status for all cores in gic_update
 * Fix off-by-one in exynos4210_fimd bit-swap code
 * Remove stray unused 'pending_exception' field
 * Add Cortex-A53 KVM support
 * Fix reset value of REVIDR
 * Add AArch32 MIDR aliases for ARMv8 cores
 * MAINTAINERS update for ARM ACPI code
 * Trust the kernel's value of MPIDR if we're using KVM
 * Various pxa2xx device updates to avoid old APIs
 * Mark pxa2xx copro registers as ARM_CP_IO so -icount works
 * Correctly UNDEF Thumb2 DSP insns on Cortex-M3
 * Initial work towards implementing PMSAv7
 * Fix a reset order bug introduced recently
 * Correct "preferred return address" for cpreg access exceptions
 * Add ACPI SPCR table for the virt board

# gpg: Signature made Mon Jun 15 18:19:34 2015 BST using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"

* remotes/pmaydell/tags/pull-target-arm-20150615: (28 commits)
  hw/arm/virt-acpi-build: Add SPCR table
  ACPI: Add definitions for the SPCR table
  target-arm: Correct "preferred return address" for cpreg access exceptions
  hw/arm/boot: fix rom_reset notifier registration order
  arm: helper: rename get_phys_addr_mpu
  arm: Add has-mpu property
  arm: Implement uniprocessor with MP config
  arm: Refactor get_phys_addr FSR return mechanism
  arm: helper: Factor out CP regs common to [pv]msa
  arm: Don't add v7mp registers in MPU systems
  arm: Do not define TLBTR in PMSA systems
  target-arm: Add the THUMB_DSP feature
  hw/sd/pxa2xx_mmci: Stop using old_mmio in MemoryRegionOps
  hw/arm/pxa2xx: Convert pxa2xx-ssp to VMState
  hw/arm/pxa2xx: Add reset method for pxa2xx_ssp
  hw/arm/pxa2xx: Convert pxa2xx-fir to QOM and VMState
  hw/arm/pxa2xx: Mark coprocessor registers as ARM_CP_IO
  target-arm: Use the kernel's idea of MPIDR if we're using KVM
  MAINTAINERS: Add myself as ARM ACPI Subsystem maintainer
  target-arm: add AArch32 MIDR aliases in ARMv8
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-06-15 18:43:09 +01:00
commit 1dfe73b94d
22 changed files with 578 additions and 300 deletions

View File

@ -356,6 +356,13 @@ F: hw/misc/zynq_slcr.c
F: hw/*/cadence_*
F: hw/ssi/xilinx_spips.c
ARM ACPI Subsystem
M: Shannon Zhao <zhaoshenglong@huawei.com>
M: Shannon Zhao <shannon.zhao@linaro.org>
S: Maintained
F: hw/arm/virt-acpi-build.c
F: include/hw/arm/virt-acpi-build.h
CRIS Machines
-------------
Axis Dev88

View File

@ -574,15 +574,6 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
struct arm_boot_info *info =
container_of(n, struct arm_boot_info, load_kernel_notifier);
/* CPU objects (unlike devices) are not automatically reset on system
* reset, so we must always register a handler to do so. If we're
* actually loading a kernel, the handler is also responsible for
* arranging that we start it correctly.
*/
for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) {
qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
}
/* Load the kernel. */
if (!info->kernel_filename || info->firmware_loaded) {
@ -783,7 +774,18 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
{
CPUState *cs;
info->load_kernel_notifier.cpu = cpu;
info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify;
qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier);
/* CPU objects (unlike devices) are not automatically reset on system
* reset, so we must always register a handler to do so. If we're
* actually loading a kernel, the handler is also responsible for
* arranging that we start it correctly.
*/
for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) {
qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
}
}

View File

@ -334,10 +334,10 @@ static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
static const ARMCPRegInfo pxa_cp_reginfo[] = {
/* cp14 crm==1: perf registers */
{ .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0,
.access = PL1_RW,
.access = PL1_RW, .type = ARM_CP_IO,
.readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write },
{ .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
.access = PL1_RW,
.access = PL1_RW, .type = ARM_CP_IO,
.readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore },
{ .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0,
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
@ -356,11 +356,11 @@ static const ARMCPRegInfo pxa_cp_reginfo[] = {
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
/* cp14 crn==6: CLKCFG */
{ .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW,
.access = PL1_RW, .type = ARM_CP_IO,
.readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write },
/* cp14 crn==7: PWRMODE */
{ .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW,
.access = PL1_RW, .type = ARM_CP_IO,
.readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write },
REGINFO_SENTINEL
};
@ -457,7 +457,7 @@ typedef struct {
MemoryRegion iomem;
qemu_irq irq;
int enable;
uint32_t enable;
SSIBus *bus;
uint32_t sscr[2];
@ -470,10 +470,39 @@ typedef struct {
uint8_t ssacd;
uint32_t rx_fifo[16];
int rx_level;
int rx_start;
uint32_t rx_level;
uint32_t rx_start;
} PXA2xxSSPState;
static bool pxa2xx_ssp_vmstate_validate(void *opaque, int version_id)
{
PXA2xxSSPState *s = opaque;
return s->rx_start < sizeof(s->rx_fifo);
}
static const VMStateDescription vmstate_pxa2xx_ssp = {
.name = "pxa2xx-ssp",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(enable, PXA2xxSSPState),
VMSTATE_UINT32_ARRAY(sscr, PXA2xxSSPState, 2),
VMSTATE_UINT32(sspsp, PXA2xxSSPState),
VMSTATE_UINT32(ssto, PXA2xxSSPState),
VMSTATE_UINT32(ssitr, PXA2xxSSPState),
VMSTATE_UINT32(sssr, PXA2xxSSPState),
VMSTATE_UINT8(sstsa, PXA2xxSSPState),
VMSTATE_UINT8(ssrsa, PXA2xxSSPState),
VMSTATE_UINT8(ssacd, PXA2xxSSPState),
VMSTATE_UINT32(rx_level, PXA2xxSSPState),
VMSTATE_UINT32(rx_start, PXA2xxSSPState),
VMSTATE_VALIDATE("fifo is 16 bytes", pxa2xx_ssp_vmstate_validate),
VMSTATE_UINT32_ARRAY(rx_fifo, PXA2xxSSPState, 16),
VMSTATE_END_OF_LIST()
}
};
#define SSCR0 0x00 /* SSP Control register 0 */
#define SSCR1 0x04 /* SSP Control register 1 */
#define SSSR 0x08 /* SSP Status register */
@ -705,55 +734,20 @@ static const MemoryRegionOps pxa2xx_ssp_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void pxa2xx_ssp_save(QEMUFile *f, void *opaque)
static void pxa2xx_ssp_reset(DeviceState *d)
{
PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
int i;
PXA2xxSSPState *s = PXA2XX_SSP(d);
qemu_put_be32(f, s->enable);
qemu_put_be32s(f, &s->sscr[0]);
qemu_put_be32s(f, &s->sscr[1]);
qemu_put_be32s(f, &s->sspsp);
qemu_put_be32s(f, &s->ssto);
qemu_put_be32s(f, &s->ssitr);
qemu_put_be32s(f, &s->sssr);
qemu_put_8s(f, &s->sstsa);
qemu_put_8s(f, &s->ssrsa);
qemu_put_8s(f, &s->ssacd);
qemu_put_byte(f, s->rx_level);
for (i = 0; i < s->rx_level; i ++)
qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 0xf]);
}
static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
{
PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
int i, v;
s->enable = qemu_get_be32(f);
qemu_get_be32s(f, &s->sscr[0]);
qemu_get_be32s(f, &s->sscr[1]);
qemu_get_be32s(f, &s->sspsp);
qemu_get_be32s(f, &s->ssto);
qemu_get_be32s(f, &s->ssitr);
qemu_get_be32s(f, &s->sssr);
qemu_get_8s(f, &s->sstsa);
qemu_get_8s(f, &s->ssrsa);
qemu_get_8s(f, &s->ssacd);
v = qemu_get_byte(f);
if (v < 0 || v > ARRAY_SIZE(s->rx_fifo)) {
return -EINVAL;
}
s->rx_level = v;
s->rx_start = 0;
for (i = 0; i < s->rx_level; i ++)
s->rx_fifo[i] = qemu_get_byte(f);
return 0;
s->enable = 0;
s->sscr[0] = s->sscr[1] = 0;
s->sspsp = 0;
s->ssto = 0;
s->ssitr = 0;
s->sssr = 0;
s->sstsa = 0;
s->ssrsa = 0;
s->ssacd = 0;
s->rx_start = s->rx_level = 0;
}
static int pxa2xx_ssp_init(SysBusDevice *sbd)
@ -766,8 +760,6 @@ static int pxa2xx_ssp_init(SysBusDevice *sbd)
memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_ssp_ops, s,
"pxa2xx-ssp", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
register_savevm(dev, "pxa2xx_ssp", -1, 0,
pxa2xx_ssp_save, pxa2xx_ssp_load, s);
s->bus = ssi_create_bus(dev, "ssi");
return 0;
@ -1759,24 +1751,33 @@ static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem,
}
/* PXA Fast Infra-red Communications Port */
#define TYPE_PXA2XX_FIR "pxa2xx-fir"
#define PXA2XX_FIR(obj) OBJECT_CHECK(PXA2xxFIrState, (obj), TYPE_PXA2XX_FIR)
struct PXA2xxFIrState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion iomem;
qemu_irq irq;
qemu_irq rx_dma;
qemu_irq tx_dma;
int enable;
uint32_t enable;
CharDriverState *chr;
uint8_t control[3];
uint8_t status[2];
int rx_len;
int rx_start;
uint32_t rx_len;
uint32_t rx_start;
uint8_t rx_fifo[64];
};
static void pxa2xx_fir_reset(PXA2xxFIrState *s)
static void pxa2xx_fir_reset(DeviceState *d)
{
PXA2xxFIrState *s = PXA2XX_FIR(d);
s->control[0] = 0x00;
s->control[1] = 0x00;
s->control[2] = 0x00;
@ -1953,73 +1954,94 @@ static void pxa2xx_fir_event(void *opaque, int event)
{
}
static void pxa2xx_fir_save(QEMUFile *f, void *opaque)
static void pxa2xx_fir_instance_init(Object *obj)
{
PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
int i;
PXA2xxFIrState *s = PXA2XX_FIR(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
qemu_put_be32(f, s->enable);
qemu_put_8s(f, &s->control[0]);
qemu_put_8s(f, &s->control[1]);
qemu_put_8s(f, &s->control[2]);
qemu_put_8s(f, &s->status[0]);
qemu_put_8s(f, &s->status[1]);
qemu_put_byte(f, s->rx_len);
for (i = 0; i < s->rx_len; i ++)
qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 63]);
memory_region_init_io(&s->iomem, NULL, &pxa2xx_fir_ops, s,
"pxa2xx-fir", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
sysbus_init_irq(sbd, &s->rx_dma);
sysbus_init_irq(sbd, &s->tx_dma);
}
static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id)
static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
{
PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
int i;
PXA2xxFIrState *s = PXA2XX_FIR(dev);
s->enable = qemu_get_be32(f);
qemu_get_8s(f, &s->control[0]);
qemu_get_8s(f, &s->control[1]);
qemu_get_8s(f, &s->control[2]);
qemu_get_8s(f, &s->status[0]);
qemu_get_8s(f, &s->status[1]);
s->rx_len = qemu_get_byte(f);
s->rx_start = 0;
for (i = 0; i < s->rx_len; i ++)
s->rx_fifo[i] = qemu_get_byte(f);
return 0;
}
static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
hwaddr base,
qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma,
CharDriverState *chr)
{
PXA2xxFIrState *s = (PXA2xxFIrState *)
g_malloc0(sizeof(PXA2xxFIrState));
s->irq = irq;
s->rx_dma = rx_dma;
s->tx_dma = tx_dma;
s->chr = chr;
pxa2xx_fir_reset(s);
memory_region_init_io(&s->iomem, NULL, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000);
memory_region_add_subregion(sysmem, base, &s->iomem);
if (chr) {
qemu_chr_fe_claim_no_fail(chr);
qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
if (s->chr) {
qemu_chr_fe_claim_no_fail(s->chr);
qemu_chr_add_handlers(s->chr, pxa2xx_fir_is_empty,
pxa2xx_fir_rx, pxa2xx_fir_event, s);
}
}
register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save,
pxa2xx_fir_load, s);
static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)
{
PXA2xxFIrState *s = opaque;
return s;
return s->rx_start < ARRAY_SIZE(s->rx_fifo);
}
static const VMStateDescription pxa2xx_fir_vmsd = {
.name = "pxa2xx-fir",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(enable, PXA2xxFIrState),
VMSTATE_UINT8_ARRAY(control, PXA2xxFIrState, 3),
VMSTATE_UINT8_ARRAY(status, PXA2xxFIrState, 2),
VMSTATE_UINT32(rx_len, PXA2xxFIrState),
VMSTATE_UINT32(rx_start, PXA2xxFIrState),
VMSTATE_VALIDATE("fifo is 64 bytes", pxa2xx_fir_vmstate_validate),
VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxFIrState, 64),
VMSTATE_END_OF_LIST()
}
};
static Property pxa2xx_fir_properties[] = {
DEFINE_PROP_CHR("chardev", PXA2xxFIrState, chr),
DEFINE_PROP_END_OF_LIST(),
};
static void pxa2xx_fir_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pxa2xx_fir_realize;
dc->vmsd = &pxa2xx_fir_vmsd;
dc->props = pxa2xx_fir_properties;
dc->reset = pxa2xx_fir_reset;
}
static const TypeInfo pxa2xx_fir_info = {
.name = TYPE_PXA2XX_FIR,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(PXA2xxFIrState),
.class_init = pxa2xx_fir_class_init,
.instance_init = pxa2xx_fir_instance_init,
};
static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
hwaddr base,
qemu_irq irq, qemu_irq rx_dma,
qemu_irq tx_dma,
CharDriverState *chr)
{
DeviceState *dev;
SysBusDevice *sbd;
dev = qdev_create(NULL, TYPE_PXA2XX_FIR);
qdev_prop_set_chr(dev, "chardev", chr);
qdev_init_nofail(dev);
sbd = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(sbd, 0, base);
sysbus_connect_irq(sbd, 0, irq);
sysbus_connect_irq(sbd, 1, rx_dma);
sysbus_connect_irq(sbd, 2, tx_dma);
return PXA2XX_FIR(dev);
}
static void pxa2xx_reset(void *opaque, int line, int level)
@ -2306,8 +2328,11 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
{
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
sdc->init = pxa2xx_ssp_init;
dc->reset = pxa2xx_ssp_reset;
dc->vmsd = &vmstate_pxa2xx_ssp;
}
static const TypeInfo pxa2xx_ssp_info = {
@ -2323,6 +2348,7 @@ static void pxa2xx_register_types(void)
type_register_static(&pxa2xx_ssp_info);
type_register_static(&pxa2xx_i2c_info);
type_register_static(&pxa2xx_rtc_sysbus_info);
type_register_static(&pxa2xx_fir_info);
}
type_init(pxa2xx_register_types)

View File

@ -232,7 +232,7 @@ static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
#define REGINFO_FOR_PIC_CP(NAME, CRN) \
{ .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \
.access = PL1_RW, \
.access = PL1_RW, .type = ARM_CP_IO, \
.readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write }
static const ARMCPRegInfo pxa_pic_cp_reginfo[] = {

View File

@ -84,6 +84,12 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
AML_EXCLUSIVE, uart_irq));
aml_append(dev, aml_name_decl("_CRS", crs));
/* The _ADR entry is used to link this device to the UART described
* in the SPCR table, i.e. SPCR.base_address.address == _ADR.
*/
aml_append(dev, aml_name_decl("_ADR", aml_int(uart_memmap->base)));
aml_append(scope, dev);
}
@ -333,6 +339,38 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
return rsdp_table;
}
static void
build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
{
AcpiSerialPortConsoleRedirection *spcr;
const MemMapEntry *uart_memmap = &guest_info->memmap[VIRT_UART];
int irq = guest_info->irqmap[VIRT_UART] + ARM_SPI_BASE;
spcr = acpi_data_push(table_data, sizeof(*spcr));
spcr->interface_type = 0x3; /* ARM PL011 UART */
spcr->base_address.space_id = AML_SYSTEM_MEMORY;
spcr->base_address.bit_width = 8;
spcr->base_address.bit_offset = 0;
spcr->base_address.access_width = 1;
spcr->base_address.address = cpu_to_le64(uart_memmap->base);
spcr->interrupt_types = (1 << 3); /* Bit[3] ARMH GIC interrupt */
spcr->gsi = cpu_to_le32(irq); /* Global System Interrupt */
spcr->baud = 3; /* Baud Rate: 3 = 9600 */
spcr->parity = 0; /* No Parity */
spcr->stopbits = 1; /* 1 Stop bit */
spcr->flowctrl = (1 << 1); /* Bit[1] = RTS/CTS hardware flow control */
spcr->term_type = 0; /* Terminal Type: 0 = VT100 */
spcr->pci_device_id = 0xffff; /* PCI Device ID: not a PCI device */
spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */
build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2);
}
static void
build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
{
@ -514,7 +552,7 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
dsdt = tables_blob->len;
build_dsdt(tables_blob, tables->linker, guest_info);
/* FADT MADT GTDT pointed to by RSDT */
/* FADT MADT GTDT SPCR pointed to by RSDT */
acpi_add_table(table_offsets, tables_blob);
build_fadt(tables_blob, tables->linker, dsdt);
@ -527,6 +565,9 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
acpi_add_table(table_offsets, tables_blob);
build_mcfg(tables_blob, tables->linker, guest_info);
acpi_add_table(table_offsets, tables_blob);
build_spcr(tables_blob, tables->linker, guest_info);
/* RSDT is pointed to by RSDP */
rsdt = tables_blob->len;
build_rsdt(tables_blob, tables->linker, table_offsets);

View File

@ -144,6 +144,11 @@ static VirtBoardInfo machines[] = {
.memmap = a15memmap,
.irqmap = a15irqmap,
},
{
.cpu_model = "cortex-a53",
.memmap = a15memmap,
.irqmap = a15irqmap,
},
{
.cpu_model = "cortex-a57",
.memmap = a15memmap,
@ -306,7 +311,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
"enable-method", "psci");
}
qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", cpu);
qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", armcpu->mp_affinity);
g_free(nodename);
}
}

View File

@ -337,7 +337,7 @@ static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data)
if (swap_ctl & FIMD_WINCON_SWAP_BITS) {
res = 0;
for (i = 0; i < 64; i++) {
if (x & (1ULL << (64 - i))) {
if (x & (1ULL << (63 - i))) {
res |= (1ULL << i);
}
}

View File

@ -71,7 +71,7 @@ void gic_update(GICState *s)
|| !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) {
qemu_irq_lower(s->parent_irq[cpu]);
qemu_irq_lower(s->parent_fiq[cpu]);
return;
continue;
}
best_prio = 0x100;
best_irq = 1023;

View File

@ -48,7 +48,6 @@ struct PXA2xxMMCIState {
int resp_len;
int cmdreq;
int ac_width;
};
#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */
@ -215,7 +214,7 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
pxa2xx_mmci_fifo_update(s);
}
static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset)
static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size)
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
uint32_t ret;
@ -257,8 +256,8 @@ static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset)
return 0;
case MMC_RXFIFO:
ret = 0;
while (s->ac_width -- && s->rx_len) {
ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3);
while (size-- && s->rx_len) {
ret |= s->rx_fifo[s->rx_start++] << (size << 3);
s->rx_start &= 0x1f;
s->rx_len --;
}
@ -277,7 +276,7 @@ static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset)
}
static void pxa2xx_mmci_write(void *opaque,
hwaddr offset, uint32_t value)
hwaddr offset, uint64_t value, unsigned size)
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
@ -370,9 +369,9 @@ static void pxa2xx_mmci_write(void *opaque,
break;
case MMC_TXFIFO:
while (s->ac_width -- && s->tx_len < 0x20)
while (size-- && s->tx_len < 0x20)
s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
(value >> (s->ac_width << 3)) & 0xff;
(value >> (size << 3)) & 0xff;
s->intreq &= ~INT_TXFIFO_REQ;
pxa2xx_mmci_fifo_update(s);
break;
@ -386,60 +385,9 @@ static void pxa2xx_mmci_write(void *opaque,
}
}
static uint32_t pxa2xx_mmci_readb(void *opaque, hwaddr offset)
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
s->ac_width = 1;
return pxa2xx_mmci_read(opaque, offset);
}
static uint32_t pxa2xx_mmci_readh(void *opaque, hwaddr offset)
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
s->ac_width = 2;
return pxa2xx_mmci_read(opaque, offset);
}
static uint32_t pxa2xx_mmci_readw(void *opaque, hwaddr offset)
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
s->ac_width = 4;
return pxa2xx_mmci_read(opaque, offset);
}
static void pxa2xx_mmci_writeb(void *opaque,
hwaddr offset, uint32_t value)
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
s->ac_width = 1;
pxa2xx_mmci_write(opaque, offset, value);
}
static void pxa2xx_mmci_writeh(void *opaque,
hwaddr offset, uint32_t value)
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
s->ac_width = 2;
pxa2xx_mmci_write(opaque, offset, value);
}
static void pxa2xx_mmci_writew(void *opaque,
hwaddr offset, uint32_t value)
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
s->ac_width = 4;
pxa2xx_mmci_write(opaque, offset, value);
}
static const MemoryRegionOps pxa2xx_mmci_ops = {
.old_mmio = {
.read = { pxa2xx_mmci_readb,
pxa2xx_mmci_readh,
pxa2xx_mmci_readw, },
.write = { pxa2xx_mmci_writeb,
pxa2xx_mmci_writeh,
pxa2xx_mmci_writew, },
},
.read = pxa2xx_mmci_read,
.write = pxa2xx_mmci_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};

View File

@ -196,6 +196,38 @@ enum {
ACPI_FADT_ARM_PSCI_USE_HVC = 1,
};
/*
* Serial Port Console Redirection Table (SPCR), Rev. 1.02
*
* For .interface_type see Debug Port Table 2 (DBG2) serial port
* subtypes in Table 3, Rev. May 22, 2012
*/
struct AcpiSerialPortConsoleRedirection {
ACPI_TABLE_HEADER_DEF
uint8_t interface_type;
uint8_t reserved1[3];
struct AcpiGenericAddress base_address;
uint8_t interrupt_types;
uint8_t irq;
uint32_t gsi;
uint8_t baud;
uint8_t parity;
uint8_t stopbits;
uint8_t flowctrl;
uint8_t term_type;
uint8_t reserved2;
uint16_t pci_device_id;
uint16_t pci_vendor_id;
uint8_t pci_bus;
uint8_t pci_slot;
uint8_t pci_func;
uint32_t pci_flags;
uint8_t pci_seg;
uint32_t reserved3;
} QEMU_PACKED;
typedef struct AcpiSerialPortConsoleRedirection
AcpiSerialPortConsoleRedirection;
/*
* ACPI 1.0 Root System Description Table (RSDT)
*/

View File

@ -103,6 +103,9 @@ typedef struct ARMCPU {
/* CPU has security extension */
bool has_el3;
/* CPU has memory protection unit */
bool has_mpu;
/* PSCI conduit used to invoke PSCI methods
* 0 - disabled, 1 - smc, 2 - hvc
*/
@ -116,6 +119,9 @@ typedef struct ARMCPU {
/* KVM init features for this CPU */
uint32_t kvm_init_features[7];
/* Uniprocessor system with MP extensions */
bool mp_is_up;
/* The instance init functions for implementation-specific subclasses
* set these fields to specify the implementation-dependent values of
* various constant registers and reset values of non-constant
@ -127,6 +133,7 @@ typedef struct ARMCPU {
* prefix means a constant register.
*/
uint32_t midr;
uint32_t revidr;
uint32_t reset_fpsid;
uint32_t mvfr0;
uint32_t mvfr1;
@ -159,6 +166,7 @@ typedef struct ARMCPU {
uint64_t id_aa64mmfr1;
uint32_t dbgdidr;
uint32_t clidr;
uint64_t mp_affinity; /* MP ID without feature bits */
/* The elements of this array are the CCSIDR values for each cache,
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
*/

View File

@ -383,17 +383,29 @@ static inline void unset_feature(CPUARMState *env, int feature)
env->features &= ~(1ULL << feature);
}
#define ARM_CPUS_PER_CLUSTER 8
static void arm_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
ARMCPU *cpu = ARM_CPU(obj);
static bool inited;
uint32_t Aff1, Aff0;
cs->env_ptr = &cpu->env;
cpu_exec_init(&cpu->env);
cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal,
g_free, g_free);
/* This cpu-id-to-MPIDR affinity is used only for TCG; KVM will override it.
* We don't support setting cluster ID ([16..23]) (known as Aff2
* in later ARM ARM versions), or any of the higher affinity level fields,
* so these bits always RAZ.
*/
Aff1 = cs->cpu_index / ARM_CPUS_PER_CLUSTER;
Aff0 = cs->cpu_index % ARM_CPUS_PER_CLUSTER;
cpu->mp_affinity = (Aff1 << 8) | Aff0;
#ifndef CONFIG_USER_ONLY
/* Our inbound IRQ and FIQ lines */
if (kvm_enabled()) {
@ -442,6 +454,9 @@ static Property arm_cpu_rvbar_property =
static Property arm_cpu_has_el3_property =
DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
static Property arm_cpu_has_mpu_property =
DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
static void arm_cpu_post_init(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@ -469,6 +484,12 @@ static void arm_cpu_post_init(Object *obj)
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el3_property,
&error_abort);
}
if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) {
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property,
&error_abort);
}
}
static void arm_cpu_finalizefn(Object *obj)
@ -533,6 +554,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
if (arm_feature(env, ARM_FEATURE_CBAR_RO)) {
set_feature(env, ARM_FEATURE_CBAR);
}
if (arm_feature(env, ARM_FEATURE_THUMB2) &&
!arm_feature(env, ARM_FEATURE_M)) {
set_feature(env, ARM_FEATURE_THUMB_DSP);
}
if (cpu->reset_hivecs) {
cpu->reset_sctlr |= (1 << 13);
@ -551,6 +576,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
cpu->id_aa64pfr0 &= ~0xf000;
}
if (!cpu->has_mpu) {
unset_feature(env, ARM_FEATURE_MPU);
}
register_cp_regs_for_features(cpu);
arm_cpu_register_gdb_regs_for_features(cpu);

View File

@ -384,7 +384,6 @@ typedef struct CPUARMState {
uint32_t control;
int current_sp;
int exception;
int pending_exception;
} v7m;
/* Information associated with an exception about to be taken:
@ -890,6 +889,7 @@ enum arm_features {
ARM_FEATURE_V8_SHA1, /* implements SHA1 part of v8 Crypto Extensions */
ARM_FEATURE_V8_SHA256, /* implements SHA256 part of v8 Crypto Extensions */
ARM_FEATURE_V8_PMULL, /* implements PMULL part of v8 Crypto Extensions */
ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */
};
static inline int arm_feature(CPUARMState *env, int feature)

View File

@ -110,6 +110,7 @@ static void aarch64_a57_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_CRC);
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
cpu->midr = 0x411fd070;
cpu->revidr = 0x00000000;
cpu->reset_fpsid = 0x41034070;
cpu->mvfr0 = 0x10110222;
cpu->mvfr1 = 0x12111111;
@ -159,7 +160,9 @@ static void aarch64_a53_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V8_SHA256);
set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
set_feature(&cpu->env, ARM_FEATURE_CRC);
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
cpu->midr = 0x410fd034;
cpu->revidr = 0x00000000;
cpu->reset_fpsid = 0x41034070;
cpu->mvfr0 = 0x10110222;
cpu->mvfr1 = 0x12111111;

View File

@ -12,10 +12,10 @@
#include <zlib.h> /* For crc32 */
#ifndef CONFIG_USER_ONLY
static inline int get_phys_addr(CPUARMState *env, target_ulong address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
target_ulong *page_size);
static inline bool get_phys_addr(CPUARMState *env, target_ulong address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
target_ulong *page_size, uint32_t *fsr);
/* Definitions for the PMCCNTR and PMCR registers */
#define PMCRD 0x8
@ -1495,19 +1495,20 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
hwaddr phys_addr;
target_ulong page_size;
int prot;
int ret;
uint32_t fsr;
bool ret;
uint64_t par64;
MemTxAttrs attrs = {};
ret = get_phys_addr(env, value, access_type, mmu_idx,
&phys_addr, &attrs, &prot, &page_size);
&phys_addr, &attrs, &prot, &page_size, &fsr);
if (extended_addresses_enabled(env)) {
/* ret is a DFSR/IFSR value for the long descriptor
/* fsr is a DFSR/IFSR value for the long descriptor
* translation table format, but with WnR always clear.
* Convert it to a 64-bit PAR.
*/
par64 = (1 << 11); /* LPAE bit always set */
if (ret == 0) {
if (!ret) {
par64 |= phys_addr & ~0xfffULL;
if (!attrs.secure) {
par64 |= (1 << 9); /* NS */
@ -1515,18 +1516,18 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
/* We don't set the ATTR or SH fields in the PAR. */
} else {
par64 |= 1; /* F */
par64 |= (ret & 0x3f) << 1; /* FS */
par64 |= (fsr & 0x3f) << 1; /* FS */
/* Note that S2WLK and FSTAGE are always zero, because we don't
* implement virtualization and therefore there can't be a stage 2
* fault.
*/
}
} else {
/* ret is a DFSR/IFSR value for the short descriptor
/* fsr is a DFSR/IFSR value for the short descriptor
* translation table format (with WnR always clear).
* Convert it to a 32-bit PAR.
*/
if (ret == 0) {
if (!ret) {
/* We do not set any attribute bits in the PAR */
if (page_size == (1 << 24)
&& arm_feature(env, ARM_FEATURE_V7)) {
@ -1538,8 +1539,8 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
par64 |= (1 << 9); /* NS */
}
} else {
par64 = ((ret & (1 << 10)) >> 5) | ((ret & (1 << 12)) >> 6) |
((ret & 0xf) << 1) | 1;
par64 = ((fsr & (1 << 10)) >> 5) | ((fsr & (1 << 12)) >> 6) |
((fsr & 0xf) << 1) | 1;
}
}
return par64;
@ -1846,7 +1847,7 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
raw_write(env, ri, value);
}
static const ARMCPRegInfo vmsa_cp_reginfo[] = {
static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = {
{ .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW, .type = ARM_CP_ALIAS,
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dfsr_s),
@ -1856,6 +1857,18 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
.access = PL1_RW, .resetvalue = 0,
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.ifsr_s),
offsetoflow32(CPUARMState, cp15.ifsr_ns) } },
{ .name = "DFAR", .cp = 15, .opc1 = 0, .crn = 6, .crm = 0, .opc2 = 0,
.access = PL1_RW, .resetvalue = 0,
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.dfar_s),
offsetof(CPUARMState, cp15.dfar_ns) } },
{ .name = "FAR_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]),
.resetvalue = 0, },
REGINFO_SENTINEL
};
static const ARMCPRegInfo vmsa_cp_reginfo[] = {
{ .name = "ESR_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
.access = PL1_RW,
@ -1880,14 +1893,6 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
.resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write,
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tcr_el[3]),
offsetoflow32(CPUARMState, cp15.tcr_el[1])} },
{ .name = "FAR_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]),
.resetvalue = 0, },
{ .name = "DFAR", .cp = 15, .opc1 = 0, .crn = 6, .crm = 0, .opc2 = 0,
.access = PL1_RW, .resetvalue = 0,
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.dfar_s),
offsetof(CPUARMState, cp15.dfar_ns) } },
REGINFO_SENTINEL
};
@ -2063,19 +2068,18 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = {
static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
CPUState *cs = CPU(arm_env_get_cpu(env));
uint32_t mpidr = cs->cpu_index;
/* We don't support setting cluster ID ([8..11]) (known as Aff1
* in later ARM ARM versions), or any of the higher affinity level fields,
* so these bits always RAZ.
*/
ARMCPU *cpu = ARM_CPU(arm_env_get_cpu(env));
uint64_t mpidr = cpu->mp_affinity;
if (arm_feature(env, ARM_FEATURE_V7MP)) {
mpidr |= (1U << 31);
/* Cores which are uniprocessor (non-coherent)
* but still implement the MP extensions set
* bit 30. (For instance, A9UP.) However we do
* not currently model any of those cores.
* bit 30. (For instance, Cortex-R5).
*/
if (cpu->mp_is_up) {
mpidr |= (1u << 30);
}
}
return mpidr;
}
@ -3196,7 +3200,8 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (arm_feature(env, ARM_FEATURE_V6K)) {
define_arm_cp_regs(cpu, v6k_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_V7MP)) {
if (arm_feature(env, ARM_FEATURE_V7MP) &&
!arm_feature(env, ARM_FEATURE_MPU)) {
define_arm_cp_regs(cpu, v7mp_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_V7)) {
@ -3348,6 +3353,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
assert(!arm_feature(env, ARM_FEATURE_V6));
define_arm_cp_regs(cpu, pmsav5_cp_reginfo);
} else {
define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo);
define_arm_cp_regs(cpu, vmsa_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
@ -3423,16 +3429,19 @@ void register_cp_regs_for_features(ARMCPU *cpu)
REGINFO_SENTINEL
};
ARMCPRegInfo id_v8_midr_cp_reginfo[] = {
/* v8 MIDR -- the wildcard isn't necessary, and nor is the
* variable-MIDR TI925 behaviour. Instead we have a single
* (strictly speaking IMPDEF) alias of the MIDR, REVIDR.
*/
{ .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 0,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->midr },
/* crn = 0 op1 = 0 crm = 0 op2 = 4,7 : AArch32 aliases of MIDR */
{ .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST,
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 4,
.access = PL1_R, .resetvalue = cpu->midr },
{ .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST,
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 7,
.access = PL1_R, .resetvalue = cpu->midr },
{ .name = "REVIDR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 6,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->midr },
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->revidr },
REGINFO_SENTINEL
};
ARMCPRegInfo id_cp_reginfo[] = {
@ -3448,11 +3457,14 @@ void register_cp_regs_for_features(ARMCPU *cpu)
{ .name = "TCMTR",
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 2,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "TLBTR",
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 3,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
REGINFO_SENTINEL
};
/* TLBTR is specific to VMSA */
ARMCPRegInfo id_tlbtr_reginfo = {
.name = "TLBTR",
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 3,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0,
};
ARMCPRegInfo crn0_wi_reginfo = {
.name = "CRN0_WI", .cp = 15, .crn = 0, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W,
@ -3474,6 +3486,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
for (r = id_cp_reginfo; r->type != ARM_CP_SENTINEL; r++) {
r->access = PL1_RW;
}
id_tlbtr_reginfo.access = PL1_RW;
}
if (arm_feature(env, ARM_FEATURE_V8)) {
define_arm_cp_regs(cpu, id_v8_midr_cp_reginfo);
@ -3481,6 +3494,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_arm_cp_regs(cpu, id_pre_v8_midr_cp_reginfo);
}
define_arm_cp_regs(cpu, id_cp_reginfo);
if (!arm_feature(env, ARM_FEATURE_MPU)) {
define_one_arm_cp_reg(cpu, &id_tlbtr_reginfo);
}
}
if (arm_feature(env, ARM_FEATURE_MPIDR)) {
@ -5229,9 +5245,10 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure)
return address_space_ldq(cs->as, addr, attrs, NULL);
}
static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type,
ARMMMUIdx mmu_idx, hwaddr *phys_ptr,
int *prot, target_ulong *page_size)
static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, int *prot,
target_ulong *page_size, uint32_t *fsr)
{
CPUState *cs = CPU(arm_env_get_cpu(env));
int code;
@ -5302,20 +5319,25 @@ static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type,
ap = (desc >> (4 + ((address >> 9) & 6))) & 3;
*page_size = 0x1000;
break;
case 3: /* 1k page. */
case 3: /* 1k page, or ARMv6/XScale "extended small (4k) page" */
if (type == 1) {
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
/* ARMv6/XScale extended small page format */
if (arm_feature(env, ARM_FEATURE_XSCALE)
|| arm_feature(env, ARM_FEATURE_V6)) {
phys_addr = (desc & 0xfffff000) | (address & 0xfff);
*page_size = 0x1000;
} else {
/* Page translation fault. */
/* UNPREDICTABLE in ARMv5; we choose to take a
* page translation fault.
*/
code = 7;
goto do_fault;
}
} else {
phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
*page_size = 0x400;
}
ap = (desc >> 4) & 3;
*page_size = 0x400;
break;
default:
/* Never happens, but compiler isn't smart enough to tell. */
@ -5330,15 +5352,16 @@ static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type,
goto do_fault;
}
*phys_ptr = phys_addr;
return 0;
return false;
do_fault:
return code | (domain << 4);
*fsr = code | (domain << 4);
return true;
}
static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
ARMMMUIdx mmu_idx, hwaddr *phys_ptr,
MemTxAttrs *attrs,
int *prot, target_ulong *page_size)
static bool get_phys_addr_v6(CPUARMState *env, uint32_t address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
target_ulong *page_size, uint32_t *fsr)
{
CPUState *cs = CPU(arm_env_get_cpu(env));
int code;
@ -5392,6 +5415,8 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
if (desc & (1 << 18)) {
/* Supersection. */
phys_addr = (desc & 0xff000000) | (address & 0x00ffffff);
phys_addr |= (uint64_t)extract32(desc, 20, 4) << 32;
phys_addr |= (uint64_t)extract32(desc, 5, 4) << 36;
*page_size = 0x1000000;
} else {
/* Section. */
@ -5469,9 +5494,10 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
attrs->secure = false;
}
*phys_ptr = phys_addr;
return 0;
return false;
do_fault:
return code | (domain << 4);
*fsr = code | (domain << 4);
return true;
}
/* Fault type for long-descriptor MMU fault reporting; this corresponds
@ -5483,10 +5509,10 @@ typedef enum {
permission_fault = 3,
} MMUFaultType;
static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot,
target_ulong *page_size_ptr)
static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot,
target_ulong *page_size_ptr, uint32_t *fsr)
{
CPUState *cs = CPU(arm_env_get_cpu(env));
/* Read an LPAE long-descriptor translation table. */
@ -5725,16 +5751,17 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
}
*phys_ptr = descaddr;
*page_size_ptr = page_size;
return 0;
return false;
do_fault:
/* Long-descriptor format IFSR/DFSR value */
return (1 << 9) | (fault_type << 2) | level;
*fsr = (1 << 9) | (fault_type << 2) | level;
return true;
}
static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, int *prot)
static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, int *prot, uint32_t *fsr)
{
int n;
uint32_t mask;
@ -5756,7 +5783,8 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
}
}
if (n < 0) {
return 2;
*fsr = 2;
return true;
}
if (access_type == 2) {
@ -5767,10 +5795,12 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
mask = (mask >> (n * 4)) & 0xf;
switch (mask) {
case 0:
return 1;
*fsr = 1;
return true;
case 1:
if (is_user) {
return 1;
*fsr = 1;
return true;
}
*prot = PAGE_READ | PAGE_WRITE;
break;
@ -5785,7 +5815,8 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
break;
case 5:
if (is_user) {
return 1;
*fsr = 1;
return true;
}
*prot = PAGE_READ;
break;
@ -5794,10 +5825,11 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
break;
default:
/* Bad permission. */
return 1;
*fsr = 1;
return true;
}
*prot |= PAGE_EXEC;
return 0;
return false;
}
/* get_phys_addr - get the physical address for this virtual address
@ -5806,8 +5838,8 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
* by doing a translation table walk on MMU based systems or using the
* MPU state on MPU based systems.
*
* Returns 0 if the translation was successful. Otherwise, phys_ptr, attrs,
* prot and page_size may not be filled in, and the return value provides
* Returns false if the translation was successful. Otherwise, phys_ptr, attrs,
* prot and page_size may not be filled in, and the populated fsr value provides
* information on why the translation aborted, in the format of a
* DFSR/IFSR fault register, with the following caveats:
* * we honour the short vs long DFSR format differences.
@ -5823,11 +5855,12 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
* @attrs: set to the memory transaction attributes to use
* @prot: set to the permissions for the page containing phys_ptr
* @page_size: set to the size of the page containing phys_ptr
* @fsr: set to the DFSR/IFSR value on failure
*/
static inline int get_phys_addr(CPUARMState *env, target_ulong address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
target_ulong *page_size)
static inline bool get_phys_addr(CPUARMState *env, target_ulong address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
target_ulong *page_size, uint32_t *fsr)
{
if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
/* TODO: when we support EL2 we should here call ourselves recursively
@ -5869,28 +5902,28 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
if (arm_feature(env, ARM_FEATURE_MPU)) {
*page_size = TARGET_PAGE_SIZE;
return get_phys_addr_mpu(env, address, access_type, mmu_idx, phys_ptr,
prot);
return get_phys_addr_pmsav5(env, address, access_type, mmu_idx,
phys_ptr, prot, fsr);
}
if (regime_using_lpae_format(env, mmu_idx)) {
return get_phys_addr_lpae(env, address, access_type, mmu_idx, phys_ptr,
attrs, prot, page_size);
attrs, prot, page_size, fsr);
} else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) {
return get_phys_addr_v6(env, address, access_type, mmu_idx, phys_ptr,
attrs, prot, page_size);
attrs, prot, page_size, fsr);
} else {
return get_phys_addr_v5(env, address, access_type, mmu_idx, phys_ptr,
prot, page_size);
prot, page_size, fsr);
}
}
/* Walk the page table and (if the mapping exists) add the page
* to the TLB. Return 0 on success, or an ARM DFSR/IFSR fault
* register format value on failure.
* to the TLB. Return false on success, or true on failure. Populate
* fsr with ARM DFSR/IFSR fault register format value on failure.
*/
int arm_tlb_fill(CPUState *cs, vaddr address,
int access_type, int mmu_idx)
bool arm_tlb_fill(CPUState *cs, vaddr address,
int access_type, int mmu_idx, uint32_t *fsr)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@ -5901,8 +5934,8 @@ int arm_tlb_fill(CPUState *cs, vaddr address,
MemTxAttrs attrs = {};
ret = get_phys_addr(env, address, access_type, mmu_idx, &phys_addr,
&attrs, &prot, &page_size);
if (ret == 0) {
&attrs, &prot, &page_size, fsr);
if (!ret) {
/* Map a single [sub]page. */
phys_addr &= TARGET_PAGE_MASK;
address &= TARGET_PAGE_MASK;
@ -5921,13 +5954,14 @@ hwaddr arm_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
hwaddr phys_addr;
target_ulong page_size;
int prot;
int ret;
bool ret;
uint32_t fsr;
MemTxAttrs attrs = {};
ret = get_phys_addr(env, addr, 0, cpu_mmu_index(env), &phys_addr,
&attrs, &prot, &page_size);
&attrs, &prot, &page_size, &fsr);
if (ret != 0) {
if (ret) {
return -1;
}

View File

@ -388,6 +388,7 @@ void arm_handle_psci_call(ARMCPU *cpu);
#endif
/* Do a page table walk and add page to TLB if possible */
int arm_tlb_fill(CPUState *cpu, vaddr address, int rw, int mmu_idx);
bool arm_tlb_fill(CPUState *cpu, vaddr address, int rw, int mmu_idx,
uint32_t *fsr);
#endif

View File

@ -127,6 +127,8 @@ MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED)
#define QEMU_KVM_ARM_TARGET_AEM_V8 0
#define QEMU_KVM_ARM_TARGET_FOUNDATION_V8 1
#define QEMU_KVM_ARM_TARGET_CORTEX_A57 2
#define QEMU_KVM_ARM_TARGET_XGENE_POTENZA 3
#define QEMU_KVM_ARM_TARGET_CORTEX_A53 4
/* There's no kernel define for this: sentinel value which
* matches no KVM target value for either 64 or 32 bit
@ -137,6 +139,8 @@ MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED)
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_AEM_V8, KVM_ARM_TARGET_AEM_V8)
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8)
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A57, KVM_ARM_TARGET_CORTEX_A57)
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_XGENE_POTENZA, KVM_ARM_TARGET_XGENE_POTENZA)
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A53, KVM_ARM_TARGET_CORTEX_A53)
#else
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A15, KVM_ARM_TARGET_CORTEX_A15)
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A7, KVM_ARM_TARGET_CORTEX_A7)

View File

@ -153,10 +153,14 @@ bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx)
}
}
#define ARM_MPIDR_HWID_BITMASK 0xFFFFFF
#define ARM_CPU_ID_MPIDR 0, 0, 0, 5
int kvm_arch_init_vcpu(CPUState *cs)
{
int ret;
uint64_t v;
uint32_t mpidr;
struct kvm_one_reg r;
ARMCPU *cpu = ARM_CPU(cs);
@ -193,6 +197,17 @@ int kvm_arch_init_vcpu(CPUState *cs)
return -EINVAL;
}
/*
* When KVM is in use, PSCI is emulated in-kernel and not by qemu.
* Currently KVM has its own idea about MPIDR assignment, so we
* override our defaults with what we get from KVM.
*/
ret = kvm_get_one_reg(cs, ARM_CP15_REG32(ARM_CPU_ID_MPIDR), &mpidr);
if (ret) {
return ret;
}
cpu->mp_affinity = mpidr & ARM_MPIDR_HWID_BITMASK;
return kvm_arm_init_cpreg_list(cpu);
}

View File

@ -77,9 +77,13 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
return true;
}
#define ARM_MPIDR_HWID_BITMASK 0xFF00FFFFFFULL
#define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5
int kvm_arch_init_vcpu(CPUState *cs)
{
int ret;
uint64_t mpidr;
ARMCPU *cpu = ARM_CPU(cs);
if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
@ -107,6 +111,17 @@ int kvm_arch_init_vcpu(CPUState *cs)
return ret;
}
/*
* When KVM is in use, PSCI is emulated in-kernel and not by qemu.
* Currently KVM has its own idea about MPIDR assignment, so we
* override our defaults with what we get from KVM.
*/
ret = kvm_get_one_reg(cs, ARM64_SYS_REG(ARM_CPU_ID_MPIDR), &mpidr);
if (ret) {
return ret;
}
cpu->mp_affinity = mpidr & ARM_MPIDR_HWID_BITMASK;
return kvm_arm_init_cpreg_list(cpu);
}

View File

@ -81,9 +81,10 @@ uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def,
void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
uintptr_t retaddr)
{
int ret;
bool ret;
uint32_t fsr = 0;
ret = arm_tlb_fill(cs, addr, is_write, mmu_idx);
ret = arm_tlb_fill(cs, addr, is_write, mmu_idx, &fsr);
if (unlikely(ret)) {
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@ -96,7 +97,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
}
/* AArch64 syndrome does not have an LPAE bit */
syn = ret & ~(1 << 9);
syn = fsr & ~(1 << 9);
/* For insn and data aborts we assume there is no instruction syndrome
* information; this is always true for exceptions reported to EL1.
@ -107,13 +108,13 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
} else {
syn = syn_data_abort(same_el, 0, 0, 0, is_write == 1, syn);
if (is_write == 1 && arm_feature(env, ARM_FEATURE_V6)) {
ret |= (1 << 11);
fsr |= (1 << 11);
}
exc = EXCP_DATA_ABORT;
}
env->exception.vaddress = addr;
env->exception.fsr = ret;
env->exception.fsr = fsr;
raise_exception(env, exc, syn, exception_target_el(env));
}
}

View File

@ -72,6 +72,21 @@ bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
}
}
static CPUState *get_cpu_by_id(uint64_t id)
{
CPUState *cpu;
CPU_FOREACH(cpu) {
ARMCPU *armcpu = ARM_CPU(cpu);
if (armcpu->mp_affinity == id) {
return cpu;
}
}
return NULL;
}
void arm_handle_psci_call(ARMCPU *cpu)
{
/*
@ -121,7 +136,7 @@ void arm_handle_psci_call(ARMCPU *cpu)
switch (param[2]) {
case 0:
target_cpu_state = qemu_get_cpu(mpidr & 0xff);
target_cpu_state = get_cpu_by_id(mpidr);
if (!target_cpu_state) {
ret = QEMU_PSCI_RET_INVALID_PARAMS;
break;
@ -153,7 +168,7 @@ void arm_handle_psci_call(ARMCPU *cpu)
context_id = param[3];
/* change to the cpu we are powering up */
target_cpu_state = qemu_get_cpu(mpidr & 0xff);
target_cpu_state = get_cpu_by_id(mpidr);
if (!target_cpu_state) {
ret = QEMU_PSCI_RET_INVALID_PARAMS;
break;

View File

@ -7175,7 +7175,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
break;
}
gen_set_pc_im(s, s->pc);
gen_set_pc_im(s, s->pc - 4);
tmpptr = tcg_const_ptr(ri);
tcg_syn = tcg_const_i32(syndrome);
gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn);
@ -9444,6 +9444,9 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
op = (insn >> 21) & 0xf;
if (op == 6) {
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
goto illegal_op;
}
/* Halfword pack. */
tmp = load_reg(s, rn);
tmp2 = load_reg(s, rm);
@ -9508,6 +9511,27 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
store_reg_bx(s, rd, tmp);
break;
case 1: /* Sign/zero extend. */
op = (insn >> 20) & 7;
switch (op) {
case 0: /* SXTAH, SXTH */
case 1: /* UXTAH, UXTH */
case 4: /* SXTAB, SXTB */
case 5: /* UXTAB, UXTB */
break;
case 2: /* SXTAB16, SXTB16 */
case 3: /* UXTAB16, UXTB16 */
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
goto illegal_op;
}
break;
default:
goto illegal_op;
}
if (rn != 15) {
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
goto illegal_op;
}
}
tmp = load_reg(s, rm);
shift = (insn >> 4) & 3;
/* ??? In many cases it's not necessary to do a
@ -9522,7 +9546,8 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
case 3: gen_uxtb16(tmp); break;
case 4: gen_sxtb(tmp); break;
case 5: gen_uxtb(tmp); break;
default: goto illegal_op;
default:
g_assert_not_reached();
}
if (rn != 15) {
tmp2 = load_reg(s, rn);
@ -9536,6 +9561,9 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
store_reg(s, rd, tmp);
break;
case 2: /* SIMD add/subtract. */
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
goto illegal_op;
}
op = (insn >> 20) & 7;
shift = (insn >> 4) & 7;
if ((op & 3) == 3 || (shift & 3) == 3)
@ -9550,6 +9578,9 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
if (op < 4) {
/* Saturating add/subtract. */
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
goto illegal_op;
}
tmp = load_reg(s, rn);
tmp2 = load_reg(s, rm);
if (op & 1)
@ -9560,6 +9591,31 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
tcg_temp_free_i32(tmp2);
} else {
switch (op) {
case 0x0a: /* rbit */
case 0x08: /* rev */
case 0x09: /* rev16 */
case 0x0b: /* revsh */
case 0x18: /* clz */
break;
case 0x10: /* sel */
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
goto illegal_op;
}
break;
case 0x20: /* crc32/crc32c */
case 0x21:
case 0x22:
case 0x28:
case 0x29:
case 0x2a:
if (!arm_dc_feature(s, ARM_FEATURE_CRC)) {
goto illegal_op;
}
break;
default:
goto illegal_op;
}
tmp = load_reg(s, rn);
switch (op) {
case 0x0a: /* rbit */
@ -9596,10 +9652,6 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
uint32_t sz = op & 0x3;
uint32_t c = op & 0x8;
if (!arm_dc_feature(s, ARM_FEATURE_CRC)) {
goto illegal_op;
}
tmp2 = load_reg(s, rm);
if (sz == 0) {
tcg_gen_andi_i32(tmp2, tmp2, 0xff);
@ -9617,12 +9669,26 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
break;
}
default:
goto illegal_op;
g_assert_not_reached();
}
}
store_reg(s, rd, tmp);
break;
case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */
switch ((insn >> 20) & 7) {
case 0: /* 32 x 32 -> 32 */
case 7: /* Unsigned sum of absolute differences. */
break;
case 1: /* 16 x 16 -> 32 */
case 2: /* Dual multiply add. */
case 3: /* 32 * 16 -> 32msb */
case 4: /* Dual multiply subtract. */
case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
goto illegal_op;
}
break;
}
op = (insn >> 4) & 0xf;
tmp = load_reg(s, rn);
tmp2 = load_reg(s, rm);
@ -9735,6 +9801,11 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
store_reg(s, rd, tmp);
} else if ((op & 0xe) == 0xc) {
/* Dual multiply accumulate long. */
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
tcg_temp_free_i32(tmp);
tcg_temp_free_i32(tmp2);
goto illegal_op;
}
if (op & 1)
gen_swap_half(tmp2);
gen_smul_dual(tmp, tmp2);
@ -9758,6 +9829,11 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
} else {
if (op & 8) {
/* smlalxy */
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
tcg_temp_free_i32(tmp2);
tcg_temp_free_i32(tmp);
goto illegal_op;
}
gen_mulxy(tmp, tmp2, op & 2, op & 1);
tcg_temp_free_i32(tmp2);
tmp64 = tcg_temp_new_i64();
@ -9770,6 +9846,10 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
}
if (op & 4) {
/* umaal */
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
tcg_temp_free_i64(tmp64);
goto illegal_op;
}
gen_addq_lo(s, tmp64, rs);
gen_addq_lo(s, tmp64, rd);
} else if (op & 0x40) {
@ -10034,16 +10114,28 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
tmp2 = tcg_const_i32(imm);
if (op & 4) {
/* Unsigned. */
if ((op & 1) && shift == 0)
if ((op & 1) && shift == 0) {
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
tcg_temp_free_i32(tmp);
tcg_temp_free_i32(tmp2);
goto illegal_op;
}
gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
else
} else {
gen_helper_usat(tmp, cpu_env, tmp, tmp2);
}
} else {
/* Signed. */
if ((op & 1) && shift == 0)
if ((op & 1) && shift == 0) {
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
tcg_temp_free_i32(tmp);
tcg_temp_free_i32(tmp2);
goto illegal_op;
}
gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
else
} else {
gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
}
}
tcg_temp_free_i32(tmp2);
break;