aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2023-05-30 23:12:12 +1000
committerMichael Tokarev <mjt@tls.msk.ru>2023-06-30 09:18:28 +0300
commit4d8459c36596c881db28319044aef8145ef91819 (patch)
tree87102d4719dc878388f8ea91344ee9ab05b731ef
parent78c4994e94477b2e438cc5b4fef2ea2a0599f7f3 (diff)
downloadqemu-4d8459c36596c881db28319044aef8145ef91819.zip
qemu-4d8459c36596c881db28319044aef8145ef91819.tar.gz
qemu-4d8459c36596c881db28319044aef8145ef91819.tar.bz2
target/ppc: Fix decrementer time underflow and infinite timer loop
It is possible to store a very large value to the decrementer that it does not raise the decrementer exception so the timer is scheduled, but the next time value wraps and is treated as in the past. This can occur if (u64)-1 is stored on a zero-triggered exception, or (u64)-1 is stored twice on an underflow-triggered exception, for example. If such a value is set in DECAR, it gets stored to the decrementer by the timer function, which then immediately causes another timer, which hangs QEMU. Clamp the decrementer to the implemented width, and use that as the value for the timer calculation, effectively preventing this overflow. Reported-by: sdicaro@DDCI.com Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com> Message-Id: <20230530131214.373524-1-npiggin@gmail.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> (cherry picked from commit 09d2db9f46e38e2da990df8ad914d735d764251a) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
-rw-r--r--hw/ppc/ppc.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index dc86c1c..fbdc489 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -806,6 +806,8 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
int64_t signed_decr;
/* Truncate value to decr_width and sign extend for simplicity */
+ value = extract64(value, 0, nr_bits);
+ decr = extract64(decr, 0, nr_bits);
signed_value = sextract64(value, 0, nr_bits);
signed_decr = sextract64(decr, 0, nr_bits);