diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index b8f4dfc108..603a38cae8 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -930,7 +930,7 @@ enum { #define BOOKE206_MAX_TLBN 4 /*****************************************************************************/ -/* Embedded.Processor Control */ +/* Server and Embedded Processor Control */ #define DBELL_TYPE_SHIFT 27 #define DBELL_TYPE_MASK (0x1f << DBELL_TYPE_SHIFT) @@ -940,11 +940,15 @@ enum { #define DBELL_TYPE_G_DBELL_CRIT (0x03 << DBELL_TYPE_SHIFT) #define DBELL_TYPE_G_DBELL_MC (0x04 << DBELL_TYPE_SHIFT) -#define DBELL_BRDCAST (1 << 26) +#define DBELL_TYPE_DBELL_SERVER (0x05 << DBELL_TYPE_SHIFT) + +#define DBELL_BRDCAST PPC_BIT(37) #define DBELL_LPIDTAG_SHIFT 14 #define DBELL_LPIDTAG_MASK (0xfff << DBELL_LPIDTAG_SHIFT) #define DBELL_PIRTAG_MASK 0x3fff +#define DBELL_PROCIDTAG_MASK PPC_BITMASK(44, 63) + /*****************************************************************************/ /* Segment page size information, used by recent hash MMUs * The format of this structure mirrors kvm_ppc_smmu_info diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 4e548a4487..c092fbead0 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -417,6 +417,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ + case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ case POWERPC_EXCP_HV_EMU: srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; @@ -846,6 +847,11 @@ static void ppc_hw_interrupt(CPUPPCState *env) powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI); return; } + if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); + powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV); + return; + } if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM); @@ -1145,4 +1151,50 @@ void helper_msgsnd(target_ulong rb) } qemu_mutex_unlock_iothread(); } + +/* Server Processor Control */ +static int book3s_dbell2irq(target_ulong rb) +{ + int msg = rb & DBELL_TYPE_MASK; + + /* A Directed Hypervisor Doorbell message is sent only if the + * message type is 5. All other types are reserved and the + * instruction is a no-op */ + return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1; +} + +void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) +{ + int irq = book3s_dbell2irq(rb); + + if (irq < 0) { + return; + } + + env->pending_interrupts &= ~(1 << irq); +} + +void helper_book3s_msgsnd(target_ulong rb) +{ + int irq = book3s_dbell2irq(rb); + int pir = rb & DBELL_PROCIDTAG_MASK; + CPUState *cs; + + if (irq < 0) { + return; + } + + qemu_mutex_lock_iothread(); + CPU_FOREACH(cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *cenv = &cpu->env; + + /* TODO: broadcast message to all threads of the same processor */ + if (cenv->spr_cb[SPR_PIR].default_value == pir) { + cenv->pending_interrupts |= 1 << irq; + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } + } + qemu_mutex_unlock_iothread(); +} #endif diff --git a/target/ppc/helper.h b/target/ppc/helper.h index bb6a94a8b3..5b739179b8 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -679,6 +679,8 @@ DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl) DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_1(msgsnd, void, tl) DEF_HELPER_2(msgclr, void, env, tl) +DEF_HELPER_1(book3s_msgsnd, void, tl) +DEF_HELPER_2(book3s_msgclr, void, env, tl) #endif DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index bcd36d5353..4132f67bb1 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6170,7 +6170,12 @@ static void gen_msgclr(DisasContext *ctx) GEN_PRIV; #else CHK_HV; - gen_helper_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]); + /* 64-bit server processors compliant with arch 2.x */ + if (ctx->insns_flags & PPC_SEGMENT_64B) { + gen_helper_book3s_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]); + } else { + gen_helper_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]); + } #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6180,10 +6185,24 @@ static void gen_msgsnd(DisasContext *ctx) GEN_PRIV; #else CHK_HV; - gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]); + /* 64-bit server processors compliant with arch 2.x */ + if (ctx->insns_flags & PPC_SEGMENT_64B) { + gen_helper_book3s_msgsnd(cpu_gpr[rB(ctx->opcode)]); + } else { + gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]); + } #endif /* defined(CONFIG_USER_ONLY) */ } +static void gen_msgsync(DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY) + GEN_PRIV; +#else + CHK_HV; +#endif /* defined(CONFIG_USER_ONLY) */ + /* interpreted as no-op */ +} #if defined(TARGET_PPC64) static void gen_maddld(DisasContext *ctx) @@ -6664,6 +6683,8 @@ GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 0x03ff0001, PPC_NONE, PPC2_PRCNTL), GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001, PPC_NONE, PPC2_PRCNTL), +GEN_HANDLER2_E(msgsync, "msgsync", 0x1F, 0x16, 0x1B, 0x00000000, + PPC_NONE, PPC2_PRCNTL), GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE), GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE), GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC), diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index 70ff15a51a..55c99c97e3 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -8866,7 +8866,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | - PPC2_TM | PPC2_PM_ISA206 | PPC2_ISA300; + PPC2_TM | PPC2_PM_ISA206 | PPC2_ISA300 | PPC2_PRCNTL; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_TM) | (1ull << MSR_VR) |