diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index b8f4dfc1084a..603a38cae83f 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 4e548a448747..0f32cab1ff57 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);
@@ -1088,8 +1094,8 @@ void helper_rfsvc(CPUPPCState *env)
     do_rfi(env, env->lr, env->ctr & 0x0000FFFF);
 }
 
-/* Embedded.Processor Control */
-static int dbell2irq(target_ulong rb)
+/* Server and Embedded Processor Control */
+static int dbell2irq(target_ulong rb, bool book3s)
 {
     int msg = rb & DBELL_TYPE_MASK;
     int irq = -1;
@@ -1109,12 +1115,21 @@ static int dbell2irq(target_ulong rb)
         break;
     }
 
+    /* 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 */
+    if (book3s && msg == DBELL_TYPE_DBELL_SERVER) {
+        irq = PPC_INTERRUPT_HDOORBELL;
+    }
+
     return irq;
 }
 
 void helper_msgclr(CPUPPCState *env, target_ulong rb)
 {
-    int irq = dbell2irq(rb);
+    /* 64-bit server processors compliant with arch 2.x */
+    bool book3s = (env->insns_flags & PPC_SEGMENT_64B);
+    int irq = dbell2irq(rb, book3s);
 
     if (irq < 0) {
         return;
@@ -1123,10 +1138,11 @@ void helper_msgclr(CPUPPCState *env, target_ulong rb)
     env->pending_interrupts &= ~(1 << irq);
 }
 
-void helper_msgsnd(target_ulong rb)
+void helper_msgsnd(CPUPPCState *env, target_ulong rb)
 {
-    int irq = dbell2irq(rb);
-    int pir = rb & DBELL_PIRTAG_MASK;
+    /* 64-bit server processors compliant with arch 2.x */
+    bool book3s = (env->insns_flags & PPC_SEGMENT_64B);
+    int irq = dbell2irq(rb, book3s);
     CPUState *cs;
 
     if (irq < 0) {
@@ -1137,8 +1153,17 @@ void helper_msgsnd(target_ulong rb)
     CPU_FOREACH(cs) {
         PowerPCCPU *cpu = POWERPC_CPU(cs);
         CPUPPCState *cenv = &cpu->env;
+        bool send;
 
-        if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
+        /* TODO: broadcast message to all threads of the same  processor */
+        if (book3s) {
+            int pir = rb & DBELL_PROCIDTAG_MASK;
+            send = (cenv->spr_cb[SPR_PIR].default_value == pir);
+        } else {
+            int pir = rb & DBELL_PROCIDTAG_MASK;
+            send = (rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir);
+        }
+        if (send) {
             cenv->pending_interrupts |= 1 << irq;
             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
         }
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index bb6a94a8b390..3e98bd9eecb8 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -677,7 +677,7 @@ DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl)
 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(msgsnd, void, env, tl)
 DEF_HELPER_2(msgclr, void, env, tl)
 #endif
 
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index bcd36d53537f..1ad7e0fd4efd 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6180,10 +6180,19 @@ static void gen_msgsnd(DisasContext *ctx)
     GEN_PRIV;
 #else
     CHK_HV;
-    gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]);
+    gen_helper_msgsnd(cpu_env, 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 +6673,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 70ff15a51a6b..55c99c97e377 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) |
