[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-ppc] [PATCH 18/77] ppc: Rework POWER7 & POWER8 exception model
From: |
David Gibson |
Subject: |
Re: [Qemu-ppc] [PATCH 18/77] ppc: Rework POWER7 & POWER8 exception model |
Date: |
Thu, 19 Nov 2015 17:44:09 +1100 |
User-agent: |
Mutt/1.5.23 (2015-06-09) |
On Wed, Nov 11, 2015 at 11:27:31AM +1100, Benjamin Herrenschmidt wrote:
> Properly implement LPES0/1 handling for HV vs. !HV mode and fix AIL
> implementation.
>
> Signed-off-by: Benjamin Herrenschmidt <address@hidden>
> ---
> target-ppc/cpu.h | 2 +
> target-ppc/excp_helper.c | 175
> ++++++++++++++++++++++----------------------
> target-ppc/translate_init.c | 2 +-
> 3 files changed, 92 insertions(+), 87 deletions(-)
>
> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> index 062644e..8185812 100644
> --- a/target-ppc/cpu.h
> +++ b/target-ppc/cpu.h
> @@ -162,6 +162,8 @@ enum powerpc_excp_t {
> POWERPC_EXCP_970,
> /* POWER7 exception model */
> POWERPC_EXCP_POWER7,
> + /* POWER8 exception model */
> + POWERPC_EXCP_POWER8,
> #endif /* defined(TARGET_PPC64) */
> };
>
> diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> index 83e6c07..716b27b 100644
> --- a/target-ppc/excp_helper.c
> +++ b/target-ppc/excp_helper.c
> @@ -74,22 +74,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> CPUState *cs = CPU(cpu);
> CPUPPCState *env = &cpu->env;
> target_ulong msr, new_msr, vector;
> - int srr0, srr1, asrr0, asrr1;
> - int lpes0, lpes1, lev;
> + int srr0, srr1, asrr0, asrr1, lev, ail;
> + bool lpes0;
>
> - if (0) {
> - /* XXX: find a suitable condition to enable the hypervisor mode */
> - lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
> - lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
> - } else {
> - /* Those values ensure we won't enter the hypervisor mode */
> - lpes0 = 0;
> - lpes1 = 1;
> - }
>
> qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
> " => %08x (%02x)\n", env->nip, excp, env->error_code);
>
> +
> /* new srr1 value excluding must-be-zero bits */
> if (excp_model == POWERPC_EXCP_BOOKE) {
> msr = env->msr;
> @@ -97,8 +89,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> msr = env->msr & ~0x783f0000ULL;
> }
>
> - /* new interrupt handler msr */
> - new_msr = env->msr & ((target_ulong)1 << MSR_ME);
> + /* new interrupt handler msr preserves existing HV and ME unless
> + * explicitly overriden
> + */
> + new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
Ouch. The fact that MSR_ME is a bit number, but MSR_HVB is a mask is
certainly confusing, but that's a pre-existing problem.
> /* target registers */
> srr0 = SPR_SRR0;
> @@ -106,6 +100,33 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> asrr0 = -1;
> asrr1 = -1;
>
> + /* Exception targetting modifiers
> + *
> + * LPES0 is supported on POWER7/8
> + * LPES1 is not supported (old iSeries mode)
> + *
> + * On anything else, we behave as if LPES0 is 1
> + * (externals don't alter MSR:HV)
> + *
> + * AIL is initialized here but can be cleared by
> + * selected exceptions
> + */
> +#if defined(TARGET_PPC64)
> + if (excp_model == POWERPC_EXCP_POWER7 ||
> + excp_model == POWERPC_EXCP_POWER8) {
> + lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
> + if (excp_model == POWERPC_EXCP_POWER8) {
> + ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
> + } else {
> + ail = 0;
> + }
> + } else
> +#endif /* defined(TARGET_PPC64) */
> + {
> + lpes0 = true;
> + ail = 0;
> + }
> +
> switch (excp) {
> case POWERPC_EXCP_NONE:
> /* Should never happen */
> @@ -141,10 +162,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> cs->halted = 1;
> cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
> }
> - if (0) {
> - /* XXX: find a suitable condition to enable the hypervisor mode
> */
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> + new_msr |= (target_ulong)MSR_HVB;
> + ail = 0;
>
> /* machine check exceptions don't have ME set */
> new_msr &= ~((target_ulong)1 << MSR_ME);
> @@ -169,23 +188,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> case POWERPC_EXCP_DSI: /* Data storage exception
> */
> LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
> "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> goto store_next;
> case POWERPC_EXCP_ISI: /* Instruction storage exception
> */
> LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
> "\n", msr, env->nip);
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> msr |= env->error_code;
> goto store_next;
> case POWERPC_EXCP_EXTERNAL: /* External input
> */
> cs = CPU(cpu);
>
> - if (lpes0 == 1) {
> + if (!lpes0) {
> new_msr |= (target_ulong)MSR_HVB;
> + new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> + srr0 = SPR_HSRR0;
> + srr1 = SPR_HSRR1;
> }
> if (env->mpic_proxy) {
> /* IACK the IRQ on delivery */
> @@ -193,9 +209,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> }
> goto store_next;
> case POWERPC_EXCP_ALIGN: /* Alignment exception
> */
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> /* XXX: this is false */
> /* Get rS/rD and rA from faulting opcode */
> env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
> @@ -210,9 +223,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> env->error_code = 0;
> return;
> }
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> msr |= 0x00100000;
> if (msr_fe0 == msr_fe1) {
> goto store_next;
> @@ -221,23 +231,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> break;
> case POWERPC_EXCP_INVAL:
> LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> msr |= 0x00080000;
> env->spr[SPR_BOOKE_ESR] = ESR_PIL;
> break;
> case POWERPC_EXCP_PRIV:
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> msr |= 0x00040000;
> env->spr[SPR_BOOKE_ESR] = ESR_PPR;
> break;
> case POWERPC_EXCP_TRAP:
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> msr |= 0x00020000;
> env->spr[SPR_BOOKE_ESR] = ESR_PTR;
> break;
> @@ -249,27 +250,23 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> }
> goto store_current;
> case POWERPC_EXCP_FPU: /* Floating-point unavailable exception
> */
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> goto store_current;
> case POWERPC_EXCP_SYSCALL: /* System call exception
> */
> dump_syscall(env);
> lev = env->error_code;
> +
> + /* "PAPR mode" built-in hypercall emulation */
> if ((lev == 1) && cpu_ppc_hypercall) {
> cpu_ppc_hypercall(cpu);
> return;
> }
> - if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
> + if (lev == 1) {
> new_msr |= (target_ulong)MSR_HVB;
> }
> goto store_next;
> case POWERPC_EXCP_APU: /* Auxiliary processor unavailable
> */
> goto store_current;
> case POWERPC_EXCP_DECR: /* Decrementer exception
> */
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> goto store_next;
> case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt
> */
> /* FIT on 4xx */
> @@ -338,21 +335,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> } else {
> new_msr &= ~((target_ulong)1 << MSR_ME);
> }
> -
> - if (0) {
> - /* XXX: find a suitable condition to enable the hypervisor mode
> */
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> + new_msr |= (target_ulong)MSR_HVB;
> + ail = 0;
> goto store_next;
> case POWERPC_EXCP_DSEG: /* Data segment exception
> */
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> goto store_next;
> case POWERPC_EXCP_ISEG: /* Instruction segment exception
> */
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> goto store_next;
> case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception
> */
> srr0 = SPR_HSRR0;
> @@ -361,21 +349,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> goto store_next;
> case POWERPC_EXCP_TRACE: /* Trace exception
> */
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> goto store_next;
> case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception
> */
> srr0 = SPR_HSRR0;
> srr1 = SPR_HSRR1;
> new_msr |= (target_ulong)MSR_HVB;
> new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> + ail = 0;
Do you need to set ail explicitly here, given the general ail logic below?
> goto store_next;
> case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception
> */
> srr0 = SPR_HSRR0;
> srr1 = SPR_HSRR1;
> new_msr |= (target_ulong)MSR_HVB;
> new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> + ail = 0;
> goto store_next;
> case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception
> */
> srr0 = SPR_HSRR0;
> @@ -390,19 +377,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> goto store_next;
> case POWERPC_EXCP_VPU: /* Vector unavailable exception
> */
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> goto store_current;
> case POWERPC_EXCP_VSXU: /* VSX unavailable exception
> */
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> goto store_current;
> case POWERPC_EXCP_FU: /* Facility unavailable exception
> */
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> goto store_current;
> case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt
> */
> LOG_EXCP("PIT exception\n");
> @@ -421,9 +399,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> "is not implemented yet !\n");
> goto store_next;
> case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error
> */
> - if (lpes1 == 0) { /* XXX: check this */
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> switch (excp_model) {
> case POWERPC_EXCP_602:
> case POWERPC_EXCP_603:
> @@ -440,9 +415,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> }
> break;
> case POWERPC_EXCP_DLTLB: /* Data load TLB miss
> */
> - if (lpes1 == 0) { /* XXX: check this */
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> switch (excp_model) {
> case POWERPC_EXCP_602:
> case POWERPC_EXCP_603:
> @@ -459,9 +431,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> }
> break;
> case POWERPC_EXCP_DSTLB: /* Data store TLB miss
> */
> - if (lpes1 == 0) { /* XXX: check this */
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> switch (excp_model) {
> case POWERPC_EXCP_602:
> case POWERPC_EXCP_603:
> @@ -567,9 +536,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> "is not implemented yet !\n");
> goto store_next;
> case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt
> */
> - if (lpes1 == 0) {
> - new_msr |= (target_ulong)MSR_HVB;
> - }
> /* XXX: TODO */
> cpu_abort(cs,
> "Performance counter exception is not implemented yet
> !\n");
> @@ -613,6 +579,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> }
> /* Save MSR */
> env->spr[srr1] = msr;
> +
> + /* Sanity check */
> + if (!(env->msr_mask & MSR_HVB) && (srr0 == SPR_HSRR0)) {
> + cpu_abort(cs, "Trying to deliver HV exception %d with no HV
> support\n", excp);
> + }
> +
> /* If any alternate SRR register are defined, duplicate saved values */
> if (asrr0 != -1) {
> env->spr[asrr0] = env->spr[srr0];
> @@ -621,13 +593,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> env->spr[asrr1] = env->spr[srr1];
> }
>
> - if (env->spr[SPR_LPCR] & LPCR_AIL) {
> - new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
> - }
> -
> + /* Sort out endianness of interrupt, this differs depending on the
> + * CPU, the HV mode, etc...
> + */
> #ifdef TARGET_PPC64
> if (excp_model == POWERPC_EXCP_POWER7) {
> - if (env->spr[SPR_LPCR] & LPCR_ILE) {
> + if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
> + new_msr |= (target_ulong)1 << MSR_LE;
> + }
> + } else if (excp_model == POWERPC_EXCP_POWER8) {
> + if (new_msr & MSR_HVB) {
> + if (env->spr[SPR_HID0] & HID0_HILE) {
> + new_msr |= (target_ulong)1 << MSR_LE;
> + }
> + } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
> new_msr |= (target_ulong)1 << MSR_LE;
> }
> } else if (msr_ile) {
> @@ -646,6 +625,30 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int
> excp_model, int excp)
> excp);
> }
> vector |= env->excp_prefix;
> +
> + /* AIL only works if there is no HV transition and we are running with
> + * translations enabled
> + */
> + if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) ||
> + ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) {
> + ail = 0;
> + }
> + /* Handle AIL */
> + if (ail) {
> + new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
> + switch(ail) {
> + case 2:
> + vector |= 0x18000;
> + break;
> + case 3:
> + vector |= 0xc000000000004000ull;
> + break;
> + default:
> + cpu_abort(cs, "Invalid AIL combination %d\n", ail);
> + break;
> + }
> + }
> +
> #if defined(TARGET_PPC64)
> if (excp_model == POWERPC_EXCP_BOOKE) {
> if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
> diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
> index f11e7d0..8a50273 100644
> --- a/target-ppc/translate_init.c
> +++ b/target-ppc/translate_init.c
> @@ -8412,7 +8412,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
> #if defined(CONFIG_SOFTMMU)
> pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
> #endif
> - pcc->excp_model = POWERPC_EXCP_POWER7;
> + pcc->excp_model = POWERPC_EXCP_POWER8;
> pcc->bus_model = PPC_FLAGS_INPUT_POWER7;
> pcc->bfd_mach = bfd_mach_ppc64;
> pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
signature.asc
Description: PGP signature
- Re: [Qemu-ppc] [PATCH 19/77] ppc: Fix POWER7 and POWER8 exception definitions, (continued)
- [Qemu-ppc] [PATCH 17/77] ppc: Add PPC_64H instruction flag to POWER7 and POWER8, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 20/77] ppc: Fix generation if ISI/DSI vs. HV mode, Benjamin Herrenschmidt, 2015/11/10
- [Qemu-ppc] [PATCH 18/77] ppc: Rework POWER7 & POWER8 exception model, Benjamin Herrenschmidt, 2015/11/10
- Re: [Qemu-ppc] [PATCH 18/77] ppc: Rework POWER7 & POWER8 exception model,
David Gibson <=
- [Qemu-ppc] [PATCH 21/77] ppc: Rework generation of priv and inval interrupts, Benjamin Herrenschmidt, 2015/11/10
[Qemu-ppc] [PATCH 28/77] ppc/xics: Rename existing XICS classe to XICS_SPAPR, Benjamin Herrenschmidt, 2015/11/10
[Qemu-ppc] [PATCH 25/77] ppc: Add P7/P8 Power Management instructions, Benjamin Herrenschmidt, 2015/11/10