From patchwork Thu Jul 2 14:13:59 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Fedin X-Patchwork-Id: 490665 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 93E07140081 for ; Fri, 3 Jul 2015 00:26:20 +1000 (AEST) Received: from localhost ([::1]:36916 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZAfRS-0006dg-N6 for incoming@patchwork.ozlabs.org; Thu, 02 Jul 2015 10:26:18 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36731) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZAfFt-0003qN-0X for qemu-devel@nongnu.org; Thu, 02 Jul 2015 10:14:26 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZAfFl-0003Pi-GY for qemu-devel@nongnu.org; Thu, 02 Jul 2015 10:14:20 -0400 Received: from mailout4.w1.samsung.com ([210.118.77.14]:32463) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZAfFk-0003Mc-Tl for qemu-devel@nongnu.org; Thu, 02 Jul 2015 10:14:13 -0400 Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout4.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0NQV00BH867K3TB0@mailout4.w1.samsung.com> for qemu-devel@nongnu.org; Thu, 02 Jul 2015 15:14:08 +0100 (BST) X-AuditID: cbfec7f4-f79c56d0000012ee-38-5595473017b5 Received: from eusync4.samsung.com ( [203.254.199.214]) by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id 60.35.04846.03745955; Thu, 2 Jul 2015 15:14:08 +0100 (BST) Received: from localhost ([106.109.131.169]) by eusync4.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0NQV00HBB67K7W60@eusync4.samsung.com>; Thu, 02 Jul 2015 15:14:08 +0100 (BST) From: Pavel Fedin To: qemu-devel@nongnu.org Date: Thu, 02 Jul 2015 17:13:59 +0300 Message-id: X-Mailer: git-send-email 1.9.5.msysgit.0 In-reply-to: References: In-reply-to: References: X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprELMWRmVeSWpSXmKPExsVy+t/xa7oG7lNDDVoO6VnMOfOAxeJ47w4W i7bP39kdmD1ajrxl9bhzbQ+bx5Nrm5kCmKO4bFJSczLLUov07RK4Mo6+28JW8G41Y8XN9R9Z Ghg3tzJ2MXJySAiYSEy7dZYVwhaTuHBvPVsXIxeHkMBSRomT+5azQDjfGCWen4XoYBNQlzj9 9QMLiC0iICnxu+s0M0gRs8AkJomTG7+ygSSEgcaeutsHNpZFQFXi5s6rYM28AtES63rPMUOs 05BY9GUOWD2ngLnE9adN7CC2kICZxMGbbYy4xCcw8i9gZFjFKJpamlxQnJSea6hXnJhbXJqX rpecn7uJERJSX3YwLj5mdYhRgINRiYd3Rc2UUCHWxLLiytxDjBIczEoivFssp4YK8aYkVlal FuXHF5XmpBYfYpTmYFES5527632IkEB6YklqdmpqQWoRTJaJg1OqgTHmjFj74f2rdFXuZF+w 3FrUd6t+ksLra08sfS+zHKyaNunx/ti6vVYKa/lLEt7yP9k41zDV9KgTZ+M23rfbV0e2KH/W Dlqnbf7qleC28HlCSvuqn/QU2ikkf7ux2/5VusWjLIac2ydKK3SSlxRPqci+ZsEjeXbhf6aO S69ltHMsWSuCTRrvGiixFGckGmoxFxUnAgAPX90jJQIAAA== X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 210.118.77.14 Cc: Peter Maydell , Shlomo Pongratz , Shlomo Pongratz , Christoffer Dall , Eric Auger Subject: [Qemu-devel] [PATCH v4 1/9] Implement GIC-500 base class X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Shlomo Pongratz This class is to be used by both software and KVM implementations of GICv3 Signed-off-by: Shlomo Pongratz Signed-off-by: Pavel Fedin --- hw/intc/Makefile.objs | 1 + hw/intc/arm_gicv3_common.c | 216 +++++++++++++++++++++++++++++++++++++ hw/intc/gicv3_internal.h | 159 +++++++++++++++++++++++++++ include/hw/intc/arm_gicv3.h | 44 ++++++++ include/hw/intc/arm_gicv3_common.h | 116 ++++++++++++++++++++ 5 files changed, 536 insertions(+) create mode 100644 hw/intc/arm_gicv3_common.c create mode 100644 hw/intc/gicv3_internal.h create mode 100644 include/hw/intc/arm_gicv3.h create mode 100644 include/hw/intc/arm_gicv3_common.h diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 092d8a8..1317e5a 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -12,6 +12,7 @@ common-obj-$(CONFIG_IOAPIC) += ioapic_common.o common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o common-obj-$(CONFIG_ARM_GIC) += arm_gic.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o +common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o common-obj-$(CONFIG_OPENPIC) += openpic.o obj-$(CONFIG_APIC) += apic.o apic_common.o diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c new file mode 100644 index 0000000..5bd7725 --- /dev/null +++ b/hw/intc/arm_gicv3_common.c @@ -0,0 +1,216 @@ +/* + * ARM GIC support - common bits of emulated and KVM kernel model + * + * Copyright (c) 2012 Linaro Limited + * Copyright (c) 2015 Huawei. + * Written by Peter Maydell + * Extended to 64 cores by Shlomo Pongratz + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "gicv3_internal.h" + +static void gicv3_pre_save(void *opaque) +{ + GICv3State *s = (GICv3State *)opaque; + ARMGICv3CommonClass *c = ARM_GICV3_COMMON_GET_CLASS(s); + + if (c->pre_save) { + c->pre_save(s); + } +} + +static int gicv3_post_load(void *opaque, int version_id) +{ + GICv3State *s = (GICv3State *)opaque; + ARMGICv3CommonClass *c = ARM_GICV3_COMMON_GET_CLASS(s); + + if (c->post_load) { + c->post_load(s); + } + return 0; +} + +static const VMStateDescription vmstate_gicv3_irq_state = { + .name = "arm_gicv3_irq_state", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(pending, gicv3_irq_state), + VMSTATE_UINT64(active, gicv3_irq_state), + VMSTATE_UINT64(level, gicv3_irq_state), + VMSTATE_UINT64(group, gicv3_irq_state), + VMSTATE_BOOL(edge_trigger, gicv3_irq_state), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_gicv3_sgi_state = { + .name = "arm_gicv3_sgi_state", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64_ARRAY(pending, gicv3_sgi_state, GICV3_NCPU), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_gicv3 = { + .name = "arm_gicv3", + .version_id = 7, + .minimum_version_id = 7, + .pre_save = gicv3_pre_save, + .post_load = gicv3_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ctlr, GICv3State), + VMSTATE_UINT32_ARRAY(cpu_ctlr, GICv3State, GICV3_NCPU), + VMSTATE_STRUCT_ARRAY(irq_state, GICv3State, GICV3_MAXIRQ, 1, + vmstate_gicv3_irq_state, gicv3_irq_state), + VMSTATE_UINT64_ARRAY(irq_target, GICv3State, GICV3_MAXIRQ), + VMSTATE_UINT8_2DARRAY(priority1, GICv3State, GICV3_INTERNAL, GICV3_NCPU), + VMSTATE_UINT8_ARRAY(priority2, GICv3State, GICV3_MAXIRQ - GICV3_INTERNAL), + VMSTATE_UINT16_2DARRAY(last_active, GICv3State, GICV3_MAXIRQ, GICV3_NCPU), + VMSTATE_STRUCT_ARRAY(sgi_state, GICv3State, GICV3_NR_SGIS, 1, + vmstate_gicv3_sgi_state, gicv3_sgi_state), + VMSTATE_UINT16_ARRAY(priority_mask, GICv3State, GICV3_NCPU), + VMSTATE_UINT16_ARRAY(running_irq, GICv3State, GICV3_NCPU), + VMSTATE_UINT16_ARRAY(running_priority, GICv3State, GICV3_NCPU), + VMSTATE_UINT16_ARRAY(current_pending, GICv3State, GICV3_NCPU), + VMSTATE_END_OF_LIST() + } +}; + +static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) +{ + GICv3State *s = ARM_GICV3_COMMON(dev); + int num_irq = s->num_irq; + + if (s->num_cpu > GICV3_NCPU) { + error_setg(errp, "requested %u CPUs exceeds GIC maximum %d", + s->num_cpu, GICV3_NCPU); + return; + } + s->num_irq += GICV3_BASE_IRQ; + if (s->num_irq > GICV3_MAXIRQ) { + error_setg(errp, + "requested %u interrupt lines exceeds GIC maximum %d", + num_irq, GICV3_MAXIRQ); + return; + } + /* ITLinesNumber is represented as (N / 32) - 1 (see + * gic_dist_readb) so this is an implementation imposed + * restriction, not an architectural one: + */ + if (s->num_irq < 32 || (s->num_irq % 32)) { + error_setg(errp, + "%d interrupt lines unsupported: not divisible by 32", + num_irq); + return; + } +} + +static void arm_gicv3_common_reset(DeviceState *dev) +{ + GICv3State *s = ARM_GICV3_COMMON(dev); + int i; + + /* Note num_cpu and num_irq are properties */ + + /* Don't reset anything assigned in arm_gic_realize or any property */ + + /* No GICv2 backwards computability support */ + for (i = 0; i < s->num_cpu; i++) { + s->priority_mask[i] = 0; + s->current_pending[i] = 1023; + s->running_irq[i] = 1023; + s->running_priority[i] = 0x100; + s->cpu_ctlr[i] = 0; + } + + memset(s->irq_state, 0, sizeof(s->irq_state)); + /* GIC-500 comment 'j' SGI are always enabled */ + for (i = 0; i < GICV3_NR_SGIS; i++) { + GIC_SET_ENABLED(i, ALL_CPU_MASK); + GIC_SET_EDGE_TRIGGER(i); + } + memset(s->sgi_state, 0, sizeof(s->sgi_state)); + memset(s->irq_target, 0, sizeof(s->irq_target)); + if (s->num_cpu == 1) { + /* For uniprocessor GICs all interrupts always target the sole CPU */ + for (i = 0; i < GICV3_MAXIRQ; i++) { + s->irq_target[i] = 1; + } + } + memset(s->priority1, 0, sizeof(s->priority1)); + memset(s->priority2, 0, sizeof(s->priority2)); + memset(s->last_active, 0, sizeof(s->last_active)); + + /* With all configuration we don't support GICv2 backwards computability */ + if (s->security_levels > 1) { + /* GICv3 5.3.20 With two security So DS is RAZ/WI ARE_NS is RAO/WI + * and ARE_S is RAO/WI + */ + s->ctlr = GICD_CTLR_ARE_S | GICD_CTLR_ARE_NS; + } else { + /* GICv3 5.3.20 With one security So DS is RAO/WI ARE is RAO/WI + */ + s->ctlr = GICD_CTLR_DS | GICD_CTLR_ARE; + } + /* Workaround! + * Linux (drivers/irqchip/irq-gic-v3.c) is enabling only group one, + * in gic_cpu_sys_reg_init it calls gic_write_grpen1(1); + * but it doesn't conigure any interrupt to be in group one + */ + for (i = 0; i < s->num_irq; i++) + GIC_SET_GROUP(i, ALL_CPU_MASK); +} + +static Property arm_gicv3_common_properties[] = { + DEFINE_PROP_UINT32("num-cpu", GICv3State, num_cpu, 1), + DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32), + /* Revision can be 3 for GIC architecture specification + * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".) + */ + DEFINE_PROP_UINT32("revision", GICv3State, revision, 3), + /* How many security levels are supported */ + DEFINE_PROP_BOOL("security-levels", GICv3State, security_levels, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void arm_gicv3_common_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = arm_gicv3_common_reset; + dc->realize = arm_gicv3_common_realize; + dc->props = arm_gicv3_common_properties; + dc->vmsd = &vmstate_gicv3; +} + +static const TypeInfo arm_gicv3_common_type = { + .name = TYPE_ARM_GICV3_COMMON, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GICv3State), + .class_size = sizeof(ARMGICv3CommonClass), + .class_init = arm_gicv3_common_class_init, + .abstract = true, +}; + +static void register_types(void) +{ + type_register_static(&arm_gicv3_common_type); +} + +type_init(register_types) diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h new file mode 100644 index 0000000..4b65ee2 --- /dev/null +++ b/hw/intc/gicv3_internal.h @@ -0,0 +1,159 @@ +/* + * ARM GIC support - internal interfaces + * + * Copyright (c) 2012 Linaro Limited + * Copyright (c) 2015 Huawei. + * Written by Peter Maydell + * Extended to 64 cores by Shlomo Pongratz + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef QEMU_ARM_GICV3_INTERNAL_H +#define QEMU_ARM_GICV3_INTERNAL_H + +#include "hw/intc/arm_gicv3.h" + +#define ALL_CPU_MASK ((uint64_t) (0xffffffffffffffff)) + +/* Keep this macro so it will be easy to compare the code to GICv2 code. + * The compiler will optimize any +/- operation involving this macro + */ +#define GICV3_BASE_IRQ (0) + +#define GIC_SET_ENABLED(irq, cm) s->irq_state[irq].enabled |= (cm) +#define GIC_CLEAR_ENABLED(irq, cm) s->irq_state[irq].enabled &= ~(cm) +#define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0) +#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm) +#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0) +#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm) +#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm) +#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm) +#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0) +#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level |= (cm) +#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm) +#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0) +#define GIC_SET_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = true +#define GIC_CLEAR_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = false +#define GIC_TEST_EDGE_TRIGGER(irq) (s->irq_state[irq].edge_trigger) +#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GICV3_INTERNAL) ? \ + s->priority1[irq][cpu] : \ + s->priority2[(irq) - GICV3_INTERNAL]) +#define GIC_TARGET(irq) s->irq_target[irq] +#define GIC_CLEAR_GROUP(irq, cm) (s->irq_state[irq].group &= ~(cm)) +#define GIC_SET_GROUP(irq, cm) (s->irq_state[irq].group |= (cm)) +#define GIC_TEST_GROUP(irq, cm) ((s->irq_state[irq].group & (cm)) != 0) + +/* The special cases for the revision property: */ +#define REV_V3 3 + +static inline bool gic_test_pending(GICv3State *s, int irq, uint64_t cm) +{ + /* Edge-triggered interrupts are marked pending on a rising edge, but + * level-triggered interrupts are either considered pending when the + * level is active or if software has explicitly written to + * GICD_ISPENDR to set the state pending. + */ + return (s->irq_state[irq].pending & cm) || + (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_LEVEL(irq, cm)); +} + +#define GICD_CTLR 0x0000 +#define GICD_TYPER 0x0004 +#define GICD_IIDR 0x0008 +#define GICD_STATUSR 0x0010 +#define GICD_SETSPI_NSR 0x0040 +#define GICD_CLRSPI_NSR 0x0048 +#define GICD_SETSPI_SR 0x0050 +#define GICD_CLRSPI_SR 0x0058 +#define GICD_SEIR 0x0068 +#define GICD_ISENABLER 0x0100 +#define GICD_ICENABLER 0x0180 +#define GICD_ISPENDR 0x0200 +#define GICD_ICPENDR 0x0280 +#define GICD_ISACTIVER 0x0300 +#define GICD_ICACTIVER 0x0380 +#define GICD_IPRIORITYR 0x0400 +#define GICD_ICFGR 0x0C00 +#define GICD_IROUTER 0x6000 +#define GICD_PIDR2 0xFFE8 + +/* GICD_CTLR fields */ +#define GICD_CTLR_EN_GRP0 (1U << 0) +#define GICD_CTLR_EN_GRP1NS (1U << 1) /* GICv3 5.3.20 */ +#define GICD_CTLR_EN_GRP1S (1U << 2) +#define GICD_CTLR_EN_GRP1_ALL (GICD_CTLR_EN_GRP1NS | GICD_CTLR_EN_GRP1S) +#define GICD_CTLR_ARE (1U << 4) +#define GICD_CTLR_ARE_S (1U << 4) +#define GICD_CTLR_ARE_NS (1U << 5) +#define GICD_CTLR_DS (1U << 6) +#define GICD_CTLR_RWP (1U << 31) + +#define GICD_IROUTER_SPI_MODE_ONE (0U << 31) +#define GICD_IROUTER_SPI_MODE_ANY (1U << 31) + +#define GIC_PIDR2_ARCH_MASK 0xf0 +#define GIC_PIDR2_ARCH_GICv3 0x30 +#define GIC_PIDR2_ARCH_GICv4 0x40 + +/* + * Re-Distributor registers, offsets from RD_base + */ +#define GICR_CTLR GICD_CTLR +#define GICR_IIDR 0x0004 +#define GICR_TYPER 0x0008 +#define GICR_STATUSR GICD_STATUSR +#define GICR_WAKER 0x0014 +#define GICR_SETLPIR 0x0040 +#define GICR_CLRLPIR 0x0048 +#define GICR_SEIR GICD_SEIR +#define GICR_PROPBASER 0x0070 +#define GICR_PENDBASER 0x0078 +#define GICR_INVLPIR 0x00A0 +#define GICR_INVALLR 0x00B0 +#define GICR_SYNCR 0x00C0 +#define GICR_MOVLPIR 0x0100 +#define GICR_MOVALLR 0x0110 +#define GICR_PIDR2 GICD_PIDR2 + +#define GICR_WAKER_ProcessorSleep (1U << 1) +#define GICR_WAKER_ChildrenAsleep (1U << 2) + +/* + * Re-Distributor registers, offsets from SGI_base + */ +#define GICR_ISENABLER0 GICD_ISENABLER +#define GICR_ICENABLER0 GICD_ICENABLER +#define GICR_ISPENDR0 GICD_ISPENDR +#define GICR_ICPENDR0 GICD_ICPENDR +#define GICR_ISACTIVER0 GICD_ISACTIVER +#define GICR_ICACTIVER0 GICD_ICACTIVER +#define GICR_IPRIORITYR0 GICD_IPRIORITYR +#define GICR_ICFGR0 GICD_ICFGR + +#define GICR_TYPER_VLPIS (1U << 1) +#define GICR_TYPER_LAST (1U << 4) + +/* + * Simulated used system registers + */ +#define GICC_CTLR_EN_GRP0 (1U << 0) +#define GICC_CTLR_EN_GRP1 (1U << 1) +#define GICC_CTLR_ACK_CTL (1U << 2) +#define GICC_CTLR_FIQ_EN (1U << 3) +#define GICC_CTLR_CBPR (1U << 4) /* GICv1: SBPR */ +#define GICC_CTLR_EOIMODE (1U << 9) +#define GICC_CTLR_EOIMODE_NS (1U << 10) + +#endif /* !QEMU_ARM_GIC_INTERNAL_H */ diff --git a/include/hw/intc/arm_gicv3.h b/include/hw/intc/arm_gicv3.h new file mode 100644 index 0000000..a03af35 --- /dev/null +++ b/include/hw/intc/arm_gicv3.h @@ -0,0 +1,44 @@ +/* + * ARM GIC support + * + * Copyright (c) 2012 Linaro Limited + * Copyright (c) 2015 Huawei. + * Written by Peter Maydell + * Extended to 64 cores by Shlomo Pongratz + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HW_ARM_GICV3_H +#define HW_ARM_GICV3_H + +#include "arm_gicv3_common.h" + +#define TYPE_ARM_GICV3 "arm_gicv3" +#define ARM_GICV3(obj) \ + OBJECT_CHECK(GICv3State, (obj), TYPE_ARM_GICV3) +#define ARM_GICV3_CLASS(klass) \ + OBJECT_CLASS_CHECK(ARMGICv3Class, (klass), TYPE_ARM_GICV3) +#define ARM_GICV3_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ARMGICv3Class, (obj), TYPE_ARM_GICV3) + +typedef struct ARMGICv3Class { + /*< private >*/ + ARMGICv3CommonClass parent_class; + /*< public >*/ + + DeviceRealize parent_realize; +} ARMGICv3Class; + +#endif diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h new file mode 100644 index 0000000..71634c0 --- /dev/null +++ b/include/hw/intc/arm_gicv3_common.h @@ -0,0 +1,116 @@ +/* + * ARM GIC support + * + * Copyright (c) 2012 Linaro Limited + * Copyright (c) 2015 Huawei. + * Written by Peter Maydell + * Extended to 64 cores by Shlomo Pongratz + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HW_ARM_GICV3_COMMON_H +#define HW_ARM_GICV3_COMMON_H + +#include "hw/sysbus.h" + +/* Maximum number of possible interrupts, determined by the GIC architecture */ +#define GICV3_MAXIRQ 1020 +/* First 32 are private to each CPU (SGIs and PPIs). */ +#define GICV3_INTERNAL 32 +#define GICV3_NR_SGIS 16 +#define GICV3_NCPU 64 + +#define MAX_NR_GROUP_PRIO 128 + +typedef struct gicv3_irq_state { + /* The enable bits are only banked for per-cpu interrupts. */ + uint64_t enabled; + uint64_t pending; + uint64_t active; + uint64_t level; + uint64_t group; + bool edge_trigger; /* true: edge-triggered, false: level-triggered */ +} gicv3_irq_state; + +typedef struct gicv3_sgi_state { + uint64_t pending[GICV3_NCPU]; +} gicv3_sgi_state; + +typedef struct GICv3State { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + qemu_irq parent_irq[GICV3_NCPU]; + qemu_irq parent_fiq[GICV3_NCPU]; + /* GICD_CTLR; for a GIC with the security extensions the NS banked version + * of this register is just an alias of bit 1 of the S banked version. + */ + uint32_t ctlr; + /* Sim GICC_CTLR; again, the NS banked version is just aliases of bits of + * the S banked register, so our state only needs to store the S version. + */ + uint32_t cpu_ctlr[GICV3_NCPU]; + bool cpu_enabled[GICV3_NCPU]; + + gicv3_irq_state irq_state[GICV3_MAXIRQ]; + uint64_t irq_target[GICV3_MAXIRQ]; + uint8_t priority1[GICV3_INTERNAL][GICV3_NCPU]; + uint8_t priority2[GICV3_MAXIRQ - GICV3_INTERNAL]; + uint16_t last_active[GICV3_MAXIRQ][GICV3_NCPU]; + /* For each SGI on the target CPU, we store 64 bits + * indicating which source CPUs have made this SGI + * pending on the target CPU. These correspond to + * the bytes in the GIC_SPENDSGIR* registers as + * read by the target CPU. + */ + gicv3_sgi_state sgi_state[GICV3_NR_SGIS]; + + uint16_t priority_mask[GICV3_NCPU]; + uint16_t running_irq[GICV3_NCPU]; + uint16_t running_priority[GICV3_NCPU]; + uint16_t current_pending[GICV3_NCPU]; + + uint32_t cpu_mask; /* For redistributor */ + uint32_t num_cpu; + MemoryRegion iomem_dist; /* Distributor */ + MemoryRegion iomem_mbi; + MemoryRegion iomem_its_cntrl; + MemoryRegion iomem_its; + MemoryRegion iomem_lpi; /* Redistributor */ + uint32_t num_irq; + uint32_t revision; + bool security_levels; + int dev_fd; /* kvm device fd if backed by kvm vgic support */ +} GICv3State; + +#define TYPE_ARM_GICV3_COMMON "arm_gicv3_common" +#define ARM_GICV3_COMMON(obj) \ + OBJECT_CHECK(GICv3State, (obj), TYPE_ARM_GICV3_COMMON) +#define ARM_GICV3_COMMON_CLASS(klass) \ + OBJECT_CLASS_CHECK(ARMGICv3CommonClass, (klass), TYPE_ARM_GICV3_COMMON) +#define ARM_GICV3_COMMON_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ARMGICv3CommonClass, (obj), TYPE_ARM_GICV3_COMMON) + +typedef struct ARMGICv3CommonClass { + /*< private >*/ + SysBusDeviceClass parent_class; + /*< public >*/ + + void (*pre_save)(GICv3State *s); + void (*post_load)(GICv3State *s); +} ARMGICv3CommonClass; + +#endif