target-arm queue:

* i.MX code cleanup/refactorings
  * i.MX UART fix to work with uninitialized chardev
  * minor GIC code refactorings
  * implement the ARM Secure physical timer
  * implement the ARM Hypervisor timer
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJVzHQ4AAoJEDwlJe0UNgzefeAQAJoUuhCUnssxy8eVXZ81ijpF
 MxBm7jy/l64iCWXmVb85j2xAWNbcStE775BOlJNWYdFTeXJRKBNnFxAgQP75XLbs
 r1pszGqjQDz15Raa9yCq3mcZ/W1ww/ZqbKMq4OxIfBaSvsPAIN73sJaYnE9J08RX
 oAMZ7Ji76mNU4fp6D9c/aMzhODcKlCkjhWfr3d9WKQNcxBTlNWhaeZEDKHCChnKw
 CyRekUn8hMgdtVHpUG8hO7Q8/l8BgB9dhY8twS5rurVt1Pm7PSS+t2OmUFkR3E9Y
 hwHeJANV2kWxBi5iL20YSDQCtxETpcvfo1ASUWfKU39yYYHk/zFIAskMuZ5T9iah
 +I1dLt3gP+Md6D4S5vMPr6s8s5iInc3qHYs7hMMWsxbubZ9+poflyNRdhh7sJIJ+
 75GmLIePxRCIukzEDbIp51y4kmBNi376oR/3HHOs4rp9Nvt0PQOsSj+Prk5vmWq+
 klZ7hdE5cDZhvTHhmkGstswT9+XtXZsef7kFRhgf83LnSIim2iZmH23jpKTi7x5i
 6hluA/JLoS/OSLuXFdmo84GbSoh962dIk73UT7jhef+9D8306v/VC2nv0oXR/iNm
 sxNIN7MqMilWeMVfB5TELhqoBuSr10tfUgWaQMvRHaF6KrzkJtNZBcZxb302g6n0
 5RIKpvNw2lK2jtmziCca
 =geLz
 -----END PGP SIGNATURE-----

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

target-arm queue:
 * i.MX code cleanup/refactorings
 * i.MX UART fix to work with uninitialized chardev
 * minor GIC code refactorings
 * implement the ARM Secure physical timer
 * implement the ARM Hypervisor timer

# gpg: Signature made Thu 13 Aug 2015 11:40:56 BST using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"

* remotes/pmaydell/tags/pull-target-arm-20150813: (27 commits)
  i.MX: Fix UART driver to work with unitialized "chardev" device
  hw/cpu/a15mpcore: Wire up hyp and secure physical timer interrupts
  hw/arm/virt: Wire up secure timer interrupt
  target-arm: Add AArch32 banked register access to secure physical timer
  target-arm: Add the AArch64 view of the Secure physical timer
  target-arm: Add debug check for mismatched cpreg resets
  Introduce gic_class_name() instead of repeating condition
  hw/arm/gic: Kill code duplication
  Merge memory_region_init_reservation() into memory_region_init_io()
  i.MX: Fix Coding style for GPT emulator
  i.MX: Split GPT emulator in a header file and a source file
  i.MX: Fix Coding style for EPIT emulator
  i.MX: Split EPIT emulator in a header file and a source file
  i.MX: Fix Coding style for CCM emulator
  i.MX: Split CCM emulator in a header file and a source file
  i.MX: Fix Coding style for AVIC emulator.
  i.MX: Split AVIC emulator in a header file and a source file
  i.MX:Fix Coding style for UART emulator.
  i.MX: Move serial initialization to init/realize of DeviceClass.
  i.MX: Split UART emulator in a header file and a source file
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2015-08-13 12:04:24 +01:00
commit 425591e3ef
25 changed files with 1003 additions and 524 deletions

View File

