提交 c7288767 编写于 作者: P Peter Maydell

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: NPeter Maydell <peter.maydell@linaro.org>
......@@ -102,11 +102,15 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_PARAMETER;
}
} else {
target_ulong wimg_flags;
/* Looks like an IO address */
/* FIXME: What WIMG combinations could be sensible for IO?
* For now we allow WIMG=010x, but are there others? */
/* FIXME: Should we check against registered IO addresses? */
if ((ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)) != HPTE64_R_I) {
wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M));
if (wimg_flags != HPTE64_R_I &&
wimg_flags != (HPTE64_R_I | HPTE64_R_M)) {
return H_PARAMETER;
}
}
......
......@@ -149,6 +149,13 @@ static void spapr_tce_table_pre_save(void *opaque)
tcet->bus_offset, tcet->page_shift);
}
static uint64_t spapr_tce_get_min_page_size(MemoryRegion *iommu)
{
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
return 1ULL << tcet->page_shift;
}
static int spapr_tce_table_post_load(void *opaque, int version_id)
{
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque);
......@@ -228,6 +235,7 @@ static const VMStateDescription vmstate_spapr_tce_table = {
static MemoryRegionIOMMUOps spapr_iommu_ops = {
.translate = spapr_tce_translate_iommu,
.get_min_page_size = spapr_tce_get_min_page_size,
};
static int spapr_tce_table_realize(DeviceState *dev)
......
......@@ -321,11 +321,6 @@ out:
rcu_read_unlock();
}
static hwaddr vfio_container_granularity(VFIOContainer *container)
{
return (hwaddr)1 << ctz64(container->iova_pgsizes);
}
static void vfio_listener_region_add(MemoryListener *listener,
MemoryRegionSection *section)
{
......@@ -392,9 +387,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
memory_region_register_iommu_notifier(giommu->iommu, &giommu->n);
memory_region_iommu_replay(giommu->iommu, &giommu->n,
vfio_container_granularity(container),
false);
memory_region_iommu_replay(giommu->iommu, &giommu->n, false);
return;
}
......
......@@ -151,6 +151,8 @@ typedef struct MemoryRegionIOMMUOps MemoryRegionIOMMUOps;
struct MemoryRegionIOMMUOps {
/* Return a TLB entry that contains a given address. */
IOMMUTLBEntry (*translate)(MemoryRegion *iommu, hwaddr addr, bool is_write);
/* Returns minimum supported page size */
uint64_t (*get_min_page_size)(MemoryRegion *iommu);
};
typedef struct CoalescedMemoryRange CoalescedMemoryRange;
......@@ -572,6 +574,16 @@ static inline bool memory_region_is_iommu(MemoryRegion *mr)
}
/**
* memory_region_iommu_get_min_page_size: get minimum supported page size
* for an iommu
*
* Returns minimum supported page size for an iommu.
*
* @mr: the memory region being queried
*/
uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr);
/**
* memory_region_notify_iommu: notify a change in an IOMMU translation entry.
*
......@@ -596,16 +608,15 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr, Notifier *n);
/**
* memory_region_iommu_replay: replay existing IOMMU translations to
* a notifier
* a notifier with the minimum page granularity returned by
* mr->iommu_ops->get_page_size().
*
* @mr: the memory region to observe
* @n: the notifier to which to replay iommu mappings
* @granularity: Minimum page granularity to replay notifications for
* @is_write: Whether to treat the replay as a translate "write"
* through the iommu
*/
void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n,
hwaddr granularity, bool is_write);
void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n, bool is_write);
/**
* memory_region_unregister_iommu_notifier: unregister a notifier for
......
......@@ -1721,6 +1721,7 @@ void cpu_loop(CPUPPCState *env)
queue_signal(env, info.si_signo, &info);
break;
case POWERPC_EXCP_PROGRAM: /* Program exception */
case POWERPC_EXCP_HV_EMU: /* HV emulation */
/* XXX: check this */
switch (env->error_code & ~0xF) {
case POWERPC_EXCP_FP:
......
......@@ -1502,12 +1502,22 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr, Notifier *n)
notifier_list_add(&mr->iommu_notify, n);
}
void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n,
hwaddr granularity, bool is_write)
uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr)
{
hwaddr addr;
assert(memory_region_is_iommu(mr));
if (mr->iommu_ops && mr->iommu_ops->get_min_page_size) {
return mr->iommu_ops->get_min_page_size(mr);
}
return TARGET_PAGE_SIZE;
}
void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n, bool is_write)
{
hwaddr addr, granularity;
IOMMUTLBEntry iotlb;
granularity = memory_region_iommu_get_min_page_size(mr);
for (addr = 0; addr < memory_region_size(mr); addr += granularity) {
iotlb = mr->iommu_ops->translate(mr, addr, is_write);
if (iotlb.perm != IOMMU_NONE) {
......
......@@ -125,6 +125,15 @@ enum powerpc_excp_t {
POWERPC_EXCP_POWER8,
};
/*****************************************************************************/
/* 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;
......
......@@ -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) */
......
......@@ -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,7 +101,51 @@ 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
......@@ -117,6 +153,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
#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 */
......
......@@ -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)
......@@ -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)
......
......@@ -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;
}
}
......@@ -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;
}
......
此差异已折叠。
......@@ -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;
......
......@@ -259,11 +259,11 @@ check-qtest-ppc-y += tests/boot-order-test$(EXESUF)
check-qtest-ppc64-y += tests/boot-order-test$(EXESUF)
check-qtest-ppc64-y += tests/spapr-phb-test$(EXESUF)
gcov-files-ppc64-y += ppc64-softmmu/hw/ppc/spapr_pci.c
check-qtest-ppc-y = tests/prom-env-test$(EXESUF)
check-qtest-ppc64-y = tests/prom-env-test$(EXESUF)
check-qtest-sparc-y = tests/prom-env-test$(EXESUF)
check-qtest-ppc-y += tests/prom-env-test$(EXESUF)
check-qtest-ppc64-y += tests/prom-env-test$(EXESUF)
check-qtest-sparc-y += tests/prom-env-test$(EXESUF)
#Disabled for now, triggers a TCG bug on 32-bit hosts
#check-qtest-sparc64-y = tests/prom-env-test$(EXESUF)
#check-qtest-sparc64-y += tests/prom-env-test$(EXESUF)
check-qtest-microblazeel-y = $(check-qtest-microblaze-y)
check-qtest-xtensaeb-y = $(check-qtest-xtensa-y)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册