diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-06-23 11:53:14 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-06-23 11:53:14 +0100 |
commit | c7288767523f6510cf557707d3eb5e78e519b90d (patch) | |
tree | 241dd0aa246a75b6f76acb8f810789b0d1993996 /target-ppc | |
parent | c6eb076aecbe85e816a320d03d8dc1951be97efd (diff) | |
parent | 86b50f2e1befc33407bdfeb6f45f7b0d2439a740 (diff) |
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.7-20160623' into staging
ppc patch queue for 2016-06-23
Currently outstanding patches for spapr, target-ppc and related
devices. This batch has:
* Significant new progress towards full support for hypervisor
mode
* Assorted bugfixes
* Some preliminary patches towards dynamic DMA window support
The last involves a change to memory.c, which Paolo has said I can
take through this tree.
# gpg: Signature made Thu 23 Jun 2016 06:47:53 BST
# gpg: using RSA key 0x6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg: It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-2.7-20160623:
ppc: Disable huge page support if it is not available for main RAM
ppc: Add P7/P8 Power Management instructions
ppc: Move exception generation code out of line
ppc: Turn a bunch of booleans from int to bool
ppc: Add real mode CI load/store instructions for P7 and P8
ppc: Rework generation of priv and inval interrupts
ppc: Fix generation if ISI/DSI vs. HV mode
ppc: Fix POWER7 and POWER8 exception definitions
ppc: fix exception model for HV mode
ppc: define a default LPCR value
ppc: Fix rfi/rfid/hrfi/... emulation
memory: Add reporting of supported page sizes
ppc: Improve emulation of THRM registers
target-ppc: Fix rlwimi, rlwinm, rlwnm again
ppc64: disable gen_pause() for linux-user mode
tests: Use '+=' to add additional tests, not '='
powerpc/mm: Update the WIMG check during H_ENTER
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-ppc')
-rw-r--r-- | target-ppc/cpu-qom.h | 9 | ||||
-rw-r--r-- | target-ppc/cpu.h | 32 | ||||
-rw-r--r-- | target-ppc/excp_helper.c | 263 | ||||
-rw-r--r-- | target-ppc/helper.h | 2 | ||||
-rw-r--r-- | target-ppc/kvm.c | 17 | ||||
-rw-r--r-- | target-ppc/misc_helper.c | 41 | ||||
-rw-r--r-- | target-ppc/mmu-hash64.c | 69 | ||||
-rw-r--r-- | target-ppc/translate.c | 870 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 154 |
9 files changed, 865 insertions, 592 deletions
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 969ecdfbd4..0fad2def0a 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -126,6 +126,15 @@ enum powerpc_excp_t { }; /*****************************************************************************/ +/* PM instructions */ +typedef enum { + PPC_PM_DOZE, + PPC_PM_NAP, + PPC_PM_SLEEP, + PPC_PM_RVWINKLE, +} powerpc_pm_insn_t; + +/*****************************************************************************/ /* Input pins model */ typedef enum powerpc_input_t powerpc_input_t; enum powerpc_input_t { diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 93c2dd5a65..b1354a4791 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -116,6 +116,9 @@ enum { POWERPC_EXCP_HYPPRIV = 41, /* Embedded hypervisor priv instruction */ /* Vectors 42 to 63 are reserved */ /* Exceptions defined in the PowerPC server specification */ + /* Server doorbell variants */ +#define POWERPC_EXCP_SDOOR POWERPC_EXCP_GDOORI +#define POWERPC_EXCP_SDOOR_HV POWERPC_EXCP_DOORI POWERPC_EXCP_RESET = 64, /* System reset exception */ POWERPC_EXCP_DSEG = 65, /* Data segment exception */ POWERPC_EXCP_ISEG = 66, /* Instruction segment exception */ @@ -158,8 +161,12 @@ enum { /* VSX Unavailable (Power ISA 2.06 and later) */ POWERPC_EXCP_VSXU = 94, /* VSX Unavailable */ POWERPC_EXCP_FU = 95, /* Facility Unavailable */ + /* Additional ISA 2.06 and later server exceptions */ + POWERPC_EXCP_HV_EMU = 96, /* HV emulation assistance */ + POWERPC_EXCP_HV_MAINT = 97, /* HMI */ + POWERPC_EXCP_HV_FU = 98, /* Hypervisor Facility unavailable */ /* EOL */ - POWERPC_EXCP_NB = 96, + POWERPC_EXCP_NB = 99, /* QEMU exceptions: used internally during code translation */ POWERPC_EXCP_STOP = 0x200, /* stop translation */ POWERPC_EXCP_BRANCH = 0x201, /* branch instruction */ @@ -376,6 +383,14 @@ struct ppc_slb_t { #define LPCR_LPES1 (1ull << (63 - 61)) #define LPCR_AIL_SHIFT (63 - 40) /* Alternate interrupt location */ #define LPCR_AIL (3ull << LPCR_AIL_SHIFT) +#define LPCR_P7_PECE0 (1ull << (63 - 49)) +#define LPCR_P7_PECE1 (1ull << (63 - 50)) +#define LPCR_P7_PECE2 (1ull << (63 - 51)) +#define LPCR_P8_PECE0 (1ull << (63 - 47)) +#define LPCR_P8_PECE1 (1ull << (63 - 48)) +#define LPCR_P8_PECE2 (1ull << (63 - 49)) +#define LPCR_P8_PECE3 (1ull << (63 - 50)) +#define LPCR_P8_PECE4 (1ull << (63 - 51)) #define msr_sf ((env->msr >> MSR_SF) & 1) #define msr_isf ((env->msr >> MSR_ISF) & 1) @@ -1052,6 +1067,11 @@ struct CPUPPCState { * instructions and SPRs are diallowed if MSR:HV is 0 */ bool has_hv_mode; + /* On P7/P8, set when in PM state, we need to handle resume + * in a special way (such as routing some resume causes to + * 0x100), so flag this here. + */ + bool in_pm_state; #endif /* Those resources are used only during code translation */ @@ -1905,6 +1925,8 @@ enum { PPC_POPCNTB = 0x0000000000001000ULL, /* string load / store */ PPC_STRING = 0x0000000000002000ULL, + /* real mode cache inhibited load / store */ + PPC_CILDST = 0x0000000000004000ULL, /* Floating-point unit extensions */ /* Optional floating point instructions */ @@ -2019,7 +2041,7 @@ enum { | PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \ | PPC_4xx_COMMON | PPC_40x_ICBT | PPC_RFMCI \ | PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_DCRUX \ - | PPC_POPCNTWD) + | PPC_POPCNTWD | PPC_CILDST) /* extended type values */ @@ -2059,6 +2081,8 @@ enum { PPC2_FP_CVT_S64 = 0x0000000000010000ULL, /* Transactional Memory (ISA 2.07, Book II) */ PPC2_TM = 0x0000000000020000ULL, + /* Server PM instructgions (ISA 2.06, Book III) */ + PPC2_PM_ISA206 = 0x0000000000040000ULL, #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \ @@ -2066,7 +2090,7 @@ enum { PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \ PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \ PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \ - PPC2_FP_CVT_S64 | PPC2_TM) + PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206) }; /*****************************************************************************/ @@ -2196,6 +2220,8 @@ enum { PPC_INTERRUPT_CDOORBELL, /* Critical doorbell interrupt */ PPC_INTERRUPT_DOORBELL, /* Doorbell interrupt */ PPC_INTERRUPT_PERFM, /* Performance monitor interrupt */ + PPC_INTERRUPT_HMI, /* Hypervisor Maintainance interrupt */ + PPC_INTERRUPT_HDOORBELL, /* Hypervisor Doorbell interrupt */ }; /* Processor Compatibility mask (PCR) */ diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 30e960e30b..533866b87b 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -77,18 +77,8 @@ 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, ail; - - 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; - } + int srr0, srr1, asrr0, asrr1, lev, ail; + bool lpes0; qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx " => %08x (%02x)\n", env->nip, excp, env->error_code); @@ -100,8 +90,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); /* target registers */ srr0 = SPR_SRR0; @@ -109,14 +101,59 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) asrr0 = -1; asrr1 = -1; + /* check for special resume at 0x100 from doze/nap/sleep/winkle on P7/P8 */ + if (env->in_pm_state) { + env->in_pm_state = false; + + /* Pretend to be returning from doze always as we don't lose state */ + msr |= (0x1ull << (63 - 47)); + + /* Non-machine check are routed to 0x100 with a wakeup cause + * encoded in SRR1 + */ + if (excp != POWERPC_EXCP_MCHECK) { + switch (excp) { + case POWERPC_EXCP_RESET: + msr |= 0x4ull << (63 - 45); + break; + case POWERPC_EXCP_EXTERNAL: + msr |= 0x8ull << (63 - 45); + break; + case POWERPC_EXCP_DECR: + msr |= 0x6ull << (63 - 45); + break; + case POWERPC_EXCP_SDOOR: + msr |= 0x5ull << (63 - 45); + break; + case POWERPC_EXCP_SDOOR_HV: + msr |= 0x3ull << (63 - 45); + break; + case POWERPC_EXCP_HV_MAINT: + msr |= 0xaull << (63 - 45); + break; + default: + cpu_abort(cs, "Unsupported exception %d in Power Save mode\n", + excp); + } + excp = POWERPC_EXCP_RESET; + } + } + /* 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 { @@ -125,9 +162,23 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } else #endif /* defined(TARGET_PPC64) */ { + lpes0 = true; ail = 0; } + /* Hypervisor emulation assistance interrupt only exists on server + * arch 2.05 server or later. We also don't want to generate it if + * we don't have HVB in msr_mask (PAPR mode). + */ + if (excp == POWERPC_EXCP_HV_EMU +#if defined(TARGET_PPC64) + && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB)) +#endif /* defined(TARGET_PPC64) */ + + ) { + excp = POWERPC_EXCP_PROGRAM; + } + switch (excp) { case POWERPC_EXCP_NONE: /* Should never happen */ @@ -162,10 +213,7 @@ 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 */ @@ -191,23 +239,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 */ @@ -215,9 +260,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)) @@ -232,9 +274,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; @@ -243,23 +282,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; @@ -270,28 +300,30 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) break; } goto store_current; + case POWERPC_EXCP_HV_EMU: + srr0 = SPR_HSRR0; + srr1 = SPR_HSRR1; + new_msr |= (target_ulong)MSR_HVB; + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + 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 */ @@ -361,21 +393,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) 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; @@ -384,9 +407,6 @@ 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; @@ -413,19 +433,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"); @@ -444,9 +455,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: @@ -463,9 +471,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: @@ -482,9 +487,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: @@ -590,9 +592,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"); @@ -636,6 +635,13 @@ 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]; @@ -644,14 +650,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 || - excp_model == POWERPC_EXCP_POWER8) { - if (env->spr[SPR_LPCR] & LPCR_ILE) { + if (excp_model == POWERPC_EXCP_POWER7) { + 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) { @@ -674,7 +686,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) /* 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)) { + if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) || + ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { ail = 0; } /* Handle AIL */ @@ -922,25 +935,41 @@ void helper_store_msr(CPUPPCState *env, target_ulong val) } } -static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, - target_ulong msrm, int keep_msrh) +#if defined(TARGET_PPC64) +void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) +{ + CPUState *cs; + + cs = CPU(ppc_env_get_cpu(env)); + cs->halted = 1; + env->in_pm_state = true; + + /* Technically, nap doesn't set EE, but if we don't set it + * then ppc_hw_interrupt() won't deliver. We could add some + * other tests there based on LPCR but it's simpler to just + * whack EE in. It will be cleared by the 0x100 at wakeup + * anyway. It will still be observable by the guest in SRR1 + * but this doesn't seem to be a problem. + */ + env->msr |= (1ull << MSR_EE); + helper_raise_exception(env, EXCP_HLT); +} +#endif /* defined(TARGET_PPC64) */ + +static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) { CPUState *cs = CPU(ppc_env_get_cpu(env)); + /* MSR:POW cannot be set by any form of rfi */ + msr &= ~(1ULL << MSR_POW); + #if defined(TARGET_PPC64) - if (msr_is_64bit(env, msr)) { - nip = (uint64_t)nip; - msr &= (uint64_t)msrm; - } else { + /* Switching to 32-bit ? Crop the nip */ + if (!msr_is_64bit(env, msr)) { nip = (uint32_t)nip; - msr = (uint32_t)(msr & msrm); - if (keep_msrh) { - msr |= env->msr & ~((uint64_t)0xFFFFFFFF); - } } #else nip = (uint32_t)nip; - msr &= (uint32_t)msrm; #endif /* XXX: beware: this is false if VLE is supported */ env->nip = nip & ~((target_ulong)0x00000003); @@ -959,26 +988,24 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, void helper_rfi(CPUPPCState *env) { - if (env->excp_model == POWERPC_EXCP_BOOKE) { - do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], - ~((target_ulong)0), 0); - } else { - do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], - ~((target_ulong)0x783F0000), 1); - } + do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); } +#define MSR_BOOK3S_MASK #if defined(TARGET_PPC64) void helper_rfid(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], - ~((target_ulong)0x783F0000), 0); + /* The architeture defines a number of rules for which bits + * can change but in practice, we handle this in hreg_store_msr() + * which will be called by do_rfi(), so there is no need to filter + * here + */ + do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]); } void helper_hrfid(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1], - ~((target_ulong)0x783F0000), 0); + do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); } #endif @@ -986,28 +1013,24 @@ void helper_hrfid(CPUPPCState *env) /* Embedded PowerPC specific helpers */ void helper_40x_rfci(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3], - ~((target_ulong)0xFFFF0000), 0); + do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]); } void helper_rfci(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1], - ~((target_ulong)0), 0); + do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]); } void helper_rfdi(CPUPPCState *env) { /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ - do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1], - ~((target_ulong)0), 0); + do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]); } void helper_rfmci(CPUPPCState *env) { /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ - do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1], - ~((target_ulong)0), 0); + do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); } #endif @@ -1045,7 +1068,7 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, void helper_rfsvc(CPUPPCState *env) { - do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0); + do_rfi(env, env->lr, env->ctr & 0x0000FFFF); } /* Embedded.Processor Control */ diff --git a/target-ppc/helper.h b/target-ppc/helper.h index f4410a8369..5056ac2095 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -13,6 +13,7 @@ DEF_HELPER_1(rfci, void, env) DEF_HELPER_1(rfdi, void, env) DEF_HELPER_1(rfmci, void, env) #if defined(TARGET_PPC64) +DEF_HELPER_2(pminsn, void, env, i32) DEF_HELPER_1(rfid, void, env) DEF_HELPER_1(hrfid, void, env) #endif @@ -670,3 +671,4 @@ DEF_HELPER_4(dscli, void, env, fprp, fprp, i32) DEF_HELPER_4(dscliq, void, env, fprp, fprp, i32) DEF_HELPER_1(tbegin, void, env) +DEF_HELPER_1(fixup_thrm, void, env) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index e14da60b77..884d564e0f 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -27,6 +27,7 @@ #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" +#include "sysemu/numa.h" #include "kvm_ppc.h" #include "sysemu/cpus.h" #include "sysemu/device_tree.h" @@ -388,7 +389,21 @@ static long getrampagesize(void) object_child_foreach(memdev_root, find_max_supported_pagesize, &hpsize); - return (hpsize == LONG_MAX) ? getpagesize() : hpsize; + if (hpsize == LONG_MAX) { + return getpagesize(); + } + + if (nb_numa_nodes == 0 && hpsize > getpagesize()) { + /* No NUMA nodes and normal RAM without -mem-path ==> no huge pages! */ + static bool warned; + if (!warned) { + error_report("Huge page support disabled (n/a for main memory)."); + warned = true; + } + return getpagesize(); + } + + return hpsize; } static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift) diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c index 7d41b017c8..cb5ebf56cf 100644 --- a/target-ppc/misc_helper.c +++ b/target-ppc/misc_helper.c @@ -166,3 +166,44 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value) { hreg_store_msr(env, value, 0); } + +/* This code is lifted from MacOnLinux. It is called whenever + * THRM1,2 or 3 is read an fixes up the values in such a way + * that will make MacOS not hang. These registers exist on some + * 75x and 74xx processors. + */ +void helper_fixup_thrm(CPUPPCState *env) +{ + target_ulong v, t; + int i; + +#define THRM1_TIN (1 << 31) +#define THRM1_TIV (1 << 30) +#define THRM1_THRES(x) (((x) & 0x7f) << 23) +#define THRM1_TID (1 << 2) +#define THRM1_TIE (1 << 1) +#define THRM1_V (1 << 0) +#define THRM3_E (1 << 0) + + if (!(env->spr[SPR_THRM3] & THRM3_E)) { + return; + } + + /* Note: Thermal interrupts are unimplemented */ + for (i = SPR_THRM1; i <= SPR_THRM2; i++) { + v = env->spr[i]; + if (!(v & THRM1_V)) { + continue; + } + v |= THRM1_TIV; + v &= ~THRM1_TIN; + t = v & THRM1_THRES(127); + if ((v & THRM1_TID) && t < THRM1_THRES(24)) { + v |= THRM1_TIN; + } + if (!(v & THRM1_TID) && t > THRM1_THRES(24)) { + v |= THRM1_TIN; + } + env->spr[i] = v; + } +} diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index 668da5e226..5b7b5e9eb1 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; } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index df4e0a308b..2f1c59166e 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -193,22 +193,21 @@ struct DisasContext { uint32_t opcode; uint32_t exception; /* Routine used to access memory */ - bool pr, hv; + bool pr, hv, dr, le_mode; bool lazy_tlb_flush; int mem_idx; int access_type; /* Translation flags */ - int le_mode; TCGMemOp default_tcg_memop_mask; #if defined(TARGET_PPC64) - int sf_mode; - int has_cfar; -#endif - int fpu_enabled; - int altivec_enabled; - int vsx_enabled; - int spe_enabled; - int tm_enabled; + bool sf_mode; + bool has_cfar; +#endif + bool fpu_enabled; + bool altivec_enabled; + bool vsx_enabled; + bool spe_enabled; + bool tm_enabled; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; uint64_t insns_flags; @@ -285,7 +284,7 @@ void gen_update_current_nip(void *opaque) tcg_gen_movi_tl(cpu_nip, ctx->nip); } -static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error) +static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error) { TCGv_i32 t0, t1; if (ctx->exception == POWERPC_EXCP_NONE) { @@ -299,7 +298,7 @@ static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t ctx->exception = (excp); } -static inline void gen_exception(DisasContext *ctx, uint32_t excp) +static void gen_exception(DisasContext *ctx, uint32_t excp) { TCGv_i32 t0; if (ctx->exception == POWERPC_EXCP_NONE) { @@ -311,7 +310,7 @@ static inline void gen_exception(DisasContext *ctx, uint32_t excp) ctx->exception = (excp); } -static inline void gen_debug_exception(DisasContext *ctx) +static void gen_debug_exception(DisasContext *ctx) { TCGv_i32 t0; @@ -326,7 +325,19 @@ static inline void gen_debug_exception(DisasContext *ctx) static inline void gen_inval_exception(DisasContext *ctx, uint32_t error) { - gen_exception_err(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | error); + /* Will be converted to program check if needed */ + gen_exception_err(ctx, POWERPC_EXCP_HV_EMU, POWERPC_EXCP_INVAL | error); +} + +static inline void gen_priv_exception(DisasContext *ctx, uint32_t error) +{ + gen_exception_err(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_PRIV | error); +} + +static inline void gen_hvpriv_exception(DisasContext *ctx, uint32_t error) +{ + /* Will be converted to program check if needed */ + gen_exception_err(ctx, POWERPC_EXCP_HV_EMU, POWERPC_EXCP_PRIV | error); } /* Stop translation */ @@ -367,6 +378,40 @@ typedef struct opcode_t { const char *oname; } opcode_t; +/* Helpers for priv. check */ +#define GEN_PRIV \ + do { \ + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; \ + } while (0) + +#if defined(CONFIG_USER_ONLY) +#define CHK_HV GEN_PRIV +#define CHK_SV GEN_PRIV +#define CHK_HVRM GEN_PRIV +#else +#define CHK_HV \ + do { \ + if (unlikely(ctx->pr || !ctx->hv)) { \ + GEN_PRIV; \ + } \ + } while (0) +#define CHK_SV \ + do { \ + if (unlikely(ctx->pr)) { \ + GEN_PRIV; \ + } \ + } while (0) +#define CHK_HVRM \ + do { \ + if (unlikely(ctx->pr || !ctx->hv || ctx->dr)) { \ + GEN_PRIV; \ + } \ + } while (0) +#endif + +#define CHK_NONE + + /*****************************************************************************/ /*** Instruction decoding ***/ #define EXTRACT_HELPER(name, shift, nb) \ @@ -1394,7 +1439,7 @@ GEN_LOGICAL2(nand, tcg_gen_nand_tl, 0x0E, PPC_INTEGER); /* nor & nor. */ GEN_LOGICAL2(nor, tcg_gen_nor_tl, 0x03, PPC_INTEGER); -#if defined(TARGET_PPC64) +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) static void gen_pause(DisasContext *ctx) { TCGv_i32 t0 = tcg_const_i32(0); @@ -1482,7 +1527,9 @@ static void gen_or(DisasContext *ctx) /* Pause us out of TCG otherwise spin loops with smt_low * eat too much CPU and the kernel hangs */ +#if !defined(CONFIG_USER_ONLY) gen_pause(ctx); +#endif } #endif } @@ -1694,9 +1741,7 @@ static void gen_rlwinm(DisasContext *ctx) #endif mask = MASK(mb, me); - if (sh == 0) { - tcg_gen_andi_tl(t_ra, t_rs, mask); - } else if (mask <= 0xffffffffu) { + if (mask <= 0xffffffffu) { TCGv_i32 t0 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(t0, t_rs); tcg_gen_rotli_i32(t0, t0, sh); @@ -2888,18 +2933,23 @@ static void glue(gen_, name##ux)(DisasContext *ctx) tcg_temp_free(EA); \ } -#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2) \ +#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2, chk) \ static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ + chk; \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA); \ tcg_temp_free(EA); \ } + #define GEN_LDX(name, ldop, opc2, opc3, type) \ - GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE) + GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE, CHK_NONE) + +#define GEN_LDX_HVRM(name, ldop, opc2, opc3, type) \ + GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE, CHK_HVRM) #define GEN_LDS(name, ldop, op, type) \ GEN_LD(name, ldop, op | 0x20, type); \ @@ -2925,6 +2975,12 @@ GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B); /* ldx */ GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B); +/* CI load/store variants */ +GEN_LDX_HVRM(ldcix, ld64, 0x15, 0x1b, PPC_CILDST) +GEN_LDX_HVRM(lwzcix, ld32u, 0x15, 0x15, PPC_CILDST) +GEN_LDX_HVRM(lhzcix, ld16u, 0x15, 0x19, PPC_CILDST) +GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST) + static void gen_ld(DisasContext *ctx) { TCGv EA; @@ -2961,7 +3017,7 @@ static void gen_lq(DisasContext *ctx) bool le_is_supported = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0; if (!legal_in_user_mode && ctx->pr) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -3043,10 +3099,11 @@ static void glue(gen_, name##ux)(DisasContext *ctx) tcg_temp_free(EA); \ } -#define GEN_STX_E(name, stop, opc2, opc3, type, type2) \ +#define GEN_STX_E(name, stop, opc2, opc3, type, type2, chk) \ static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ + chk; \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ @@ -3054,7 +3111,10 @@ static void glue(gen_, name##x)(DisasContext *ctx) \ tcg_temp_free(EA); \ } #define GEN_STX(name, stop, opc2, opc3, type) \ - GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE) + GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE, CHK_NONE) + +#define GEN_STX_HVRM(name, stop, opc2, opc3, type) \ + GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE, CHK_HVRM) #define GEN_STS(name, stop, op, type) \ GEN_ST(name, stop, op | 0x20, type); \ @@ -3071,6 +3131,10 @@ GEN_STS(stw, st32, 0x04, PPC_INTEGER); #if defined(TARGET_PPC64) GEN_STUX(std, st64, 0x15, 0x05, PPC_64B); GEN_STX(std, st64, 0x15, 0x04, PPC_64B); +GEN_STX_HVRM(stdcix, st64, 0x15, 0x1f, PPC_CILDST) +GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST) +GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST) +GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST) static void gen_std(DisasContext *ctx) { @@ -3087,7 +3151,7 @@ static void gen_std(DisasContext *ctx) } if (!legal_in_user_mode && ctx->pr) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } @@ -3159,7 +3223,7 @@ static inline void gen_qemu_ld64ur(DisasContext *ctx, TCGv arg1, TCGv arg2) TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP); tcg_gen_qemu_ld_i64(arg1, arg2, ctx->mem_idx, op); } -GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX); +GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE); #endif /* TARGET_PPC64 */ /* sthbrx */ @@ -3185,7 +3249,7 @@ static inline void gen_qemu_st64r(DisasContext *ctx, TCGv arg1, TCGv arg2) TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP); tcg_gen_qemu_st_i64(arg1, arg2, ctx->mem_idx, op); } -GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX); +GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE); #endif /* TARGET_PPC64 */ /*** Integer load and store multiple ***/ @@ -3539,6 +3603,68 @@ static void gen_wait(DisasContext *ctx) gen_exception_err(ctx, EXCP_HLT, 1); } +#if defined(TARGET_PPC64) +static void gen_doze(DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY) + GEN_PRIV; +#else + TCGv_i32 t; + + CHK_HV; + t = tcg_const_i32(PPC_PM_DOZE); + gen_helper_pminsn(cpu_env, t); + tcg_temp_free_i32(t); + gen_stop_exception(ctx); +#endif /* defined(CONFIG_USER_ONLY) */ +} + +static void gen_nap(DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY) + GEN_PRIV; +#else + TCGv_i32 t; + + CHK_HV; + t = tcg_const_i32(PPC_PM_NAP); + gen_helper_pminsn(cpu_env, t); + tcg_temp_free_i32(t); + gen_stop_exception(ctx); +#endif /* defined(CONFIG_USER_ONLY) */ +} + +static void gen_sleep(DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY) + GEN_PRIV; +#else + TCGv_i32 t; + + CHK_HV; + t = tcg_const_i32(PPC_PM_SLEEP); + gen_helper_pminsn(cpu_env, t); + tcg_temp_free_i32(t); + gen_stop_exception(ctx); +#endif /* defined(CONFIG_USER_ONLY) */ +} + +static void gen_rvwinkle(DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY) + GEN_PRIV; +#else + TCGv_i32 t; + + CHK_HV; + t = tcg_const_i32(PPC_PM_RVWINKLE); + gen_helper_pminsn(cpu_env, t); + tcg_temp_free_i32(t); + gen_stop_exception(ctx); +#endif /* defined(CONFIG_USER_ONLY) */ +} +#endif /* #if defined(TARGET_PPC64) */ + /*** Floating-point load ***/ #define GEN_LDF(name, ldop, opc, type) \ static void glue(gen_, name)(DisasContext *ctx) \ @@ -4117,13 +4243,14 @@ static void gen_mcrf(DisasContext *ctx) static void gen_rfi(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else + /* FIXME: This instruction doesn't exist anymore on 64-bit server + * processors compliant with arch 2.x, we should remove it there, + * but we need to fix OpenBIOS not to use it on 970 first + */ /* Restore CPU state */ - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; gen_update_cfar(ctx, ctx->nip); gen_helper_rfi(cpu_env); gen_sync_exception(ctx); @@ -4134,13 +4261,10 @@ static void gen_rfi(DisasContext *ctx) static void gen_rfid(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else /* Restore CPU state */ - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; gen_update_cfar(ctx, ctx->nip); gen_helper_rfid(cpu_env); gen_sync_exception(ctx); @@ -4150,13 +4274,10 @@ static void gen_rfid(DisasContext *ctx) static void gen_hrfid(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else /* Restore CPU state */ - if (unlikely(ctx->pr || !ctx->hv)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_HV; gen_helper_hrfid(cpu_env); gen_sync_exception(ctx); #endif @@ -4319,15 +4440,8 @@ static void gen_mfcr(DisasContext *ctx) /* mfmsr */ static void gen_mfmsr(DisasContext *ctx) { -#if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); -#else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + CHK_SV; tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_msr); -#endif } static void spr_noaccess(DisasContext *ctx, int gprn, int sprn) @@ -4373,9 +4487,15 @@ static inline void gen_op_mfspr(DisasContext *ctx) TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); } } - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG); } } else { + /* ISA 2.07 defines these as no-ops */ + if ((ctx->insns_flags2 & PPC2_ISA207S) && + (sprn >= 808 && sprn <= 811)) { + /* This is a nop */ + return; + } /* Not defined */ fprintf(stderr, "Trying to read invalid spr %d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); @@ -4383,9 +4503,18 @@ static inline void gen_op_mfspr(DisasContext *ctx) qemu_log("Trying to read invalid spr %d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); } - /* Only generate an exception in user space, otherwise this is a nop */ - if (ctx->pr) { - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR); + + /* The behaviour depends on MSR:PR and SPR# bit 0x10, + * it can generate a priv, a hv emu or a no-op + */ + if (sprn & 0x10) { + if (ctx->pr) { + gen_priv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + } + } else { + if (ctx->pr || sprn == 0 || sprn == 4 || sprn == 5 || sprn == 6) { + gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + } } } } @@ -4433,13 +4562,9 @@ static void gen_mtcrf(DisasContext *ctx) #if defined(TARGET_PPC64) static void gen_mtmsrd(DisasContext *ctx) { -#if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); -#else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + CHK_SV; + +#if !defined(CONFIG_USER_ONLY) if (ctx->opcode & 0x00010000) { /* Special form that does not need any synchronisation */ TCGv t0 = tcg_temp_new(); @@ -4458,20 +4583,16 @@ static void gen_mtmsrd(DisasContext *ctx) /* Note that mtmsr is not always defined as context-synchronizing */ gen_stop_exception(ctx); } -#endif +#endif /* !defined(CONFIG_USER_ONLY) */ } -#endif +#endif /* defined(TARGET_PPC64) */ static void gen_mtmsr(DisasContext *ctx) { -#if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); -#else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } - if (ctx->opcode & 0x00010000) { + CHK_SV; + +#if !defined(CONFIG_USER_ONLY) + if (ctx->opcode & 0x00010000) { /* Special form that does not need any synchronisation */ TCGv t0 = tcg_temp_new(); tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE)); @@ -4528,9 +4649,16 @@ static void gen_mtspr(DisasContext *ctx) qemu_log("Trying to write privileged spr %d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); } - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG); } } else { + /* ISA 2.07 defines these as no-ops */ + if ((ctx->insns_flags2 & PPC2_ISA207S) && + (sprn >= 808 && sprn <= 811)) { + /* This is a nop */ + return; + } + /* Not defined */ if (qemu_log_separate()) { qemu_log("Trying to write invalid spr %d (0x%03x) at " @@ -4539,9 +4667,18 @@ static void gen_mtspr(DisasContext *ctx) fprintf(stderr, "Trying to write invalid spr %d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); - /* Only generate an exception in user space, otherwise this is a nop */ - if (ctx->pr) { - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR); + + /* The behaviour depends on MSR:PR and SPR# bit 0x10, + * it can generate a priv, a hv emu or a no-op + */ + if (sprn & 0x10) { + if (ctx->pr) { + gen_priv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + } + } else { + if (ctx->pr || sprn == 0) { + gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + } } } } @@ -4564,13 +4701,11 @@ static void gen_dcbf(DisasContext *ctx) static void gen_dcbi(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv EA, val; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + + CHK_SV; EA = tcg_temp_new(); gen_set_access_type(ctx, ACCESS_CACHE); gen_addr_reg_index(ctx, EA); @@ -4580,7 +4715,7 @@ static void gen_dcbi(DisasContext *ctx) gen_qemu_st8(ctx, val, EA); tcg_temp_free(val); tcg_temp_free(EA); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* dcdst */ @@ -4701,72 +4836,64 @@ static void gen_dcba(DisasContext *ctx) static void gen_mfsr(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + + CHK_SV; t0 = tcg_const_tl(SR(ctx->opcode)); gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* mfsrin */ static void gen_mfsrin(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + + CHK_SV; t0 = tcg_temp_new(); tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28); tcg_gen_andi_tl(t0, t0, 0xF); gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* mtsr */ static void gen_mtsr(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + + CHK_SV; t0 = tcg_const_tl(SR(ctx->opcode)); gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* mtsrin */ static void gen_mtsrin(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + CHK_SV; + t0 = tcg_temp_new(); tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28); tcg_gen_andi_tl(t0, t0, 0xF); gen_helper_store_sr(cpu_env, t0, cpu_gpr[rD(ctx->opcode)]); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } #if defined(TARGET_PPC64) @@ -4776,115 +4903,101 @@ static void gen_mtsrin(DisasContext *ctx) static void gen_mfsr_64b(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + + CHK_SV; t0 = tcg_const_tl(SR(ctx->opcode)); gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* mfsrin */ static void gen_mfsrin_64b(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + + CHK_SV; t0 = tcg_temp_new(); tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28); tcg_gen_andi_tl(t0, t0, 0xF); gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* mtsr */ static void gen_mtsr_64b(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + + CHK_SV; t0 = tcg_const_tl(SR(ctx->opcode)); gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* mtsrin */ static void gen_mtsrin_64b(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + + CHK_SV; t0 = tcg_temp_new(); tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28); tcg_gen_andi_tl(t0, t0, 0xF); gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* slbmte */ static void gen_slbmte(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + CHK_SV; + gen_helper_store_slb(cpu_env, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } static void gen_slbmfee(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + CHK_SV; + gen_helper_load_slb_esid(cpu_gpr[rS(ctx->opcode)], cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } static void gen_slbmfev(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + CHK_SV; + gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)], cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } static void gen_slbfee_(DisasContext *ctx) @@ -4920,40 +5033,34 @@ static void gen_slbfee_(DisasContext *ctx) static void gen_tlbia(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr || !ctx->hv)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_HV; + gen_helper_tlbia(cpu_env); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* tlbiel */ static void gen_tlbiel(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; + gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* tlbie */ static void gen_tlbie(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr || !ctx->hv)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_HV; + if (NARROW_MODE(ctx)) { TCGv t0 = tcg_temp_new(); tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]); @@ -4962,25 +5069,23 @@ static void gen_tlbie(DisasContext *ctx) } else { gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); } -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* tlbsync */ static void gen_tlbsync(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr || !ctx->hv)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_HV; + /* tlbsync is a nop for server, ptesync handles delayed tlb flush, * embedded however needs to deal with tlbsync. We don't try to be * fancy and swallow the overhead of checking for both. */ gen_check_tlb_flush(ctx); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } #if defined(TARGET_PPC64) @@ -4988,30 +5093,26 @@ static void gen_tlbsync(DisasContext *ctx) static void gen_slbia(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; + gen_helper_slbia(cpu_env); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* slbie */ static void gen_slbie(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; + gen_helper_slbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } -#endif +#endif /* defined(TARGET_PPC64) */ /*** External control ***/ /* Optional: */ @@ -5710,14 +5811,11 @@ static void gen_esa(DisasContext *ctx) static void gen_mfrom(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* 602 - 603 - G2 TLB management */ @@ -5726,28 +5824,22 @@ static void gen_mfrom(DisasContext *ctx) static void gen_tlbld_6xx(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; gen_helper_6xx_tlbd(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* tlbli */ static void gen_tlbli_6xx(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; gen_helper_6xx_tlbi(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* 74xx TLB management */ @@ -5756,28 +5848,22 @@ static void gen_tlbli_6xx(DisasContext *ctx) static void gen_tlbld_74xx(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; gen_helper_74xx_tlbd(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* tlbli */ static void gen_tlbli_74xx(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; gen_helper_74xx_tlbi(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* POWER instructions not in PowerPC 601 */ @@ -5791,15 +5877,12 @@ static void gen_clf(DisasContext *ctx) /* cli */ static void gen_cli(DisasContext *ctx) { - /* Cache line invalidate: privileged and treated as no-op */ #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } -#endif + /* Cache line invalidate: privileged and treated as no-op */ + CHK_SV; +#endif /* defined(CONFIG_USER_ONLY) */ } /* dclst */ @@ -5811,15 +5894,13 @@ static void gen_dclst(DisasContext *ctx) static void gen_mfsri(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else int ra = rA(ctx->opcode); int rd = rD(ctx->opcode); TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + + CHK_SV; t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); tcg_gen_shri_tl(t0, t0, 28); @@ -5828,38 +5909,34 @@ static void gen_mfsri(DisasContext *ctx) tcg_temp_free(t0); if (ra != 0 && ra != rd) tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } static void gen_rac(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + + CHK_SV; t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_rac(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } static void gen_rfsvc(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; + gen_helper_rfsvc(cpu_env); gen_sync_exception(ctx); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* svc is not implemented for now */ @@ -6012,18 +6089,16 @@ static void gen_mfapidi(DisasContext *ctx) static void gen_tlbiva(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + + CHK_SV; t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_tlbiva(cpu_env, cpu_gpr[rB(ctx->opcode)]); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* All 405 MAC instructions are translated here */ @@ -6245,38 +6320,34 @@ GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C); static void gen_mfdcr(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else TCGv dcrn; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + + CHK_SV; /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); dcrn = tcg_const_tl(SPR(ctx->opcode)); gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, dcrn); tcg_temp_free(dcrn); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* mtdcr */ static void gen_mtdcr(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else TCGv dcrn; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + + CHK_SV; /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); dcrn = tcg_const_tl(SPR(ctx->opcode)); gen_helper_store_dcr(cpu_env, dcrn, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(dcrn); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* mfdcrx */ @@ -6284,18 +6355,15 @@ static void gen_mtdcr(DisasContext *ctx) static void gen_mfdcrx(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + CHK_SV; /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* mtdcrx */ @@ -6303,18 +6371,15 @@ static void gen_mfdcrx(DisasContext *ctx) static void gen_mtdcrx(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + CHK_SV; /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* mfdcrux (PPC 460) : user-mode access to DCR */ @@ -6340,28 +6405,19 @@ static void gen_mtdcrux(DisasContext *ctx) /* dccci */ static void gen_dccci(DisasContext *ctx) { -#if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); -#else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; /* interpreted as no-op */ -#endif } /* dcread */ static void gen_dcread(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv EA, val; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + + CHK_SV; gen_set_access_type(ctx, ACCESS_CACHE); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); @@ -6370,7 +6426,7 @@ static void gen_dcread(DisasContext *ctx) tcg_temp_free(val); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], EA); tcg_temp_free(EA); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* icbt */ @@ -6385,60 +6441,40 @@ static void gen_icbt_40x(DisasContext *ctx) /* iccci */ static void gen_iccci(DisasContext *ctx) { -#if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); -#else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; /* interpreted as no-op */ -#endif } /* icread */ static void gen_icread(DisasContext *ctx) { -#if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); -#else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; /* interpreted as no-op */ -#endif } /* rfci (supervisor only) */ static void gen_rfci_40x(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; /* Restore CPU state */ gen_helper_40x_rfci(cpu_env); gen_sync_exception(ctx); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } static void gen_rfci(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; /* Restore CPU state */ gen_helper_rfci(cpu_env); gen_sync_exception(ctx); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* BookE specific */ @@ -6447,32 +6483,26 @@ static void gen_rfci(DisasContext *ctx) static void gen_rfdi(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; /* Restore CPU state */ gen_helper_rfdi(cpu_env); gen_sync_exception(ctx); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* XXX: not implemented on 440 ? */ static void gen_rfmci(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; /* Restore CPU state */ gen_helper_rfmci(cpu_env); gen_sync_exception(ctx); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* TLB management - PowerPC 405 implementation */ @@ -6481,12 +6511,9 @@ static void gen_rfmci(DisasContext *ctx) static void gen_tlbre_40x(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; switch (rB(ctx->opcode)) { case 0: gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_env, @@ -6500,20 +6527,18 @@ static void gen_tlbre_40x(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); break; } -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* tlbsx - tlbsx. */ static void gen_tlbsx_40x(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + + CHK_SV; t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); @@ -6525,19 +6550,17 @@ static void gen_tlbsx_40x(DisasContext *ctx) tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02); gen_set_label(l1); } -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* tlbwe */ static void gen_tlbwe_40x(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; + switch (rB(ctx->opcode)) { case 0: gen_helper_4xx_tlbwe_hi(cpu_env, cpu_gpr[rA(ctx->opcode)], @@ -6551,7 +6574,7 @@ static void gen_tlbwe_40x(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); break; } -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* TLB management - PowerPC 440 implementation */ @@ -6560,12 +6583,10 @@ static void gen_tlbwe_40x(DisasContext *ctx) static void gen_tlbre_440(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; + switch (rB(ctx->opcode)) { case 0: case 1: @@ -6581,20 +6602,18 @@ static void gen_tlbre_440(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); break; } -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* tlbsx - tlbsx. */ static void gen_tlbsx_440(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + + CHK_SV; t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); @@ -6606,19 +6625,16 @@ static void gen_tlbsx_440(DisasContext *ctx) tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02); gen_set_label(l1); } -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* tlbwe */ static void gen_tlbwe_440(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; switch (rB(ctx->opcode)) { case 0: case 1: @@ -6634,7 +6650,7 @@ static void gen_tlbwe_440(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); break; } -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* TLB management - PowerPC BookE 2.06 implementation */ @@ -6642,30 +6658,23 @@ static void gen_tlbwe_440(DisasContext *ctx) /* tlbre */ static void gen_tlbre_booke206(DisasContext *ctx) { -#if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + #if defined(CONFIG_USER_ONLY) + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } - + CHK_SV; gen_helper_booke206_tlbre(cpu_env); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* tlbsx - tlbsx. */ static void gen_tlbsx_booke206(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; if (rA(ctx->opcode)) { t0 = tcg_temp_new(); tcg_gen_mov_tl(t0, cpu_gpr[rD(ctx->opcode)]); @@ -6676,54 +6685,44 @@ static void gen_tlbsx_booke206(DisasContext *ctx) tcg_gen_add_tl(t0, t0, cpu_gpr[rB(ctx->opcode)]); gen_helper_booke206_tlbsx(cpu_env, t0); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* tlbwe */ static void gen_tlbwe_booke206(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; gen_update_nip(ctx, ctx->nip - 4); gen_helper_booke206_tlbwe(cpu_env); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } static void gen_tlbivax_booke206(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_booke206_tlbivax(cpu_env, t0); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } static void gen_tlbilx_booke206(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); @@ -6743,7 +6742,7 @@ static void gen_tlbilx_booke206(DisasContext *ctx) } tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } @@ -6751,13 +6750,11 @@ static void gen_tlbilx_booke206(DisasContext *ctx) static void gen_wrtee(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + + CHK_SV; t0 = tcg_temp_new(); tcg_gen_andi_tl(t0, cpu_gpr[rD(ctx->opcode)], (1 << MSR_EE)); tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE)); @@ -6767,19 +6764,16 @@ static void gen_wrtee(DisasContext *ctx) * if we just set msr_ee to 1 */ gen_stop_exception(ctx); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* wrteei */ static void gen_wrteei(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + CHK_SV; if (ctx->opcode & 0x00008000) { tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE)); /* Stop translation to have a chance to raise an exception */ @@ -6787,7 +6781,7 @@ static void gen_wrteei(DisasContext *ctx) } else { tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE)); } -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /* PowerPC 440 specific instructions */ @@ -6827,29 +6821,21 @@ static void gen_icbt_440(DisasContext *ctx) static void gen_msgclr(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } - + CHK_SV; gen_helper_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } static void gen_msgsnd(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } - + CHK_SV; gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ } /*** Altivec vector extension ***/ @@ -9851,7 +9837,7 @@ static void gen_tcheck(DisasContext *ctx) #define GEN_TM_PRIV_NOOP(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); \ + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); \ } #else @@ -9859,10 +9845,7 @@ static inline void gen_##name(DisasContext *ctx) \ #define GEN_TM_PRIV_NOOP(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ - if (unlikely(ctx->pr)) { \ - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); \ - return; \ - } \ + CHK_SV; \ if (unlikely(!ctx->tm_enabled)) { \ gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); \ return; \ @@ -9990,6 +9973,10 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER), GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW), #if defined(TARGET_PPC64) GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B), +GEN_HANDLER_E(doze, 0x13, 0x12, 0x0c, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206), +GEN_HANDLER_E(nap, 0x13, 0x12, 0x0d, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206), +GEN_HANDLER_E(sleep, 0x13, 0x12, 0x0e, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206), +GEN_HANDLER_E(rvwinkle, 0x13, 0x12, 0x0f, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206), GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H), #endif GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW), @@ -10342,7 +10329,7 @@ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type), #define GEN_LDUX(name, ldop, opc2, opc3, type) \ GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type), -#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2) \ +#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2, chk) \ GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2), #define GEN_LDS(name, ldop, op, type) \ GEN_LD(name, ldop, op | 0x20, type) \ @@ -10359,7 +10346,13 @@ GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B) GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B) GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B) GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B) -GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX) +GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE) + +/* HV/P7 and later only */ +GEN_LDX_HVRM(ldcix, ld64, 0x15, 0x1b, PPC_CILDST) +GEN_LDX_HVRM(lwzcix, ld32u, 0x15, 0x18, PPC_CILDST) +GEN_LDX_HVRM(lhzcix, ld16u, 0x15, 0x19, PPC_CILDST) +GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST) #endif GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER) GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER) @@ -10375,7 +10368,7 @@ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type), #define GEN_STUX(name, stop, opc2, opc3, type) \ GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type), -#define GEN_STX_E(name, stop, opc2, opc3, type, type2) \ +#define GEN_STX_E(name, stop, opc2, opc3, type, type2, chk) \ GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2), #define GEN_STS(name, stop, op, type) \ GEN_ST(name, stop, op | 0x20, type) \ @@ -10389,7 +10382,11 @@ GEN_STS(stw, st32, 0x04, PPC_INTEGER) #if defined(TARGET_PPC64) GEN_STUX(std, st64, 0x15, 0x05, PPC_64B) GEN_STX(std, st64, 0x15, 0x04, PPC_64B) -GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX) +GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE) +GEN_STX_HVRM(stdcix, st64, 0x15, 0x1f, PPC_CILDST) +GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST) +GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST) +GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST) #endif GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER) GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER) @@ -11557,13 +11554,14 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.spr_cb = env->spr_cb; ctx.pr = msr_pr; ctx.mem_idx = env->dmmu_idx; + ctx.dr = msr_dr; #if !defined(CONFIG_USER_ONLY) ctx.hv = msr_hv || !env->has_hv_mode; #endif ctx.insns_flags = env->insns_flags; ctx.insns_flags2 = env->insns_flags2; ctx.access_type = -1; - ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0; + ctx.le_mode = !!(env->hflags & (1 << MSR_LE)); ctx.default_tcg_memop_mask = ctx.le_mode ? MO_LE : MO_BE; #if defined(TARGET_PPC64) ctx.sf_mode = msr_is_64bit(env, env->msr); @@ -11574,25 +11572,25 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) (env->mmu_model & POWERPC_MMU_64B)) ctx.lazy_tlb_flush = true; - ctx.fpu_enabled = msr_fp; + ctx.fpu_enabled = !!msr_fp; if ((env->flags & POWERPC_FLAG_SPE) && msr_spe) - ctx.spe_enabled = msr_spe; + ctx.spe_enabled = !!msr_spe; else - ctx.spe_enabled = 0; + ctx.spe_enabled = false; if ((env->flags & POWERPC_FLAG_VRE) && msr_vr) - ctx.altivec_enabled = msr_vr; + ctx.altivec_enabled = !!msr_vr; else - ctx.altivec_enabled = 0; + ctx.altivec_enabled = false; if ((env->flags & POWERPC_FLAG_VSX) && msr_vsx) { - ctx.vsx_enabled = msr_vsx; + ctx.vsx_enabled = !!msr_vsx; } else { - ctx.vsx_enabled = 0; + ctx.vsx_enabled = false; } #if defined(TARGET_PPC64) if ((env->flags & POWERPC_FLAG_TM) && msr_tm) { - ctx.tm_enabled = msr_tm; + ctx.tm_enabled = !!msr_tm; } else { - ctx.tm_enabled = 0; + ctx.tm_enabled = false; } #endif if ((env->flags & POWERPC_FLAG_SE) && msr_se) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ca894ff4af..08bdd07751 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1179,23 +1179,32 @@ static void gen_spr_amr(CPUPPCState *env, bool has_iamr) } #endif /* TARGET_PPC64 */ +#ifndef CONFIG_USER_ONLY +static void spr_read_thrm(DisasContext *ctx, int gprn, int sprn) +{ + gen_helper_fixup_thrm(cpu_env); + gen_load_spr(cpu_gpr[gprn], sprn); + spr_load_dump_spr(sprn); +} +#endif /* !CONFIG_USER_ONLY */ + static void gen_spr_thrm (CPUPPCState *env) { /* Thermal management */ /* XXX : not implemented */ spr_register(env, SPR_THRM1, "THRM1", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_thrm, &spr_write_generic, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_THRM2, "THRM2", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_thrm, &spr_write_generic, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_THRM3, "THRM3", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_thrm, &spr_write_generic, 0x00000000); } @@ -3171,18 +3180,30 @@ static void init_excp_POWER7 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_HDECR] = 0x00000980; env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_HDSI] = 0x00000E00; + env->excp_vectors[POWERPC_EXCP_HISI] = 0x00000E20; + env->excp_vectors[POWERPC_EXCP_HV_EMU] = 0x00000E40; + env->excp_vectors[POWERPC_EXCP_HV_MAINT] = 0x00000E60; env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; env->excp_vectors[POWERPC_EXCP_VSXU] = 0x00000F40; - env->excp_vectors[POWERPC_EXCP_FU] = 0x00000F60; - env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; - env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; - env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; - env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800; /* Hardware reset vector */ env->hreset_vector = 0x0000000000000100ULL; #endif } + +static void init_excp_POWER8(CPUPPCState *env) +{ + init_excp_POWER7(env); + +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_SDOOR] = 0x00000A00; + env->excp_vectors[POWERPC_EXCP_FU] = 0x00000F60; + env->excp_vectors[POWERPC_EXCP_HV_FU] = 0x00000F80; + env->excp_vectors[POWERPC_EXCP_SDOOR_HV] = 0x00000E80; +#endif +} + #endif /*****************************************************************************/ @@ -8123,10 +8144,13 @@ static void init_proc_book3s_64(CPUPPCState *env, int version) ppc970_irq_init(ppc_env_get_cpu(env)); break; case BOOK3S_CPU_POWER7: - case BOOK3S_CPU_POWER8: init_excp_POWER7(env); ppcPOWER7_irq_init(ppc_env_get_cpu(env)); break; + case BOOK3S_CPU_POWER8: + init_excp_POWER8(env); + ppcPOWER7_irq_init(ppc_env_get_cpu(env)); + break; default: g_assert_not_reached(); } @@ -8356,10 +8380,45 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr) return false; } +static bool cpu_has_work_POWER7(CPUState *cs) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + if (cs->halted) { + if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { + return false; + } + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) { + return true; + } + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) { + return true; + } + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK)) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { + return true; + } + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HMI)) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { + return true; + } + if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { + return true; + } + return false; + } else { + return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); + } +} + POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + CPUClass *cc = CPU_CLASS(oc); dc->fw_name = "PowerPC,POWER7"; dc->desc = "POWER7"; @@ -8369,6 +8428,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05; pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; + cc->has_work = cpu_has_work_POWER7; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -8380,11 +8440,13 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI | - PPC_POPCNTB | PPC_POPCNTWD; + PPC_POPCNTB | PPC_POPCNTWD | + PPC_CILDST; pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 | PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | - PPC2_FP_TST_ISA206 | PPC2_FP_CVT_S64; + PPC2_FP_TST_ISA206 | PPC2_FP_CVT_S64 | + PPC2_PM_ISA206; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_VR) | (1ull << MSR_VSX) | @@ -8437,10 +8499,53 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr) return false; } +static bool cpu_has_work_POWER8(CPUState *cs) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + if (cs->halted) { + if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { + return false; + } + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) { + return true; + } + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) { + return true; + } + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK)) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { + return true; + } + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HMI)) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { + return true; + } + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) { + return true; + } + if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) { + return true; + } + if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { + return true; + } + return false; + } else { + return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); + } +} + POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + CPUClass *cc = CPU_CLASS(oc); dc->fw_name = "PowerPC,POWER8"; dc->desc = "POWER8"; @@ -8450,6 +8555,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05; pcc->init_proc = init_proc_POWER8; pcc->check_pow = check_pow_nocheck; + cc->has_work = cpu_has_work_POWER8; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -8461,14 +8567,15 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI | - PPC_POPCNTB | PPC_POPCNTWD; + PPC_POPCNTB | PPC_POPCNTWD | + PPC_CILDST; pcc->insns_flags2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX | PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | - PPC2_TM; + PPC2_TM | PPC2_PM_ISA206; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_SHV) | (1ull << MSR_TM) | @@ -8509,6 +8616,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) void cpu_ppc_set_papr(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; + ppc_spr_t *lpcr = &env->spr_cb[SPR_LPCR]; ppc_spr_t *amor = &env->spr_cb[SPR_AMOR]; /* PAPR always has exception vectors in RAM not ROM. To ensure this, @@ -8518,6 +8626,26 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu) */ env->msr_mask &= ~((1ull << MSR_EP) | MSR_HVB); + /* Set emulated LPCR to not send interrupts to hypervisor. Note that + * under KVM, the actual HW LPCR will be set differently by KVM itself, + * the settings below ensure proper operations with TCG in absence of + * a real hypervisor + */ + lpcr->default_value &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV); + lpcr->default_value |= LPCR_LPES0 | LPCR_LPES1; + + /* P7 and P8 has slightly different PECE bits, mostly because P8 adds + * bit 47 and 48 which are reserved on P7. Here we set them all, which + * will work as expected for both implementations + */ + lpcr->default_value |= LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 | + LPCR_P8_PECE3 | LPCR_P8_PECE4; + + /* We should be followed by a CPU reset but update the active value + * just in case... + */ + env->spr[SPR_LPCR] = lpcr->default_value; + /* Set a full AMOR so guest can use the AMR as it sees fit */ env->spr[SPR_AMOR] = amor->default_value = 0xffffffffffffffffull; |