@ -22,6 +22,7 @@
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "hw/char/serial.h"
#include "hw/intc/imx_avic.h"
#include "hw/arm/imx.h"
/* Memory map for Kzm Emulation Baseboard:
@ -106,7 +107,7 @@ static void kzm_init(MachineState *machine)
memory_region_init_ram(sram, NULL, "kzm.sram", 0x4000, &error_abort);
memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram);
dev = sysbus_create_varargs("imx_avic", 0x68000000,
dev = sysbus_create_varargs(TYPE_IMX_AVIC, 0x68000000,
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
NULL);
@ -114,7 +115,7 @@ static void kzm_init(MachineState *machine)
imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45));
imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32));
ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL);
ccm = sysbus_create_simple(TYPE_IMX_CCM, 0x53f80000, NULL);
imx_timerp_create(0x53f94000, qdev_get_gpio_in(dev, 28), ccm);
imx_timerp_create(0x53f98000, qdev_get_gpio_in(dev, 27), ccm);

View File

@ -48,6 +48,8 @@
#include "hw/arm/sysbus-fdt.h"
#include "hw/platform-bus.h"
#include "hw/arm/fdt.h"
#include "hw/intc/arm_gic_common.h"
#include "kvm_arm.h"
/* Number of external interrupt lines to configure the GIC with */
#define NUM_IRQS 256
@ -365,12 +367,10 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
/* We create a standalone GIC v2 */
DeviceState *gicdev;
SysBusDevice *gicbusdev;
const char *gictype = "arm_gic";
const char *gictype;
int i;
if (kvm_irqchip_in_kernel()) {
gictype = "kvm-arm-gic";
}
gictype = gic_class_name();
gicdev = qdev_create(NULL, gictype);
qdev_prop_set_uint32(gicdev, "revision", 2);
@ -390,15 +390,23 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
*/
for (i = 0; i < smp_cpus; i++) {
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
int ppibase = NUM_IRQS + 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.
int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
int irq;
/* Mapping from the output timer irq lines from the CPU to the
* GIC PPI inputs we use for the virt board.
*/
qdev_connect_gpio_out(cpudev, 0,
qdev_get_gpio_in(gicdev, ppibase + 30));
/* virtual timer */
qdev_connect_gpio_out(cpudev, 1,
qdev_get_gpio_in(gicdev, ppibase + 27));
const int timer_irq[] = {
[GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
[GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
[GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
[GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
};
for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
qdev_connect_gpio_out(cpudev, irq,
qdev_get_gpio_in(gicdev,
ppibase + timer_irq[irq]));
}
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
sysbus_connect_irq(gicbusdev, i + smp_cpus,

View File

@ -4,6 +4,7 @@
* Copyright (c) 2008 OKL
* Originally Written by Hans Jiang
* Copyright (c) 2011 NICTA Pty Ltd.
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@ -17,8 +18,7 @@
* is a real serial device.
*/
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/char/imx_serial.h"
#include "sysemu/sysemu.h"
#include "sysemu/char.h"
#include "hw/arm/imx.h"
@ -26,7 +26,7 @@
//#define DEBUG_SERIAL 1
#ifdef DEBUG_SERIAL
#define DPRINTF(fmt, args...) \
do { printf("imx_serial: " fmt , ##args); } while (0)
do { printf("%s: " fmt , TYPE_IMX_SERIAL, ##args); } while (0)
#else
#define DPRINTF(fmt, args...) do {} while (0)
#endif
@ -38,42 +38,13 @@ do { printf("imx_serial: " fmt , ##args); } while (0)
//#define DEBUG_IMPLEMENTATION 1
#ifdef DEBUG_IMPLEMENTATION
# define IPRINTF(fmt, args...) \
do { fprintf(stderr, "imx_serial: " fmt, ##args); } while (0)
do { fprintf(stderr, "%s: " fmt, TYPE_IMX_SERIAL, ##args); } while (0)
#else
# define IPRINTF(fmt, args...) do {} while (0)
#endif
#define TYPE_IMX_SERIAL "imx-serial"
#define IMX_SERIAL(obj) OBJECT_CHECK(IMXSerialState, (obj), TYPE_IMX_SERIAL)
typedef struct IMXSerialState {
SysBusDevice parent_obj;
MemoryRegion iomem;
int32_t readbuff;
uint32_t usr1;
uint32_t usr2;
uint32_t ucr1;
uint32_t ucr2;
uint32_t uts1;
/*
* The registers below are implemented just so that the
* guest OS sees what it has written
*/
uint32_t onems;
uint32_t ufcr;
uint32_t ubmr;
uint32_t ubrc;
uint32_t ucr3;
qemu_irq irq;
CharDriverState *chr;
} IMXSerialState;
static const VMStateDescription vmstate_imx_serial = {
.name = "imx-serial",
.name = TYPE_IMX_SERIAL,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
@ -91,55 +62,6 @@ static const VMStateDescription vmstate_imx_serial = {
},
};
#define URXD_CHARRDY (1<<15) /* character read is valid */
#define URXD_ERR (1<<14) /* Character has error */
#define URXD_BRK (1<<11) /* Break received */
#define USR1_PARTYER (1<<15) /* Parity Error */
#define USR1_RTSS (1<<14) /* RTS pin status */
#define USR1_TRDY (1<<13) /* Tx ready */
#define USR1_RTSD (1<<12) /* RTS delta: pin changed state */
#define USR1_ESCF (1<<11) /* Escape sequence interrupt */
#define USR1_FRAMERR (1<<10) /* Framing error */
#define USR1_RRDY (1<<9) /* receiver ready */
#define USR1_AGTIM (1<<8) /* Aging timer interrupt */
#define USR1_DTRD (1<<7) /* DTR changed */
#define USR1_RXDS (1<<6) /* Receiver is idle */
#define USR1_AIRINT (1<<5) /* Aysnch IR interrupt */
#define USR1_AWAKE (1<<4) /* Falling edge detected on RXd pin */
#define USR2_ADET (1<<15) /* Autobaud complete */
#define USR2_TXFE (1<<14) /* Transmit FIFO empty */
#define USR2_DTRF (1<<13) /* DTR/DSR transition */
#define USR2_IDLE (1<<12) /* UART has been idle for too long */
#define USR2_ACST (1<<11) /* Autobaud counter stopped */
#define USR2_RIDELT (1<<10) /* Ring Indicator delta */
#define USR2_RIIN (1<<9) /* Ring Indicator Input */
#define USR2_IRINT (1<<8) /* Serial Infrared Interrupt */
#define USR2_WAKE (1<<7) /* Start bit detected */
#define USR2_DCDDELT (1<<6) /* Data Carrier Detect delta */
#define USR2_DCDIN (1<<5) /* Data Carrier Detect Input */
#define USR2_RTSF (1<<4) /* RTS transition */
#define USR2_TXDC (1<<3) /* Transmission complete */
#define USR2_BRCD (1<<2) /* Break condition detected */
#define USR2_ORE (1<<1) /* Overrun error */
#define USR2_RDR (1<<0) /* Receive data ready */
#define UCR1_TRDYEN (1<<13) /* Tx Ready Interrupt Enable */
#define UCR1_RRDYEN (1<<9) /* Rx Ready Interrupt Enable */
#define UCR1_TXMPTYEN (1<<6) /* Tx Empty Interrupt Enable */
#define UCR1_UARTEN (1<<0) /* UART Enable */
#define UCR2_TXEN (1<<2) /* Transmitter enable */
#define UCR2_RXEN (1<<1) /* Receiver enable */
#define UCR2_SRST (1<<0) /* Reset complete */
#define UTS1_TXEMPTY (1<<6)
#define UTS1_RXEMPTY (1<<5)
#define UTS1_TXFULL (1<<4)
#define UTS1_RXFULL (1<<3)
static void imx_update(IMXSerialState *s)
{
uint32_t flags;
@ -203,7 +125,9 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
s->usr2 &= ~USR2_RDR;
s->uts1 |= UTS1_RXEMPTY;
imx_update(s);
qemu_chr_accept_input(s->chr);
if (s->chr) {
qemu_chr_accept_input(s->chr);
}
}
return c;
@ -242,13 +166,13 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
return 0x0; /* TODO */
default:
IPRINTF("imx_serial_read: bad offset: 0x%x\n", (int)offset);
IPRINTF("%s: bad offset: 0x%x\n", __func__, (int)offset);
return 0;
}
}
static void imx_serial_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
uint64_t value, unsigned size)
{
IMXSerialState *s = (IMXSerialState *)opaque;
unsigned char ch;
@ -290,7 +214,9 @@ static void imx_serial_write(void *opaque, hwaddr offset,
}
if (value & UCR2_RXEN) {
if (!(s->ucr2 & UCR2_RXEN)) {
qemu_chr_accept_input(s->chr);
if (s->chr) {
qemu_chr_accept_input(s->chr);
}
}
}
s->ucr2 = value & 0xffff;
@ -298,25 +224,25 @@ static void imx_serial_write(void *opaque, hwaddr offset,
case 0x25: /* USR1 */
value &= USR1_AWAKE | USR1_AIRINT | USR1_DTRD | USR1_AGTIM |
USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER;
USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER;
s->usr1 &= ~value;
break;
case 0x26: /* USR2 */
/*
* Writing 1 to some bits clears them; all other
* values are ignored
*/
/*
* Writing 1 to some bits clears them; all other
* values are ignored
*/
value &= USR2_ADET | USR2_DTRF | USR2_IDLE | USR2_ACST |
USR2_RIDELT | USR2_IRINT | USR2_WAKE |
USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE;
USR2_RIDELT | USR2_IRINT | USR2_WAKE |
USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE;
s->usr2 &= ~value;
break;
/*
* Linux expects to see what it writes to these registers
* We don't currently alter the baud rate
*/
/*
* Linux expects to see what it writes to these registers
* We don't currently alter the baud rate
*/
case 0x29: /* UBIR */
s->ubrc = value & 0xffff;
break;
@ -344,7 +270,7 @@ static void imx_serial_write(void *opaque, hwaddr offset,
break;
default:
IPRINTF("imx_serial_write: Bad offset 0x%x\n", (int)offset);
IPRINTF("%s: Bad offset 0x%x\n", __func__, (int)offset);
}
}
@ -384,16 +310,10 @@ static const struct MemoryRegionOps imx_serial_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
static int imx_serial_init(SysBusDevice *dev)
static void imx_serial_realize(DeviceState *dev, Error **errp)
{
IMXSerialState *s = IMX_SERIAL(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &imx_serial_ops, s,
"imx-serial", 0x1000);
sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
if (s->chr) {
qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
imx_event, s);
@ -401,8 +321,17 @@ static int imx_serial_init(SysBusDevice *dev)
DPRINTF("No char dev for uart at 0x%lx\n",
(unsigned long)s->iomem.ram_addr);
}
}
return 0;
static void imx_serial_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
IMXSerialState *s = IMX_SERIAL(obj);
memory_region_init_io(&s->iomem, obj, &imx_serial_ops, s,
TYPE_IMX_SERIAL, 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
}
void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq)
@ -439,7 +368,7 @@ void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq)
}
static Property imx32_serial_properties[] = {
static Property imx_serial_properties[] = {
DEFINE_PROP_CHR("chardev", IMXSerialState, chr),
DEFINE_PROP_END_OF_LIST(),
};
@ -447,21 +376,21 @@ static Property imx32_serial_properties[] = {
static void imx_serial_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
k->init = imx_serial_init;
dc->realize = imx_serial_realize;
dc->vmsd = &vmstate_imx_serial;
dc->reset = imx_serial_reset_at_boot;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
dc->desc = "i.MX series UART";
dc->props = imx32_serial_properties;
dc->props = imx_serial_properties;
}
static const TypeInfo imx_serial_info = {
.name = TYPE_IMX_SERIAL,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IMXSerialState),
.class_init = imx_serial_class_init,
.name = TYPE_IMX_SERIAL,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IMXSerialState),
.instance_init = imx_serial_init,
.class_init = imx_serial_class_init,
};
static void imx_serial_register_types(void)

View File

@ -20,6 +20,7 @@
#include "hw/cpu/a15mpcore.h"
#include "sysemu/kvm.h"
#include "kvm_arm.h"
static void a15mp_priv_set_irq(void *opaque, int irq, int level)
{
@ -33,16 +34,11 @@ static void a15mp_priv_initfn(Object *obj)
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
A15MPPrivState *s = A15MPCORE_PRIV(obj);
DeviceState *gicdev;
const char *gictype = "arm_gic";
if (kvm_irqchip_in_kernel()) {
gictype = "kvm-arm-gic";
}
memory_region_init(&s->container, obj, "a15mp-priv-container", 0x8000);
sysbus_init_mmio(sbd, &s->container);
object_initialize(&s->gic, sizeof(s->gic), gictype);
object_initialize(&s->gic, sizeof(s->gic), gic_class_name());
gicdev = DEVICE(&s->gic);
qdev_set_parent_bus(gicdev, sysbus_get_default());
qdev_prop_set_uint32(gicdev, "revision", 2);
@ -79,14 +75,21 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
for (i = 0; i < s->num_cpu; i++) {
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
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.
int irq;
/* Mapping from the output timer irq lines from the CPU to the
* GIC PPI inputs used on the A15:
*/
qdev_connect_gpio_out(cpudev, 0,
qdev_get_gpio_in(gicdev, ppibase + 30));
/* virtual timer */
qdev_connect_gpio_out(cpudev, 1,
qdev_get_gpio_in(gicdev, ppibase + 27));
const int timer_irq[] = {
[GTIMER_PHYS] = 30,
[GTIMER_VIRT] = 27,
[GTIMER_HYP] = 26,
[GTIMER_SEC] = 29,
};
for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
qdev_connect_gpio_out(cpudev, irq,
qdev_get_gpio_in(gicdev,
ppibase + timer_irq[irq]));
}
}
/* Memory map (addresses are offsets from PERIPHBASE):

View File

@ -922,12 +922,6 @@ static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data,
}
}
static const MemoryRegionOps gic_dist_ops = {
.read_with_attrs = gic_dist_read,
.write_with_attrs = gic_dist_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
uint64_t *data, MemTxAttrs attrs)
{
@ -1056,10 +1050,17 @@ static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr,
return gic_cpu_write(s, id, addr, value, attrs);
}
static const MemoryRegionOps gic_thiscpu_ops = {
.read_with_attrs = gic_thiscpu_read,
.write_with_attrs = gic_thiscpu_write,
.endianness = DEVICE_NATIVE_ENDIAN,
static const MemoryRegionOps gic_ops[2] = {
{
.read_with_attrs = gic_dist_read,
.write_with_attrs = gic_dist_write,
.endianness = DEVICE_NATIVE_ENDIAN,
},
{
.read_with_attrs = gic_thiscpu_read,
.write_with_attrs = gic_thiscpu_write,
.endianness = DEVICE_NATIVE_ENDIAN,
}
};
static const MemoryRegionOps gic_cpu_ops = {
@ -1068,31 +1069,10 @@ static const MemoryRegionOps gic_cpu_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
/* This function is used by nvic model */
void gic_init_irqs_and_distributor(GICState *s)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
int i;
i = s->num_irq - GIC_INTERNAL;
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
* GPIO array layout is thus:
* [0..N-1] SPIs
* [N..N+31] PPIs for CPU 0
* [N+32..N+63] PPIs for CPU 1
* ...
*/
if (s->revision != REV_NVIC) {
i += (GIC_INTERNAL * s->num_cpu);
}
qdev_init_gpio_in(DEVICE(s), gic_set_irq, i);
for (i = 0; i < NUM_CPU(s); i++) {
sysbus_init_irq(sbd, &s->parent_irq[i]);
}
for (i = 0; i < NUM_CPU(s); i++) {
sysbus_init_irq(sbd, &s->parent_fiq[i]);
}
memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s,
"gic_dist", 0x1000);
gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops);
}
static void arm_gic_realize(DeviceState *dev, Error **errp)
@ -1110,28 +1090,22 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
return;
}
gic_init_irqs_and_distributor(s);
/* This creates distributor and main CPU interface (s->cpuiomem[0]) */
gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops);
/* Memory regions for the CPU interfaces (NVIC doesn't have these):
* a region for "CPU interface for this core", then a region for
* "CPU interface for core 0", "for core 1", ...
/* Extra core-specific regions for the CPU interfaces. This is
* necessary for "franken-GIC" implementations, for example on
* Exynos 4.
* NB that the memory region size of 0x100 applies for the 11MPCore
* and also cores following the GIC v1 spec (ie A9).
* GIC v2 defines a larger memory region (0x1000) so this will need
* to be extended when we implement A15.
*/
memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s,
"gic_cpu", 0x100);
for (i = 0; i < NUM_CPU(s); i++) {
s->backref[i] = s;
memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops,
&s->backref[i], "gic_cpu", 0x100);
}
/* Distributor */
sysbus_init_mmio(sbd, &s->iomem);
/* cpu interfaces (one for "current cpu" plus one per cpu) */
for (i = 0; i <= NUM_CPU(s); i++) {
sysbus_init_mmio(sbd, &s->cpuiomem[i]);
sysbus_init_mmio(sbd, &s->cpuiomem[i+1]);
}
}

View File

@ -84,6 +84,47 @@ static const VMStateDescription vmstate_gic = {
}
};
void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
const MemoryRegionOps *ops)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
int i = s->num_irq - GIC_INTERNAL;
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
* GPIO array layout is thus:
* [0..N-1] SPIs
* [N..N+31] PPIs for CPU 0
* [N+32..N+63] PPIs for CPU 1
* ...
*/
if (s->revision != REV_NVIC) {
i += (GIC_INTERNAL * s->num_cpu);
}
qdev_init_gpio_in(DEVICE(s), handler, i);
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->parent_irq[i]);
}
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->parent_fiq[i]);
}
/* Distributor */
memory_region_init_io(&s->iomem, OBJECT(s), ops, s, "gic_dist", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
if (s->revision != REV_NVIC) {
/* This is the main CPU interface "for this core". It is always
* present because it is required by both software emulation and KVM.
* NVIC is not handled here because its CPU interface is different,
* neither it can use KVM.
*/
memory_region_init_io(&s->cpuiomem[0], OBJECT(s), ops ? &ops[1] : NULL,
s, "gic_cpu", s->revision == 2 ? 0x1000 : 0x100);
sysbus_init_mmio(sbd, &s->cpuiomem[0]);
}
}
static void arm_gic_common_realize(DeviceState *dev, Error **errp)
{
GICState *s = ARM_GIC_COMMON(dev);

View File

@ -543,7 +543,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
{
int i;
GICState *s = KVM_ARM_GIC(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
Error *local_err = NULL;
int ret;
@ -560,32 +559,13 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
return;
}
i = s->num_irq - GIC_INTERNAL;
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
* GPIO array layout is thus:
* [0..N-1] SPIs
* [N..N+31] PPIs for CPU 0
* [N+32..N+63] PPIs for CPU 1
* ...
*/
i += (GIC_INTERNAL * s->num_cpu);
qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);
gic_init_irqs_and_mmio(s, kvm_arm_gic_set_irq, NULL);
for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
qemu_irq irq = qdev_get_gpio_in(dev, i);
kvm_irqchip_set_qemuirq_gsi(kvm_state, irq, i);
}
/* We never use our outbound IRQ/FIQ lines but provide them so that
* we maintain the same interface as the non-KVM GIC.
*/
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->parent_irq[i]);
}
for (i = 0; i < s->num_cpu; i++) {
sysbus_init_irq(sbd, &s->parent_fiq[i]);
}
/* Try to create the device via the device control API */
s->dev_fd = -1;
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false);
@ -609,9 +589,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
}
/* Distributor */
memory_region_init_reservation(&s->iomem, OBJECT(s),
"kvm-gic_dist", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
kvm_arm_register_device(&s->iomem,
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
| KVM_VGIC_V2_ADDR_TYPE_DIST,
@ -622,9 +599,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
* provide the "interface for core #N" memory regions, because
* cores with a VGIC don't have those.
*/
memory_region_init_reservation(&s->cpuiomem[0], OBJECT(s),
"kvm-gic_cpu", 0x1000);
sysbus_init_mmio(sbd, &s->cpuiomem[0]);
kvm_arm_register_device(&s->cpuiomem[0],
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
| KVM_VGIC_V2_ADDR_TYPE_CPU,

View File

@ -7,6 +7,7 @@
* Copyright (c) 2008 OKL
* Copyright (c) 2011 NICTA Pty Ltd
* Originally written by Hans Jiang
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
*
* This code is licensed under the GPL version 2 or later. See
* the COPYING file in the top-level directory.
@ -14,16 +15,14 @@
* TODO: implement vectors.
*/
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "qemu/host-utils.h"
#include "hw/intc/imx_avic.h"
#define DEBUG_INT 1
#undef DEBUG_INT /* comment out for debugging */
#ifdef DEBUG_INT
#define DPRINTF(fmt, args...) \
do { printf("imx_avic: " fmt , ##args); } while (0)
do { printf("%s: " fmt , TYPE_IMX_AVIC, ##args); } while (0)
#else
#define DPRINTF(fmt, args...) do {} while (0)
#endif
@ -35,46 +34,13 @@ do { printf("imx_avic: " fmt , ##args); } while (0)
#define DEBUG_IMPLEMENTATION 1
#if DEBUG_IMPLEMENTATION
# define IPRINTF(fmt, args...) \
do { fprintf(stderr, "imx_avic: " fmt, ##args); } while (0)
do { fprintf(stderr, "%s: " fmt, TYPE_IMX_AVIC, ##args); } while (0)
#else
# define IPRINTF(fmt, args...) do {} while (0)
#endif
#define IMX_AVIC_NUM_IRQS 64
/* Interrupt Control Bits */
#define ABFLAG (1<<25)
#define ABFEN (1<<24)
#define NIDIS (1<<22) /* Normal Interrupt disable */
#define FIDIS (1<<21) /* Fast interrupt disable */
#define NIAD (1<<20) /* Normal Interrupt Arbiter Rise ARM level */
#define FIAD (1<<19) /* Fast Interrupt Arbiter Rise ARM level */
#define NM (1<<18) /* Normal interrupt mode */
#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4)
#define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD)
#define TYPE_IMX_AVIC "imx_avic"
#define IMX_AVIC(obj) \
OBJECT_CHECK(IMXAVICState, (obj), TYPE_IMX_AVIC)
typedef struct IMXAVICState {
SysBusDevice parent_obj;
MemoryRegion iomem;
uint64_t pending;
uint64_t enabled;
uint64_t is_fiq;
uint32_t intcntl;
uint32_t intmask;
qemu_irq irq;
qemu_irq fiq;
uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */
} IMXAVICState;
static const VMStateDescription vmstate_imx_avic = {
.name = "imx-avic",
.name = TYPE_IMX_AVIC,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
@ -88,8 +54,6 @@ static const VMStateDescription vmstate_imx_avic = {
},
};
static inline int imx_avic_prio(IMXAVICState *s, int irq)
{
uint32_t word = irq / PRIO_PER_WORD;
@ -249,7 +213,7 @@ static uint64_t imx_avic_read(void *opaque,
return 0x4;
default:
IPRINTF("imx_avic_read: Bad offset 0x%x\n", (int)offset);
IPRINTF("%s: Bad offset 0x%x\n", __func__, (int)offset);
return 0;
}
}
@ -261,12 +225,12 @@ static void imx_avic_write(void *opaque, hwaddr offset,
/* Vector Registers not yet supported */
if (offset >= 0x100 && offset <= 0x2fc) {
IPRINTF("imx_avic_write to vector register %d ignored\n",
IPRINTF("%s to vector register %d ignored\n", __func__,
(unsigned int)((offset - 0x100) >> 2));
return;
}
DPRINTF("imx_avic_write(0x%x) = %x\n",
DPRINTF("%s(0x%x) = %x\n", __func__,
(unsigned int)offset>>2, (unsigned int)val);
switch (offset >> 2) {
case 0: /* Interrupt Control Register, INTCNTL */
@ -341,7 +305,7 @@ static void imx_avic_write(void *opaque, hwaddr offset,
return;
default:
IPRINTF("imx_avic_write: Bad offset %x\n", (int)offset);
IPRINTF("%s: Bad offset %x\n", __func__, (int)offset);
}
imx_avic_update(s);
}
@ -370,7 +334,7 @@ static int imx_avic_init(SysBusDevice *sbd)
IMXAVICState *s = IMX_AVIC(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &imx_avic_ops, s,
"imx_avic", 0x1000);
TYPE_IMX_AVIC, 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS);

View File

@ -2,6 +2,7 @@
* IMX31 Clock Control Module
*
* Copyright (C) 2012 NICTA
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@ -10,51 +11,23 @@
* the CCM.
*/
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
#include "hw/arm/imx.h"
#include "hw/misc/imx_ccm.h"
#define CKIH_FREQ 26000000 /* 26MHz crystal input */
#define CKIL_FREQ 32768 /* nominal 32khz clock */
//#define DEBUG_CCM 1
#ifdef DEBUG_CCM
#define DPRINTF(fmt, args...) \
do { printf("imx_ccm: " fmt , ##args); } while (0)
do { printf("%s: " fmt , TYPE_IMX_CCM, ##args); } while (0)
#else
#define DPRINTF(fmt, args...) do {} while (0)
#endif
static int imx_ccm_post_load(void *opaque, int version_id);
#define TYPE_IMX_CCM "imx_ccm"
#define IMX_CCM(obj) OBJECT_CHECK(IMXCCMState, (obj), TYPE_IMX_CCM)
typedef struct IMXCCMState {
SysBusDevice parent_obj;
MemoryRegion iomem;
uint32_t ccmr;
uint32_t pdr0;
uint32_t pdr1;
uint32_t mpctl;
uint32_t spctl;
uint32_t cgr[3];
uint32_t pmcr0;
uint32_t pmcr1;
/* Frequencies precalculated on register changes */
uint32_t pll_refclk_freq;
uint32_t mcu_clk_freq;
uint32_t hsp_clk_freq;
uint32_t ipg_clk_freq;
} IMXCCMState;
static const VMStateDescription vmstate_imx_ccm = {
.name = "imx-ccm",
.name = TYPE_IMX_CCM,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
@ -72,44 +45,6 @@ static const VMStateDescription vmstate_imx_ccm = {
.post_load = imx_ccm_post_load,
};
/* CCMR */
#define CCMR_FPME (1<<0)
#define CCMR_MPE (1<<3)
#define CCMR_MDS (1<<7)
#define CCMR_FPMF (1<<26)
#define CCMR_PRCS (3<<1)
/* PDR0 */
#define PDR0_MCU_PODF_SHIFT (0)
#define PDR0_MCU_PODF_MASK (0x7)
#define PDR0_MAX_PODF_SHIFT (3)
#define PDR0_MAX_PODF_MASK (0x7)
#define PDR0_IPG_PODF_SHIFT (6)
#define PDR0_IPG_PODF_MASK (0x3)
#define PDR0_NFC_PODF_SHIFT (8)
#define PDR0_NFC_PODF_MASK (0x7)
#define PDR0_HSP_PODF_SHIFT (11)
#define PDR0_HSP_PODF_MASK (0x7)
#define PDR0_PER_PODF_SHIFT (16)
#define PDR0_PER_PODF_MASK (0x1f)
#define PDR0_CSI_PODF_SHIFT (23)
#define PDR0_CSI_PODF_MASK (0x1ff)
#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
& PDR0_##name##_PODF_MASK)
#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
PDR0_##name##_PODF_SHIFT)
/* PLL control registers */
#define PD(v) (((v) >> 26) & 0xf)
#define MFD(v) (((v) >> 16) & 0x3ff)
#define MFI(v) (((v) >> 10) & 0xf);
#define MFN(v) ((v) & 0x3ff)
#define PLL_PD(x) (((x) & 0xf) << 26)
#define PLL_MFD(x) (((x) & 0x3ff) << 16)
#define PLL_MFI(x) (((x) & 0xf) << 10)
#define PLL_MFN(x) (((x) & 0x3ff) << 0)
uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock)
{
IMXCCMState *s = IMX_CCM(dev);
@ -174,7 +109,7 @@ static void update_clocks(IMXCCMState *s)
s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP));
s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG));
DPRINTF("Clocks: mcu %uMHz, HSP %uMHz, IPG %uHz\n",
DPRINTF("%s: mcu %uMHz, HSP %uMHz, IPG %uHz\n", __func__,
s->mcu_clk_freq / 1000000,
s->hsp_clk_freq / 1000000,
s->ipg_clk_freq);
@ -200,7 +135,7 @@ static uint64_t imx_ccm_read(void *opaque, hwaddr offset,
{
IMXCCMState *s = (IMXCCMState *)opaque;
DPRINTF("read(offset=%x)", offset >> 2);
DPRINTF("%s(offset=%x)", __func__, offset >> 2);
switch (offset >> 2) {
case 0: /* CCMR */
DPRINTF(" ccmr = 0x%x\n", s->ccmr);
@ -241,7 +176,7 @@ static void imx_ccm_write(void *opaque, hwaddr offset,
{
IMXCCMState *s = (IMXCCMState *)opaque;
DPRINTF("write(offset=%x, value = %x)\n",
DPRINTF("%s(offset=%x, value = %x)\n", __func__,
offset >> 2, (unsigned int)value);
switch (offset >> 2) {
case 0:
@ -286,7 +221,7 @@ static int imx_ccm_init(SysBusDevice *dev)
IMXCCMState *s = IMX_CCM(dev);
memory_region_init_io(&s->iomem, OBJECT(dev), &imx_ccm_ops, s,
"imx_ccm", 0x1000);
TYPE_IMX_CCM, 0x1000);
sysbus_init_mmio(dev, &s->iomem);
return 0;

View File

@ -5,23 +5,18 @@
* Copyright (c) 2011 NICTA Pty Ltd
* Originally written by Hans Jiang
* Updated by Peter Chubb
* Updated by Jean-Christophe Dubois
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
*
* This code is licensed under GPL version 2 or later. See
* the COPYING file in the top-level directory.
*
*/
#include "hw/hw.h"
#include "qemu/bitops.h"
#include "qemu/timer.h"
#include "hw/ptimer.h"
#include "hw/sysbus.h"
#include "hw/arm/imx.h"
#include "hw/timer/imx_epit.h"
#include "hw/misc/imx_ccm.h"
#include "qemu/main-loop.h"
#define TYPE_IMX_EPIT "imx.epit"
#define DEBUG_TIMER 0
#if DEBUG_TIMER
@ -61,30 +56,6 @@ static char const *imx_epit_reg_name(uint32_t reg)
# define IPRINTF(fmt, args...) do {} while (0)
#endif
#define IMX_EPIT(obj) \
OBJECT_CHECK(IMXEPITState, (obj), TYPE_IMX_EPIT)
/*
* EPIT: Enhanced periodic interrupt timer
*/
#define CR_EN (1 << 0)
#define CR_ENMOD (1 << 1)
#define CR_OCIEN (1 << 2)
#define CR_RLD (1 << 3)
#define CR_PRESCALE_SHIFT (4)
#define CR_PRESCALE_MASK (0xfff)
#define CR_SWR (1 << 16)
#define CR_IOVW (1 << 17)
#define CR_DBGEN (1 << 18)
#define CR_WAITEN (1 << 19)
#define CR_DOZEN (1 << 20)
#define CR_STOPEN (1 << 21)
#define CR_CLKSRC_SHIFT (24)
#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT)
#define EPIT_TIMER_MAX 0XFFFFFFFFUL
/*
* Exact clock frequencies vary from board to board.
* These are typical.
@ -96,23 +67,6 @@ static const IMXClk imx_epit_clocks[] = {
CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */
};
typedef struct {
SysBusDevice busdev;
ptimer_state *timer_reload;
ptimer_state *timer_cmp;
MemoryRegion iomem;
DeviceState *ccm;
uint32_t cr;
uint32_t sr;
uint32_t lr;
uint32_t cmp;
uint32_t cnt;
uint32_t freq;
qemu_irq irq;
} IMXEPITState;
/*
* Update interrupt status
*/
@ -174,9 +128,9 @@ static void imx_epit_reset(DeviceState *dev)
static uint32_t imx_epit_update_count(IMXEPITState *s)
{
s->cnt = ptimer_get_count(s->timer_reload);
s->cnt = ptimer_get_count(s->timer_reload);
return s->cnt;
return s->cnt;
}
static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
@ -344,13 +298,13 @@ void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
}
static const MemoryRegionOps imx_epit_ops = {
.read = imx_epit_read,
.write = imx_epit_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.read = imx_epit_read,
.write = imx_epit_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static const VMStateDescription vmstate_imx_timer_epit = {
.name = "imx.epit",
.name = TYPE_IMX_EPIT,
.version_id = 2,
.minimum_version_id = 2,
.fields = (VMStateField[]) {

View File

@ -5,23 +5,18 @@
* Copyright (c) 2011 NICTA Pty Ltd
* Originally written by Hans Jiang
* Updated by Peter Chubb
* Updated by Jean-Christophe Dubois
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
*
* This code is licensed under GPL version 2 or later. See
* the COPYING file in the top-level directory.
*
*/
#include "hw/hw.h"
#include "qemu/bitops.h"
#include "qemu/timer.h"
#include "hw/ptimer.h"
#include "hw/sysbus.h"
#include "hw/arm/imx.h"
#include "hw/timer/imx_gpt.h"
#include "hw/misc/imx_ccm.h"
#include "qemu/main-loop.h"
#define TYPE_IMX_GPT "imx.gpt"
/*
* Define to 1 for debug messages
*/
@ -74,76 +69,8 @@ static char const *imx_gpt_reg_name(uint32_t reg)
# define IPRINTF(fmt, args...) do {} while (0)
#endif
#define IMX_GPT(obj) \
OBJECT_CHECK(IMXGPTState, (obj), TYPE_IMX_GPT)
/*
* GPT : General purpose timer
*
* This timer counts up continuously while it is enabled, resetting itself
* to 0 when it reaches GPT_TIMER_MAX (in freerun mode) or when it
* reaches the value of one of the ocrX (in periodic mode).
*/
#define GPT_TIMER_MAX 0XFFFFFFFFUL
/* Control register. Not all of these bits have any effect (yet) */
#define GPT_CR_EN (1 << 0) /* GPT Enable */
#define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */
#define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */
#define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */
#define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */
#define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */
#define GPT_CR_CLKSRC_SHIFT (6)
#define GPT_CR_CLKSRC_MASK (0x7)
#define GPT_CR_FRR (1 << 9) /* Freerun or Restart */
#define GPT_CR_SWR (1 << 15) /* Software Reset */
#define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */
#define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */
#define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */
#define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */
#define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */
#define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */
#define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */
#define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */
#define GPT_SR_OF1 (1 << 0)
#define GPT_SR_OF2 (1 << 1)
#define GPT_SR_OF3 (1 << 2)
#define GPT_SR_ROV (1 << 5)
#define GPT_IR_OF1IE (1 << 0)
#define GPT_IR_OF2IE (1 << 1)
#define GPT_IR_OF3IE (1 << 2)
#define GPT_IR_ROVIE (1 << 5)
typedef struct {
SysBusDevice busdev;
ptimer_state *timer;
MemoryRegion iomem;
DeviceState *ccm;
uint32_t cr;
uint32_t pr;
uint32_t sr;
uint32_t ir;
uint32_t ocr1;
uint32_t ocr2;
uint32_t ocr3;
uint32_t icr1;
uint32_t icr2;
uint32_t cnt;
uint32_t next_timeout;
uint32_t next_int;
uint32_t freq;
qemu_irq irq;
} IMXGPTState;
static const VMStateDescription vmstate_imx_timer_gpt = {
.name = "imx.gpt",
.name = TYPE_IMX_GPT,
.version_id = 3,
.minimum_version_id = 3,
.fields = (VMStateField[]) {
@ -180,7 +107,7 @@ static void imx_gpt_set_freq(IMXGPTState *s)
{
uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3);
uint32_t freq = imx_clock_frequency(s->ccm, imx_gpt_clocks[clksrc])
/ (1 + s->pr);
/ (1 + s->pr);
s->freq = freq;
DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, freq);
@ -207,7 +134,7 @@ static uint32_t imx_gpt_update_count(IMXGPTState *s)
}
static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg,
uint32_t timeout)
uint32_t timeout)
{
if ((count < reg) && (timeout > reg)) {
timeout = reg;

View File

@ -437,6 +437,9 @@ void memory_region_init_alias(MemoryRegion *mr,
* memory_region_init_rom_device: Initialize a ROM memory region. Writes are
* handled via callbacks.
*
* If NULL callbacks pointer is given, then I/O space is not supposed to be
* handled by QEMU itself. Any access via the memory API will cause an abort().
*
* @mr: the #MemoryRegion to be initialized.
* @owner: the object that tracks the region's reference count
* @ops: callbacks for write access handling.
@ -459,16 +462,21 @@ void memory_region_init_rom_device(MemoryRegion *mr,
* A reservation region primariy serves debugging purposes. It claims I/O
* space that is not supposed to be handled by QEMU itself. Any access via
* the memory API will cause an abort().
* This function is deprecated. Use memory_region_init_io() with NULL
* callbacks instead.
*
* @mr: the #MemoryRegion to be initialized
* @owner: the object that tracks the region's reference count
* @name: used for debugging; not visible to the user or ABI
* @size: size of the region.
*/
void memory_region_init_reservation(MemoryRegion *mr,
struct Object *owner,
static inline void memory_region_init_reservation(MemoryRegion *mr,
Object *owner,
const char *name,
uint64_t size);
uint64_t size)
{
memory_region_init_io(mr, owner, NULL, mr, name, size);
}
/**
* memory_region_init_iommu: Initialize a memory region that translates

View File

@ -11,18 +11,10 @@
#ifndef IMX_H
#define IMX_H
#include "hw/misc/imx_ccm.h"
void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq);
typedef enum {
NOCLK,
MCU,
HSP,
IPG,
CLK_32k
} IMXClk;
uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock);
void imx_timerp_create(const hwaddr addr,
qemu_irq irq,
DeviceState *ccm);

View File

@ -0,0 +1,102 @@
/*
* Device model for i.MX UART
*
* Copyright (c) 2008 OKL
* Originally Written by Hans Jiang
* Copyright (c) 2011 NICTA Pty Ltd.
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IMX_SERIAL_H
#define IMX_SERIAL_H
#include "hw/sysbus.h"
#define TYPE_IMX_SERIAL "imx.serial"
#define IMX_SERIAL(obj) OBJECT_CHECK(IMXSerialState, (obj), TYPE_IMX_SERIAL)
#define URXD_CHARRDY (1<<15) /* character read is valid */
#define URXD_ERR (1<<14) /* Character has error */
#define URXD_BRK (1<<11) /* Break received */
#define USR1_PARTYER (1<<15) /* Parity Error */
#define USR1_RTSS (1<<14) /* RTS pin status */
#define USR1_TRDY (1<<13) /* Tx ready */
#define USR1_RTSD (1<<12) /* RTS delta: pin changed state */
#define USR1_ESCF (1<<11) /* Escape sequence interrupt */
#define USR1_FRAMERR (1<<10) /* Framing error */
#define USR1_RRDY (1<<9) /* receiver ready */
#define USR1_AGTIM (1<<8) /* Aging timer interrupt */
#define USR1_DTRD (1<<7) /* DTR changed */
#define USR1_RXDS (1<<6) /* Receiver is idle */
#define USR1_AIRINT (1<<5) /* Aysnch IR interrupt */
#define USR1_AWAKE (1<<4) /* Falling edge detected on RXd pin */
#define USR2_ADET (1<<15) /* Autobaud complete */
#define USR2_TXFE (1<<14) /* Transmit FIFO empty */
#define USR2_DTRF (1<<13) /* DTR/DSR transition */
#define USR2_IDLE (1<<12) /* UART has been idle for too long */
#define USR2_ACST (1<<11) /* Autobaud counter stopped */
#define USR2_RIDELT (1<<10) /* Ring Indicator delta */
#define USR2_RIIN (1<<9) /* Ring Indicator Input */
#define USR2_IRINT (1<<8) /* Serial Infrared Interrupt */
#define USR2_WAKE (1<<7) /* Start bit detected */
#define USR2_DCDDELT (1<<6) /* Data Carrier Detect delta */
#define USR2_DCDIN (1<<5) /* Data Carrier Detect Input */
#define USR2_RTSF (1<<4) /* RTS transition */
#define USR2_TXDC (1<<3) /* Transmission complete */
#define USR2_BRCD (1<<2) /* Break condition detected */
#define USR2_ORE (1<<1) /* Overrun error */
#define USR2_RDR (1<<0) /* Receive data ready */
#define UCR1_TRDYEN (1<<13) /* Tx Ready Interrupt Enable */
#define UCR1_RRDYEN (1<<9) /* Rx Ready Interrupt Enable */
#define UCR1_TXMPTYEN (1<<6) /* Tx Empty Interrupt Enable */
#define UCR1_UARTEN (1<<0) /* UART Enable */
#define UCR2_TXEN (1<<2) /* Transmitter enable */
#define UCR2_RXEN (1<<1) /* Receiver enable */
#define UCR2_SRST (1<<0) /* Reset complete */
#define UTS1_TXEMPTY (1<<6)
#define UTS1_RXEMPTY (1<<5)
#define UTS1_TXFULL (1<<4)
#define UTS1_RXFULL (1<<3)
typedef struct IMXSerialState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion iomem;
int32_t readbuff;
uint32_t usr1;
uint32_t usr2;
uint32_t ucr1;
uint32_t ucr2;
uint32_t uts1;
/*
* The registers below are implemented just so that the
* guest OS sees what it has written
*/
uint32_t onems;
uint32_t ufcr;
uint32_t ubmr;
uint32_t ubrc;
uint32_t ucr3;
qemu_irq irq;
CharDriverState *chr;
} IMXSerialState;
#endif

View File

@ -138,4 +138,7 @@ typedef struct ARMGICCommonClass {
void (*post_load)(GICState *s);
} ARMGICCommonClass;
void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
const MemoryRegionOps *ops);
#endif

View File

@ -0,0 +1,55 @@
/*
* i.MX31 Vectored Interrupt Controller
*
* Note this is NOT the PL192 provided by ARM, but
* a custom implementation by Freescale.
*
* Copyright (c) 2008 OKL
* Copyright (c) 2011 NICTA Pty Ltd
* Originally written by Hans Jiang
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
*
* This code is licensed under the GPL version 2 or later. See
* the COPYING file in the top-level directory.
*
* TODO: implement vectors.
*/
#ifndef IMX_AVIC_H
#define IMX_AVIC_H
#include "hw/sysbus.h"
#define TYPE_IMX_AVIC "imx.avic"
#define IMX_AVIC(obj) OBJECT_CHECK(IMXAVICState, (obj), TYPE_IMX_AVIC)
#define IMX_AVIC_NUM_IRQS 64
/* Interrupt Control Bits */
#define ABFLAG (1<<25)
#define ABFEN (1<<24)
#define NIDIS (1<<22) /* Normal Interrupt disable */
#define FIDIS (1<<21) /* Fast interrupt disable */
#define NIAD (1<<20) /* Normal Interrupt Arbiter Rise ARM level */
#define FIAD (1<<19) /* Fast Interrupt Arbiter Rise ARM level */
#define NM (1<<18) /* Normal interrupt mode */
#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4)
#define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD)
typedef struct IMXAVICState{
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion iomem;
uint64_t pending;
uint64_t enabled;
uint64_t is_fiq;
uint32_t intcntl;
uint32_t intmask;
qemu_irq irq;
qemu_irq fiq;
uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */
} IMXAVICState;
#endif /* IMX_AVIC_H */

91
include/hw/misc/imx_ccm.h Normal file
View File

@ -0,0 +1,91 @@
/*
* IMX31 Clock Control Module
*
* Copyright (C) 2012 NICTA
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef IMX_CCM_H
#define IMX_CCM_H
#include "hw/sysbus.h"
/* CCMR */
#define CCMR_FPME (1<<0)
#define CCMR_MPE (1<<3)
#define CCMR_MDS (1<<7)
#define CCMR_FPMF (1<<26)
#define CCMR_PRCS (3<<1)
/* PDR0 */
#define PDR0_MCU_PODF_SHIFT (0)
#define PDR0_MCU_PODF_MASK (0x7)
#define PDR0_MAX_PODF_SHIFT (3)
#define PDR0_MAX_PODF_MASK (0x7)
#define PDR0_IPG_PODF_SHIFT (6)
#define PDR0_IPG_PODF_MASK (0x3)
#define PDR0_NFC_PODF_SHIFT (8)
#define PDR0_NFC_PODF_MASK (0x7)
#define PDR0_HSP_PODF_SHIFT (11)
#define PDR0_HSP_PODF_MASK (0x7)
#define PDR0_PER_PODF_SHIFT (16)
#define PDR0_PER_PODF_MASK (0x1f)
#define PDR0_CSI_PODF_SHIFT (23)
#define PDR0_CSI_PODF_MASK (0x1ff)
#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
& PDR0_##name##_PODF_MASK)
#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
PDR0_##name##_PODF_SHIFT)
/* PLL control registers */
#define PD(v) (((v) >> 26) & 0xf)
#define MFD(v) (((v) >> 16) & 0x3ff)
#define MFI(v) (((v) >> 10) & 0xf);
#define MFN(v) ((v) & 0x3ff)
#define PLL_PD(x) (((x) & 0xf) << 26)
#define PLL_MFD(x) (((x) & 0x3ff) << 16)
#define PLL_MFI(x) (((x) & 0xf) << 10)
#define PLL_MFN(x) (((x) & 0x3ff) << 0)
#define TYPE_IMX_CCM "imx.ccm"
#define IMX_CCM(obj) OBJECT_CHECK(IMXCCMState, (obj), TYPE_IMX_CCM)
typedef struct IMXCCMState {
/* <private> */
SysBusDevice parent_obj;
/* <public> */
MemoryRegion iomem;
uint32_t ccmr;
uint32_t pdr0;
uint32_t pdr1;
uint32_t mpctl;
uint32_t spctl;
uint32_t cgr[3];
uint32_t pmcr0;
uint32_t pmcr1;
/* Frequencies precalculated on register changes */
uint32_t pll_refclk_freq;
uint32_t mcu_clk_freq;
uint32_t hsp_clk_freq;
uint32_t ipg_clk_freq;
} IMXCCMState;
typedef enum {
NOCLK,
MCU,
HSP,
IPG,
CLK_32k
} IMXClk;
uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock);
#endif /* IMX_CCM_H */

View File

@ -0,0 +1,79 @@
/*
* i.MX EPIT Timer
*
* Copyright (c) 2008 OK Labs
* Copyright (c) 2011 NICTA Pty Ltd
* Originally written by Hans Jiang
* Updated by Peter Chubb
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef IMX_EPIT_H
#define IMX_EPIT_H
#include "hw/sysbus.h"
#include "hw/ptimer.h"
/*
* EPIT: Enhanced periodic interrupt timer
*/
#define CR_EN (1 << 0)
#define CR_ENMOD (1 << 1)
#define CR_OCIEN (1 << 2)
#define CR_RLD (1 << 3)
#define CR_PRESCALE_SHIFT (4)
#define CR_PRESCALE_MASK (0xfff)
#define CR_SWR (1 << 16)
#define CR_IOVW (1 << 17)
#define CR_DBGEN (1 << 18)
#define CR_WAITEN (1 << 19)
#define CR_DOZEN (1 << 20)
#define CR_STOPEN (1 << 21)
#define CR_CLKSRC_SHIFT (24)
#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT)
#define EPIT_TIMER_MAX 0XFFFFFFFFUL
#define TYPE_IMX_EPIT "imx.epit"
#define IMX_EPIT(obj) OBJECT_CHECK(IMXEPITState, (obj), TYPE_IMX_EPIT)
typedef struct IMXEPITState{
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
ptimer_state *timer_reload;
ptimer_state *timer_cmp;
MemoryRegion iomem;
DeviceState *ccm;
uint32_t cr;
uint32_t sr;
uint32_t lr;
uint32_t cmp;
uint32_t cnt;
uint32_t freq;
qemu_irq irq;
} IMXEPITState;
#endif /* IMX_EPIT_H */

107
include/hw/timer/imx_gpt.h Normal file
View File

@ -0,0 +1,107 @@
/*
* i.MX GPT Timer
*
* Copyright (c) 2008 OK Labs
* Copyright (c) 2011 NICTA Pty Ltd
* Originally written by Hans Jiang
* Updated by Peter Chubb
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef IMX_GPT_H
#define IMX_GPT_H
#include "hw/sysbus.h"
#include "hw/ptimer.h"
/*
* GPT : General purpose timer
*
* This timer counts up continuously while it is enabled, resetting itself
* to 0 when it reaches GPT_TIMER_MAX (in freerun mode) or when it
* reaches the value of one of the ocrX (in periodic mode).
*/
#define GPT_TIMER_MAX 0XFFFFFFFFUL
/* Control register. Not all of these bits have any effect (yet) */
#define GPT_CR_EN (1 << 0) /* GPT Enable */
#define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */
#define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */
#define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */
#define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */
#define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */
#define GPT_CR_CLKSRC_SHIFT (6)
#define GPT_CR_CLKSRC_MASK (0x7)
#define GPT_CR_FRR (1 << 9) /* Freerun or Restart */
#define GPT_CR_SWR (1 << 15) /* Software Reset */
#define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */
#define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */
#define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */
#define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */
#define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */
#define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */
#define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */
#define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */
#define GPT_SR_OF1 (1 << 0)
#define GPT_SR_OF2 (1 << 1)
#define GPT_SR_OF3 (1 << 2)
#define GPT_SR_ROV (1 << 5)
#define GPT_IR_OF1IE (1 << 0)
#define GPT_IR_OF2IE (1 << 1)
#define GPT_IR_OF3IE (1 << 2)
#define GPT_IR_ROVIE (1 << 5)
#define TYPE_IMX_GPT "imx.gpt"
#define IMX_GPT(obj) OBJECT_CHECK(IMXGPTState, (obj), TYPE_IMX_GPT)
typedef struct IMXGPTState{
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
ptimer_state *timer;
MemoryRegion iomem;
DeviceState *ccm;
uint32_t cr;
uint32_t pr;
uint32_t sr;
uint32_t ir;
uint32_t ocr1;
uint32_t ocr2;
uint32_t ocr3;
uint32_t icr1;
uint32_t icr2;
uint32_t cnt;
uint32_t next_timeout;
uint32_t next_int;
uint32_t freq;
qemu_irq irq;
} IMXGPTState;
#endif /* IMX_GPT_H */

View File

@ -1182,7 +1182,7 @@ void memory_region_init_io(MemoryRegion *mr,
uint64_t size)
{
memory_region_init(mr, owner, name, size);
mr->ops = ops;
mr->ops = ops ? ops : &unassigned_mem_ops;
mr->opaque = opaque;
mr->terminates = true;
}
@ -1300,14 +1300,6 @@ void memory_region_init_iommu(MemoryRegion *mr,
notifier_list_init(&mr->iommu_notify);
}
void memory_region_init_reservation(MemoryRegion *mr,
Object *owner,
const char *name,
uint64_t size)
{
memory_region_init_io(mr, owner, &unassigned_mem_ops, mr, name, size);
}
static void memory_region_finalize(Object *obj)
{
MemoryRegion *mr = MEMORY_REGION(obj);

View File

@ -224,6 +224,8 @@ 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);
void arm_gt_htimer_cb(void *opaque);
void arm_gt_stimer_cb(void *opaque);
#ifdef TARGET_AARCH64
int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);

View File

@ -79,6 +79,27 @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
}
}
static void cp_reg_check_reset(gpointer key, gpointer value, gpointer opaque)
{
/* Purely an assertion check: we've already done reset once,
* so now check that running the reset for the cpreg doesn't
* change its value. This traps bugs where two different cpregs
* both try to reset the same state field but to different values.
*/
ARMCPRegInfo *ri = value;
ARMCPU *cpu = opaque;
uint64_t oldvalue, newvalue;
if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS | ARM_CP_NO_RAW)) {
return;
}
oldvalue = read_raw_cp_reg(&cpu->env, ri);
cp_reg_reset(key, value, opaque);
newvalue = read_raw_cp_reg(&cpu->env, ri);
assert(oldvalue == newvalue);
}
/* CPUClass::reset() */
static void arm_cpu_reset(CPUState *s)
{
@ -90,6 +111,8 @@ static void arm_cpu_reset(CPUState *s)
memset(env, 0, offsetof(CPUARMState, features));
g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu);
g_hash_table_foreach(cpu->cp_regs, cp_reg_check_reset, cpu);
env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
@ -453,6 +476,10 @@ static void arm_cpu_initfn(Object *obj)
arm_gt_ptimer_cb, cpu);
cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
arm_gt_vtimer_cb, cpu);
cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
arm_gt_htimer_cb, cpu);
cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
arm_gt_stimer_cb, cpu);
qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs,
ARRAY_SIZE(cpu->gt_timer_outputs));
#endif

View File

@ -113,7 +113,9 @@ typedef struct ARMGenericTimer {
#define GTIMER_PHYS 0
#define GTIMER_VIRT 1
#define NUM_GTIMERS 2
#define GTIMER_HYP 2
#define GTIMER_SEC 3
#define NUM_GTIMERS 4
typedef struct {
uint64_t raw_tcr;
@ -358,6 +360,8 @@ typedef struct CPUARMState {
};
uint64_t c14_cntfrq; /* Counter Frequency register */
uint64_t c14_cntkctl; /* Timer Control register */
uint32_t cnthctl_el2; /* Counter/Timer Hyp Control register */
uint64_t cntvoff_el2; /* Counter Virtual Offset register */
ARMGenericTimer c14_timer[NUM_GTIMERS];
uint32_t c15_cpar; /* XScale Coprocessor Access Register */
uint32_t c15_ticonfig; /* TI925T configuration byte. */
@ -1445,6 +1449,9 @@ static inline bool cp_access_ok(int current_el,
return (ri->access >> ((current_el * 2) + isread)) & 1;
}
/* Raw read of a coprocessor register (as needed for migration, etc) */
uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri);
/**
* write_list_to_cpustate
* @cpu: ARMCPU

View File

@ -144,7 +144,7 @@ static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri)
return (char *)env + ri->fieldoffset;
}
static uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri)
uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri)
{
/* Raw read of a coprocessor register (as needed for migration, etc). */
if (ri->type & ARM_CP_CONST) {
@ -1154,23 +1154,41 @@ static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri)
static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx)
{
unsigned int cur_el = arm_current_el(env);
bool secure = arm_is_secure(env);
/* CNT[PV]CT: not visible from PL0 if ELO[PV]CTEN is zero */
if (arm_current_el(env) == 0 &&
if (cur_el == 0 &&
!extract32(env->cp15.c14_cntkctl, timeridx, 1)) {
return CP_ACCESS_TRAP;
}
if (arm_feature(env, ARM_FEATURE_EL2) &&
timeridx == GTIMER_PHYS && !secure && cur_el < 2 &&
!extract32(env->cp15.cnthctl_el2, 0, 1)) {
return CP_ACCESS_TRAP_EL2;
}
return CP_ACCESS_OK;
}
static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx)
{
unsigned int cur_el = arm_current_el(env);
bool secure = arm_is_secure(env);
/* CNT[PV]_CVAL, CNT[PV]_CTL, CNT[PV]_TVAL: not visible from PL0 if
* EL0[PV]TEN is zero.
*/
if (arm_current_el(env) == 0 &&
if (cur_el == 0 &&
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
return CP_ACCESS_TRAP;
}
if (arm_feature(env, ARM_FEATURE_EL2) &&
timeridx == GTIMER_PHYS && !secure && cur_el < 2 &&
!extract32(env->cp15.cnthctl_el2, 1, 1)) {
return CP_ACCESS_TRAP_EL2;
}
return CP_ACCESS_OK;
}
@ -1196,6 +1214,32 @@ static CPAccessResult gt_vtimer_access(CPUARMState *env, const ARMCPRegInfo *ri)
return gt_timer_access(env, GTIMER_VIRT);
}
static CPAccessResult gt_stimer_access(CPUARMState *env,
const ARMCPRegInfo *ri)
{
/* The AArch64 register view of the secure physical timer is
* always accessible from EL3, and configurably accessible from
* Secure EL1.
*/
switch (arm_current_el(env)) {
case 1:
if (!arm_is_secure(env)) {
return CP_ACCESS_TRAP;
}
if (!(env->cp15.scr_el3 & SCR_ST)) {
return CP_ACCESS_TRAP_EL3;
}
return CP_ACCESS_OK;
case 0:
case 2:
return CP_ACCESS_TRAP;
case 3:
return CP_ACCESS_OK;
default:
g_assert_not_reached();
}
}
static uint64_t gt_get_countervalue(CPUARMState *env)
{
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE;
@ -1209,9 +1253,11 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
/* Timer enabled: calculate and set current ISTATUS, irq, and
* reset timer to when ISTATUS next has to change
*/
uint64_t offset = timeridx == GTIMER_VIRT ?
cpu->env.cp15.cntvoff_el2 : 0;
uint64_t count = gt_get_countervalue(&cpu->env);
/* Note that this must be unsigned 64 bit arithmetic: */
int istatus = count >= gt->cval;
int istatus = count - offset >= gt->cval;
uint64_t nexttick;
gt->ctl = deposit32(gt->ctl, 2, 1, istatus);
@ -1222,7 +1268,7 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
nexttick = UINT64_MAX;
} else {
/* Next transition is when we hit cval */
nexttick = gt->cval;
nexttick = gt->cval + offset;
}
/* Note that the desired next expiry time might be beyond the
* signed-64-bit range of a QEMUTimer -- in this case we just
@ -1241,10 +1287,10 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
}
}
static void gt_cnt_reset(CPUARMState *env, const ARMCPRegInfo *ri)
static void gt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri,
int timeridx)
{
ARMCPU *cpu = arm_env_get_cpu(env);
int timeridx = ri->opc1 & 1;
timer_del(cpu->gt_timer[timeridx]);
}
@ -1254,38 +1300,44 @@ static uint64_t gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
return gt_get_countervalue(env);
}
static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
return gt_get_countervalue(env) - env->cp15.cntvoff_el2;
}
static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
int timeridx,
uint64_t value)
{
int timeridx = ri->opc1 & 1;
env->cp15.c14_timer[timeridx].cval = value;
gt_recalc_timer(arm_env_get_cpu(env), timeridx);
}
static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
int timeridx)
{
int timeridx = ri->crm & 1;
uint64_t offset = timeridx == GTIMER_VIRT ? env->cp15.cntvoff_el2 : 0;
return (uint32_t)(env->cp15.c14_timer[timeridx].cval -
gt_get_countervalue(env));
(gt_get_countervalue(env) - offset));
}
static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
int timeridx,
uint64_t value)
{
int timeridx = ri->crm & 1;
uint64_t offset = timeridx == GTIMER_VIRT ? env->cp15.cntvoff_el2 : 0;
env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) +
env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) - offset +
sextract64(value, 0, 32);
gt_recalc_timer(arm_env_get_cpu(env), timeridx);
}
static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
int timeridx,
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 = deposit64(oldval, 0, 2, value);
@ -1301,6 +1353,127 @@ static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
}
}
static void gt_phys_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
{
gt_timer_reset(env, ri, GTIMER_PHYS);
}
static void gt_phys_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_cval_write(env, ri, GTIMER_PHYS, value);
}
static uint64_t gt_phys_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
return gt_tval_read(env, ri, GTIMER_PHYS);
}
static void gt_phys_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_tval_write(env, ri, GTIMER_PHYS, value);
}
static void gt_phys_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_ctl_write(env, ri, GTIMER_PHYS, value);
}
static void gt_virt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
{
gt_timer_reset(env, ri, GTIMER_VIRT);
}
static void gt_virt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_cval_write(env, ri, GTIMER_VIRT, value);
}
static uint64_t gt_virt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
return gt_tval_read(env, ri, GTIMER_VIRT);
}
static void gt_virt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_tval_write(env, ri, GTIMER_VIRT, value);
}
static void gt_virt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_ctl_write(env, ri, GTIMER_VIRT, value);
}
static void gt_cntvoff_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
ARMCPU *cpu = arm_env_get_cpu(env);
raw_write(env, ri, value);
gt_recalc_timer(cpu, GTIMER_VIRT);
}
static void gt_hyp_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
{
gt_timer_reset(env, ri, GTIMER_HYP);
}
static void gt_hyp_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_cval_write(env, ri, GTIMER_HYP, value);
}
static uint64_t gt_hyp_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
return gt_tval_read(env, ri, GTIMER_HYP);
}
static void gt_hyp_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_tval_write(env, ri, GTIMER_HYP, value);
}
static void gt_hyp_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_ctl_write(env, ri, GTIMER_HYP, value);
}
static void gt_sec_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
{
gt_timer_reset(env, ri, GTIMER_SEC);
}
static void gt_sec_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_cval_write(env, ri, GTIMER_SEC, value);
}
static uint64_t gt_sec_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
return gt_tval_read(env, ri, GTIMER_SEC);
}
static void gt_sec_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_tval_write(env, ri, GTIMER_SEC, value);
}
static void gt_sec_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
gt_ctl_write(env, ri, GTIMER_SEC, value);
}
void arm_gt_ptimer_cb(void *opaque)
{
ARMCPU *cpu = opaque;
@ -1315,6 +1488,20 @@ void arm_gt_vtimer_cb(void *opaque)
gt_recalc_timer(cpu, GTIMER_VIRT);
}
void arm_gt_htimer_cb(void *opaque)
{
ARMCPU *cpu = opaque;
gt_recalc_timer(cpu, GTIMER_HYP);
}
void arm_gt_stimer_cb(void *opaque)
{
ARMCPU *cpu = opaque;
gt_recalc_timer(cpu, GTIMER_SEC);
}
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
/* Note that CNTFRQ is purely reads-as-written for the benefit
* of software; writing it doesn't actually change the timer frequency.
@ -1340,11 +1527,21 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
},
/* per-timer control */
{ .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1,
.secure = ARM_CP_SECSTATE_NS,
.type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R,
.accessfn = gt_ptimer_access,
.fieldoffset = offsetoflow32(CPUARMState,
cp15.c14_timer[GTIMER_PHYS].ctl),
.writefn = gt_ctl_write, .raw_writefn = raw_write,
.writefn = gt_phys_ctl_write, .raw_writefn = raw_write,
},
{ .name = "CNTP_CTL(S)",
.cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1,
.secure = ARM_CP_SECSTATE_S,
.type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R,
.accessfn = gt_ptimer_access,
.fieldoffset = offsetoflow32(CPUARMState,
cp15.c14_timer[GTIMER_SEC].ctl),
.writefn = gt_sec_ctl_write, .raw_writefn = raw_write,
},
{ .name = "CNTP_CTL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 1,
@ -1352,14 +1549,14 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
.accessfn = gt_ptimer_access,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
.resetvalue = 0,
.writefn = gt_ctl_write, .raw_writefn = raw_write,
.writefn = gt_phys_ctl_write, .raw_writefn = raw_write,
},
{ .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1,
.type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R,
.accessfn = gt_vtimer_access,
.fieldoffset = offsetoflow32(CPUARMState,
cp15.c14_timer[GTIMER_VIRT].ctl),
.writefn = gt_ctl_write, .raw_writefn = raw_write,
.writefn = gt_virt_ctl_write, .raw_writefn = raw_write,
},
{ .name = "CNTV_CTL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 1,
@ -1367,30 +1564,38 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
.accessfn = gt_vtimer_access,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
.resetvalue = 0,
.writefn = gt_ctl_write, .raw_writefn = raw_write,
.writefn = gt_virt_ctl_write, .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,
.secure = ARM_CP_SECSTATE_NS,
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R,
.accessfn = gt_ptimer_access,
.readfn = gt_tval_read, .writefn = gt_tval_write,
.readfn = gt_phys_tval_read, .writefn = gt_phys_tval_write,
},
{ .name = "CNTP_TVAL(S)",
.cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0,
.secure = ARM_CP_SECSTATE_S,
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R,
.accessfn = gt_ptimer_access,
.readfn = gt_sec_tval_read, .writefn = gt_sec_tval_write,
},
{ .name = "CNTP_TVAL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 0,
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R,
.accessfn = gt_ptimer_access,
.readfn = gt_tval_read, .writefn = gt_tval_write,
.accessfn = gt_ptimer_access, .resetfn = gt_phys_timer_reset,
.readfn = gt_phys_tval_read, .writefn = gt_phys_tval_write,
},
{ .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0,
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R,
.accessfn = gt_vtimer_access,
.readfn = gt_tval_read, .writefn = gt_tval_write,
.readfn = gt_virt_tval_read, .writefn = gt_virt_tval_write,
},
{ .name = "CNTV_TVAL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 0,
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R,
.accessfn = gt_vtimer_access,
.readfn = gt_tval_read, .writefn = gt_tval_write,
.accessfn = gt_vtimer_access, .resetfn = gt_virt_timer_reset,
.readfn = gt_virt_tval_read, .writefn = gt_virt_tval_write,
},
/* The counter itself */
{ .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0,
@ -1401,27 +1606,34 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
{ .name = "CNTPCT_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 1,
.access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
.accessfn = gt_pct_access,
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
.accessfn = gt_pct_access, .readfn = gt_cnt_read,
},
{ .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1,
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_RAW | ARM_CP_IO,
.accessfn = gt_vct_access,
.readfn = gt_cnt_read, .resetfn = arm_cp_reset_ignore,
.readfn = gt_virt_cnt_read, .resetfn = arm_cp_reset_ignore,
},
{ .name = "CNTVCT_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 2,
.access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
.accessfn = gt_vct_access,
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
.accessfn = gt_vct_access, .readfn = gt_virt_cnt_read,
},
/* Comparison value, indicating when the timer goes off */
{ .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2,
.secure = ARM_CP_SECSTATE_NS,
.access = PL1_RW | PL0_R,
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
.accessfn = gt_ptimer_access,
.writefn = gt_cval_write, .raw_writefn = raw_write,
.writefn = gt_phys_cval_write, .raw_writefn = raw_write,
},
{ .name = "CNTP_CVAL(S)", .cp = 15, .crm = 14, .opc1 = 2,
.secure = ARM_CP_SECSTATE_S,
.access = PL1_RW | PL0_R,
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].cval),
.accessfn = gt_ptimer_access,
.writefn = gt_sec_cval_write, .raw_writefn = raw_write,
},
{ .name = "CNTP_CVAL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 2,
@ -1429,14 +1641,14 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
.type = ARM_CP_IO,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
.resetvalue = 0, .accessfn = gt_ptimer_access,
.writefn = gt_cval_write, .raw_writefn = raw_write,
.writefn = gt_phys_cval_write, .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 | ARM_CP_ALIAS,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
.accessfn = gt_vtimer_access,
.writefn = gt_cval_write, .raw_writefn = raw_write,
.writefn = gt_virt_cval_write, .raw_writefn = raw_write,
},
{ .name = "CNTV_CVAL_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 2,
@ -1444,7 +1656,33 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
.type = ARM_CP_IO,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
.resetvalue = 0, .accessfn = gt_vtimer_access,
.writefn = gt_cval_write, .raw_writefn = raw_write,
.writefn = gt_virt_cval_write, .raw_writefn = raw_write,
},
/* Secure timer -- this is actually restricted to only EL3
* and configurably Secure-EL1 via the accessfn.
*/
{ .name = "CNTPS_TVAL_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 7, .crn = 14, .crm = 2, .opc2 = 0,
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW,
.accessfn = gt_stimer_access,
.readfn = gt_sec_tval_read,
.writefn = gt_sec_tval_write,
.resetfn = gt_sec_timer_reset,
},
{ .name = "CNTPS_CTL_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 7, .crn = 14, .crm = 2, .opc2 = 1,
.type = ARM_CP_IO, .access = PL1_RW,
.accessfn = gt_stimer_access,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].ctl),
.resetvalue = 0,
.writefn = gt_sec_ctl_write, .raw_writefn = raw_write,
},
{ .name = "CNTPS_CVAL_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 7, .crn = 14, .crm = 2, .opc2 = 2,
.type = ARM_CP_IO, .access = PL1_RW,
.accessfn = gt_stimer_access,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].cval),
.writefn = gt_sec_cval_write, .raw_writefn = raw_write,
},
REGINFO_SENTINEL
};
@ -2613,6 +2851,27 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
{ .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2,
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST,
.resetvalue = 0 },
{ .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14,
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST,
.resetvalue = 0 },
{ .name = "CNTHP_CVAL_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 2,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "CNTHP_CVAL", .cp = 15, .opc1 = 6, .crm = 14,
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST,
.resetvalue = 0 },
{ .name = "CNTHP_TVAL_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 0,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "CNTHP_CTL_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 1,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
REGINFO_SENTINEL
};
@ -2724,6 +2983,46 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbi_aa64_vaa_write },
#ifndef CONFIG_USER_ONLY
{ .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0,
/* ARMv7 requires bit 0 and 1 to reset to 1. ARMv8 defines the
* reset values as IMPDEF. We choose to reset to 3 to comply with
* both ARMv7 and ARMv8.
*/
.access = PL2_RW, .resetvalue = 3,
.fieldoffset = offsetof(CPUARMState, cp15.cnthctl_el2) },
{ .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3,
.access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 0,
.writefn = gt_cntvoff_write,
.fieldoffset = offsetof(CPUARMState, cp15.cntvoff_el2) },
{ .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14,
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS | ARM_CP_IO,
.writefn = gt_cntvoff_write,
.fieldoffset = offsetof(CPUARMState, cp15.cntvoff_el2) },
{ .name = "CNTHP_CVAL_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 2,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_HYP].cval),
.type = ARM_CP_IO, .access = PL2_RW,
.writefn = gt_hyp_cval_write, .raw_writefn = raw_write },
{ .name = "CNTHP_CVAL", .cp = 15, .opc1 = 6, .crm = 14,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_HYP].cval),
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_IO,
.writefn = gt_hyp_cval_write, .raw_writefn = raw_write },
{ .name = "CNTHP_TVAL_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 0,
.type = ARM_CP_IO, .access = PL2_RW,
.resetfn = gt_hyp_timer_reset,
.readfn = gt_hyp_tval_read, .writefn = gt_hyp_tval_write },
{ .name = "CNTHP_CTL_EL2", .state = ARM_CP_STATE_BOTH,
.type = ARM_CP_IO,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 1,
.access = PL2_RW,
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_HYP].ctl),
.resetvalue = 0,
.writefn = gt_hyp_ctl_write, .raw_writefn = raw_write },
#endif
REGINFO_SENTINEL
};

View File

@ -191,4 +191,9 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu);
#endif
static inline const char *gic_class_name(void)
{
return kvm_irqchip_in_kernel() ? "kvm-arm-gic" : "arm_gic";
}
#endif