* THE SOFTWARE.
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "cpu.h"
#include "hw/hw.h"
#include "hw/ppc/ppc.h"
}
if (old_pending != env->pending_interrupts) {
-#ifdef CONFIG_KVM
kvmppc_set_interrupt(cpu, n_IRQ, level);
-#endif
}
void store_40x_dbcr0(CPUPPCState *env, uint32_t val)
{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPU *cpu = env_archcpu(env);
switch ((val >> 28) & 0x3) {
case 0x0:
return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
}
-static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
+static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
{
ppc_tb_t *tb_env = env->tb_env;
- uint32_t decr;
- int64_t diff;
+ int64_t decr, diff;
diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if (diff >= 0) {
} else {
decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND);
}
- LOG_TB("%s: %08" PRIx32 "\n", __func__, decr);
+ LOG_TB("%s: %016" PRIx64 "\n", __func__, decr);
return decr;
}
-uint32_t cpu_ppc_load_decr (CPUPPCState *env)
+target_ulong cpu_ppc_load_decr(CPUPPCState *env)
{
ppc_tb_t *tb_env = env->tb_env;
+ uint64_t decr;
if (kvm_enabled()) {
return env->spr[SPR_DECR];
}
- return _cpu_ppc_load_decr(env, tb_env->decr_next);
+ decr = _cpu_ppc_load_decr(env, tb_env->decr_next);
+
+ /*
+ * If large decrementer is enabled then the decrementer is signed extened
+ * to 64 bits, otherwise it is a 32 bit value.
+ */
+ if (env->spr[SPR_LPCR] & LPCR_LD) {
+ return decr;
+ }
+ return (uint32_t) decr;
}
-uint32_t cpu_ppc_load_hdecr (CPUPPCState *env)
+target_ulong cpu_ppc_load_hdecr(CPUPPCState *env)
{
+ PowerPCCPU *cpu = env_archcpu(env);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
ppc_tb_t *tb_env = env->tb_env;
+ uint64_t hdecr;
+
+ hdecr = _cpu_ppc_load_decr(env, tb_env->hdecr_next);
- return _cpu_ppc_load_decr(env, tb_env->hdecr_next);
+ /*
+ * If we have a large decrementer (POWER9 or later) then hdecr is sign
+ * extended to 64 bits, otherwise it is 32 bits.
+ */
+ if (pcc->lrg_decr_bits > 32) {
+ return hdecr;
+ }
+ return (uint32_t) hdecr;
}
uint64_t cpu_ppc_load_purr (CPUPPCState *env)
QEMUTimer *timer,
void (*raise_excp)(void *),
void (*lower_excp)(PowerPCCPU *),
- uint32_t decr, uint32_t value)
+ target_ulong decr, target_ulong value,
+ int nr_bits)
{
CPUPPCState *env = &cpu->env;
ppc_tb_t *tb_env = env->tb_env;
uint64_t now, next;
+ bool negative;
+
+ /* Truncate value to decr_width and sign extend for simplicity */
+ value &= ((1ULL << nr_bits) - 1);
+ negative = !!(value & (1ULL << (nr_bits - 1)));
+ if (negative) {
+ value |= (0xFFFFFFFFULL << nr_bits);
+ }
- LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
+ LOG_TB("%s: " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", __func__,
decr, value);
if (kvm_enabled()) {
* an edge interrupt, so raise it here too.
*/
if ((value < 3) ||
- ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && (value & 0x80000000)) ||
- ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000)
- && !(decr & 0x80000000))) {
+ ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && negative) ||
+ ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && negative
+ && !(decr & (1ULL << (nr_bits - 1))))) {
(*raise_excp)(cpu);
return;
}
/* On MSB level based systems a 0 for the MSB stops interrupt delivery */
- if (!(value & 0x80000000) && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
+ if (!negative && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
(*lower_excp)(cpu);
}
timer_mod(timer, next);
}
-static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr,
- uint32_t value)
+static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr,
+ target_ulong value, int nr_bits)
{
ppc_tb_t *tb_env = cpu->env.tb_env;
__cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr,
- value);
+ value, nr_bits);
}
-void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
+void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value)
{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPU *cpu = env_archcpu(env);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ int nr_bits = 32;
+
+ if (env->spr[SPR_LPCR] & LPCR_LD) {
+ nr_bits = pcc->lrg_decr_bits;
+ }
- _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value);
+ _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, nr_bits);
}
static void cpu_ppc_decr_cb(void *opaque)
cpu_ppc_decr_excp(cpu);
}
-static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr,
- uint32_t value)
+static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr,
+ target_ulong value, int nr_bits)
{
ppc_tb_t *tb_env = cpu->env.tb_env;
if (tb_env->hdecr_timer != NULL) {
__cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
- hdecr, value);
+ hdecr, value, nr_bits);
}
}
-void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value)
+void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value)
{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPU *cpu = env_archcpu(env);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
- _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value);
+ _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value,
+ pcc->lrg_decr_bits);
}
static void cpu_ppc_hdecr_cb(void *opaque)
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
{
CPUPPCState *env = opaque;
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPU *cpu = env_archcpu(env);
ppc_tb_t *tb_env = env->tb_env;
tb_env->tb_freq = freq;
* if a decrementer exception is pending when it enables msr_ee at startup,
* it's not ready to handle it...
*/
- _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
- _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
+ _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
+ _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
}
CPU_FOREACH(cpu) {
PowerPCCPU *pcpu = POWERPC_CPU(cpu);
pcpu->env.tb_env->tb_offset = tb_off_adj;
-#if defined(CONFIG_KVM)
- kvm_set_one_reg(cpu, KVM_REG_PPC_TB_OFFSET,
- &pcpu->env.tb_env->tb_offset);
-#endif
+ kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset);
}
}
/* Set up (once) timebase frequency (in Hz) */
clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPU *cpu = env_archcpu(env);
ppc_tb_t *tb_env;
tb_env = g_malloc0(sizeof(ppc_tb_t));
env->tb_env = tb_env;
tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
- if (env->insns_flags & PPC_SEGMENT_64B) {
+ if (is_book3s_arch2x(env)) {
/* All Book3S 64bit CPUs implement level based DEC logic */
tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
}
uint64_t now, next;
env = opaque;
- cpu = ppc_env_get_cpu(env);
+ cpu = env_archcpu(env);
tb_env = env->tb_env;
ppc40x_timer = tb_env->opaque;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
ppc40x_timer_t *ppc40x_timer;
env = opaque;
- cpu = ppc_env_get_cpu(env);
+ cpu = env_archcpu(env);
tb_env = env->tb_env;
ppc40x_timer = tb_env->opaque;
env->spr[SPR_40x_TSR] |= 1 << 27;
uint64_t now, next;
env = opaque;
- cpu = ppc_env_get_cpu(env);
+ cpu = env_archcpu(env);
tb_env = env->tb_env;
ppc40x_timer = tb_env->opaque;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
break;
}
}
+
+PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
+ if (env->spr_cb[SPR_PIR].default_value == pir) {
+ return cpu;
+ }
+ }
+
+ return NULL;
+}