mirror of https://github.com/xemu-project/xemu.git
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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJXa3gJAAoJEGw4ysog2bOSzRQQAI0K+F2CoKuiGJ3csr40edlA rDvHJd0a3DvF5ez8YBY9iiG2nXaphz7LrsfkFUQ/UmqlIpVLNdJaJ8l/RnjwrVnP coJ9sFkzzARQF39BybGYPOVMalgi/MhnN/+zm87JaSD+C7gihG+ghYR4sgLHWalb xWDFLnZVg3uTC1IQzS14NMjqswQN1O0d9wyfYjBogAAEvP4daGKVTQCgpoVwGaXw JNE4Sm1vVIqJtiYr48V4cNVQWodpTMoHdVPJ6LPXWBlJMd3K5BEy3QsFc+jra+kG Uj8dayNJwu4CjIwDWz4kpL/H0XtLNxfC2/6n1khc53OEnG5SzrgN80yJBvAKzU5S KDQemwyOd3R2YTItkHR++QhLqHVx39Hr3BsFGXGyugAaczD7v4NLx87xmMEQOyQB ai+B4EpQqS/lEOCxyf7nRzgRxA5uB2My9L31peWt862G/LH+UixMWn7CwKW4aKul CuV4kqVdVQHrWe966HNYnDwfGpmaEXF9W5uLu7GenhFtW6R6IRhT1oORiyqHRfEi 9lTVx/vvHK2U3Ie3RCu3ZYuSbwDhP482J8ysfSo1iCkbSXHwNNACkLQmh0s/WmOs X2erIOUAja/Ku2DyZ6bXngXN/W/JR6Hw1IpEMeo6LxeK8VIm7F8PkCgrJCg88EEp ZFxGGYkc3HqksgJy1tuV =Da1O -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
c728876752
|
@ -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:
|
||||
|
|
16
memory.c
16
memory.c
|
@ -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;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue