From nobody Fri Sep 25 21:02:39 2026 Received: from mta0.migadu.com (out-14.mta0.migadu.com [91.218.175.14]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 26DCB4A093D for ; Mon, 21 Sep 2026 14:04:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.14 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789999474; cv=none; b=sg+bHQFw7ryi9nfymBX/Qdhw28Jow5iUh1nSIBjyOlPfN5C5pInB45ou1VxefZC3BO3C6UxvwBaR7I0twLb7gKlF61MebEu8hRYYGwEXX/D0I5AAWGDtYK61fI47rc8UeU4vzx9vhCEfaf4qW4PtLUEWn+CYnd5G2PseiV1lG2U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789999474; c=relaxed/simple; bh=OSYAyJkxVLSPK+NkLdepaf6lI/E2wi+QfFe45FHXmeM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=LD9jS1uBs3j1TGBaNlliJtm/uyLLPyvsz/BlSGB/mb0ZcsmEwV1jlmvXBMtBtasx0YhNUpe8A/SK/1m0rKhhuq+DLn2kI7+akJ4Wkus35mI+Wxa07ZMmfO9ybpst1l+1DuQTa3REI+cSgQa5K6vTaHIXQ03HMOOp3zoD1o0ooIg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=Sk5a9FvZ; arc=none smtp.client-ip=91.218.175.14 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="Sk5a9FvZ" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=OSYAyJkxVLSPK+NkLdepaf6lI/E2wi+QfFe45FHXmeM=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1789999470; v=1; x=1790604270; b=Sk5a9FvZBlY/6bf164Jy3nmRv5LY6eEHg5avMTVpYBAI71bK86cnfGRDWp7d/R/xM9g7/QXJ Aa2Bdcjt+nLLeKrc+SthqXxIxax/HACY4nHAO5Y8N3mFT3uWS72dOphDUdq82nHpgavJOl1Q0tO ltX7KYvWBmswKZUBvfgiLdUo= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id cfe6841c27b4352f; Mon, 21 Sep 2026 14:04:29 +0000 X-Mizu-Trace-ID: cfe6841c27b4352f X-Migadu-Flow: FLOW_OUT From: Fuad Tabba To: Marc Zyngier , Oliver Upton Cc: Joey Gouly , Suzuki K Poulose , Zenghui Yu , Zenghui Yu , Ganapatrao Kulkarni , Will Deacon , Fuad Tabba , kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH 1/3] KVM: arm64: timers: Compute an offset-applied CVAL from the current count Date: Mon, 21 Sep 2026 15:04:25 +0100 Message-Id: <20260921140427.2211373-2-fuad.tabba@linux.dev> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260921140427.2211373-1-fuad.tabba@linux.dev> References: <20260921140427.2211373-1-fuad.tabba@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When the hardware won't apply a timer's offset, KVM programs CVAL + offset and lets it compare that against the raw counter. The compare is unsigned (IsTimerConditionMet, DDI0487M_c J1.4.3.29): condition_met =3D (UInt(PhysicalCountInt() - offset) - UInt(compare_value)) >=3D 0; Adding the offset to both sides preserves it only when both sums wrap or neither does: a guest whose counter is ahead of the host's by more than CVAL has an expired timer that CVAL + offset puts in the far future, and one behind it has a far-future timer that CVAL + offset wraps into the past. On a CNTPOFF_EL2 host the first case livelocks: __activate_traps() reloads the guest's CVAL and the timer fires, __deactivate_traps() rewrites it as CVAL + offset on the way out and the line drops before the host can take the interrupt, and the vCPU only makes progress once an unrelated vcpu_put() and vcpu_load() inject the interrupt from the memory copy. arch_timer_edge_cases stops in its physical past-timer cases. Without CNTPOFF_EL2 the same cases hang until the vCPU is next loaded, which is what Zenghui reported on a Kunpeng920. Derive the programmed value from the current count instead: CVAL + offset while the deadline is ahead, 0 for a timer that has already expired for the guest, ~0 for one past the counter's wrap. That value can't be inverted, so timer_save_state() keeps the memory copy whenever an offset is in play; it's current there, written by the trap handler when the accesses are trapped and by __deactivate_traps() on the CNTPOFF_EL2 path. kvm_hyp_handle_timer() subtracted the offset back out for a guest hypervisor's read of its own physical CVAL, so return the memory copy there too. Fixes: c605ee245097 ("KVM: arm64: timers: Allow physical offset without CNT= POFF_EL2") Fixes: 9404673293b0 ("KVM: arm64: timers: Correctly handle TGE flip with CN= TPOFF_EL2") Fixes: 0bc9a9e85fcf ("KVM: arm64: Work around x1e's CNTVOFF_EL2 bogosity") Reported-by: Zenghui Yu Closes: https://lore.kernel.org/r/460258be-0102-e922-c342-4e87cd94b9e5@huaw= ei.com Cc: stable@vger.kernel.org Signed-off-by: Fuad Tabba --- arch/arm64/kvm/arch_timer.c | 27 ++++++++++++--------------- arch/arm64/kvm/hyp/vhe/switch.c | 11 ++++++----- include/kvm/arm_arch_timer.h | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index 6ac3321f4c575..9278b5383c044 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -528,17 +528,11 @@ static void timer_save_state(struct arch_timer_contex= t *ctx) goto out; =20 switch (index) { - u64 cval; - case TIMER_VTIMER: case TIMER_HVTIMER: timer_set_ctl(ctx, read_sysreg_el0(SYS_CNTV_CTL)); - cval =3D read_sysreg_el0(SYS_CNTV_CVAL); - - if (has_broken_cntvoff()) - cval -=3D timer_get_offset(ctx); - - timer_set_cval(ctx, cval); + if (!has_broken_cntvoff() || !timer_get_offset(ctx)) + timer_set_cval(ctx, read_sysreg_el0(SYS_CNTV_CVAL)); =20 /* Disable the timer */ write_sysreg_el0(0, SYS_CNTV_CTL); @@ -564,11 +558,12 @@ static void timer_save_state(struct arch_timer_contex= t *ctx) case TIMER_PTIMER: case TIMER_HPTIMER: timer_set_ctl(ctx, read_sysreg_el0(SYS_CNTP_CTL)); - cval =3D read_sysreg_el0(SYS_CNTP_CVAL); - - cval -=3D timer_get_offset(ctx); - - timer_set_cval(ctx, cval); + /* + * With an offset, memory already holds the guest's CVAL (the + * trap handler or __deactivate_traps() wrote it). + */ + if (!timer_get_offset(ctx)) + timer_set_cval(ctx, read_sysreg_el0(SYS_CNTP_CVAL)); =20 /* Disable the timer */ write_sysreg_el0(0, SYS_CNTP_CTL); @@ -647,7 +642,8 @@ static void timer_restore_state(struct arch_timer_conte= xt *ctx) offset =3D timer_get_offset(ctx); if (has_broken_cntvoff()) { set_cntvoff(0); - cval +=3D offset; + if (offset) + cval =3D timer_apply_offset(cval, offset, kvm_phys_timer_read()); } else { set_cntvoff(offset); } @@ -660,7 +656,8 @@ static void timer_restore_state(struct arch_timer_conte= xt *ctx) cval =3D timer_get_cval(ctx); offset =3D timer_get_offset(ctx); set_cntpoff(offset); - cval +=3D offset; + if (offset) + cval =3D timer_apply_offset(cval, offset, kvm_phys_timer_read()); write_sysreg_el0(cval, SYS_CNTP_CVAL); isb(); write_sysreg_el0(timer_get_ctl(ctx), SYS_CNTP_CTL); diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switc= h.c index 7875911c05063..14aada311bac4 100644 --- a/arch/arm64/kvm/hyp/vhe/switch.c +++ b/arch/arm64/kvm/hyp/vhe/switch.c @@ -175,7 +175,8 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu) offset =3D read_sysreg_s(SYS_CNTPOFF_EL2); =20 if (map.direct_ptimer && offset) { - write_sysreg_el0(val + offset, SYS_CNTP_CVAL); + val =3D timer_apply_offset(val, offset, arch_timer_read_cntpct_el0()); + write_sysreg_el0(val, SYS_CNTP_CVAL); isb(); } } @@ -296,10 +297,10 @@ static bool kvm_hyp_handle_timer(struct kvm_vcpu *vcp= u, u64 *exit_code) break; case SYS_CNTP_CVAL_EL0: if (vcpu_el2_e2h_is_set(vcpu)) { - val =3D read_sysreg_el0(SYS_CNTP_CVAL); - - if (!has_cntpoff()) - val -=3D timer_get_offset(vcpu_hptimer(vcpu)); + if (!has_cntpoff() && timer_get_offset(vcpu_hptimer(vcpu))) + val =3D __vcpu_sys_reg(vcpu, CNTHP_CVAL_EL2); + else + val =3D read_sysreg_el0(SYS_CNTP_CVAL); } else { val =3D __vcpu_sys_reg(vcpu, CNTP_CVAL_EL0); } diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h index bc6f2fdd7ad33..80f96ea59f1ae 100644 --- a/include/kvm/arm_arch_timer.h +++ b/include/kvm/arm_arch_timer.h @@ -195,4 +195,19 @@ static inline void timer_set_offset(struct arch_timer_= context *ctxt, u64 offset) WRITE_ONCE(*ctxt->offset.vm_offset, offset); } =20 +/* + * CVAL to program when the hardware won't apply the timer's offset, so th= at + * its compare against the raw counter matches the guest's at 'now'. An + * expired timer stays expired; one past the wrap never fires. + */ +static inline u64 timer_apply_offset(u64 cval, u64 offset, u64 now) +{ + u64 hw =3D cval + offset; + + if (now - offset >=3D cval) + return 0; + + return hw > now ? hw : U64_MAX; +} + #endif --=20 2.39.5 From nobody Fri Sep 25 21:02:39 2026 Received: from mta1.migadu.com (out-139.mta1.migadu.com [95.215.58.139]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A2EA64A2A55 for ; Mon, 21 Sep 2026 14:04:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.139 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789999478; cv=none; b=ad+Yy2IO9kZIhmmdhDbCIb0xEQzCBu18DqJXjfvboWy8bswGxC1d5QByKJ6rEgOHtZKrecD7MGLLWU2H5Q9jXfog4BgiuG1C9zWVj0WUQglR3qrT0q8xu5Lq0ihtHqw1+2LHGKVvgp9QKyq6i5sBgURRP7qixKpYvF3lCamAiyk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789999478; c=relaxed/simple; bh=DEbyYnw/QNFLD6hov3Wk8Emu00bFpjJHBWq6l30twn8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=EyYbEIM2fF1+KePJbkyMandfcBMPDQhKQHwtNaMUNEeso+ToNxs7f9Onz4UCoGiGNjoCRJMdbhefz5A7XLHynHAiyM4fJ3oS1rdpJrbv7VbOci+dQo82Uz2VBGvJspLDV6LWTOkm+WU70eY14eTmJGe7PYgUfwrkbnoUVw7UUrI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=DeA0SiAV; arc=none smtp.client-ip=95.215.58.139 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="DeA0SiAV" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=DEbyYnw/QNFLD6hov3Wk8Emu00bFpjJHBWq6l30twn8=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1789999474; v=1; x=1790604274; b=DeA0SiAVyCbwA7WhbXf8p5FFtA1y9BGn+/at6/dcBj2TouLzRqimrd+JiZ9IpWw9i28ru18l Wvh3EotSdIL7vKByViObc7FL8CeaKxRWxMqAfzHKYtQIq6FEOURtCSE3EEdQu58i4T0q38I4BTy Fda4x2vD+FbwbbR2m4svxk3s= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id a77cef6fbb8dcc1e; Mon, 21 Sep 2026 14:04:34 +0000 X-Mizu-Trace-ID: a77cef6fbb8dcc1e X-Migadu-Flow: FLOW_OUT From: Fuad Tabba To: Marc Zyngier , Oliver Upton Cc: Joey Gouly , Suzuki K Poulose , Zenghui Yu , Zenghui Yu , Ganapatrao Kulkarni , Will Deacon , Fuad Tabba , kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH 2/3] KVM: arm64: nv: Read a guest hypervisor's CNTV_CVAL_EL0 from memory on x1e Date: Mon, 21 Sep 2026 15:04:26 +0100 Message-Id: <20260921140427.2211373-3-fuad.tabba@linux.dev> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260921140427.2211373-1-fuad.tabba@linux.dev> References: <20260921140427.2211373-1-fuad.tabba@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" On x1e KVM keeps CNTVOFF_EL2 at zero, traps the virtual timer whenever it has an offset and programs the hardware with the offset applied. kvm_hyp_handle_timer() returns that hardware value for a VHE guest hypervisor's read of its own CNTV_CVAL_EL0, instead of the CVAL it wrote. Its writes trap to the kernel and land in CNTHV_CVAL_EL2, so return that, as the physical timer's read does without CNTPOFF_EL2. Fixes: 0bc9a9e85fcf ("KVM: arm64: Work around x1e's CNTVOFF_EL2 bogosity") Signed-off-by: Fuad Tabba --- arch/arm64/kvm/hyp/vhe/switch.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switc= h.c index 14aada311bac4..4c965f9b1e1de 100644 --- a/arch/arm64/kvm/hyp/vhe/switch.c +++ b/arch/arm64/kvm/hyp/vhe/switch.c @@ -322,10 +322,14 @@ static bool kvm_hyp_handle_timer(struct kvm_vcpu *vcp= u, u64 *exit_code) val =3D __vcpu_sys_reg(vcpu, CNTV_CVAL_EL0); break; case SYS_CNTV_CVAL_EL0: - if (vcpu_el2_e2h_is_set(vcpu)) - val =3D read_sysreg_el0(SYS_CNTV_CVAL); - else + if (vcpu_el2_e2h_is_set(vcpu)) { + if (has_broken_cntvoff() && timer_get_offset(vcpu_hvtimer(vcpu))) + val =3D __vcpu_sys_reg(vcpu, CNTHV_CVAL_EL2); + else + val =3D read_sysreg_el0(SYS_CNTV_CVAL); + } else { val =3D __vcpu_sys_reg(vcpu, CNTV_CVAL_EL0); + } break; case SYS_CNTVCT_EL0: case SYS_CNTVCTSS_EL0: --=20 2.39.5 From nobody Fri Sep 25 21:02:39 2026 Received: from mta1.migadu.com (out-144.mta1.migadu.com [95.215.58.144]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 54E634A4993 for ; Mon, 21 Sep 2026 14:04:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.144 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789999483; cv=none; b=pH+kpPx2kcWOvq1w/OOLd708j1Q+0Bh0aj1col1x0eUjSsrnii4ZnHzc+f6+EUdRwRFl17zc8nK0GLFeO6Rf15juK6OZnsMennsBN+SQE+RDagfwOeT0OpWwWI4EZSR88U0MJvQp3QqROG13d1Fyx8skYmHEf38T3qaOl5Dl5kA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789999483; c=relaxed/simple; bh=ie878rU/JdV+WHZq6reEkW3LocI09006Gd3UryYGcEA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=dX7UusGzZ/HLCKhdMzXjnOHB3YmzYOZX79Q7nqp6aNwyesdYLtTWR8GO4zzHTmQr6NSRdQlyVOMwhWQXsx/6AijdHBMRpJeRUjAhqWEl/CkrEpEnV6eS5qS8BJp+xbmTDBWvrXN82JjNwYy4SOtCeV6rMtAZhaMOYoigXPRr/MA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=Ym+yjfJS; arc=none smtp.client-ip=95.215.58.144 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="Ym+yjfJS" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=ie878rU/JdV+WHZq6reEkW3LocI09006Gd3UryYGcEA=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1789999479; v=1; x=1790604279; b=Ym+yjfJSNoAEEYEZ8nF7MSCaOlkglFvG2PXUFTZUSCR2WK5OnYpE4u5G9is82wrKVkT62a4N 3BKH6UbTddmpZt07+o7ZsSKH+CNw6hyAPpGlQybfsJ5CmBCRHD0QRiaeTp1SU8NtV/OZ11iSrDi U11Fua0vRpoxEyOe7hpcnV+U= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id ad4db469fc531011; Mon, 21 Sep 2026 14:04:39 +0000 X-Mizu-Trace-ID: ad4db469fc531011 X-Migadu-Flow: FLOW_OUT From: Fuad Tabba To: Marc Zyngier , Oliver Upton Cc: Joey Gouly , Suzuki K Poulose , Zenghui Yu , Zenghui Yu , Ganapatrao Kulkarni , Will Deacon , Fuad Tabba , kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH 3/3] KVM: arm64: selftests: Test a timer set past the counter's wrap Date: Mon, 21 Sep 2026 15:04:27 +0100 Message-Id: <20260921140427.2211373-4-fuad.tabba@linux.dev> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260921140427.2211373-1-fuad.tabba@linux.dev> References: <20260921140427.2211373-1-fuad.tabba@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Program an unmasked timer whose cval sits within long_wait_ms of the counter's wrap while the guest's counter is at wait_ms, and expect no interrupt. The guest's counter can't reach it, but a host that applies the timer's offset by adding it to cval wraps the sum into the past and fires at once. The one existing case with a cval past the wrap, in the sanity checks, runs with the timer masked and can't see that. Signed-off-by: Fuad Tabba --- .../kvm/arm64/arch_timer_edge_cases.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c b/to= ols/testing/selftests/kvm/arm64/arch_timer_edge_cases.c index d9c9377a63256..69986a7f0d37d 100644 --- a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c +++ b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c @@ -787,6 +787,30 @@ static void test_timers_in_the_past(enum arch_timer ti= mer) } } =20 +/* + * With the counter at wait_ms, a tval of -(wait_ms + long_wait_ms) puts c= val + * within long_wait_ms of the counter's wrap: a deadline further away than= the + * counter can reach. Unmasked, so an early ISTATUS shows up as an IRQ. + */ +static void test_timers_past_counter_wrap(enum arch_timer timer) +{ + s32 tval =3D -(s32)msec_to_cycles(test_args.wait_ms + test_args.long_wait= _ms); + int i; + + for (i =3D 0; i < ARRAY_SIZE(sleep_method); i++) { + sleep_method_t sm =3D sleep_method[i]; + + local_irq_disable(); + set_counter(timer, msec_to_cycles(test_args.wait_ms)); + set_tval_irq(timer, tval, CTL_ENABLE); + sm(timer, msecs_to_usecs(test_args.wait_ms) + TIMEOUT_NO_IRQ_US); + local_irq_enable(); + isb(); + assert_irqs_handled(0); + timer_set_ctl(timer, CTL_IMASK); + } +} + static void test_long_timer_delays(enum arch_timer timer) { s32 tval =3D (s32)msec_to_cycles(test_args.long_wait_ms); @@ -806,6 +830,7 @@ static void guest_run_iteration(enum arch_timer timer) test_basic_functionality(timer); test_timers_sanity_checks(timer); =20 + test_timers_past_counter_wrap(timer); test_timers_above_tval_max(timer); test_timers_in_the_past(timer); =20 --=20 2.39.5