All of lore.kernel.org
 help / color / mirror / Atom feed
From: Luc Michel <luc.michel@greensocs.com>
To: qemu-devel@nongnu.org
Cc: Luc Michel <luc.michel@greensocs.com>,
	qemu-arm@nongnu.org, Peter Maydell <peter.maydell@linaro.org>,
	saipava@xilinx.com, edgari@xilinx.com, mark.burton@greensocs.com,
	Jan Kiszka <jan.kiszka@web.de>
Subject: [Qemu-devel] [PATCH v5 15/20] intc/arm_gic: Implement the virtual interface registers
Date: Fri, 27 Jul 2018 11:54:16 +0200	[thread overview]
Message-ID: <20180727095421.386-16-luc.michel@greensocs.com> (raw)
In-Reply-To: <20180727095421.386-1-luc.michel@greensocs.com>

Implement the read and write functions for the virtual interface of the
virtualization extensions in the GICv2.

One mirror region per CPU is also created, which maps to that specific
CPU id. This is required by the GIC architecture specification.

Signed-off-by: Luc Michel <luc.michel@greensocs.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/arm_gic.c | 235 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 233 insertions(+), 2 deletions(-)

diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 7ee2e6bcbb..6063196487 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -145,10 +145,28 @@ static void gic_update(GICState *s)
         qemu_set_irq(s->parent_irq[cpu], irq_level);
         qemu_set_irq(s->parent_fiq[cpu], fiq_level);
     }
 }
 
