target/ppc: Fix 64-bit decrementer

The current way the mask is built can overflow with a 64-bit decrementer.
Use sextract64() to extract the signed values and remove the logic to
handle negative values which has become useless.

Cc: Luis Fernando Fujita Pires <luis.pires@eldorado.org.br>
Fixes: a8dafa5251 ("target/ppc: Implement large decrementer support for TCG")
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20210920061203.989563-5-clg@kaod.org>
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Cédric Le Goater 2021-09-20 08:12:03 +02:00 committed by David Gibson
parent af96d2e692
commit 4d9b8ef9b5

View File

@ -821,14 +821,12 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
CPUPPCState *env = &cpu->env; CPUPPCState *env = &cpu->env;
ppc_tb_t *tb_env = env->tb_env; ppc_tb_t *tb_env = env->tb_env;
uint64_t now, next; uint64_t now, next;
bool negative; int64_t signed_value;
int64_t signed_decr;
/* Truncate value to decr_width and sign extend for simplicity */ /* Truncate value to decr_width and sign extend for simplicity */
value &= ((1ULL << nr_bits) - 1); signed_value = sextract64(value, 0, nr_bits);
negative = !!(value & (1ULL << (nr_bits - 1))); signed_decr = sextract64(decr, 0, nr_bits);
if (negative) {
value |= (0xFFFFFFFFULL << nr_bits);
}
trace_ppc_decr_store(nr_bits, decr, value); trace_ppc_decr_store(nr_bits, decr, value);
@ -850,16 +848,16 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
* On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
* an edge interrupt, so raise it here too. * an edge interrupt, so raise it here too.
*/ */
if ((value < 3) || if ((signed_value < 3) ||
((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && negative) || ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) ||
((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && negative ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0
&& !(decr & (1ULL << (nr_bits - 1))))) { && signed_decr >= 0)) {
(*raise_excp)(cpu); (*raise_excp)(cpu);
return; return;
} }
/* On MSB level based systems a 0 for the MSB stops interrupt delivery */ /* On MSB level based systems a 0 for the MSB stops interrupt delivery */
if (!negative && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) { if (signed_value >= 0 && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
(*lower_excp)(cpu); (*lower_excp)(cpu);
} }