From nobody Tue Feb 10 06:08:19 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1541775821721394.80049235925594; Fri, 9 Nov 2018 07:03:41 -0800 (PST) Received: from localhost ([::1]:34216 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gL7C5-0004Vt-5D for importer@patchew.org; Fri, 09 Nov 2018 08:51:29 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37763) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gL78n-0001Te-Qt for qemu-devel@nongnu.org; Fri, 09 Nov 2018 08:48:06 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gL78j-0008Gp-VL for qemu-devel@nongnu.org; Fri, 09 Nov 2018 08:48:04 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:52456) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gL78b-0007ON-7I; Fri, 09 Nov 2018 08:47:54 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1gL78L-0002kw-Ll; Fri, 09 Nov 2018 13:47:37 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Fri, 9 Nov 2018 13:47:31 +0000 Message-Id: <20181109134731.11605-4-peter.maydell@linaro.org> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181109134731.11605-1-peter.maydell@linaro.org> References: <20181109134731.11605-1-peter.maydell@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PATCH for-v3.1 3/3] target/arm: Correctly implement handling of HCR_EL2.{VI, VF} 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: , Cc: Adam Lackorzynski , patches@linaro.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" In commit 8a0fc3a29fc2315325400 we tried to implement HCR_EL2.{VI,VF}, but we got it wrong and had to revert it. In that commit we implemented them as simply tracking whether there is a pending virtual IRQ or virtual FIQ. This is not correct -- these bits cause a software-generated VIRQ/VFIQ, which is distinct from whether there is a hardware-generated VIRQ/VFIQ caused by the external interrupt controller. So we need to track separately the HCR_EL2 bit state and the external virq/vfiq line state, and OR the two together to get the actual pending VIRQ/VFIQ state. Fixes: 8a0fc3a29fc2315325400c738f807d0d4ae0ab7f Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- target/arm/internals.h | 18 ++++++++++++++++ target/arm/cpu.c | 48 +++++++++++++++++++++++++++++++++++++++++- target/arm/helper.c | 20 ++++++++++++++++-- 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index 6c2bb2deebd..a32d359dd03 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -871,4 +871,22 @@ static inline const char *aarch32_mode_name(uint32_t p= sr) return cpu_mode_names[psr & 0xf]; } =20 +/** + * arm_cpu_update_virq: Update CPU_INTERRUPT_VIRQ bit in cs->interrupt_req= uest + * + * Update the CPU_INTERRUPT_VIRQ bit in cs->interrupt_request, following + * a change to either the input VIRQ line from the GIC or the HCR_EL2.VI b= it. + * Must be called with the iothread lock held. + */ +void arm_cpu_update_virq(ARMCPU *cpu); + +/** + * arm_cpu_update_vfiq: Update CPU_INTERRUPT_VFIQ bit in cs->interrupt_req= uest + * + * Update the CPU_INTERRUPT_VFIQ bit in cs->interrupt_request, following + * a change to either the input VFIQ line from the GIC or the HCR_EL2.VF b= it. + * Must be called with the iothread lock held. + */ +void arm_cpu_update_vfiq(ARMCPU *cpu); + #endif diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 45c16ae90ba..6fbea4dc88c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -436,6 +436,48 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, i= nt interrupt_request) } #endif =20 +void arm_cpu_update_virq(ARMCPU *cpu) +{ + /* + * Update the interrupt level for VIRQ, which is the logical OR of + * the HCR_EL2.VI bit and the input line level from the GIC. + */ + CPUARMState *env =3D &cpu->env; + CPUState *cs =3D CPU(cpu); + + bool new_state =3D (env->cp15.hcr_el2 & HCR_VI) || + (env->irq_line_state & CPU_INTERRUPT_VIRQ); + + if (new_state !=3D ((cs->interrupt_request & CPU_INTERRUPT_VIRQ) !=3D = 0)) { + if (new_state) { + cpu_interrupt(cs, CPU_INTERRUPT_VIRQ); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_VIRQ); + } + } +} + +void arm_cpu_update_vfiq(ARMCPU *cpu) +{ + /* + * Update the interrupt level for VFIQ, which is the logical OR of + * the HCR_EL2.VF bit and the input line level from the GIC. + */ + CPUARMState *env =3D &cpu->env; + CPUState *cs =3D CPU(cpu); + + bool new_state =3D (env->cp15.hcr_el2 & HCR_VF) || + (env->irq_line_state & CPU_INTERRUPT_VFIQ); + + if (new_state !=3D ((cs->interrupt_request & CPU_INTERRUPT_VFIQ) !=3D = 0)) { + if (new_state) { + cpu_interrupt(cs, CPU_INTERRUPT_VFIQ); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_VFIQ); + } + } +} + #ifndef CONFIG_USER_ONLY static void arm_cpu_set_irq(void *opaque, int irq, int level) { @@ -457,9 +499,13 @@ static void arm_cpu_set_irq(void *opaque, int irq, int= level) =20 switch (irq) { case ARM_CPU_VIRQ: + assert(arm_feature(env, ARM_FEATURE_EL2)); + arm_cpu_update_virq(cpu); + break; case ARM_CPU_VFIQ: assert(arm_feature(env, ARM_FEATURE_EL2)); - /* fall through */ + arm_cpu_update_vfiq(cpu); + break; case ARM_CPU_IRQ: case ARM_CPU_FIQ: if (level) { diff --git a/target/arm/helper.c b/target/arm/helper.c index f3878f505b7..771e4c3d0fb 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -3958,6 +3958,21 @@ static void hcr_write(CPUARMState *env, const ARMCPR= egInfo *ri, uint64_t value) tlb_flush(CPU(cpu)); } env->cp15.hcr_el2 =3D value; + + /* + * Updates to VI and VF require us to update the status of + * virtual interrupts, which are the logical OR of these bits + * and the state of the input lines from the GIC. (This requires + * that we have the iothread lock, which is done by marking the + * reginfo structs as ARM_CP_IO.) + * Note that if a write to HCR pends a VIRQ or VFIQ it is never + * possible for it to be taken immediately, because VIRQ and + * VFIQ are masked unless running at EL0 or EL1, and HCR + * can only be written at EL2. + */ + g_assert(qemu_mutex_iothread_locked()); + arm_cpu_update_virq(cpu); + arm_cpu_update_vfiq(cpu); } =20 static void hcr_writehigh(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3978,11 +3993,12 @@ static void hcr_writelow(CPUARMState *env, const AR= MCPRegInfo *ri, =20 static const ARMCPRegInfo el2_cp_reginfo[] =3D { { .name =3D "HCR_EL2", .state =3D ARM_CP_STATE_AA64, + .type =3D ARM_CP_IO, .opc0 =3D 3, .opc1 =3D 4, .crn =3D 1, .crm =3D 1, .opc2 =3D 0, .access =3D PL2_RW, .fieldoffset =3D offsetof(CPUARMState, cp15.hcr_= el2), .writefn =3D hcr_write }, { .name =3D "HCR", .state =3D ARM_CP_STATE_AA32, - .type =3D ARM_CP_ALIAS, + .type =3D ARM_CP_ALIAS | ARM_CP_IO, .cp =3D 15, .opc1 =3D 4, .crn =3D 1, .crm =3D 1, .opc2 =3D 0, .access =3D PL2_RW, .fieldoffset =3D offsetof(CPUARMState, cp15.hcr_= el2), .writefn =3D hcr_writelow }, @@ -4222,7 +4238,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] =3D { =20 static const ARMCPRegInfo el2_v8_cp_reginfo[] =3D { { .name =3D "HCR2", .state =3D ARM_CP_STATE_AA32, - .type =3D ARM_CP_ALIAS, + .type =3D ARM_CP_ALIAS | ARM_CP_IO, .cp =3D 15, .opc1 =3D 4, .crn =3D 1, .crm =3D 1, .opc2 =3D 4, .access =3D PL2_RW, .fieldoffset =3D offsetofhigh32(CPUARMState, cp15.hcr_el2), --=20 2.19.1