+/* Return true if this LR is empty, i.e. the corresponding bit
+ * in ELRSR is set.
+ */
+static inline bool gic_lr_entry_is_free(uint32_t entry)
+{
+    return (GICH_LR_STATE(entry) == GICH_LR_STATE_INVALID)
+        && (GICH_LR_HW(entry) || !GICH_LR_EOI(entry));
+}
+
+/* Return true if this LR should trigger an EOI maintenance interrupt, i.e. the
+ * corrsponding bit in EISR is set.
+ */
+static inline bool gic_lr_entry_is_eoi(uint32_t entry)
+{
+    return (GICH_LR_STATE(entry) == GICH_LR_STATE_INVALID)
+        && !GICH_LR_HW(entry) && GICH_LR_EOI(entry);
+}
+
 static void gic_set_irq_11mpcore(GICState *s, int irq, int level,
                                  int cm, int target)
 {
     if (level) {
         GIC_DIST_SET_LEVEL(irq, cm);
@@ -1570,10 +1588,204 @@ static MemTxResult gic_thisvcpu_write(void *opaque, hwaddr addr,
     GICState *s = (GICState *)opaque;
 
     return gic_cpu_write(s, gic_get_current_vcpu(s), addr, value, attrs);
 }
 
+static uint32_t gic_compute_eisr(GICState *s, int cpu, int lr_start)
+{
+    int lr_idx;
+    uint32_t ret = 0;
+
+    for (lr_idx = lr_start; lr_idx < s->num_lrs; lr_idx++) {
+        uint32_t *entry = &s->h_lr[lr_idx][cpu];
+        ret = deposit32(ret, lr_idx - lr_start, 1,
+                        gic_lr_entry_is_eoi(*entry));
+    }
+
+    return ret;
+}
+
+static uint32_t gic_compute_elrsr(GICState *s, int cpu, int lr_start)
+{
+    int lr_idx;
+    uint32_t ret = 0;
+
+    for (lr_idx = lr_start; lr_idx < s->num_lrs; lr_idx++) {
+        uint32_t *entry = &s->h_lr[lr_idx][cpu];
+        ret = deposit32(ret, lr_idx - lr_start, 1,
+                        gic_lr_entry_is_free(*entry));
+    }
+
+    return ret;
+}
+
+static void gic_vmcr_write(GICState *s, uint32_t value, MemTxAttrs attrs)
+{
+    int vcpu = gic_get_current_vcpu(s);
+    uint32_t ctlr;
+    uint32_t abpr;
+    uint32_t bpr;
+    uint32_t prio_mask;
+
+    ctlr = FIELD_EX32(value, GICH_VMCR, VMCCtlr);
+    abpr = FIELD_EX32(value, GICH_VMCR, VMABP);
+    bpr = FIELD_EX32(value, GICH_VMCR, VMBP);
+    prio_mask = FIELD_EX32(value, GICH_VMCR, VMPriMask) << 3;
+
+    gic_set_cpu_control(s, vcpu, ctlr, attrs);
+    s->abpr[vcpu] = MAX(abpr, GIC_VIRT_MIN_ABPR);
+    s->bpr[vcpu] = MAX(bpr, GIC_VIRT_MIN_BPR);
+    gic_set_priority_mask(s, vcpu, prio_mask, attrs);
+}
+
+static MemTxResult gic_hyp_read(void *opaque, int cpu, hwaddr addr,
+                                uint64_t *data, MemTxAttrs attrs)
+{
+    GICState *s = ARM_GIC(opaque);
+    int vcpu = cpu + GIC_NCPU;
+
+    switch (addr) {
+    case A_GICH_HCR: /* Hypervisor Control */
+        *data = s->h_hcr[cpu];
+        break;
+
+    case A_GICH_VTR: /* VGIC Type */
+        *data = FIELD_DP32(0, GICH_VTR, ListRegs, s->num_lrs - 1);
+        *data = FIELD_DP32(*data, GICH_VTR, PREbits,
+                           GIC_VIRT_MAX_GROUP_PRIO_BITS - 1);
+        *data = FIELD_DP32(*data, GICH_VTR, PRIbits,
+                           (7 - GIC_VIRT_MIN_BPR) - 1);
+        break;
+
+    case A_GICH_VMCR: /* Virtual Machine Control */
+        *data = FIELD_DP32(0, GICH_VMCR, VMCCtlr,
+                           extract32(s->cpu_ctlr[vcpu], 0, 10));
+        *data = FIELD_DP32(*data, GICH_VMCR, VMABP, s->abpr[vcpu]);
+        *data = FIELD_DP32(*data, GICH_VMCR, VMBP, s->bpr[vcpu]);
+        *data = FIELD_DP32(*data, GICH_VMCR, VMPriMask,
+                           extract32(s->priority_mask[vcpu], 3, 5));
+        break;
+
+    case A_GICH_MISR: /* Maintenance Interrupt Status */
+        *data = s->h_misr[cpu];
+        break;
+
+    case A_GICH_EISR0: /* End of Interrupt Status 0 and 1 */
+    case A_GICH_EISR1:
+        *data = gic_compute_eisr(s, cpu, (addr - A_GICH_EISR0) * 8);
+        break;
+
+    case A_GICH_ELRSR0: /* Empty List Status 0 and 1 */
+    case A_GICH_ELRSR1:
+        *data = gic_compute_elrsr(s, cpu, (addr - A_GICH_ELRSR0) * 8);
+        break;
+
+    case A_GICH_APR: /* Active Priorities */
+        *data = s->h_apr[cpu];
+        break;
+
+    case A_GICH_LR0 ... A_GICH_LR63: /* List Registers */
+    {
+        int lr_idx = (addr - A_GICH_LR0) / 4;
+
+        if (lr_idx > s->num_lrs) {
+            *data = 0;
+        } else {
+            *data = s->h_lr[lr_idx][cpu];
+        }
+        break;
+    }
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "gic_hyp_read: Bad offset %" HWADDR_PRIx "\n", addr);
+        return MEMTX_OK;
+    }
+
+    return MEMTX_OK;
+}
+
+static MemTxResult gic_hyp_write(void *opaque, int cpu, hwaddr addr,
+                                 uint64_t value, MemTxAttrs attrs)
+{
+    GICState *s = ARM_GIC(opaque);
+    int vcpu = cpu + GIC_NCPU;
+
+    switch (addr) {
+    case A_GICH_HCR: /* Hypervisor Control */
+        s->h_hcr[cpu] = value & GICH_HCR_MASK;
+        break;
+
+    case A_GICH_VMCR: /* Virtual Machine Control */
+        gic_vmcr_write(s, value, attrs);
+        break;
+
+    case A_GICH_APR: /* Active Priorities */
+        s->h_apr[cpu] = value;
+        s->running_priority[vcpu] = gic_get_prio_from_apr_bits(s, vcpu);
+        break;
+
+    case A_GICH_LR0 ... A_GICH_LR63: /* List Registers */
+    {
+        int lr_idx = (addr - A_GICH_LR0) / 4;
+
+        if (lr_idx > s->num_lrs) {
+            return MEMTX_OK;
+        }
+
+        s->h_lr[lr_idx][cpu] = value & GICH_LR_MASK;
+        break;
+    }
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "gic_hyp_write: Bad offset %" HWADDR_PRIx "\n", addr);
+        return MEMTX_OK;
+    }
+
+    return MEMTX_OK;
+}
+
+static MemTxResult gic_thiscpu_hyp_read(void *opaque, hwaddr addr, uint64_t *data,
+                                    unsigned size, MemTxAttrs attrs)
+{
+    GICState *s = (GICState *)opaque;
+
+    return gic_hyp_read(s, gic_get_current_cpu(s), addr, data, attrs);
+}
+
+static MemTxResult gic_thiscpu_hyp_write(void *opaque, hwaddr addr,
+                                     uint64_t value, unsigned size,
+                                     MemTxAttrs attrs)
+{
+    GICState *s = (GICState *)opaque;
+
+    return gic_hyp_write(s, gic_get_current_cpu(s), addr, value, attrs);
+}
+
+static MemTxResult gic_do_hyp_read(void *opaque, hwaddr addr, uint64_t *data,
+                                    unsigned size, MemTxAttrs attrs)
+{
+    GICState **backref = (GICState **)opaque;
+    GICState *s = *backref;
+    int id = (backref - s->backref);
+
+    return gic_hyp_read(s, id, addr, data, attrs);
+}
+
+static MemTxResult gic_do_hyp_write(void *opaque, hwaddr addr,
+                                     uint64_t value, unsigned size,
+                                     MemTxAttrs attrs)
+{
+    GICState **backref = (GICState **)opaque;
+    GICState *s = *backref;
+    int id = (backref - s->backref);
+
+    return gic_hyp_write(s, id + GIC_NCPU, addr, value, attrs);
+
+}
+
 static const MemoryRegionOps gic_ops[2] = {
     {
         .read_with_attrs = gic_dist_read,
         .write_with_attrs = gic_dist_write,
         .endianness = DEVICE_NATIVE_ENDIAN,
@@ -1591,21 +1803,27 @@ static const MemoryRegionOps gic_cpu_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const MemoryRegionOps gic_virt_ops[2] = {
     {
-        .read_with_attrs = NULL,
-        .write_with_attrs = NULL,
+        .read_with_attrs = gic_thiscpu_hyp_read,
+        .write_with_attrs = gic_thiscpu_hyp_write,
         .endianness = DEVICE_NATIVE_ENDIAN,
     },
     {
         .read_with_attrs = gic_thisvcpu_read,
         .write_with_attrs = gic_thisvcpu_write,
         .endianness = DEVICE_NATIVE_ENDIAN,
     }
 };
 
+static const MemoryRegionOps gic_viface_ops = {
+    .read_with_attrs = gic_do_hyp_read,
+    .write_with_attrs = gic_do_hyp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
 static void arm_gic_realize(DeviceState *dev, Error **errp)
 {
     /* Device instance realize function for the GIC sysbus device */
     int i;
     GICState *s = ARM_GIC(dev);
@@ -1643,10 +1861,23 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
         s->backref[i] = s;
         memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops,
                               &s->backref[i], "gic_cpu", 0x100);
         sysbus_init_mmio(sbd, &s->cpuiomem[i+1]);
     }
+
+    /* Extra core-specific regions for virtual interfaces. This is required by
+     * the GICv2 specification.
+     */
+    if (s->virt_extn) {
+        for (i = 0; i < s->num_cpu; i++) {
+            memory_region_init_io(&s->vifaceiomem[i + 1], OBJECT(s),
+                                  &gic_viface_ops, &s->backref[i],
+                                  "gic_viface", 0x1000);
+            sysbus_init_mmio(sbd, &s->vifaceiomem[i + 1]);
+        }
+    }
+
 }
 
 static void arm_gic_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-- 
2.18.0

  parent reply	other threads:[~2018-07-27  9:55 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-27  9:54 [Qemu-devel] [PATCH v5 00/20] arm_gic: add virtualization extensions support Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 01/20] intc/arm_gic: Refactor operations on the distributor Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 02/20] intc/arm_gic: Implement GICD_ISACTIVERn and GICD_ICACTIVERn registers Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 03/20] intc/arm_gic: Remove some dead code and put some functions static Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 04/20] vmstate.h: Provide VMSTATE_UINT16_SUB_ARRAY Luc Michel
