From patchwork Tue Aug 14 18:17:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 144225 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp4721235ljj; Tue, 14 Aug 2018 11:53:02 -0700 (PDT) X-Google-Smtp-Source: AA+uWPx8XU3Mj5T+Vuhoktca/EI89579TtlpyPhZqG9zJPJluQ/wWV0PZnmTrYK3qE8Kd1NoHjP5 X-Received: by 2002:a0c:c90d:: with SMTP id r13-v6mr20114065qvj.45.1534272782218; Tue, 14 Aug 2018 11:53:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1534272782; cv=none; d=google.com; s=arc-20160816; b=fHhqQsJPJTI8YTY5pr4k2gGVZFhdfXCiIxF2l6CkB0ZmVJ+43Ok8xXezJ3l2Z4zil/ e63QjB+c5ERvQ0+yz+z0viSdLMpk3NP/FxK1oTfYjmwIrHxVtxDkZcbc7a8Er4WLzktr GBU6my2tWSWEVladJB8IX1Kg+QqDe12c4PoRZcwjmyEJTb8ax8nKVnNl0MYdpH8dgaW/ c68LCqN+qvhksBAsLm1Z7b+urWIkF7UnmqZzCS5nwlo6M1r1CsIJ3FhI5XcJ1lgOap3x mecSdrFoyScrk54QF/5vwC066doVBxRsKoyHUfcGoyXJRhOYUgaley4DrmjRyelmHJuZ XoRw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject :content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:to:from:arc-authentication-results; bh=oVQbGUZkudFPXoIjybuMsiswOK1Bhq3VZxj5PD6MbFI=; b=F58AuoBHVVacKdof+oRQXfVZv+kvbgu4BjGwnMn67cGA6oFmc+jfG5RjslY3rVuUqy JpYsuN9HSDfGfVtGHCrlXgkJ4Xw0MWPbNWP11bXAIT3hUYA4Y8TKiRhz1B1Ax+WIjsrj FWxzAygbHowBDqFx5976dTcDpDp+6ys/CBpsM1FeEJXEQ2/NtjDGiVI35kDopHZ1Dkm9 819vFJp9IpievzhUlK3yIGbuMtP2QGzo6JignfhqkF/jEHsJr0VFd8t0p4oU5Yz969wo SqRkMJubr+H9kBQ0Kt/u1P0Iu7DJWK6vN5OAtLbRel+OLzJdEztE0lMnLKW8jZdbEPTk OARw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id 37-v6si1934658qvb.268.2018.08.14.11.53.02 for (version=TLS1 cipher=AES128-SHA bits=128/128); Tue, 14 Aug 2018 11:53:02 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Authentication-Results: mx.google.com; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:45775 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fpeRB-0001SU-LK for patch@linaro.org; Tue, 14 Aug 2018 14:53:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52571) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fpdvJ-0004lQ-HS for qemu-devel@nongnu.org; Tue, 14 Aug 2018 14:21:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fpdtx-0006fi-W2 for qemu-devel@nongnu.org; Tue, 14 Aug 2018 14:20:05 -0400 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:44414) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fpdtx-0006eo-Gs for qemu-devel@nongnu.org; Tue, 14 Aug 2018 14:18:41 -0400 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fpdtw-0007Fp-0Y for qemu-devel@nongnu.org; Tue, 14 Aug 2018 19:18:40 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Date: Tue, 14 Aug 2018 19:17:50 +0100 Message-Id: <20180814181815.23348-21-peter.maydell@linaro.org> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180814181815.23348-1-peter.maydell@linaro.org> References: <20180814181815.23348-1-peter.maydell@linaro.org> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PULL 20/45] intc/arm_gic: Add virtualization enabled IRQ helper functions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" From: Luc Michel Add some helper functions to gic_internal.h to get or change the state of an IRQ. When the current CPU is not a vCPU, the call is forwarded to the GIC distributor. Otherwise, it acts on the list register matching the IRQ in the current CPU virtual interface. gic_clear_active can have a side effect on the distributor, even in the vCPU case, when the correponding LR has the HW field set. Use those functions in the CPU interface code path to prepare for the vCPU interface implementation. Signed-off-by: Luc Michel Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20180727095421.386-10-luc.michel@greensocs.com Signed-off-by: Peter Maydell --- hw/intc/gic_internal.h | 83 ++++++++++++++++++++++++++++++++++++++++++ hw/intc/arm_gic.c | 32 +++++++--------- 2 files changed, 97 insertions(+), 18 deletions(-) -- 2.18.0 diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index cc5acc5d419..45c2af0bf59 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -143,6 +143,13 @@ REG32(GICH_LR63, 0x1fc) #define GICH_LR_GROUP(entry) (FIELD_EX32(entry, GICH_LR0, Grp1)) #define GICH_LR_HW(entry) (FIELD_EX32(entry, GICH_LR0, HW)) +#define GICH_LR_CLEAR_PENDING(entry) \ + ((entry) &= ~(GICH_LR_STATE_PENDING << R_GICH_LR0_State_SHIFT)) +#define GICH_LR_SET_ACTIVE(entry) \ + ((entry) |= (GICH_LR_STATE_ACTIVE << R_GICH_LR0_State_SHIFT)) +#define GICH_LR_CLEAR_ACTIVE(entry) \ + ((entry) &= ~(GICH_LR_STATE_ACTIVE << R_GICH_LR0_State_SHIFT)) + /* Valid bits for GICC_CTLR for GICv1, v1 with security extensions, * GICv2 and GICv2 with security extensions: */ @@ -238,4 +245,80 @@ static inline uint32_t *gic_get_lr_entry(GICState *s, int irq, int vcpu) g_assert_not_reached(); } +static inline bool gic_test_group(GICState *s, int irq, int cpu) +{ + if (gic_is_vcpu(cpu)) { + uint32_t *entry = gic_get_lr_entry(s, irq, cpu); + return GICH_LR_GROUP(*entry); + } else { + return GIC_DIST_TEST_GROUP(irq, 1 << cpu); + } +} + +static inline void gic_clear_pending(GICState *s, int irq, int cpu) +{ + if (gic_is_vcpu(cpu)) { + uint32_t *entry = gic_get_lr_entry(s, irq, cpu); + GICH_LR_CLEAR_PENDING(*entry); + } else { + /* Clear pending state for both level and edge triggered + * interrupts. (level triggered interrupts with an active line + * remain pending, see gic_test_pending) + */ + GIC_DIST_CLEAR_PENDING(irq, GIC_DIST_TEST_MODEL(irq) ? ALL_CPU_MASK + : (1 << cpu)); + } +} + +static inline void gic_set_active(GICState *s, int irq, int cpu) +{ + if (gic_is_vcpu(cpu)) { + uint32_t *entry = gic_get_lr_entry(s, irq, cpu); + GICH_LR_SET_ACTIVE(*entry); + } else { + GIC_DIST_SET_ACTIVE(irq, 1 << cpu); + } +} + +static inline void gic_clear_active(GICState *s, int irq, int cpu) +{ + if (gic_is_vcpu(cpu)) { + uint32_t *entry = gic_get_lr_entry(s, irq, cpu); + GICH_LR_CLEAR_ACTIVE(*entry); + + if (GICH_LR_HW(*entry)) { + /* Hardware interrupt. We must forward the deactivation request to + * the distributor. + */ + int phys_irq = GICH_LR_PHYS_ID(*entry); + int rcpu = gic_get_vcpu_real_id(cpu); + + if (phys_irq < GIC_NR_SGIS || phys_irq >= GIC_MAXIRQ) { + /* UNPREDICTABLE behaviour, we choose to ignore the request */ + return; + } + + /* This is equivalent to a NS write to DIR on the physical CPU + * interface. Hence group0 interrupt deactivation is ignored if + * the GIC is secure. + */ + if (!s->security_extn || GIC_DIST_TEST_GROUP(phys_irq, 1 << rcpu)) { + GIC_DIST_CLEAR_ACTIVE(phys_irq, 1 << rcpu); + } + } + } else { + GIC_DIST_CLEAR_ACTIVE(irq, 1 << cpu); + } +} + +static inline int gic_get_priority(GICState *s, int irq, int cpu) +{ + if (gic_is_vcpu(cpu)) { + uint32_t *entry = gic_get_lr_entry(s, irq, cpu); + return GICH_LR_PRIORITY(*entry); + } else { + return GIC_DIST_GET_PRIORITY(irq, cpu); + } +} + #endif /* QEMU_ARM_GIC_INTERNAL_H */ diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 94d5982e2ac..26ed7ea58ab 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -222,7 +222,8 @@ static uint16_t gic_get_current_pending_irq(GICState *s, int cpu, uint16_t pending_irq = s->current_pending[cpu]; if (pending_irq < GIC_MAXIRQ && gic_has_groups(s)) { - int group = GIC_DIST_TEST_GROUP(pending_irq, (1 << cpu)); + int group = gic_test_group(s, pending_irq, cpu); + /* On a GIC without the security extensions, reading this register * behaves in the same way as a secure access to a GIC with them. */ @@ -253,7 +254,7 @@ static int gic_get_group_priority(GICState *s, int cpu, int irq) if (gic_has_groups(s) && !(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) && - GIC_DIST_TEST_GROUP(irq, (1 << cpu))) { + gic_test_group(s, irq, cpu)) { bpr = s->abpr[cpu] - 1; assert(bpr >= 0); } else { @@ -266,7 +267,7 @@ static int gic_get_group_priority(GICState *s, int cpu, int irq) */ mask = ~0U << ((bpr & 7) + 1); - return GIC_DIST_GET_PRIORITY(irq, cpu) & mask; + return gic_get_priority(s, irq, cpu) & mask; } static void gic_activate_irq(GICState *s, int cpu, int irq) @@ -279,14 +280,14 @@ static void gic_activate_irq(GICState *s, int cpu, int irq) int regno = preemption_level / 32; int bitno = preemption_level % 32; - if (gic_has_groups(s) && GIC_DIST_TEST_GROUP(irq, (1 << cpu))) { + if (gic_has_groups(s) && gic_test_group(s, irq, cpu)) { s->nsapr[regno][cpu] |= (1 << bitno); } else { s->apr[regno][cpu] |= (1 << bitno); } s->running_priority[cpu] = prio; - GIC_DIST_SET_ACTIVE(irq, 1 << cpu); + gic_set_active(s, irq, cpu); } static int gic_get_prio_from_apr_bits(GICState *s, int cpu) @@ -355,7 +356,7 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) return irq; } - if (GIC_DIST_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { + if (gic_get_priority(s, irq, cpu) >= s->running_priority[cpu]) { DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq); return 1023; } @@ -364,8 +365,7 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) /* Clear pending flags for both level and edge triggered interrupts. * Level triggered IRQs will be reasserted once they become inactive. */ - GIC_DIST_CLEAR_PENDING(irq, GIC_DIST_TEST_MODEL(irq) ? ALL_CPU_MASK - : cm); + gic_clear_pending(s, irq, cpu); ret = irq; } else { if (irq < GIC_NR_SGIS) { @@ -377,9 +377,7 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) src = ctz32(s->sgi_pending[irq][cpu]); s->sgi_pending[irq][cpu] &= ~(1 << src); if (s->sgi_pending[irq][cpu] == 0) { - GIC_DIST_CLEAR_PENDING(irq, - GIC_DIST_TEST_MODEL(irq) ? ALL_CPU_MASK - : cm); + gic_clear_pending(s, irq, cpu); } ret = irq | ((src & 0x7) << 10); } else { @@ -387,8 +385,7 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) * interrupts. (level triggered interrupts with an active line * remain pending, see gic_test_pending) */ - GIC_DIST_CLEAR_PENDING(irq, GIC_DIST_TEST_MODEL(irq) ? ALL_CPU_MASK - : cm); + gic_clear_pending(s, irq, cpu); ret = irq; } } @@ -544,7 +541,6 @@ static bool gic_eoi_split(GICState *s, int cpu, MemTxAttrs attrs) static void gic_deactivate_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) { - int cm = 1 << cpu; int group; if (irq >= s->num_irq) { @@ -559,7 +555,7 @@ static void gic_deactivate_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) return; } - group = gic_has_groups(s) && GIC_DIST_TEST_GROUP(irq, cm); + group = gic_has_groups(s) && gic_test_group(s, irq, cpu); if (!gic_eoi_split(s, cpu, attrs)) { /* This is UNPREDICTABLE; we choose to ignore it */ @@ -573,7 +569,7 @@ static void gic_deactivate_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) return; } - GIC_DIST_CLEAR_ACTIVE(irq, cm); + gic_clear_active(s, irq, cpu); } static void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) @@ -608,7 +604,7 @@ static void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) } } - group = gic_has_groups(s) && GIC_DIST_TEST_GROUP(irq, cm); + group = gic_has_groups(s) && gic_test_group(s, irq, cpu); if (gic_cpu_ns_access(s, cpu, attrs) && !group) { DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq); @@ -624,7 +620,7 @@ static void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) /* In GICv2 the guest can choose to split priority-drop and deactivate */ if (!gic_eoi_split(s, cpu, attrs)) { - GIC_DIST_CLEAR_ACTIVE(irq, cm); + gic_clear_active(s, irq, cpu); } gic_update(s); }