diff mbox

[05/10] ppc: Fix generation if ISI/DSI vs. HV mode

Message ID 1465795496-15071-6-git-send-email-clg@kaod.org
State New
Headers show

Commit Message

Cédric Le Goater June 13, 2016, 5:24 a.m. UTC
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Under some circumstances, we need to direct ISI and DSI interrupts
at the hypervisor, turning them into HISI/HDSI, and using different
SPRs (HDSISR and HDAR) depending on the combination of MSR_DR and
the corresponding VPM bits in LPCR.

This moves part of the code into helpers that are fixed to select
the right exception type and registers. On pre-P7 processors, LPCR
is 0 which provides the old behaviour of directing the interrupts
at the supervisor.

Thanks to Andrei Warkentin for finding a bug when HV=1

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
---
 target-ppc/mmu-hash64.c | 69 +++++++++++++++++++++++++++++++++++--------------
 1 file changed, 50 insertions(+), 19 deletions(-)

Comments

David Gibson June 14, 2016, 6:34 a.m. UTC | #1
On Mon, Jun 13, 2016 at 07:24:51AM +0200, Cédric Le Goater wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> 
> Under some circumstances, we need to direct ISI and DSI interrupts
> at the hypervisor, turning them into HISI/HDSI, and using different
> SPRs (HDSISR and HDAR) depending on the combination of MSR_DR and
> the corresponding VPM bits in LPCR.
> 
> This moves part of the code into helpers that are fixed to select
> the right exception type and registers. On pre-P7 processors, LPCR
> is 0 which provides the old behaviour of directing the interrupts
> at the supervisor.
> 
> Thanks to Andrei Warkentin for finding a bug when HV=1
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  target-ppc/mmu-hash64.c | 69 +++++++++++++++++++++++++++++++++++--------------
>  1 file changed, 50 insertions(+), 19 deletions(-)
> 
> diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
> index 668da5e22653..072a952c8bd5 100644
> --- a/target-ppc/mmu-hash64.c
> +++ b/target-ppc/mmu-hash64.c
> @@ -613,6 +613,47 @@ unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
>      return 0;
>  }
>  
> +static void ppc_hash64_set_isi(CPUState *cs, CPUPPCState *env,
> +                               uint64_t error_code)
> +{
> +    bool vpm;
> +
> +    if (msr_ir) {
> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
> +    } else {
> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
> +    }
> +    if (vpm && !msr_hv) {
> +        cs->exception_index = POWERPC_EXCP_HISI;

In the ISI case, you use HISI if !msr_hv..

> +    } else {
> +        cs->exception_index = POWERPC_EXCP_ISI;
> +    }
> +    env->error_code = error_code;
> +}
> +
> +static void ppc_hash64_set_dsi(CPUState *cs, CPUPPCState *env, uint64_t dar,
> +                               uint64_t dsisr)
> +{
> +    bool vpm;
> +
> +    if (msr_dr) {
> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
> +    } else {
> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
> +    }
> +    if (vpm && msr_hv) {
> +        cs->exception_index = POWERPC_EXCP_HDSI;

..but in the DSI case you use HDSI if msr_hv.  Is that really right?

> +        env->spr[SPR_HDAR] = dar;
> +        env->spr[SPR_HDSISR] = dsisr;
> +    } else {
> +        cs->exception_index = POWERPC_EXCP_DSI;
> +        env->spr[SPR_DAR] = dar;
> +        env->spr[SPR_DSISR] = dsisr;
> +   }
> +    env->error_code = 0;
> +}
> +
> +
>  int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
>                                  int rwx, int mmu_idx)
>  {
> @@ -623,7 +664,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
>      hwaddr pte_offset;
>      ppc_hash_pte64_t pte;
>      int pp_prot, amr_prot, prot;
> -    uint64_t new_pte1;
> +    uint64_t new_pte1, dsisr;
>      const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
>      hwaddr raddr;
>  
> @@ -657,26 +698,21 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
>  
>      /* 3. Check for segment level no-execute violation */
>      if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
> -        cs->exception_index = POWERPC_EXCP_ISI;
> -        env->error_code = 0x10000000;
> +        ppc_hash64_set_isi(cs, env, 0x10000000);
>          return 1;
>      }
>  
>      /* 4. Locate the PTE in the hash table */
>      pte_offset = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte);
>      if (pte_offset == -1) {
> +        dsisr = 0x40000000;
>          if (rwx == 2) {
> -            cs->exception_index = POWERPC_EXCP_ISI;
> -            env->error_code = 0x40000000;
> +            ppc_hash64_set_isi(cs, env, dsisr);
>          } else {
> -            cs->exception_index = POWERPC_EXCP_DSI;
> -            env->error_code = 0;
> -            env->spr[SPR_DAR] = eaddr;
>              if (rwx == 1) {
> -                env->spr[SPR_DSISR] = 0x42000000;
> -            } else {
> -                env->spr[SPR_DSISR] = 0x40000000;
> +                dsisr |= 0x02000000;
>              }
> +            ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
>          }
>          return 1;
>      }
> @@ -705,14 +741,9 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
>          /* Access right violation */
>          qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
>          if (rwx == 2) {
> -            cs->exception_index = POWERPC_EXCP_ISI;
> -            env->error_code = 0x08000000;
> +            ppc_hash64_set_isi(cs, env, 0x08000000);
>          } else {
> -            target_ulong dsisr = 0;
> -
> -            cs->exception_index = POWERPC_EXCP_DSI;
> -            env->error_code = 0;
> -            env->spr[SPR_DAR] = eaddr;
> +            dsisr = 0;
>              if (need_prot[rwx] & ~pp_prot) {
>                  dsisr |= 0x08000000;
>              }
> @@ -722,7 +753,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
>              if (need_prot[rwx] & ~amr_prot) {
>                  dsisr |= 0x00200000;
>              }
> -            env->spr[SPR_DSISR] = dsisr;
> +            ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
>          }
>          return 1;
>      }
Cédric Le Goater June 14, 2016, 6:42 a.m. UTC | #2
On 06/14/2016 08:34 AM, David Gibson wrote:
> On Mon, Jun 13, 2016 at 07:24:51AM +0200, Cédric Le Goater wrote:
>> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>>
>> Under some circumstances, we need to direct ISI and DSI interrupts
>> at the hypervisor, turning them into HISI/HDSI, and using different
>> SPRs (HDSISR and HDAR) depending on the combination of MSR_DR and
>> the corresponding VPM bits in LPCR.
>>
>> This moves part of the code into helpers that are fixed to select
>> the right exception type and registers. On pre-P7 processors, LPCR
>> is 0 which provides the old behaviour of directing the interrupts
>> at the supervisor.
>>
>> Thanks to Andrei Warkentin for finding a bug when HV=1
>>
>> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
>> ---
>>  target-ppc/mmu-hash64.c | 69 +++++++++++++++++++++++++++++++++++--------------
>>  1 file changed, 50 insertions(+), 19 deletions(-)
>>
>> diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
>> index 668da5e22653..072a952c8bd5 100644
>> --- a/target-ppc/mmu-hash64.c
>> +++ b/target-ppc/mmu-hash64.c
>> @@ -613,6 +613,47 @@ unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
>>      return 0;
>>  }
>>  
>> +static void ppc_hash64_set_isi(CPUState *cs, CPUPPCState *env,
>> +                               uint64_t error_code)
>> +{
>> +    bool vpm;
>> +
>> +    if (msr_ir) {
>> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
>> +    } else {
>> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
>> +    }
>> +    if (vpm && !msr_hv) {
>> +        cs->exception_index = POWERPC_EXCP_HISI;
> 
> In the ISI case, you use HISI if !msr_hv..
> 
>> +    } else {
>> +        cs->exception_index = POWERPC_EXCP_ISI;
>> +    }
>> +    env->error_code = error_code;
>> +}
>> +
>> +static void ppc_hash64_set_dsi(CPUState *cs, CPUPPCState *env, uint64_t dar,
>> +                               uint64_t dsisr)
>> +{
>> +    bool vpm;
>> +
>> +    if (msr_dr) {
>> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
>> +    } else {
>> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
>> +    }
>> +    if (vpm && msr_hv) {
>> +        cs->exception_index = POWERPC_EXCP_HDSI;
> 
> ..but in the DSI case you use HDSI if msr_hv.  Is that really right?

No. I forgot to add this patch from Andrei :

	https://github.com/legoater/qemu/commit/e218fd3ba945bb0f483f5f12bedbb74d897cd5b9

I will send it as a fix.

C.  

>> +        env->spr[SPR_HDAR] = dar;
>> +        env->spr[SPR_HDSISR] = dsisr;
>> +    } else {
>> +        cs->exception_index = POWERPC_EXCP_DSI;
>> +        env->spr[SPR_DAR] = dar;
>> +        env->spr[SPR_DSISR] = dsisr;
>> +   }
>> +    env->error_code = 0;
>> +}
>> +
>> +
>>  int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
>>                                  int rwx, int mmu_idx)
>>  {
>> @@ -623,7 +664,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
>>      hwaddr pte_offset;
>>      ppc_hash_pte64_t pte;
>>      int pp_prot, amr_prot, prot;
>> -    uint64_t new_pte1;
>> +    uint64_t new_pte1, dsisr;
>>      const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
>>      hwaddr raddr;
>>  
>> @@ -657,26 +698,21 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
>>  
>>      /* 3. Check for segment level no-execute violation */
>>      if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
>> -        cs->exception_index = POWERPC_EXCP_ISI;
>> -        env->error_code = 0x10000000;
>> +        ppc_hash64_set_isi(cs, env, 0x10000000);
>>          return 1;
>>      }
>>  
>>      /* 4. Locate the PTE in the hash table */
>>      pte_offset = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte);
>>      if (pte_offset == -1) {
>> +        dsisr = 0x40000000;
>>          if (rwx == 2) {
>> -            cs->exception_index = POWERPC_EXCP_ISI;
>> -            env->error_code = 0x40000000;
>> +            ppc_hash64_set_isi(cs, env, dsisr);
>>          } else {
>> -            cs->exception_index = POWERPC_EXCP_DSI;
>> -            env->error_code = 0;
>> -            env->spr[SPR_DAR] = eaddr;
>>              if (rwx == 1) {
>> -                env->spr[SPR_DSISR] = 0x42000000;
>> -            } else {
>> -                env->spr[SPR_DSISR] = 0x40000000;
>> +                dsisr |= 0x02000000;
>>              }
>> +            ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
>>          }
>>          return 1;
>>      }
>> @@ -705,14 +741,9 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
>>          /* Access right violation */
>>          qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
>>          if (rwx == 2) {
>> -            cs->exception_index = POWERPC_EXCP_ISI;
>> -            env->error_code = 0x08000000;
>> +            ppc_hash64_set_isi(cs, env, 0x08000000);
>>          } else {
>> -            target_ulong dsisr = 0;
>> -
>> -            cs->exception_index = POWERPC_EXCP_DSI;
>> -            env->error_code = 0;
>> -            env->spr[SPR_DAR] = eaddr;
>> +            dsisr = 0;
>>              if (need_prot[rwx] & ~pp_prot) {
>>                  dsisr |= 0x08000000;
>>              }
>> @@ -722,7 +753,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
>>              if (need_prot[rwx] & ~amr_prot) {
>>                  dsisr |= 0x00200000;
>>              }
>> -            env->spr[SPR_DSISR] = dsisr;
>> +            ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
>>          }
>>          return 1;
>>      }
>
David Gibson June 15, 2016, 1:09 a.m. UTC | #3
On Tue, Jun 14, 2016 at 08:42:26AM +0200, Cédric Le Goater wrote:
> On 06/14/2016 08:34 AM, David Gibson wrote:
> > On Mon, Jun 13, 2016 at 07:24:51AM +0200, Cédric Le Goater wrote:
> >> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> >>
> >> Under some circumstances, we need to direct ISI and DSI interrupts
> >> at the hypervisor, turning them into HISI/HDSI, and using different
> >> SPRs (HDSISR and HDAR) depending on the combination of MSR_DR and
> >> the corresponding VPM bits in LPCR.
> >>
> >> This moves part of the code into helpers that are fixed to select
> >> the right exception type and registers. On pre-P7 processors, LPCR
> >> is 0 which provides the old behaviour of directing the interrupts
> >> at the supervisor.
> >>
> >> Thanks to Andrei Warkentin for finding a bug when HV=1
> >>
> >> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> >> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> >> ---
> >>  target-ppc/mmu-hash64.c | 69 +++++++++++++++++++++++++++++++++++--------------
> >>  1 file changed, 50 insertions(+), 19 deletions(-)
> >>
> >> diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
> >> index 668da5e22653..072a952c8bd5 100644
> >> --- a/target-ppc/mmu-hash64.c
> >> +++ b/target-ppc/mmu-hash64.c
> >> @@ -613,6 +613,47 @@ unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
> >>      return 0;
> >>  }
> >>  
> >> +static void ppc_hash64_set_isi(CPUState *cs, CPUPPCState *env,
> >> +                               uint64_t error_code)
> >> +{
> >> +    bool vpm;
> >> +
> >> +    if (msr_ir) {
> >> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
> >> +    } else {
> >> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
> >> +    }
> >> +    if (vpm && !msr_hv) {
> >> +        cs->exception_index = POWERPC_EXCP_HISI;
> > 
> > In the ISI case, you use HISI if !msr_hv..
> > 
> >> +    } else {
> >> +        cs->exception_index = POWERPC_EXCP_ISI;
> >> +    }
> >> +    env->error_code = error_code;
> >> +}
> >> +
> >> +static void ppc_hash64_set_dsi(CPUState *cs, CPUPPCState *env, uint64_t dar,
> >> +                               uint64_t dsisr)
> >> +{
> >> +    bool vpm;
> >> +
> >> +    if (msr_dr) {
> >> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
> >> +    } else {
> >> +        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
> >> +    }
> >> +    if (vpm && msr_hv) {
> >> +        cs->exception_index = POWERPC_EXCP_HDSI;
> > 
> > ..but in the DSI case you use HDSI if msr_hv.  Is that really right?
> 
> No. I forgot to add this patch from Andrei :
> 
> 	https://github.com/legoater/qemu/commit/e218fd3ba945bb0f483f5f12bedbb74d897cd5b9
> 
> I will send it as a fix.

Given that there are a number of tweaks this series needs, I'd prefer
to see it folded in rather than as a separate patch.

> 
> C.  
> 
> >> +        env->spr[SPR_HDAR] = dar;
> >> +        env->spr[SPR_HDSISR] = dsisr;
> >> +    } else {
> >> +        cs->exception_index = POWERPC_EXCP_DSI;
> >> +        env->spr[SPR_DAR] = dar;
> >> +        env->spr[SPR_DSISR] = dsisr;
> >> +   }
> >> +    env->error_code = 0;
> >> +}
> >> +
> >> +
> >>  int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
> >>                                  int rwx, int mmu_idx)
> >>  {
> >> @@ -623,7 +664,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
> >>      hwaddr pte_offset;
> >>      ppc_hash_pte64_t pte;
> >>      int pp_prot, amr_prot, prot;
> >> -    uint64_t new_pte1;
> >> +    uint64_t new_pte1, dsisr;
> >>      const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
> >>      hwaddr raddr;
> >>  
> >> @@ -657,26 +698,21 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
> >>  
> >>      /* 3. Check for segment level no-execute violation */
> >>      if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
> >> -        cs->exception_index = POWERPC_EXCP_ISI;
> >> -        env->error_code = 0x10000000;
> >> +        ppc_hash64_set_isi(cs, env, 0x10000000);
> >>          return 1;
> >>      }
> >>  
> >>      /* 4. Locate the PTE in the hash table */
> >>      pte_offset = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte);
> >>      if (pte_offset == -1) {
> >> +        dsisr = 0x40000000;
> >>          if (rwx == 2) {
> >> -            cs->exception_index = POWERPC_EXCP_ISI;
> >> -            env->error_code = 0x40000000;
> >> +            ppc_hash64_set_isi(cs, env, dsisr);
> >>          } else {
> >> -            cs->exception_index = POWERPC_EXCP_DSI;
> >> -            env->error_code = 0;
> >> -            env->spr[SPR_DAR] = eaddr;
> >>              if (rwx == 1) {
> >> -                env->spr[SPR_DSISR] = 0x42000000;
> >> -            } else {
> >> -                env->spr[SPR_DSISR] = 0x40000000;
> >> +                dsisr |= 0x02000000;
> >>              }
> >> +            ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
> >>          }
> >>          return 1;
> >>      }
> >> @@ -705,14 +741,9 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
> >>          /* Access right violation */
> >>          qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
> >>          if (rwx == 2) {
> >> -            cs->exception_index = POWERPC_EXCP_ISI;
> >> -            env->error_code = 0x08000000;
> >> +            ppc_hash64_set_isi(cs, env, 0x08000000);
> >>          } else {
> >> -            target_ulong dsisr = 0;
> >> -
> >> -            cs->exception_index = POWERPC_EXCP_DSI;
> >> -            env->error_code = 0;
> >> -            env->spr[SPR_DAR] = eaddr;
> >> +            dsisr = 0;
> >>              if (need_prot[rwx] & ~pp_prot) {
> >>                  dsisr |= 0x08000000;
> >>              }
> >> @@ -722,7 +753,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
> >>              if (need_prot[rwx] & ~amr_prot) {
> >>                  dsisr |= 0x00200000;
> >>              }
> >> -            env->spr[SPR_DSISR] = dsisr;
> >> +            ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
> >>          }
> >>          return 1;
> >>      }
> > 
>
diff mbox

