[PATCH v5 4/9] target/ppc: Add IBM PPE42 exception model

Glenn Miles posted 9 patches 1 month, 3 weeks ago
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, Nicholas Piggin <npiggin@gmail.com>, Chinmay Rath <rathc@linux.ibm.com>, Glenn Miles <milesg@linux.ibm.com>
There is a newer version of this series
[PATCH v5 4/9] target/ppc: Add IBM PPE42 exception model
Posted by Glenn Miles 1 month, 3 weeks ago
Add support for the IBM PPE42 exception model including
new exception vectors, exception priorities and setting
of PPE42 SPRs for determining the cause of an exception.

Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
---
 target/ppc/cpu_init.c        |  39 ++++++++-
 target/ppc/excp_helper.c     | 163 +++++++++++++++++++++++++++++++++++
 target/ppc/tcg-excp_helper.c |  12 +++
 3 files changed, 213 insertions(+), 1 deletion(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index b42673c6b5..097e3b3818 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -1720,6 +1720,30 @@ static void init_excp_4xx(CPUPPCState *env)
 #endif
 }
 
+static void init_excp_ppe42(CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    /* Machine Check vector changed after version 0 */
+    if (((env->spr[SPR_PVR] & 0xf00000ul) >> 20) == 0) {
+        env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000000;
+    } else {
+        env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000020;
+    }
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000040;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000060;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000080;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x000000A0;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x000000C0;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x000000E0;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00000120;
+    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00000140;
+    env->ivpr_mask = 0xFFFFFE00UL;
+    /* Hardware reset vector */
+    env->hreset_vector = 0x00000040UL;
+#endif
+}
+
 static void init_excp_MPC5xx(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
@@ -2245,6 +2269,7 @@ static void init_proc_ppe42(CPUPPCState *env)
 {
     register_ppe42_sprs(env);
 
+    init_excp_ppe42(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
@@ -2278,7 +2303,7 @@ static void ppe42_class_common_init(PowerPCCPUClass *pcc)
                     (1ull << MSR_IPE) |
                     R_MSR_SIBRCA_MASK;
     pcc->mmu_model = POWERPC_MMU_REAL;
-    pcc->excp_model = POWERPC_EXCP_40x;
+    pcc->excp_model = POWERPC_EXCP_PPE42;
     pcc->bus_model = PPC_FLAGS_INPUT_PPE42;
     pcc->bfd_mach = bfd_mach_ppc_403;
     pcc->flags = POWERPC_FLAG_PPE42 | POWERPC_FLAG_BUS_CLK;
@@ -7855,6 +7880,18 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
          * they can be read with "p $ivor0", "p $ivor1", etc.
          */
         break;
+    case POWERPC_EXCP_PPE42:
+        qemu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx "\n",
+                     env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
+
+        qemu_fprintf(f, "  TCR " TARGET_FMT_lx "   TSR " TARGET_FMT_lx
+                     "    ISR " TARGET_FMT_lx "   EDR " TARGET_FMT_lx "\n",
+                     env->spr[SPR_PPE42_TCR], env->spr[SPR_PPE42_TSR],
+                     env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
+
+        qemu_fprintf(f, "  PIR " TARGET_FMT_lx "   IVPR " TARGET_FMT_lx "\n",
+                     env->spr[SPR_PPE42_PIR], env->spr[SPR_PPE42_IVPR]);
+        break;
     case POWERPC_EXCP_40x:
         qemu_fprintf(f, "  TCR " TARGET_FMT_lx "   TSR " TARGET_FMT_lx
                      "    ESR " TARGET_FMT_lx "   DEAR " TARGET_FMT_lx "\n",
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 1efdc4066e..d8bca19fff 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -949,6 +949,125 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
     powerpc_set_excp_state(cpu, vector, new_msr);
 }
 
+static void powerpc_excp_ppe42(PowerPCCPU *cpu, int excp)
+{
+    CPUPPCState *env = &cpu->env;
+    target_ulong msr, new_msr, vector;
+    target_ulong mcs = PPE42_ISR_MCS_INSTRUCTION;
+    bool promote_unmaskable;
+
+    msr = env->msr;
+
+    /*
+     * New interrupt handler msr preserves SIBRC and ME unless explicitly
+     * overridden by the exception.  All other MSR bits are zeroed out.
+     */
+    new_msr = env->msr & (((target_ulong)1 << MSR_ME) | R_MSR_SIBRC_MASK);
+
+    /* HV emu assistance interrupt only exists on server arch 2.05 or later */
+    if (excp == POWERPC_EXCP_HV_EMU) {
+        excp = POWERPC_EXCP_PROGRAM;
+    }
+
+    /*
+     * Unmaskable interrupts (Program, ISI, Alignment and DSI) are promoted to
+     * machine check if MSR_UIE is 0.
+     */
+    promote_unmaskable = !(msr & ((target_ulong)1 << MSR_UIE));
+
+
+    switch (excp) {
+    case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
+        break;
+    case POWERPC_EXCP_DSI:       /* Data storage exception                   */
+        trace_ppc_excp_dsi(env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
+        if (promote_unmaskable) {
+            excp = POWERPC_EXCP_MCHECK;
+            mcs = PPE42_ISR_MCS_DSI;
+        }
+        break;
+    case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
+        trace_ppc_excp_isi(msr, env->nip);
+        if (promote_unmaskable) {
+            excp = POWERPC_EXCP_MCHECK;
+            mcs = PPE42_ISR_MCS_ISI;
+        }
+        break;
+    case POWERPC_EXCP_EXTERNAL:  /* External input                           */
+        break;
+    case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
+        if (promote_unmaskable) {
+            excp = POWERPC_EXCP_MCHECK;
+            mcs = PPE42_ISR_MCS_ALIGNMENT;
+        }
+        break;
+    case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
+        if (promote_unmaskable) {
+            excp = POWERPC_EXCP_MCHECK;
+            mcs = PPE42_ISR_MCS_PROGRAM;
+        }
+        switch (env->error_code & ~0xF) {
+        case POWERPC_EXCP_INVAL:
+            trace_ppc_excp_inval(env->nip);
+            env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_PTR);
+            break;
+        case POWERPC_EXCP_TRAP:
+            env->spr[SPR_PPE42_ISR] |= ((target_ulong)1 << PPE42_ISR_PTR);
+            break;
+        default:
+            /* Should never occur */
+            cpu_abort(env_cpu(env), "Invalid program exception %d. Aborting\n",
+                      env->error_code);
+            break;
+        }
+#ifdef CONFIG_TCG
+        env->spr[SPR_PPE42_EDR] = ppc_ldl_code(env, env->nip);
+#endif
+        break;
+    case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
+        break;
+    case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
+        trace_ppc_excp_print("FIT");
+        break;
+    case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
+        trace_ppc_excp_print("WDT");
+        break;
+    case POWERPC_EXCP_RESET:     /* System reset exception                   */
+        /* reset exceptions don't have ME set */
+        new_msr &= ~((target_ulong)1 << MSR_ME);
+        break;
+    default:
+        cpu_abort(env_cpu(env), "Invalid PPE42 exception %d. Aborting\n",
+                  excp);
+        break;
+    }
+
+    env->spr[SPR_SRR0] = env->nip;
+    env->spr[SPR_SRR1] = msr;
+
+    vector = env->excp_vectors[excp];
+    if (vector == (target_ulong)-1ULL) {
+        cpu_abort(env_cpu(env),
+                  "Raised an exception without defined vector %d\n", excp);
+    }
+    vector |= env->spr[SPR_PPE42_IVPR];
+
+    if (excp == POWERPC_EXCP_MCHECK) {
+        /* Also set the Machine Check Status (MCS) */
+        env->spr[SPR_PPE42_ISR] &= ~R_PPE42_ISR_MCS_MASK;
+        env->spr[SPR_PPE42_ISR] |= (mcs & R_PPE42_ISR_MCS_MASK);
+        env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_MFE);
+
+        /* Machine checks halt execution if MSR_ME is 0 */
+        powerpc_mcheck_checkstop(env);
+
+        /* machine check exceptions don't have ME set */
+        new_msr &= ~((target_ulong)1 << MSR_ME);
+    }
+
+    powerpc_set_excp_state(cpu, vector, new_msr);
+}
+
 static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
 {
     CPUPPCState *env = &cpu->env;
@@ -1589,6 +1708,9 @@ void powerpc_excp(PowerPCCPU *cpu, int excp)
     case POWERPC_EXCP_POWER11:
         powerpc_excp_books(cpu, excp);
         break;
+    case POWERPC_EXCP_PPE42:
+        powerpc_excp_ppe42(cpu, excp);
+        break;
     default:
         g_assert_not_reached();
     }
@@ -1945,6 +2067,43 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env,
 }
 #endif /* TARGET_PPC64 */
 
+static int ppe42_next_unmasked_interrupt(CPUPPCState *env)
+{
+    bool async_deliver;
+
+    /* External reset */
+    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+        return PPC_INTERRUPT_RESET;
+    }
+    /* Machine check exception */
+    if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+        return PPC_INTERRUPT_MCK;
+    }
+
+    async_deliver = FIELD_EX64(env->msr, MSR, EE);
+
+    if (async_deliver != 0) {
+        /* Watchdog timer */
+        if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+            return PPC_INTERRUPT_WDT;
+        }
+        /* External Interrupt */
+        if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+            return PPC_INTERRUPT_EXT;
+        }
+        /* Fixed interval timer */
+        if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+            return PPC_INTERRUPT_FIT;
+        }
+        /* Decrementer exception */
+        if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+            return PPC_INTERRUPT_DECR;
+        }
+    }
+
+    return 0;
+}
+
 static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 {
     uint32_t pending_interrupts = env->pending_interrupts;
@@ -1970,6 +2129,10 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
     }
 #endif
 
