mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 19:49:43 +00:00
target-arm queue
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABCAAGBQJSE3WMAAoJEDwlJe0UNgzetMcP/0lKE1tRvXjUk78Jazqff/ET op01vY5FiMurt9/ncV2kwTKGd5S/o8zmqf+3vbGijX9zlWMD1h1eJ/k8UeQxuCBf XYIPZhLESpBl7ex6b7G4Z0TUTT3qdLqHKTrdEzzTiwbmo1eu8cF2zWGh7eeeK/pA hX0BFlkBUo7SmlDOq4vj+88N3C+igcvE1UtOa9l17XpoLURkXZ0BFmy8Ew0f9iPj uWH9prnUpYAvzektZqEEGZQV9p1CM8O06GkdMFMqSSEU/YBnZY1pJrS+dOOZ3676 PQuGGdkOEPqBsz0dHPVifFXySg471LIYFUJWYGY69Uw4kGIkb1rEBuO8d5eJuFbn 2UYUnxOSNw3atBaE2E3TCKCQSBjrlZ/WSnuz873I50qz+DBnQ5fagG5RYKySQJcR UReC5WnWWwQh8oynx10lG6eggTSQZNxdHxF6VGTeygYPtuxlXdMPw+eveySxk6IH a4fP1GzlDKIKh7O0yc2pyPF5UsqZ1JmIwrkmBuR7sgml7r0T4AaEndu8b9xYg94j fHCgdLMFg5z8uWlzv5WzWX6PwYI9t46EWxHCk7x/Nrnp0WyF/XHhGipiS3AUOAQK pQlLOA+ru0UVAHSFM4nCikNDqo4kxuM3BOt+ypw69f56ImnpqAGruUUgH/Ua9vze DevOaXopdfsYczg6I+AF =Qnph -----END PGP SIGNATURE----- Merge remote-tracking branch 'pmaydell/tags/pull-target-arm-20130820' into staging target-arm queue # gpg: Signature made Tue 20 Aug 2013 08:56:28 AM CDT using RSA key ID 14360CDE # gpg: Can't check signature: public key not found # By Peter Maydell (20) and Peter Chubb (1) # Via Peter Maydell * pmaydell/tags/pull-target-arm-20130820: (21 commits) hw/timer/imx_epit: Simplify and fix imx_epit implementation default-configs: Fix A9MP and A15MP config names hw/cpu/a15mpcore: Wire generic timer outputs to GIC inputs target-arm: Implement the generic timer target-arm: Support coprocessor registers which do I/O target-arm: Allow raw_read() and raw_write() to handle 64 bit regs hw/arm/pic_cpu: Remove the now-unneeded arm_pic_init_cpu() hw/arm/xilinx_zynq: Don't use arm_pic_init_cpu() hw/arm/vexpress: Don't use arm_pic_init_cpu() hw/arm/versatilepb: Don't use arm_pic_init_cpu() hw/arm/strongarm: Don't use arm_pic_init_cpu() hw/arm/realview: Don't use arm_pic_init_cpu() hw/arm/omap*: Don't use arm_pic_init_cpu() hw/arm/musicpal: Don't use arm_pic_init_cpu() hw/arm/kzm: Don't use arm_pic_init_cpu() hw/arm/integratorcp: Don't use arm_pic_init_cpu() hw/arm/highbank: Don't use arm_pic_init_cpu() hw/arm/exynos4210: Don't use arm_pic_init_cpu() hw/arm/armv7m: Don't use arm_pic_init_cpu() target-arm: Make IRQ and FIQ gpio lines on the CPU object ... Message-id: 1377007680-4934-1-git-send-email-peter.maydell@linaro.org Signed-off-by: Anthony Liguori <anthony@codemonkey.ws>
This commit is contained in:
commit
ecfe10c9a6
@ -34,9 +34,9 @@ CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_MICRODRIVE=y
|
||||
CONFIG_USB_MUSB=y
|
||||
|
||||
CONFIG_ARM9MPCORE=y
|
||||
CONFIG_ARM11MPCORE=y
|
||||
CONFIG_ARM15MPCORE=y
|
||||
CONFIG_A9MPCORE=y
|
||||
CONFIG_A15MPCORE=y
|
||||
|
||||
CONFIG_ARM_GIC=y
|
||||
CONFIG_ARM_GIC_KVM=$(CONFIG_KVM)
|
||||
|
@ -1,6 +1,6 @@
|
||||
obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o
|
||||
obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
|
||||
obj-y += omap_sx1.o palm.o pic_cpu.o realview.o spitz.o stellaris.o
|
||||
obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
|
||||
obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
|
||||
|
||||
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
|
||||
|
@ -173,7 +173,6 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
|
||||
DeviceState *nvic;
|
||||
/* FIXME: make this local state. */
|
||||
static qemu_irq pic[64];
|
||||
qemu_irq *cpu_pic;
|
||||
int image_size;
|
||||
uint64_t entry;
|
||||
uint64_t lowaddr;
|
||||
@ -221,8 +220,8 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
|
||||
nvic = qdev_create(NULL, "armv7m_nvic");
|
||||
env->nvic = nvic;
|
||||
qdev_init_nofail(nvic);
|
||||
cpu_pic = arm_pic_init_cpu(cpu);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0,
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
|
||||
for (i = 0; i < 64; i++) {
|
||||
pic[i] = qdev_get_gpio_in(nvic, i);
|
||||
}
|
||||
|
@ -137,10 +137,8 @@ void exynos4210_write_secondary(ARMCPU *cpu,
|
||||
Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
||||
unsigned long ram_size)
|
||||
{
|
||||
qemu_irq cpu_irq[EXYNOS4210_NCPUS];
|
||||
int i, n;
|
||||
Exynos4210State *s = g_new(Exynos4210State, 1);
|
||||
qemu_irq *irqp;
|
||||
qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
|
||||
unsigned long mem_size;
|
||||
DeviceState *dev;
|
||||
@ -152,15 +150,6 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
||||
fprintf(stderr, "Unable to find CPU %d definition\n", n);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Create PIC controller for each processor instance */
|
||||
irqp = arm_pic_init_cpu(s->cpu[n]);
|
||||
|
||||
/*
|
||||
* Get GICs gpio_in cpu_irq to connect a combiner to them later.
|
||||
* Use only IRQ for a while.
|
||||
*/
|
||||
cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
|
||||
}
|
||||
|
||||
/*** IRQs ***/
|
||||
@ -178,8 +167,9 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
||||
}
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
|
||||
/* Connect IRQ Gate output to cpu_irq */
|
||||
sysbus_connect_irq(busdev, 0, cpu_irq[i]);
|
||||
/* Connect IRQ Gate output to CPU's IRQ line */
|
||||
sysbus_connect_irq(busdev, 0,
|
||||
qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ));
|
||||
}
|
||||
|
||||
/* Private memory region and Internal GIC */
|
||||
|
@ -209,7 +209,6 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
DeviceState *dev = NULL;
|
||||
SysBusDevice *busdev;
|
||||
qemu_irq *irqp;
|
||||
qemu_irq pic[128];
|
||||
int n;
|
||||
qemu_irq cpu_irq[4];
|
||||
@ -239,8 +238,7 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
|
||||
|
||||
/* This will become a QOM property eventually */
|
||||
cpu->reset_cbar = GIC_BASE_ADDR;
|
||||
irqp = arm_pic_init_cpu(cpu);
|
||||
cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
|
||||
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
|
||||
}
|
||||
|
||||
sysmem = get_system_memory();
|
||||
|
@ -465,7 +465,6 @@ static void integratorcp_init(QEMUMachineInitArgs *args)
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
||||
qemu_irq pic[32];
|
||||
qemu_irq *cpu_pic;
|
||||
DeviceState *dev;
|
||||
int i;
|
||||
|
||||
@ -493,10 +492,10 @@ static void integratorcp_init(QEMUMachineInitArgs *args)
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
|
||||
|
||||
cpu_pic = arm_pic_init_cpu(cpu);
|
||||
dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000,
|
||||
cpu_pic[ARM_PIC_CPU_IRQ],
|
||||
cpu_pic[ARM_PIC_CPU_FIQ], NULL);
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
|
||||
NULL);
|
||||
for (i = 0; i < 32; i++) {
|
||||
pic[i] = qdev_get_gpio_in(dev, i);
|
||||
}
|
||||
|
@ -82,7 +82,6 @@ static void kzm_init(QEMUMachineInitArgs *args)
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *sram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
||||
qemu_irq *cpu_pic;
|
||||
DeviceState *dev;
|
||||
DeviceState *ccm;
|
||||
|
||||
@ -108,11 +107,10 @@ static void kzm_init(QEMUMachineInitArgs *args)
|
||||
memory_region_init_ram(sram, NULL, "kzm.sram", 0x4000);
|
||||
memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram);
|
||||
|
||||
cpu_pic = arm_pic_init_cpu(cpu);
|
||||
dev = sysbus_create_varargs("imx_avic", 0x68000000,
|
||||
cpu_pic[ARM_PIC_CPU_IRQ],
|
||||
cpu_pic[ARM_PIC_CPU_FIQ], NULL);
|
||||
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
|
||||
NULL);
|
||||
|
||||
imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45));
|
||||
imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32));
|
||||
|
@ -1586,7 +1586,6 @@ static void musicpal_init(QEMUMachineInitArgs *args)
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ARMCPU *cpu;
|
||||
qemu_irq *cpu_pic;
|
||||
qemu_irq pic[32];
|
||||
DeviceState *dev;
|
||||
DeviceState *i2c_dev;
|
||||
@ -1610,7 +1609,6 @@ static void musicpal_init(QEMUMachineInitArgs *args)
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
cpu_pic = arm_pic_init_cpu(cpu);
|
||||
|
||||
/* For now we use a fixed - the original - RAM size */
|
||||
memory_region_init_ram(ram, NULL, "musicpal.ram", MP_RAM_DEFAULT_SIZE);
|
||||
@ -1622,7 +1620,7 @@ static void musicpal_init(QEMUMachineInitArgs *args)
|
||||
memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
|
||||
|
||||
dev = sysbus_create_simple(TYPE_MV88W8618_PIC, MP_PIC_BASE,
|
||||
cpu_pic[ARM_PIC_CPU_IRQ]);
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
|
||||
for (i = 0; i < 32; i++) {
|
||||
pic[i] = qdev_get_gpio_in(dev, i);
|
||||
}
|
||||
|
@ -3827,7 +3827,6 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
|
||||
int i;
|
||||
struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
|
||||
g_malloc0(sizeof(struct omap_mpu_state_s));
|
||||
qemu_irq *cpu_irq;
|
||||
qemu_irq dma_irqs[6];
|
||||
DriveInfo *dinfo;
|
||||
SysBusDevice *busdev;
|
||||
@ -3860,14 +3859,15 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
|
||||
|
||||
omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s);
|
||||
|
||||
cpu_irq = arm_pic_init_cpu(s->cpu);
|
||||
s->ih[0] = qdev_create(NULL, "omap-intc");
|
||||
qdev_prop_set_uint32(s->ih[0], "size", 0x100);
|
||||
qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck"));
|
||||
qdev_init_nofail(s->ih[0]);
|
||||
busdev = SYS_BUS_DEVICE(s->ih[0]);
|
||||
sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]);
|
||||
sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]);
|
||||
sysbus_connect_irq(busdev, 0,
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(busdev, 1,
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ));
|
||||
sysbus_mmio_map(busdev, 0, 0xfffecb00);
|
||||
s->ih[1] = qdev_create(NULL, "omap-intc");
|
||||
qdev_prop_set_uint32(s->ih[1], "size", 0x800);
|
||||
|
@ -2244,7 +2244,6 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
|
||||
{
|
||||
struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
|
||||
g_malloc0(sizeof(struct omap_mpu_state_s));
|
||||
qemu_irq *cpu_irq;
|
||||
qemu_irq dma_irqs[4];
|
||||
DriveInfo *dinfo;
|
||||
int i;
|
||||
@ -2277,15 +2276,16 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
|
||||
s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54);
|
||||
|
||||
/* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */
|
||||
cpu_irq = arm_pic_init_cpu(s->cpu);
|
||||
s->ih[0] = qdev_create(NULL, "omap2-intc");
|
||||
qdev_prop_set_uint8(s->ih[0], "revision", 0x21);
|
||||
qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk"));
|
||||
qdev_prop_set_ptr(s->ih[0], "iclk", omap_findclk(s, "mpu_intc_iclk"));
|
||||
qdev_init_nofail(s->ih[0]);
|
||||
busdev = SYS_BUS_DEVICE(s->ih[0]);
|
||||
sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]);
|
||||
sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]);
|
||||
sysbus_connect_irq(busdev, 0,
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(busdev, 1,
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ));
|
||||
sysbus_mmio_map(busdev, 0, 0x480fe000);
|
||||
s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3),
|
||||
qdev_get_gpio_in(s->ih[0],
|
||||
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Generic ARM Programmable Interrupt Controller support.
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This code is licensed under the LGPL
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
/* Input 0 is IRQ and input 1 is FIQ. */
|
||||
static void arm_pic_cpu_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
|
||||
switch (irq) {
|
||||
case ARM_PIC_CPU_IRQ:
|
||||
if (level) {
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
} else {
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
break;
|
||||
case ARM_PIC_CPU_FIQ:
|
||||
if (level) {
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_FIQ);
|
||||
} else {
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_FIQ);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
hw_error("arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_arm_pic_cpu_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
#ifdef CONFIG_KVM
|
||||
ARMCPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
|
||||
|
||||
switch (irq) {
|
||||
case ARM_PIC_CPU_IRQ:
|
||||
kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
|
||||
break;
|
||||
case ARM_PIC_CPU_FIQ:
|
||||
kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
|
||||
break;
|
||||
default:
|
||||
hw_error("kvm_arm_pic_cpu_handler: Bad interrupt line %d\n", irq);
|
||||
}
|
||||
kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
|
||||
kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
qemu_irq *arm_pic_init_cpu(ARMCPU *cpu)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2);
|
||||
}
|
||||
return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2);
|
||||
}
|
@ -56,7 +56,6 @@ static void realview_init(QEMUMachineInitArgs *args,
|
||||
MemoryRegion *ram_hack = g_new(MemoryRegion, 1);
|
||||
DeviceState *dev, *sysctl, *gpio2, *pl041;
|
||||
SysBusDevice *busdev;
|
||||
qemu_irq *irqp;
|
||||
qemu_irq pic[64];
|
||||
qemu_irq mmc_irq[2];
|
||||
PCIBus *pci_bus = NULL;
|
||||
@ -92,8 +91,7 @@ static void realview_init(QEMUMachineInitArgs *args,
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
irqp = arm_pic_init_cpu(cpu);
|
||||
cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
|
||||
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
|
||||
}
|
||||
env = &cpu->env;
|
||||
if (arm_feature(env, ARM_FEATURE_V7)) {
|
||||
|
@ -1588,7 +1588,6 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem,
|
||||
unsigned int sdram_size, const char *rev)
|
||||
{
|
||||
StrongARMState *s;
|
||||
qemu_irq *pic;
|
||||
int i;
|
||||
|
||||
s = g_malloc0(sizeof(StrongARMState));
|
||||
@ -1613,9 +1612,10 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem,
|
||||
vmstate_register_ram_global(&s->sdram);
|
||||
memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram);
|
||||
|
||||
pic = arm_pic_init_cpu(s->cpu);
|
||||
s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000,
|
||||
pic[ARM_PIC_CPU_IRQ], pic[ARM_PIC_CPU_FIQ], NULL);
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ),
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ),
|
||||
NULL);
|
||||
|
||||
sysbus_create_varargs("pxa25x-timer", 0x90000000,
|
||||
qdev_get_gpio_in(s->pic, SA_PIC_OSTC0),
|
||||
|
@ -178,7 +178,6 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id)
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
qemu_irq *cpu_pic;
|
||||
qemu_irq pic[32];
|
||||
qemu_irq sic[32];
|
||||
DeviceState *dev, *sysctl;
|
||||
@ -211,10 +210,10 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id)
|
||||
qdev_init_nofail(sysctl);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
|
||||
|
||||
cpu_pic = arm_pic_init_cpu(cpu);
|
||||
dev = sysbus_create_varargs("pl190", 0x10140000,
|
||||
cpu_pic[ARM_PIC_CPU_IRQ],
|
||||
cpu_pic[ARM_PIC_CPU_FIQ], NULL);
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
|
||||
NULL);
|
||||
for (n = 0; n < 32; n++) {
|
||||
pic[n] = qdev_get_gpio_in(dev, n);
|
||||
}
|
||||
|
@ -183,7 +183,6 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
MemoryRegion *lowram = g_new(MemoryRegion, 1);
|
||||
DeviceState *dev;
|
||||
SysBusDevice *busdev;
|
||||
qemu_irq *irqp;
|
||||
int n;
|
||||
qemu_irq cpu_irq[4];
|
||||
ram_addr_t low_ram_size;
|
||||
@ -198,8 +197,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
irqp = arm_pic_init_cpu(cpu);
|
||||
cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
|
||||
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
|
||||
}
|
||||
|
||||
if (ram_size > 0x40000000) {
|
||||
@ -312,15 +310,13 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
ARMCPU *cpu;
|
||||
qemu_irq *irqp;
|
||||
|
||||
cpu = cpu_arm_init(cpu_model);
|
||||
if (!cpu) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
irqp = arm_pic_init_cpu(cpu);
|
||||
cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
|
||||
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -108,11 +108,9 @@ static void zynq_init(QEMUMachineInitArgs *args)
|
||||
MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
|
||||
DeviceState *dev;
|
||||
SysBusDevice *busdev;
|
||||
qemu_irq *irqp;
|
||||
qemu_irq pic[64];
|
||||
NICInfo *nd;
|
||||
int n;
|
||||
qemu_irq cpu_irq;
|
||||
|
||||
if (!cpu_model) {
|
||||
cpu_model = "cortex-a9";
|
||||
@ -123,8 +121,6 @@ static void zynq_init(QEMUMachineInitArgs *args)
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
irqp = arm_pic_init_cpu(cpu);
|
||||
cpu_irq = irqp[ARM_PIC_CPU_IRQ];
|
||||
|
||||
/* max 2GB ram */
|
||||
if (ram_size > 0x80000000) {
|
||||
@ -159,7 +155,8 @@ static void zynq_init(QEMUMachineInitArgs *args)
|
||||
qdev_init_nofail(dev);
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, 0xF8F00000);
|
||||
sysbus_connect_irq(busdev, 0, cpu_irq);
|
||||
sysbus_connect_irq(busdev, 0,
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
|
||||
|
||||
for (n = 0; n < 64; n++) {
|
||||
pic[n] = qdev_get_gpio_in(dev, n);
|
||||
|
@ -1,5 +1,5 @@
|
||||
obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o
|
||||
obj-$(CONFIG_ARM9MPCORE) += a9mpcore.o
|
||||
obj-$(CONFIG_ARM15MPCORE) += a15mpcore.o
|
||||
obj-$(CONFIG_A9MPCORE) += a9mpcore.o
|
||||
obj-$(CONFIG_A15MPCORE) += a15mpcore.o
|
||||
obj-$(CONFIG_ICC_BUS) += icc_bus.o
|
||||
|
||||
|
@ -49,6 +49,8 @@ static int a15mp_priv_init(SysBusDevice *dev)
|
||||
A15MPPrivState *s = A15MPCORE_PRIV(dev);
|
||||
SysBusDevice *busdev;
|
||||
const char *gictype = "arm_gic";
|
||||
int i;
|
||||
CPUState *cpu;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
gictype = "kvm-arm-gic";
|
||||
@ -67,6 +69,22 @@ static int a15mp_priv_init(SysBusDevice *dev)
|
||||
/* Pass through inbound GPIO lines to the GIC */
|
||||
qdev_init_gpio_in(DEVICE(dev), a15mp_priv_set_irq, s->num_irq - 32);
|
||||
|
||||
/* Wire the outputs from each CPU's generic timer to the
|
||||
* appropriate GIC PPI inputs
|
||||
*/
|
||||
for (i = 0, cpu = first_cpu; i < s->num_cpu; i++, cpu = cpu->next_cpu) {
|
||||
DeviceState *cpudev = DEVICE(cpu);
|
||||
int ppibase = s->num_irq - 32 + i * 32;
|
||||
/* physical timer; we wire it up to the non-secure timer's ID,
|
||||
* since a real A15 always has TrustZone but QEMU doesn't.
|
||||
*/
|
||||
qdev_connect_gpio_out(cpudev, 0,
|
||||
qdev_get_gpio_in(s->gic, ppibase + 30));
|
||||
/* virtual timer */
|
||||
qdev_connect_gpio_out(cpudev, 1,
|
||||
qdev_get_gpio_in(s->gic, ppibase + 27));
|
||||
}
|
||||
|
||||
/* Memory map (addresses are offsets from PERIPHBASE):
|
||||
* 0x0000-0x0fff -- reserved
|
||||
* 0x1000-0x1fff -- GIC Distributor
|
||||
|
@ -43,7 +43,7 @@ static char const *imx_epit_reg_name(uint32_t reg)
|
||||
}
|
||||
|
||||
# define DPRINTF(fmt, args...) \
|
||||
do { printf("%s: " fmt , __func__, ##args); } while (0)
|
||||
do { fprintf(stderr, "%s: " fmt , __func__, ##args); } while (0)
|
||||
#else
|
||||
# define DPRINTF(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
@ -152,7 +152,7 @@ static void imx_epit_reset(DeviceState *dev)
|
||||
/*
|
||||
* Soft reset doesn't touch some bits; hard reset clears them
|
||||
*/
|
||||
s->cr &= ~(CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
|
||||
s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
|
||||
s->sr = 0;
|
||||
s->lr = TIMER_MAX;
|
||||
s->cmp = 0;
|
||||
@ -167,7 +167,7 @@ static void imx_epit_reset(DeviceState *dev)
|
||||
ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
|
||||
if (s->freq && (s->cr & CR_EN)) {
|
||||
/* if the timer is still enabled, restart it */
|
||||
ptimer_run(s->timer_reload, 1);
|
||||
ptimer_run(s->timer_reload, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,17 +218,17 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
|
||||
|
||||
static void imx_epit_reload_compare_timer(IMXEPITState *s)
|
||||
{
|
||||
if ((s->cr & CR_OCIEN) && s->cmp) {
|
||||
/* if the compare feature is on */
|
||||
if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) {
|
||||
/* if the compare feature is on and timers are running */
|
||||
uint32_t tmp = imx_epit_update_count(s);
|
||||
uint64_t next;
|
||||
if (tmp > s->cmp) {
|
||||
/* reinit the cmp timer if required */
|
||||
ptimer_set_count(s->timer_cmp, tmp - s->cmp);
|
||||
if ((s->cr & CR_EN)) {
|
||||
/* Restart the cmp timer if required */
|
||||
ptimer_run(s->timer_cmp, 0);
|
||||
}
|
||||
/* It'll fire in this round of the timer */
|
||||
next = tmp - s->cmp;
|
||||
} else { /* catch it next time around */
|
||||
next = tmp - s->cmp + ((s->cr & CR_RLD) ? TIMER_MAX : s->lr);
|
||||
}
|
||||
ptimer_set_count(s->timer_cmp, next);
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,11 +237,14 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
{
|
||||
IMXEPITState *s = IMX_EPIT(opaque);
|
||||
uint32_t reg = offset >> 2;
|
||||
uint64_t oldcr;
|
||||
|
||||
DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(reg), (uint32_t)value);
|
||||
|
||||
switch (reg) {
|
||||
case 0: /* CR */
|
||||
|
||||
oldcr = s->cr;
|
||||
s->cr = value & 0x03ffffff;
|
||||
if (s->cr & CR_SWR) {
|
||||
/* handle the reset */
|
||||
@ -250,22 +253,35 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
imx_epit_set_freq(s);
|
||||
}
|
||||
|
||||
if (s->freq && (s->cr & CR_EN)) {
|
||||
if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
|
||||
if (s->cr & CR_ENMOD) {
|
||||
if (s->cr & CR_RLD) {
|
||||
ptimer_set_limit(s->timer_reload, s->lr, 1);
|
||||
ptimer_set_limit(s->timer_cmp, s->lr, 1);
|
||||
} else {
|
||||
ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
|
||||
ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1);
|
||||
}
|
||||
}
|
||||
|
||||
imx_epit_reload_compare_timer(s);
|
||||
|
||||
ptimer_run(s->timer_reload, 1);
|
||||
} else {
|
||||
ptimer_run(s->timer_reload, 0);
|
||||
if (s->cr & CR_OCIEN) {
|
||||
ptimer_run(s->timer_cmp, 0);
|
||||
} else {
|
||||
ptimer_stop(s->timer_cmp);
|
||||
}
|
||||
} else if (!(s->cr & CR_EN)) {
|
||||
/* stop both timers */
|
||||
ptimer_stop(s->timer_reload);
|
||||
ptimer_stop(s->timer_cmp);
|
||||
} else if (s->cr & CR_OCIEN) {
|
||||
if (!(oldcr & CR_OCIEN)) {
|
||||
imx_epit_reload_compare_timer(s);
|
||||
ptimer_run(s->timer_cmp, 0);
|
||||
}
|
||||
} else {
|
||||
ptimer_stop(s->timer_cmp);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -284,13 +300,13 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
/* Also set the limit if the LRD bit is set */
|
||||
/* If IOVW bit is set then set the timer value */
|
||||
ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
|
||||
ptimer_set_limit(s->timer_cmp, s->lr, 0);
|
||||
} else if (s->cr & CR_IOVW) {
|
||||
/* If IOVW bit is set then set the timer value */
|
||||
ptimer_set_count(s->timer_reload, s->lr);
|
||||
}
|
||||
|
||||
imx_epit_reload_compare_timer(s);
|
||||
|
||||
break;
|
||||
|
||||
case 3: /* CMP */
|
||||
@ -306,51 +322,14 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void imx_epit_timeout(void *opaque)
|
||||
{
|
||||
IMXEPITState *s = IMX_EPIT(opaque);
|
||||
|
||||
DPRINTF("\n");
|
||||
|
||||
if (!(s->cr & CR_EN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->cr & CR_RLD) {
|
||||
ptimer_set_limit(s->timer_reload, s->lr, 1);
|
||||
} else {
|
||||
ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
|
||||
}
|
||||
|
||||
if (s->cr & CR_OCIEN) {
|
||||
/* if compare register is 0 then we handle the interrupt here */
|
||||
if (s->cmp == 0) {
|
||||
s->sr = 1;
|
||||
imx_epit_update_int(s);
|
||||
} else if (s->cmp <= s->lr) {
|
||||
/* We should launch the compare register */
|
||||
ptimer_set_count(s->timer_cmp, s->lr - s->cmp);
|
||||
ptimer_run(s->timer_cmp, 0);
|
||||
} else {
|
||||
IPRINTF("s->lr < s->cmp\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void imx_epit_cmp(void *opaque)
|
||||
{
|
||||
IMXEPITState *s = IMX_EPIT(opaque);
|
||||
|
||||
DPRINTF("\n");
|
||||
DPRINTF("sr was %d\n", s->sr);
|
||||
|
||||
ptimer_stop(s->timer_cmp);
|
||||
|
||||
/* compare register is not 0 */
|
||||
if (s->cmp) {
|
||||
s->sr = 1;
|
||||
imx_epit_update_int(s);
|
||||
}
|
||||
s->sr = 1;
|
||||
imx_epit_update_int(s);
|
||||
}
|
||||
|
||||
void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
|
||||
@ -400,8 +379,7 @@ static void imx_epit_realize(DeviceState *dev, Error **errp)
|
||||
0x00001000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
bh = qemu_bh_new(imx_epit_timeout, s);
|
||||
s->timer_reload = ptimer_init(bh);
|
||||
s->timer_reload = ptimer_init(NULL);
|
||||
|
||||
bh = qemu_bh_new(imx_epit_cmp, s);
|
||||
s->timer_cmp = ptimer_init(bh);
|
||||
|
@ -14,11 +14,6 @@
|
||||
#include "exec/memory.h"
|
||||
#include "hw/irq.h"
|
||||
|
||||
/* The CPU is also modelled as an interrupt controller. */
|
||||
#define ARM_PIC_CPU_IRQ 0
|
||||
#define ARM_PIC_CPU_FIQ 1
|
||||
qemu_irq *arm_pic_init_cpu(ARMCPU *cpu);
|
||||
|
||||
/* armv7m.c */
|
||||
qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
|
||||
int flash_size, int sram_size,
|
||||
|
@ -86,6 +86,11 @@ typedef struct ARMCPU {
|
||||
uint64_t *cpreg_vmstate_values;
|
||||
int32_t cpreg_vmstate_array_len;
|
||||
|
||||
/* Timers used by the generic (architected) timer */
|
||||
QEMUTimer *gt_timer[NUM_GTIMERS];
|
||||
/* GPIO outputs for generic timer */
|
||||
qemu_irq gt_timer_outputs[NUM_GTIMERS];
|
||||
|
||||
/* 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
|
||||
@ -152,4 +157,8 @@ hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||
int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
|
||||
/* Callback functions for the generic timer's timers. */
|
||||
void arm_gt_ptimer_cb(void *opaque);
|
||||
void arm_gt_vtimer_cb(void *opaque);
|
||||
|
||||
#endif
|
||||
|
@ -23,7 +23,9 @@
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#include "hw/loader.h"
|
||||
#endif
|
||||
#include "hw/arm/arm.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
static void arm_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
@ -129,6 +131,55 @@ static void arm_cpu_reset(CPUState *s)
|
||||
tb_flush(env);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static void arm_cpu_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
|
||||
switch (irq) {
|
||||
case ARM_CPU_IRQ:
|
||||
if (level) {
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
} else {
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
break;
|
||||
case ARM_CPU_FIQ:
|
||||
if (level) {
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_FIQ);
|
||||
} else {
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_FIQ);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
hw_error("arm_cpu_set_irq: Bad interrupt line %d\n", irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
#ifdef CONFIG_KVM
|
||||
ARMCPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
|
||||
|
||||
switch (irq) {
|
||||
case ARM_CPU_IRQ:
|
||||
kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
|
||||
break;
|
||||
case ARM_CPU_FIQ:
|
||||
kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
|
||||
break;
|
||||
default:
|
||||
hw_error("arm_cpu_kvm_set_irq: Bad interrupt line %d\n", irq);
|
||||
}
|
||||
kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
|
||||
kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void set_feature(CPUARMState *env, int feature)
|
||||
{
|
||||
env->features |= 1ULL << feature;
|
||||
@ -145,6 +196,22 @@ static void arm_cpu_initfn(Object *obj)
|
||||
cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal,
|
||||
g_free, g_free);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* Our inbound IRQ and FIQ lines */
|
||||
if (kvm_enabled()) {
|
||||
qdev_init_gpio_in(DEVICE(cpu), arm_cpu_kvm_set_irq, 2);
|
||||
} else {
|
||||
qdev_init_gpio_in(DEVICE(cpu), arm_cpu_set_irq, 2);
|
||||
}
|
||||
|
||||
cpu->gt_timer[GTIMER_PHYS] = qemu_new_timer(vm_clock, GTIMER_SCALE,
|
||||
arm_gt_ptimer_cb, cpu);
|
||||
cpu->gt_timer[GTIMER_VIRT] = qemu_new_timer(vm_clock, GTIMER_SCALE,
|
||||
arm_gt_vtimer_cb, cpu);
|
||||
qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs,
|
||||
ARRAY_SIZE(cpu->gt_timer_outputs));
|
||||
#endif
|
||||
|
||||
if (tcg_enabled() && !inited) {
|
||||
inited = true;
|
||||
arm_translate_init();
|
||||
|
@ -58,6 +58,9 @@
|
||||
/* ARM-specific interrupt pending bits. */
|
||||
#define CPU_INTERRUPT_FIQ CPU_INTERRUPT_TGT_EXT_1
|
||||
|
||||
/* Meanings of the ARMCPU object's two inbound GPIO lines */
|
||||
#define ARM_CPU_IRQ 0
|
||||
#define ARM_CPU_FIQ 1
|
||||
|
||||
typedef void ARMWriteCPFunc(void *opaque, int cp_info,
|
||||
int srcreg, int operand, uint32_t value);
|
||||
@ -76,6 +79,21 @@ struct arm_boot_info;
|
||||
s<2n+1> maps to the most significant half of d<n>
|
||||
*/
|
||||
|
||||
/* CPU state for each instance of a generic timer (in cp15 c14) */
|
||||
typedef struct ARMGenericTimer {
|
||||
uint64_t cval; /* Timer CompareValue register */
|
||||
uint32_t ctl; /* Timer Control register */
|
||||
} ARMGenericTimer;
|
||||
|
||||
#define GTIMER_PHYS 0
|
||||
#define GTIMER_VIRT 1
|
||||
#define NUM_GTIMERS 2
|
||||
|
||||
/* Scale factor for generic timers, ie number of ns per tick.
|
||||
* This gives a 62.5MHz timer.
|
||||
*/
|
||||
#define GTIMER_SCALE 16
|
||||
|
||||
typedef struct CPUARMState {
|
||||
/* Regs for current mode. */
|
||||
uint32_t regs[16];
|
||||
@ -143,6 +161,9 @@ typedef struct CPUARMState {
|
||||
uint32_t c13_tls1; /* User RW Thread register. */
|
||||
uint32_t c13_tls2; /* User RO Thread register. */
|
||||
uint32_t c13_tls3; /* Privileged Thread register. */
|
||||
uint32_t c14_cntfrq; /* Counter Frequency register */
|
||||
uint32_t c14_cntkctl; /* Timer Control register */
|
||||
ARMGenericTimer c14_timer[NUM_GTIMERS];
|
||||
uint32_t c15_cpar; /* XScale Coprocessor Access Register */
|
||||
uint32_t c15_ticonfig; /* TI925T configuration byte. */
|
||||
uint32_t c15_i_max; /* Maximum D-cache dirty line index. */
|
||||
@ -469,6 +490,9 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
|
||||
* old must have the OVERRIDE bit set.
|
||||
* NO_MIGRATE indicates that this register should be ignored for migration;
|
||||
* (eg because any state is accessed via some other coprocessor register).
|
||||
* IO indicates that this register does I/O and therefore its accesses
|
||||
* need to be surrounded by gen_io_start()/gen_io_end(). In particular,
|
||||
* registers which implement clocks or timers require this.
|
||||
*/
|
||||
#define ARM_CP_SPECIAL 1
|
||||
#define ARM_CP_CONST 2
|
||||
@ -476,13 +500,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
|
||||
#define ARM_CP_SUPPRESS_TB_END 8
|
||||
#define ARM_CP_OVERRIDE 16
|
||||
#define ARM_CP_NO_MIGRATE 32
|
||||
#define ARM_CP_IO 64
|
||||
#define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
|
||||
#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
|
||||
#define ARM_LAST_SPECIAL ARM_CP_WFI
|
||||
/* Used only as a terminator for ARMCPRegInfo lists */
|
||||
#define ARM_CP_SENTINEL 0xffff
|
||||
/* Mask of only the flag bits in a type field */
|
||||
#define ARM_CP_FLAG_MASK 0x3f
|
||||
#define ARM_CP_FLAG_MASK 0x7f
|
||||
|
||||
/* Return true if cptype is a valid type field. This is used to try to
|
||||
* catch errors where the sentinel has been accidentally left off the end
|
||||
|
@ -67,14 +67,22 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
|
||||
static int raw_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t *value)
|
||||
{
|
||||
*value = CPREG_FIELD32(env, ri);
|
||||
if (ri->type & ARM_CP_64BIT) {
|
||||
*value = CPREG_FIELD64(env, ri);
|
||||
} else {
|
||||
*value = CPREG_FIELD32(env, ri);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
CPREG_FIELD32(env, ri) = value;
|
||||
if (ri->type & ARM_CP_64BIT) {
|
||||
CPREG_FIELD64(env, ri) = value;
|
||||
} else {
|
||||
CPREG_FIELD32(env, ri) = value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -687,15 +695,261 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
static uint64_t gt_get_countervalue(CPUARMState *env)
|
||||
{
|
||||
return qemu_get_clock_ns(vm_clock) / GTIMER_SCALE;
|
||||
}
|
||||
|
||||
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
||||
{
|
||||
ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx];
|
||||
|
||||
if (gt->ctl & 1) {
|
||||
/* Timer enabled: calculate and set current ISTATUS, irq, and
|
||||
* reset timer to when ISTATUS next has to change
|
||||
*/
|
||||
uint64_t count = gt_get_countervalue(&cpu->env);
|
||||
/* Note that this must be unsigned 64 bit arithmetic: */
|
||||
int istatus = count >= gt->cval;
|
||||
uint64_t nexttick;
|
||||
|
||||
gt->ctl = deposit32(gt->ctl, 2, 1, istatus);
|
||||
qemu_set_irq(cpu->gt_timer_outputs[timeridx],
|
||||
(istatus && !(gt->ctl & 2)));
|
||||
if (istatus) {
|
||||
/* Next transition is when count rolls back over to zero */
|
||||
nexttick = UINT64_MAX;
|
||||
} else {
|
||||
/* Next transition is when we hit cval */
|
||||
nexttick = gt->cval;
|
||||
}
|
||||
/* Note that the desired next expiry time might be beyond the
|
||||
* signed-64-bit range of a QEMUTimer -- in this case we just
|
||||
* set the timer for as far in the future as possible. When the
|
||||
* timer expires we will reset the timer for any remaining period.
|
||||
*/
|
||||
if (nexttick > INT64_MAX / GTIMER_SCALE) {
|
||||
nexttick = INT64_MAX / GTIMER_SCALE;
|
||||
}
|
||||
qemu_mod_timer(cpu->gt_timer[timeridx], nexttick);
|
||||
} else {
|
||||
/* Timer disabled: ISTATUS and timer output always clear */
|
||||
gt->ctl &= ~4;
|
||||
qemu_set_irq(cpu->gt_timer_outputs[timeridx], 0);
|
||||
qemu_del_timer(cpu->gt_timer[timeridx]);
|
||||
}
|
||||
}
|
||||
|
||||
static int gt_cntfrq_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t *value)
|
||||
{
|
||||
/* Not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero */
|
||||
if (arm_current_pl(env) == 0 && !extract32(env->cp15.c14_cntkctl, 0, 2)) {
|
||||
return EXCP_UDEF;
|
||||
}
|
||||
*value = env->cp15.c14_cntfrq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gt_cnt_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
int timeridx = ri->opc1 & 1;
|
||||
|
||||
qemu_del_timer(cpu->gt_timer[timeridx]);
|
||||
}
|
||||
|
||||
static int gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t *value)
|
||||
{
|
||||
int timeridx = ri->opc1 & 1;
|
||||
|
||||
if (arm_current_pl(env) == 0 &&
|
||||
!extract32(env->cp15.c14_cntkctl, timeridx, 1)) {
|
||||
return EXCP_UDEF;
|
||||
}
|
||||
*value = gt_get_countervalue(env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gt_cval_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t *value)
|
||||
{
|
||||
int timeridx = ri->opc1 & 1;
|
||||
|
||||
if (arm_current_pl(env) == 0 &&
|
||||
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
|
||||
return EXCP_UDEF;
|
||||
}
|
||||
*value = env->cp15.c14_timer[timeridx].cval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
int timeridx = ri->opc1 & 1;
|
||||
|
||||
env->cp15.c14_timer[timeridx].cval = value;
|
||||
gt_recalc_timer(arm_env_get_cpu(env), timeridx);
|
||||
return 0;
|
||||
}
|
||||
static int gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t *value)
|
||||
{
|
||||
int timeridx = ri->crm & 1;
|
||||
|
||||
if (arm_current_pl(env) == 0 &&
|
||||
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
|
||||
return EXCP_UDEF;
|
||||
}
|
||||
*value = (uint32_t)(env->cp15.c14_timer[timeridx].cval -
|
||||
gt_get_countervalue(env));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
int timeridx = ri->crm & 1;
|
||||
|
||||
env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) +
|
||||
+ sextract64(value, 0, 32);
|
||||
gt_recalc_timer(arm_env_get_cpu(env), timeridx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gt_ctl_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t *value)
|
||||
{
|
||||
int timeridx = ri->crm & 1;
|
||||
|
||||
if (arm_current_pl(env) == 0 &&
|
||||
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
|
||||
return EXCP_UDEF;
|
||||
}
|
||||
*value = env->cp15.c14_timer[timeridx].ctl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
int timeridx = ri->crm & 1;
|
||||
uint32_t oldval = env->cp15.c14_timer[timeridx].ctl;
|
||||
|
||||
env->cp15.c14_timer[timeridx].ctl = value & 3;
|
||||
if ((oldval ^ value) & 1) {
|
||||
/* Enable toggled */
|
||||
gt_recalc_timer(cpu, timeridx);
|
||||
} else if ((oldval & value) & 2) {
|
||||
/* IMASK toggled: don't need to recalculate,
|
||||
* just set the interrupt line based on ISTATUS
|
||||
*/
|
||||
qemu_set_irq(cpu->gt_timer_outputs[timeridx],
|
||||
(oldval & 4) && (value & 2));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arm_gt_ptimer_cb(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
|
||||
gt_recalc_timer(cpu, GTIMER_PHYS);
|
||||
}
|
||||
|
||||
void arm_gt_vtimer_cb(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
|
||||
gt_recalc_timer(cpu, GTIMER_VIRT);
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
/* Dummy implementation: RAZ/WI the whole crn=14 space */
|
||||
{ .name = "GENERIC_TIMER", .cp = 15, .crn = 14,
|
||||
.crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_NO_MIGRATE,
|
||||
.resetvalue = 0 },
|
||||
/* Note that CNTFRQ is purely reads-as-written for the benefit
|
||||
* of software; writing it doesn't actually change the timer frequency.
|
||||
* Our reset value matches the fixed frequency we implement the timer at.
|
||||
*/
|
||||
{ .name = "CNTFRQ", .cp = 15, .crn = 14, .crm = 0, .opc1 = 0, .opc2 = 0,
|
||||
.access = PL1_RW | PL0_R,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq),
|
||||
.resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE,
|
||||
.readfn = gt_cntfrq_read, .raw_readfn = raw_read,
|
||||
},
|
||||
/* overall control: mostly access permissions */
|
||||
{ .name = "CNTKCTL", .cp = 15, .crn = 14, .crm = 1, .opc1 = 0, .opc2 = 0,
|
||||
.access = PL1_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl),
|
||||
.resetvalue = 0,
|
||||
},
|
||||
/* per-timer control */
|
||||
{ .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1,
|
||||
.type = ARM_CP_IO, .access = PL1_RW | PL0_R,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
|
||||
.resetvalue = 0,
|
||||
.readfn = gt_ctl_read, .writefn = gt_ctl_write,
|
||||
.raw_readfn = raw_read, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1,
|
||||
.type = ARM_CP_IO, .access = PL1_RW | PL0_R,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
|
||||
.resetvalue = 0,
|
||||
.readfn = gt_ctl_read, .writefn = gt_ctl_write,
|
||||
.raw_readfn = raw_read, .raw_writefn = raw_write,
|
||||
},
|
||||
/* TimerValue views: a 32 bit downcounting view of the underlying state */
|
||||
{ .name = "CNTP_TVAL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0,
|
||||
.type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
|
||||
.readfn = gt_tval_read, .writefn = gt_tval_write,
|
||||
},
|
||||
{ .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0,
|
||||
.type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
|
||||
.readfn = gt_tval_read, .writefn = gt_tval_write,
|
||||
},
|
||||
/* The counter itself */
|
||||
{ .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0,
|
||||
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO,
|
||||
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
|
||||
},
|
||||
{ .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1,
|
||||
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO,
|
||||
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
|
||||
},
|
||||
/* Comparison value, indicating when the timer goes off */
|
||||
{ .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2,
|
||||
.access = PL1_RW | PL0_R,
|
||||
.type = ARM_CP_64BIT | ARM_CP_IO,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
|
||||
.resetvalue = 0,
|
||||
.readfn = gt_cval_read, .writefn = gt_cval_write,
|
||||
.raw_readfn = raw_read, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3,
|
||||
.access = PL1_RW | PL0_R,
|
||||
.type = ARM_CP_64BIT | ARM_CP_IO,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
|
||||
.resetvalue = 0,
|
||||
.readfn = gt_cval_read, .writefn = gt_cval_write,
|
||||
.raw_readfn = raw_read, .raw_writefn = raw_write,
|
||||
},
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
#else
|
||||
/* In user-mode none of the generic timer registers are accessible,
|
||||
* and their implementation depends on vm_clock and qdev gpio outputs,
|
||||
* so instead just don't register any of them.
|
||||
*/
|
||||
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static int par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
||||
{
|
||||
if (arm_feature(env, ARM_FEATURE_LPAE)) {
|
||||
@ -1974,6 +2228,37 @@ static void do_v7m_exception_exit(CPUARMState *env)
|
||||
pointer. */
|
||||
}
|
||||
|
||||
/* Exception names for debug logging; note that not all of these
|
||||
* precisely correspond to architectural exceptions.
|
||||
*/
|
||||
static const char * const excnames[] = {
|
||||
[EXCP_UDEF] = "Undefined Instruction",
|
||||
[EXCP_SWI] = "SVC",
|
||||
[EXCP_PREFETCH_ABORT] = "Prefetch Abort",
|
||||
[EXCP_DATA_ABORT] = "Data Abort",
|
||||
[EXCP_IRQ] = "IRQ",
|
||||
[EXCP_FIQ] = "FIQ",
|
||||
[EXCP_BKPT] = "Breakpoint",
|
||||
[EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
|
||||
[EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
|
||||
[EXCP_STREX] = "QEMU intercept of STREX",
|
||||
};
|
||||
|
||||
static inline void arm_log_exception(int idx)
|
||||
{
|
||||
if (qemu_loglevel_mask(CPU_LOG_INT)) {
|
||||
const char *exc = NULL;
|
||||
|
||||
if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
|
||||
exc = excnames[idx];
|
||||
}
|
||||
if (!exc) {
|
||||
exc = "unknown";
|
||||
}
|
||||
qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc);
|
||||
}
|
||||
}
|
||||
|
||||
void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
@ -1982,6 +2267,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||
uint32_t lr;
|
||||
uint32_t addr;
|
||||
|
||||
arm_log_exception(env->exception_index);
|
||||
|
||||
lr = 0xfffffff1;
|
||||
if (env->v7m.current_sp)
|
||||
lr |= 4;
|
||||
@ -2011,6 +2298,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||
if (nr == 0xab) {
|
||||
env->regs[15] += 2;
|
||||
env->regs[0] = do_arm_semihosting(env);
|
||||
qemu_log_mask(CPU_LOG_INT, "...handled as semihosting call\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2064,6 +2352,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
|
||||
assert(!IS_M(env));
|
||||
|
||||
arm_log_exception(env->exception_index);
|
||||
|
||||
/* TODO: Vectored interrupt controller. */
|
||||
switch (env->exception_index) {
|
||||
case EXCP_UDEF:
|
||||
@ -2091,6 +2381,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
|| (mask == 0xab && env->thumb))
|
||||
&& (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
|
||||
env->regs[0] = do_arm_semihosting(env);
|
||||
qemu_log_mask(CPU_LOG_INT, "...handled as semihosting call\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2108,18 +2399,23 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
&& (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
|
||||
env->regs[15] += 2;
|
||||
env->regs[0] = do_arm_semihosting(env);
|
||||
qemu_log_mask(CPU_LOG_INT, "...handled as semihosting call\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
env->cp15.c5_insn = 2;
|
||||
/* Fall through to prefetch abort. */
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
|
||||
env->cp15.c5_insn, env->cp15.c6_insn);
|
||||
new_mode = ARM_CPU_MODE_ABT;
|
||||
addr = 0x0c;
|
||||
mask = CPSR_A | CPSR_I;
|
||||
offset = 4;
|
||||
break;
|
||||
case EXCP_DATA_ABORT:
|
||||
qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
|
||||
env->cp15.c5_data, env->cp15.c6_data);
|
||||
new_mode = ARM_CPU_MODE_ABT;
|
||||
addr = 0x10;
|
||||
mask = CPSR_A | CPSR_I;
|
||||
|
@ -222,9 +222,9 @@ static int cpu_post_load(void *opaque, int version_id)
|
||||
|
||||
const VMStateDescription vmstate_arm_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 12,
|
||||
.minimum_version_id = 12,
|
||||
.minimum_version_id_old = 12,
|
||||
.version_id = 13,
|
||||
.minimum_version_id = 13,
|
||||
.minimum_version_id_old = 13,
|
||||
.pre_save = cpu_pre_save,
|
||||
.post_load = cpu_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
@ -257,6 +257,8 @@ const VMStateDescription vmstate_arm_cpu = {
|
||||
VMSTATE_UINT32(env.exclusive_val, ARMCPU),
|
||||
VMSTATE_UINT32(env.exclusive_high, ARMCPU),
|
||||
VMSTATE_UINT64(env.features, ARMCPU),
|
||||
VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU),
|
||||
VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.subsections = (VMStateSubsection[]) {
|
||||
|
@ -6280,6 +6280,10 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
||||
break;
|
||||
}
|
||||
|
||||
if (use_icount && (ri->type & ARM_CP_IO)) {
|
||||
gen_io_start();
|
||||
}
|
||||
|
||||
if (isread) {
|
||||
/* Read */
|
||||
if (is64) {
|
||||
@ -6369,14 +6373,20 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
||||
store_cpu_offset(tmp, ri->fieldoffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (use_icount && (ri->type & ARM_CP_IO)) {
|
||||
/* I/O operations must end the TB here (whether read or write) */
|
||||
gen_io_end();
|
||||
gen_lookup_tb(s);
|
||||
} else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
|
||||
/* We default to ending the TB on a coprocessor register write,
|
||||
* but allow this to be suppressed by the register definition
|
||||
* (usually only necessary to work around guest bugs).
|
||||
*/
|
||||
if (!(ri->type & ARM_CP_SUPPRESS_TB_END)) {
|
||||
gen_lookup_tb(s);
|
||||
}
|
||||
gen_lookup_tb(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user