From nobody Wed Nov 19 20:20:23 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1702383657854687.2195932195983; Tue, 12 Dec 2023 04:20:57 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rD1jz-0006At-LH; Tue, 12 Dec 2023 07:19:59 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rD1jx-00068B-84; Tue, 12 Dec 2023 07:19:57 -0500 Received: from isrv.corpit.ru ([86.62.121.231]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rD1jv-0000U8-3U; Tue, 12 Dec 2023 07:19:56 -0500 Received: from tsrv.corpit.ru (tsrv.tls.msk.ru [192.168.177.2]) by isrv.corpit.ru (Postfix) with ESMTP id F015D3AF04; Tue, 12 Dec 2023 15:18:49 +0300 (MSK) Received: from tls.msk.ru (mjt.wg.tls.msk.ru [192.168.177.130]) by tsrv.corpit.ru (Postfix) with SMTP id B25F93B952; Tue, 12 Dec 2023 15:18:32 +0300 (MSK) Received: (nullmailer pid 1003447 invoked by uid 1000); Tue, 12 Dec 2023 12:18:31 -0000 From: Michael Tokarev To: qemu-devel@nongnu.org Cc: qemu-stable@nongnu.org, Peter Maydell , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Richard Henderson , Michael Tokarev Subject: [Stable-8.1.4 16/31] target/arm: Handle overflow in calculation of next timer tick Date: Tue, 12 Dec 2023 15:18:04 +0300 Message-Id: <20231212121831.1003318-16-mjt@tls.msk.ru> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=86.62.121.231; envelope-from=mjt@tls.msk.ru; helo=isrv.corpit.ru X-Spam_score_int: -68 X-Spam_score: -6.9 X-Spam_bar: ------ X-Spam_report: (-6.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_HI=-5, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1702383659590100003 From: Peter Maydell In commit edac4d8a168 back in 2015 when we added support for the virtual timer offset CNTVOFF_EL2, we didn't correctly update the timer-recalculation code that figures out when the timer interrupt is next going to change state. We got it wrong in two ways: * for the 0->1 transition, we didn't notice that gt->cval + offset can overflow a uint64_t * for the 1->0 transition, we didn't notice that the transition might now happen before the count rolls over, if offset > count In the former case, we end up trying to set the next interrupt for a time in the past, which results in QEMU hanging as the timer fires continuously. In the latter case, we would fail to update the interrupt status when we are supposed to. Fix the calculations in both cases. The test case is Alex Benn=C3=A9e's from the bug report, and tests the 0->1 transition overflow case. Fixes: edac4d8a168 ("target-arm: Add CNTVOFF_EL2") Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/60 Signed-off-by: Alex Benn=C3=A9e Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20231120173506.3729884-1-peter.maydell@linaro.org Reviewed-by: Peter Maydell (cherry picked from commit 8d37a1425b9954d7e445615dcad23456515e24c0) Signed-off-by: Michael Tokarev diff --git a/target/arm/helper.c b/target/arm/helper.c index f66b610bdd..01822b9086 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2616,11 +2616,28 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeri= dx) qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate); =20 if (istatus) { - /* Next transition is when count rolls back over to zero */ - nexttick =3D UINT64_MAX; + /* + * Next transition is when (count - offset) rolls back over to= 0. + * If offset > count then this is when count =3D=3D offset; + * if offset <=3D count then this is when count =3D=3D offset = + 2^64 + * For the latter case we set nexttick to an "as far in future + * as possible" value and let the code below handle it. + */ + if (offset > count) { + nexttick =3D offset; + } else { + nexttick =3D UINT64_MAX; + } } else { - /* Next transition is when we hit cval */ - nexttick =3D gt->cval + offset; + /* + * Next transition is when (count - offset) =3D=3D cval, i.e. + * when count =3D=3D (cval + offset). + * If that would overflow, then again we set up the next inter= rupt + * for "as far in the future as possible" for the code below. + */ + if (uadd64_overflow(gt->cval, offset, &nexttick)) { + nexttick =3D UINT64_MAX; + } } /* * Note that the desired next expiry time might be beyond the diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/= Makefile.softmmu-target index b74a2534e3..d71659cc22 100644 --- a/tests/tcg/aarch64/Makefile.softmmu-target +++ b/tests/tcg/aarch64/Makefile.softmmu-target @@ -45,7 +45,8 @@ TESTS+=3Dmemory-sve =20 # Running QEMU_BASE_MACHINE=3D-M virt -cpu max -display none -QEMU_OPTS+=3D$(QEMU_BASE_MACHINE) -semihosting-config enable=3Don,target= =3Dnative,chardev=3Doutput -kernel +QEMU_BASE_ARGS=3D-semihosting-config enable=3Don,target=3Dnative,chardev= =3Doutput +QEMU_OPTS+=3D$(QEMU_BASE_MACHINE) $(QEMU_BASE_ARGS) -kernel =20 # console test is manual only QEMU_SEMIHOST=3D-chardev stdio,mux=3Don,id=3Dstdio0 -semihosting-config en= able=3Don,chardev=3Dstdio0 -mon chardev=3Dstdio0,mode=3Dreadline @@ -55,6 +56,10 @@ run-semiconsole: semiconsole run-plugin-semiconsole-with-%: semiconsole $(call skip-test, $<, "MANUAL ONLY") =20 +# vtimer test needs EL2 +QEMU_EL2_MACHINE=3D-machine virt,virtualization=3Don,gic-version=3D2 -cpu = cortex-a57 -smp 4 +run-vtimer: QEMU_OPTS=3D$(QEMU_EL2_MACHINE) $(QEMU_BASE_ARGS) -kernel + # Simple Record/Replay Test .PHONY: memory-record run-memory-record: memory-record memory diff --git a/tests/tcg/aarch64/system/vtimer.c b/tests/tcg/aarch64/system/v= timer.c new file mode 100644 index 0000000000..42f2f7796c --- /dev/null +++ b/tests/tcg/aarch64/system/vtimer.c @@ -0,0 +1,48 @@ +/* + * Simple Virtual Timer Test + * + * Copyright (c) 2020 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include + +/* grabbed from Linux */ +#define __stringify_1(x...) #x +#define __stringify(x...) __stringify_1(x) + +#define read_sysreg(r) ({ \ + uint64_t __val; \ + asm volatile("mrs %0, " __stringify(r) : "=3Dr" (__val)); \ + __val; \ +}) + +#define write_sysreg(r, v) do { \ + uint64_t __val =3D (uint64_t)(v); \ + asm volatile("msr " __stringify(r) ", %x0" \ + : : "rZ" (__val)); \ +} while (0) + +int main(void) +{ + int i; + + ml_printf("VTimer Test\n"); + + write_sysreg(cntvoff_el2, 1); + write_sysreg(cntv_cval_el0, -1); + write_sysreg(cntv_ctl_el0, 1); + + ml_printf("cntvoff_el2=3D%lx\n", read_sysreg(cntvoff_el2)); + ml_printf("cntv_cval_el0=3D%lx\n", read_sysreg(cntv_cval_el0)); + ml_printf("cntv_ctl_el0=3D%lx\n", read_sysreg(cntv_ctl_el0)); + + /* Now read cval a few times */ + for (i =3D 0; i < 10; i++) { + ml_printf("%d: cntv_cval_el0=3D%lx\n", i, read_sysreg(cntv_cval_el= 0)); + } + + return 0; +} --=20 2.39.2