2018-07-27 12:41   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 05/20] intc/arm_gic: Add the virtualization extensions to the GIC state Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 06/20] intc/arm_gic: Add virtual interface register definitions Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 07/20] intc/arm_gic: Add virtualization extensions helper macros and functions Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 08/20] intc/arm_gic: Refactor secure/ns access check in the CPU interface Luc Michel
2018-07-27 12:45   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 09/20] intc/arm_gic: Add virtualization enabled IRQ helper functions Luc Michel
2018-07-27 12:48   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 10/20] intc/arm_gic: Implement virtualization extensions in gic_(activate_irq|drop_prio) Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 11/20] intc/arm_gic: Implement virtualization extensions in gic_acknowledge_irq Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 12/20] intc/arm_gic: Implement virtualization extensions in gic_(deactivate|complete_irq) Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 13/20] intc/arm_gic: Implement virtualization extensions in gic_cpu_(read|write) Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 14/20] intc/arm_gic: Wire the vCPU interface Luc Michel
2018-07-27  9:54 ` Luc Michel [this message]
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 16/20] intc/arm_gic: Implement gic_update_virt() function Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 17/20] intc/arm_gic: Implement maintenance interrupt generation Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 18/20] intc/arm_gic: Improve traces Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 19/20] xlnx-zynqmp: Improve GIC wiring and MMIO mapping Luc Michel
2018-07-27  9:54 ` [Qemu-devel] [PATCH v5 20/20] arm/virt: Add support for GICv2 virtualization extensions Luc Michel
2018-07-30 17:14 ` [Qemu-devel] [PATCH v5 00/20] arm_gic: add virtualization extensions support Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180727095421.386-16-luc.michel@greensocs.com \
    --to=luc.michel@greensocs.com \
    --cc=edgari@xilinx.com \
    --cc=jan.kiszka@web.de \
    --cc=mark.burton@greensocs.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=saipava@xilinx.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.