I am using qemu 7.1.0 to emulate a PPC e6500 built on Ubuntu Linux. The issue I found relates to setting the decrementer. Qemu hangs forever when the decrementer is set to a logically negative value stored in the auto reload register.
Expected behavior is to enable/clear the decrementer and set it to 0. The transition of the decrementer value should cause it to reset to the value stored in the auto-reload register. The code sets the DECAR register value to 0xffffffff. The max 32 bit value.
Below is the implementation of the BookE decrementer.
#define mfspr(rn) ({unsigned long rval; \
asm volatile("mfspr %0, %1": "=r" (rval) : "i"(rn)); \
rval;})
#define mtspr(rn, v) asm volatile("mtspr %1, %0" : : "r" ((unsigned long)(v)), "i"(rn) : "memory")
#define BOOKE_TCR 340
#define TCR_DIE_BIT (0X80000000 >> 5)
#define BOOKE_DECAR 54
#define TCR_ARE_BIT (0X80000000 >> 9)
#define DEC 22
#define BOOKE_TSR 336
#define TSR_DIS_BIT (0x80000000 >> 4)
uint32_t tcr = mfspr(BOOKE_TCR);
mtspr(BOOKE_TCR, (tcr & ~(TCR_DIE_BIT)));
mtspr(BOOKE_DECAR, 0xffffffff);
tcr = mfspr(BOOKE_TCR);
mtspr(BOOKE_TCR, (tcr|TCR_ARE_BIT));
mtspr(DEC, 0x00000000);
mtspr(BOOKE_TSR, TSR_DIS_BIT);
The issue was resolved by undoing the sign extension used in the __cpu_ppc_store_decr function in hw/ppc/ppc.c. DECAR values with 1 in the most significant bit were being passed as a sign extended 32 bit value in the function arguments. Therefore, the decrementer was being reset to a truncated 64 bit -1 instead of a 0xffffffff. This caused an infinite transition from 0 -> -1, which prevented further execution.
+++ qemu-7.1.0/hw/ppc/ppc.c 2023-01-13 10:53:27.112516808 -0700
@@ -813,6 +813,9 @@
/* Truncate value to decr_width and sign extend for simplicity */
signed_value = sextract64(value, 0, nr_bits);
signed_decr = sextract64(decr, 0, nr_bits);
+
+ // Undo 64 bit sign extension.
+ value = (value & 0xffffffff);
trace_ppc_decr_store(nr_bits, decr, value);
Is there an issue with the implementation of the BookE decrementer shown above? Basic decrementer functionality as per the BookE reference manual is such: Enable DECAR->Set DECAR to max value->Enable/Clear DECR->reset DECR to DECAR value and wait. Is it possible this is a bug in qemu-ppc implementation?