+    if (env->excp_model == POWERPC_EXCP_PPE42) {
+        return ppe42_next_unmasked_interrupt(env);
+    }
+
     /* External reset */
     if (pending_interrupts & PPC_INTERRUPT_RESET) {
         return PPC_INTERRUPT_RESET;
diff --git a/target/ppc/tcg-excp_helper.c b/target/ppc/tcg-excp_helper.c
index f835be5156..edecfb8572 100644
--- a/target/ppc/tcg-excp_helper.c
+++ b/target/ppc/tcg-excp_helper.c
@@ -229,6 +229,18 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
     case POWERPC_MMU_BOOKE206:
         env->spr[SPR_BOOKE_DEAR] = vaddr;
         break;
+    case POWERPC_MMU_REAL:
+        if (env->flags & POWERPC_FLAG_PPE42) {
+            env->spr[SPR_PPE42_EDR] = vaddr;
+            if (access_type == MMU_DATA_STORE) {
+                env->spr[SPR_PPE42_ISR] |= PPE42_ISR_ST;
+            } else {
+                env->spr[SPR_PPE42_ISR] &= ~PPE42_ISR_ST;
+            }
+        } else {
+            env->spr[SPR_DAR] = vaddr;
+        }
+        break;
     default:
         env->spr[SPR_DAR] = vaddr;
         break;
-- 
2.43.0
Re: [PATCH v5 4/9] target/ppc: Add IBM PPE42 exception model
Posted by Chinmay Rath 1 month, 2 weeks ago
On 9/18/25 23:57, Glenn Miles wrote:
> Add support for the IBM PPE42 exception model including
> new exception vectors, exception priorities and setting
> of PPE42 SPRs for determining the cause of an exception.
>
> Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
Reviewed-by: Chinmay Rath <rathc@linux.ibm.com>
> ---
>   target/ppc/cpu_init.c        |  39 ++++++++-
>   target/ppc/excp_helper.c     | 163 +++++++++++++++++++++++++++++++++++
>   target/ppc/tcg-excp_helper.c |  12 +++
>   3 files changed, 213 insertions(+), 1 deletion(-)
>
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index b42673c6b5..097e3b3818 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -1720,6 +1720,30 @@ static void init_excp_4xx(CPUPPCState *env)
>   #endif
>   }
>   
> +static void init_excp_ppe42(CPUPPCState *env)
> +{
> +#if !defined(CONFIG_USER_ONLY)
> +    /* Machine Check vector changed after version 0 */
> +    if (((env->spr[SPR_PVR] & 0xf00000ul) >> 20) == 0) {
> +        env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000000;
> +    } else {
> +        env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000020;
> +    }
> +    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000040;
> +    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000060;
> +    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000080;
> +    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x000000A0;
> +    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x000000C0;
> +    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x000000E0;
> +    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000100;
> +    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00000120;
> +    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00000140;
> +    env->ivpr_mask = 0xFFFFFE00UL;
> +    /* Hardware reset vector */
> +    env->hreset_vector = 0x00000040UL;
> +#endif
> +}
> +
>   static void init_excp_MPC5xx(CPUPPCState *env)
>   {
>   #if !defined(CONFIG_USER_ONLY)
> @@ -2245,6 +2269,7 @@ static void init_proc_ppe42(CPUPPCState *env)
>   {
>       register_ppe42_sprs(env);
>   
> +    init_excp_ppe42(env);
>       env->dcache_line_size = 32;
>       env->icache_line_size = 32;
>       /* Allocate hardware IRQ controller */
> @@ -2278,7 +2303,7 @@ static void ppe42_class_common_init(PowerPCCPUClass *pcc)
>                       (1ull << MSR_IPE) |
>                       R_MSR_SIBRCA_MASK;
>       pcc->mmu_model = POWERPC_MMU_REAL;
> -    pcc->excp_model = POWERPC_EXCP_40x;
> +    pcc->excp_model = POWERPC_EXCP_PPE42;
>       pcc->bus_model = PPC_FLAGS_INPUT_PPE42;
>       pcc->bfd_mach = bfd_mach_ppc_403;
>       pcc->flags = POWERPC_FLAG_PPE42 | POWERPC_FLAG_BUS_CLK;
> @@ -7855,6 +7880,18 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>            * they can be read with "p $ivor0", "p $ivor1", etc.
>            */
>           break;
> +    case POWERPC_EXCP_PPE42:
> +        qemu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx "\n",
> +                     env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
> +
> +        qemu_fprintf(f, "  TCR " TARGET_FMT_lx "   TSR " TARGET_FMT_lx
> +                     "    ISR " TARGET_FMT_lx "   EDR " TARGET_FMT_lx "\n",
> +                     env->spr[SPR_PPE42_TCR], env->spr[SPR_PPE42_TSR],
> +                     env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
> +
> +        qemu_fprintf(f, "  PIR " TARGET_FMT_lx "   IVPR " TARGET_FMT_lx "\n",
> +                     env->spr[SPR_PPE42_PIR], env->spr[SPR_PPE42_IVPR]);
> +        break;
>       case POWERPC_EXCP_40x:
>           qemu_fprintf(f, "  TCR " TARGET_FMT_lx "   TSR " TARGET_FMT_lx
>                        "    ESR " TARGET_FMT_lx "   DEAR " TARGET_FMT_lx "\n",
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 1efdc4066e..d8bca19fff 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -949,6 +949,125 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
>       powerpc_set_excp_state(cpu, vector, new_msr);
>   }
>   
> +static void powerpc_excp_ppe42(PowerPCCPU *cpu, int excp)
> +{
> +    CPUPPCState *env = &cpu->env;
> +    target_ulong msr, new_msr, vector;
> +    target_ulong mcs = PPE42_ISR_MCS_INSTRUCTION;
> +    bool promote_unmaskable;
> +
> +    msr = env->msr;
> +
> +    /*
> +     * New interrupt handler msr preserves SIBRC and ME unless explicitly
> +     * overridden by the exception.  All other MSR bits are zeroed out.
> +     */
> +    new_msr = env->msr & (((target_ulong)1 << MSR_ME) | R_MSR_SIBRC_MASK);
> +
> +    /* HV emu assistance interrupt only exists on server arch 2.05 or later */
> +    if (excp == POWERPC_EXCP_HV_EMU) {
> +        excp = POWERPC_EXCP_PROGRAM;
> +    }
> +
> +    /*
> +     * Unmaskable interrupts (Program, ISI, Alignment and DSI) are promoted to
> +     * machine check if MSR_UIE is 0.
> +     */
> +    promote_unmaskable = !(msr & ((target_ulong)1 << MSR_UIE));
> +
> +
> +    switch (excp) {
> +    case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
> +        break;
> +    case POWERPC_EXCP_DSI:       /* Data storage exception                   */
> +        trace_ppc_excp_dsi(env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]);
> +        if (promote_unmaskable) {
> +            excp = POWERPC_EXCP_MCHECK;
> +            mcs = PPE42_ISR_MCS_DSI;
> +        }
> +        break;
> +    case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
> +        trace_ppc_excp_isi(msr, env->nip);
> +        if (promote_unmaskable) {
> +            excp = POWERPC_EXCP_MCHECK;
> +            mcs = PPE42_ISR_MCS_ISI;
> +        }
> +        break;
> +    case POWERPC_EXCP_EXTERNAL:  /* External input                           */
> +        break;
> +    case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
> +        if (promote_unmaskable) {
> +            excp = POWERPC_EXCP_MCHECK;
> +            mcs = PPE42_ISR_MCS_ALIGNMENT;
> +        }
> +        break;
> +    case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
> +        if (promote_unmaskable) {
> +            excp = POWERPC_EXCP_MCHECK;
> +            mcs = PPE42_ISR_MCS_PROGRAM;
> +        }
> +        switch (env->error_code & ~0xF) {
> +        case POWERPC_EXCP_INVAL:
> +            trace_ppc_excp_inval(env->nip);
> +            env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_PTR);
> +            break;
> +        case POWERPC_EXCP_TRAP:
> +            env->spr[SPR_PPE42_ISR] |= ((target_ulong)1 << PPE42_ISR_PTR);
> +            break;
> +        default:
> +            /* Should never occur */
> +            cpu_abort(env_cpu(env), "Invalid program exception %d. Aborting\n",
> +                      env->error_code);
> +            break;
> +        }
> +#ifdef CONFIG_TCG
> +        env->spr[SPR_PPE42_EDR] = ppc_ldl_code(env, env->nip);
> +#endif
> +        break;
> +    case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
> +        break;
> +    case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
> +        trace_ppc_excp_print("FIT");
> +        break;
> +    case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
> +        trace_ppc_excp_print("WDT");
> +        break;
> +    case POWERPC_EXCP_RESET:     /* System reset exception                   */
> +        /* reset exceptions don't have ME set */
> +        new_msr &= ~((target_ulong)1 << MSR_ME);
> +        break;
> +    default:
> +        cpu_abort(env_cpu(env), "Invalid PPE42 exception %d. Aborting\n",
> +                  excp);
> +        break;
> +    }
> +
> +    env->spr[SPR_SRR0] = env->nip;
> +    env->spr[SPR_SRR1] = msr;
> +
> +    vector = env->excp_vectors[excp];
> +    if (vector == (target_ulong)-1ULL) {
> +        cpu_abort(env_cpu(env),
> +                  "Raised an exception without defined vector %d\n", excp);
> +    }
> +    vector |= env->spr[SPR_PPE42_IVPR];
> +
> +    if (excp == POWERPC_EXCP_MCHECK) {
> +        /* Also set the Machine Check Status (MCS) */
> +        env->spr[SPR_PPE42_ISR] &= ~R_PPE42_ISR_MCS_MASK;
> +        env->spr[SPR_PPE42_ISR] |= (mcs & R_PPE42_ISR_MCS_MASK);
> +        env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_MFE);
> +
> +        /* Machine checks halt execution if MSR_ME is 0 */
> +        powerpc_mcheck_checkstop(env);
> +
> +        /* machine check exceptions don't have ME set */
> +        new_msr &= ~((target_ulong)1 << MSR_ME);
> +    }
> +
> +    powerpc_set_excp_state(cpu, vector, new_msr);
> +}
> +
>   static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
>   {
>       CPUPPCState *env = &cpu->env;
> @@ -1589,6 +1708,9 @@ void powerpc_excp(PowerPCCPU *cpu, int excp)
>       case POWERPC_EXCP_POWER11:
>           powerpc_excp_books(cpu, excp);
>           break;
> +    case POWERPC_EXCP_PPE42:
> +        powerpc_excp_ppe42(cpu, excp);
> +        break;
>       default:
>           g_assert_not_reached();
>       }
> @@ -1945,6 +2067,43 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env,
>   }
>   #endif /* TARGET_PPC64 */
>   
> +static int ppe42_next_unmasked_interrupt(CPUPPCState *env)
> +{
> +    bool async_deliver;
> +
> +    /* External reset */
> +    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
> +        return PPC_INTERRUPT_RESET;
> +    }
> +    /* Machine check exception */
> +    if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
> +        return PPC_INTERRUPT_MCK;
> +    }
> +
> +    async_deliver = FIELD_EX64(env->msr, MSR, EE);
> +
> +    if (async_deliver != 0) {
> +        /* Watchdog timer */
> +        if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
> +            return PPC_INTERRUPT_WDT;
> +        }
> +        /* External Interrupt */
> +        if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
> +            return PPC_INTERRUPT_EXT;
> +        }
> +        /* Fixed interval timer */
> +        if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
> +            return PPC_INTERRUPT_FIT;
> +        }
> +        /* Decrementer exception */
> +        if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
> +            return PPC_INTERRUPT_DECR;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
>   static int ppc_next_unmasked_interrupt(CPUPPCState *env)
>   {
>       uint32_t pending_interrupts = env->pending_interrupts;
> @@ -1970,6 +2129,10 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
>       }
>   #endif
>   
> +    if (env->excp_model == POWERPC_EXCP_PPE42) {
> +        return ppe42_next_unmasked_interrupt(env);
> +    }
> +
>       /* External reset */
>       if (pending_interrupts & PPC_INTERRUPT_RESET) {
>           return PPC_INTERRUPT_RESET;
> diff --git a/target/ppc/tcg-excp_helper.c b/target/ppc/tcg-excp_helper.c
> index f835be5156..edecfb8572 100644
> --- a/target/ppc/tcg-excp_helper.c
> +++ b/target/ppc/tcg-excp_helper.c
> @@ -229,6 +229,18 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
>       case POWERPC_MMU_BOOKE206:
>           env->spr[SPR_BOOKE_DEAR] = vaddr;
>           break;
> +    case POWERPC_MMU_REAL:
> +        if (env->flags & POWERPC_FLAG_PPE42) {
> +            env->spr[SPR_PPE42_EDR] = vaddr;
> +            if (access_type == MMU_DATA_STORE) {
> +                env->spr[SPR_PPE42_ISR] |= PPE42_ISR_ST;
> +            } else {
> +                env->spr[SPR_PPE42_ISR] &= ~PPE42_ISR_ST;
> +            }
> +        } else {
> +            env->spr[SPR_DAR] = vaddr;
> +        }
> +        break;
>       default:
>           env->spr[SPR_DAR] = vaddr;
>           break;