Patch

diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 668da5e22653..072a952c8bd5 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -613,6 +613,47 @@  unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
     return 0;
 }
 
+static void ppc_hash64_set_isi(CPUState *cs, CPUPPCState *env,
+                               uint64_t error_code)
+{
+    bool vpm;
+
+    if (msr_ir) {
+        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
+    } else {
+        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
+    }
+    if (vpm && !msr_hv) {
+        cs->exception_index = POWERPC_EXCP_HISI;
+    } else {
+        cs->exception_index = POWERPC_EXCP_ISI;
+    }
+    env->error_code = error_code;
+}
+
+static void ppc_hash64_set_dsi(CPUState *cs, CPUPPCState *env, uint64_t dar,
+                               uint64_t dsisr)
+{
+    bool vpm;
+
+    if (msr_dr) {
+        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
+    } else {
+        vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
+    }
+    if (vpm && msr_hv) {
+        cs->exception_index = POWERPC_EXCP_HDSI;
+        env->spr[SPR_HDAR] = dar;
+        env->spr[SPR_HDSISR] = dsisr;
+    } else {
+        cs->exception_index = POWERPC_EXCP_DSI;
+        env->spr[SPR_DAR] = dar;
+        env->spr[SPR_DSISR] = dsisr;
+   }
+    env->error_code = 0;
+}
+
+
 int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
                                 int rwx, int mmu_idx)
 {
@@ -623,7 +664,7 @@  int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
     hwaddr pte_offset;
     ppc_hash_pte64_t pte;
     int pp_prot, amr_prot, prot;
-    uint64_t new_pte1;
+    uint64_t new_pte1, dsisr;
     const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
     hwaddr raddr;
 
@@ -657,26 +698,21 @@  int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
 
     /* 3. Check for segment level no-execute violation */
     if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
-        cs->exception_index = POWERPC_EXCP_ISI;
-        env->error_code = 0x10000000;
+        ppc_hash64_set_isi(cs, env, 0x10000000);
         return 1;
     }
 
     /* 4. Locate the PTE in the hash table */
     pte_offset = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte);
     if (pte_offset == -1) {
+        dsisr = 0x40000000;
         if (rwx == 2) {
-            cs->exception_index = POWERPC_EXCP_ISI;
-            env->error_code = 0x40000000;
+            ppc_hash64_set_isi(cs, env, dsisr);
         } else {
-            cs->exception_index = POWERPC_EXCP_DSI;
-            env->error_code = 0;
-            env->spr[SPR_DAR] = eaddr;
             if (rwx == 1) {
-                env->spr[SPR_DSISR] = 0x42000000;
-            } else {
-                env->spr[SPR_DSISR] = 0x40000000;
+                dsisr |= 0x02000000;
             }
+            ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
         }
         return 1;
     }
@@ -705,14 +741,9 @@  int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
         /* Access right violation */
         qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
         if (rwx == 2) {
-            cs->exception_index = POWERPC_EXCP_ISI;
-            env->error_code = 0x08000000;
+            ppc_hash64_set_isi(cs, env, 0x08000000);
         } else {
-            target_ulong dsisr = 0;
-
-            cs->exception_index = POWERPC_EXCP_DSI;
-            env->error_code = 0;
-            env->spr[SPR_DAR] = eaddr;
+            dsisr = 0;
             if (need_prot[rwx] & ~pp_prot) {
                 dsisr |= 0x08000000;
             }
@@ -722,7 +753,7 @@  int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
             if (need_prot[rwx] & ~amr_prot) {
                 dsisr |= 0x00200000;
             }
-            env->spr[SPR_DSISR] = dsisr;
+            ppc_hash64_set_dsi(cs, env, eaddr, dsisr);
         }
         return 1;
     }