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:
commit
1dfe73b94d
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
254
hw/arm/pxa2xx.c
254
hw/arm/pxa2xx.c
@ -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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)
|
||||
{
|
||||
PXA2xxFIrState *s = opaque;
|
||||
|
||||
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,
|
||||
qemu_irq irq, qemu_irq rx_dma,
|
||||
qemu_irq tx_dma,
|
||||
CharDriverState *chr)
|
||||
{
|
||||
PXA2xxFIrState *s = (PXA2xxFIrState *)
|
||||
g_malloc0(sizeof(PXA2xxFIrState));
|
||||
DeviceState *dev;
|
||||
SysBusDevice *sbd;
|
||||
|
||||
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,
|
||||
pxa2xx_fir_rx, pxa2xx_fir_event, s);
|
||||
}
|
||||
|
||||
register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save,
|
||||
pxa2xx_fir_load, s);
|
||||
|
||||
return s;
|
||||
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)
|
||||
|
@ -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[] = {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -12,10 +12,10 @@
|
||||
#include <zlib.h> /* For crc32 */
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static inline int get_phys_addr(CPUARMState *env, target_ulong address,
|
||||
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);
|
||||
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,
|
||||
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)
|
||||
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,
|
||||
static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address,
|
||||
int access_type, ARMMMUIdx mmu_idx,
|
||||
hwaddr *phys_ptr, int *prot)
|
||||
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,
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,17 +10114,29 @@ 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user