aboutsummaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/cpu-models.c3
-rw-r--r--target-ppc/cpu-models.h2
-rw-r--r--target-ppc/cpu.h8
-rw-r--r--target-ppc/kvm.c421
-rw-r--r--target-ppc/kvm_ppc.h6
-rw-r--r--target-ppc/mmu-hash64.c81
-rw-r--r--target-ppc/mmu-hash64.h11
-rw-r--r--target-ppc/mmu_helper.c13
-rw-r--r--target-ppc/translate_init.c48
9 files changed, 364 insertions, 229 deletions
diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c
index ed005d7..5209e63 100644
--- a/target-ppc/cpu-models.c
+++ b/target-ppc/cpu-models.c
@@ -1143,6 +1143,8 @@
"POWER8E v2.1")
POWERPC_DEF("POWER8_v2.0", CPU_POWERPC_POWER8_v20, POWER8,
"POWER8 v2.0")
+ POWERPC_DEF("POWER8NVL_v1.0",CPU_POWERPC_POWER8NVL_v10, POWER8,
+ "POWER8NVL v1.0")
POWERPC_DEF("970_v2.2", CPU_POWERPC_970_v22, 970,
"PowerPC 970 v2.2")
POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970,
@@ -1392,6 +1394,7 @@ PowerPCCPUAlias ppc_cpu_aliases[] = {
{ "POWER7+", "POWER7+_v2.1" },
{ "POWER8E", "POWER8E_v2.1" },
{ "POWER8", "POWER8_v2.0" },
+ { "POWER8NVL", "POWER8NVL_v1.0" },
{ "970", "970_v2.2" },
{ "970fx", "970fx_v3.1" },
{ "970mp", "970mp_v1.1" },
diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h
index 2992427..f21a44c 100644
--- a/target-ppc/cpu-models.h
+++ b/target-ppc/cpu-models.h
@@ -560,6 +560,8 @@ enum {
CPU_POWERPC_POWER8E_v21 = 0x004B0201,
CPU_POWERPC_POWER8_BASE = 0x004D0000,
CPU_POWERPC_POWER8_v20 = 0x004D0200,
+ CPU_POWERPC_POWER8NVL_BASE = 0x004C0000,
+ CPU_POWERPC_POWER8NVL_v10 = 0x004C0100,
CPU_POWERPC_970_v22 = 0x00390202,
CPU_POWERPC_970FX_v10 = 0x00391100,
CPU_POWERPC_970FX_v20 = 0x003C0200,
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2b10597..8d90d86 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1380,6 +1380,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
#define SPR_UAMOR (0x09D)
#define SPR_MPC_ICTRL (0x09E)
#define SPR_MPC_BAR (0x09F)
+#define SPR_PSPB (0x09F)
#define SPR_VRSAVE (0x100)
#define SPR_USPRG0 (0x100)
#define SPR_USPRG1 (0x101)
@@ -1563,6 +1564,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
#define SPR_PERF0 (0x300)
#define SPR_RCPU_MI_RBA0 (0x300)
#define SPR_MPC_MI_CTR (0x300)
+#define SPR_POWER_USIER (0x300)
#define SPR_PERF1 (0x301)
#define SPR_RCPU_MI_RBA1 (0x301)
#define SPR_POWER_UMMCR2 (0x301)
@@ -1612,6 +1614,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
#define SPR_PERFF (0x30F)
#define SPR_MPC_MD_TW (0x30F)
#define SPR_UPERF0 (0x310)
+#define SPR_POWER_SIER (0x310)
#define SPR_UPERF1 (0x311)
#define SPR_POWER_MMCR2 (0x311)
#define SPR_UPERF2 (0x312)
@@ -1673,7 +1676,12 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
#define SPR_440_ITV2 (0x376)
#define SPR_440_ITV3 (0x377)
#define SPR_440_CCR1 (0x378)
+#define SPR_TACR (0x378)
+#define SPR_TCSCR (0x379)
+#define SPR_CSIGR (0x37a)
#define SPR_DCRIPR (0x37B)
+#define SPR_POWER_SPMC1 (0x37C)
+#define SPR_POWER_SPMC2 (0x37D)
#define SPR_POWER_MMCRS (0x37E)
#define SPR_PPR (0x380)
#define SPR_750_GQR0 (0x390)
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index d67c169..776336b 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -867,6 +867,44 @@ static int kvm_put_vpa(CPUState *cs)
}
#endif /* TARGET_PPC64 */
+int kvmppc_put_books_sregs(PowerPCCPU *cpu)
+{
+ CPUPPCState *env = &cpu->env;
+ struct kvm_sregs sregs;
+ int i;
+
+ sregs.pvr = env->spr[SPR_PVR];
+
+ sregs.u.s.sdr1 = env->spr[SPR_SDR1];
+
+ /* Sync SLB */
+#ifdef TARGET_PPC64
+ for (i = 0; i < ARRAY_SIZE(env->slb); i++) {
+ sregs.u.s.ppc64.slb[i].slbe = env->slb[i].esid;
+ if (env->slb[i].esid & SLB_ESID_V) {
+ sregs.u.s.ppc64.slb[i].slbe |= i;
+ }
+ sregs.u.s.ppc64.slb[i].slbv = env->slb[i].vsid;
+ }
+#endif
+
+ /* Sync SRs */
+ for (i = 0; i < 16; i++) {
+ sregs.u.s.ppc32.sr[i] = env->sr[i];
+ }
+
+ /* Sync BATs */
+ for (i = 0; i < 8; i++) {
+ /* Beware. We have to swap upper and lower bits here */
+ sregs.u.s.ppc32.dbat[i] = ((uint64_t)env->DBAT[0][i] << 32)
+ | env->DBAT[1][i];
+ sregs.u.s.ppc32.ibat[i] = ((uint64_t)env->IBAT[0][i] << 32)
+ | env->IBAT[1][i];
+ }
+
+ return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS, &sregs);
+}
+
int kvm_arch_put_registers(CPUState *cs, int level)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -920,39 +958,8 @@ int kvm_arch_put_registers(CPUState *cs, int level)
}
if (cap_segstate && (level >= KVM_PUT_RESET_STATE)) {
- struct kvm_sregs sregs;
-
- sregs.pvr = env->spr[SPR_PVR];
-
- sregs.u.s.sdr1 = env->spr[SPR_SDR1];
-
- /* Sync SLB */
-#ifdef TARGET_PPC64
- for (i = 0; i < ARRAY_SIZE(env->slb); i++) {
- sregs.u.s.ppc64.slb[i].slbe = env->slb[i].esid;
- if (env->slb[i].esid & SLB_ESID_V) {
- sregs.u.s.ppc64.slb[i].slbe |= i;
- }
- sregs.u.s.ppc64.slb[i].slbv = env->slb[i].vsid;
- }
-#endif
-
- /* Sync SRs */
- for (i = 0; i < 16; i++) {
- sregs.u.s.ppc32.sr[i] = env->sr[i];
- }
-
- /* Sync BATs */
- for (i = 0; i < 8; i++) {
- /* Beware. We have to swap upper and lower bits here */
- sregs.u.s.ppc32.dbat[i] = ((uint64_t)env->DBAT[0][i] << 32)
- | env->DBAT[1][i];
- sregs.u.s.ppc32.ibat[i] = ((uint64_t)env->IBAT[0][i] << 32)
- | env->IBAT[1][i];
- }
-
- ret = kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs);
- if (ret) {
+ ret = kvmppc_put_books_sregs(cpu);
+ if (ret < 0) {
return ret;
}
}
@@ -1014,12 +1021,197 @@ static void kvm_sync_excp(CPUPPCState *env, int vector, int ivor)
env->excp_vectors[vector] = env->spr[ivor] + env->spr[SPR_BOOKE_IVPR];
}
+static int kvmppc_get_booke_sregs(PowerPCCPU *cpu)
+{
+ CPUPPCState *env = &cpu->env;
+ struct kvm_sregs sregs;
+ int ret;
+
+ ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_SREGS, &sregs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (sregs.u.e.features & KVM_SREGS_E_BASE) {
+ env->spr[SPR_BOOKE_CSRR0] = sregs.u.e.csrr0;
+ env->spr[SPR_BOOKE_CSRR1] = sregs.u.e.csrr1;
+ env->spr[SPR_BOOKE_ESR] = sregs.u.e.esr;
+ env->spr[SPR_BOOKE_DEAR] = sregs.u.e.dear;
+ env->spr[SPR_BOOKE_MCSR] = sregs.u.e.mcsr;
+ env->spr[SPR_BOOKE_TSR] = sregs.u.e.tsr;
+ env->spr[SPR_BOOKE_TCR] = sregs.u.e.tcr;
+ env->spr[SPR_DECR] = sregs.u.e.dec;
+ env->spr[SPR_TBL] = sregs.u.e.tb & 0xffffffff;
+ env->spr[SPR_TBU] = sregs.u.e.tb >> 32;
+ env->spr[SPR_VRSAVE] = sregs.u.e.vrsave;
+ }
+
+ if (sregs.u.e.features & KVM_SREGS_E_ARCH206) {
+ env->spr[SPR_BOOKE_PIR] = sregs.u.e.pir;
+ env->spr[SPR_BOOKE_MCSRR0] = sregs.u.e.mcsrr0;
+ env->spr[SPR_BOOKE_MCSRR1] = sregs.u.e.mcsrr1;
+ env->spr[SPR_BOOKE_DECAR] = sregs.u.e.decar;
+ env->spr[SPR_BOOKE_IVPR] = sregs.u.e.ivpr;
+ }
+
+ if (sregs.u.e.features & KVM_SREGS_E_64) {
+ env->spr[SPR_BOOKE_EPCR] = sregs.u.e.epcr;
+ }
+
+ if (sregs.u.e.features & KVM_SREGS_E_SPRG8) {
+ env->spr[SPR_BOOKE_SPRG8] = sregs.u.e.sprg8;
+ }
+
+ if (sregs.u.e.features & KVM_SREGS_E_IVOR) {
+ env->spr[SPR_BOOKE_IVOR0] = sregs.u.e.ivor_low[0];
+ kvm_sync_excp(env, POWERPC_EXCP_CRITICAL, SPR_BOOKE_IVOR0);
+ env->spr[SPR_BOOKE_IVOR1] = sregs.u.e.ivor_low[1];
+ kvm_sync_excp(env, POWERPC_EXCP_MCHECK, SPR_BOOKE_IVOR1);
+ env->spr[SPR_BOOKE_IVOR2] = sregs.u.e.ivor_low[2];
+ kvm_sync_excp(env, POWERPC_EXCP_DSI, SPR_BOOKE_IVOR2);
+ env->spr[SPR_BOOKE_IVOR3] = sregs.u.e.ivor_low[3];
+ kvm_sync_excp(env, POWERPC_EXCP_ISI, SPR_BOOKE_IVOR3);
+ env->spr[SPR_BOOKE_IVOR4] = sregs.u.e.ivor_low[4];
+ kvm_sync_excp(env, POWERPC_EXCP_EXTERNAL, SPR_BOOKE_IVOR4);
+ env->spr[SPR_BOOKE_IVOR5] = sregs.u.e.ivor_low[5];
+ kvm_sync_excp(env, POWERPC_EXCP_ALIGN, SPR_BOOKE_IVOR5);
+ env->spr[SPR_BOOKE_IVOR6] = sregs.u.e.ivor_low[6];
+ kvm_sync_excp(env, POWERPC_EXCP_PROGRAM, SPR_BOOKE_IVOR6);
+ env->spr[SPR_BOOKE_IVOR7] = sregs.u.e.ivor_low[7];
+ kvm_sync_excp(env, POWERPC_EXCP_FPU, SPR_BOOKE_IVOR7);
+ env->spr[SPR_BOOKE_IVOR8] = sregs.u.e.ivor_low[8];
+ kvm_sync_excp(env, POWERPC_EXCP_SYSCALL, SPR_BOOKE_IVOR8);
+ env->spr[SPR_BOOKE_IVOR9] = sregs.u.e.ivor_low[9];
+ kvm_sync_excp(env, POWERPC_EXCP_APU, SPR_BOOKE_IVOR9);
+ env->spr[SPR_BOOKE_IVOR10] = sregs.u.e.ivor_low[10];
+ kvm_sync_excp(env, POWERPC_EXCP_DECR, SPR_BOOKE_IVOR10);
+ env->spr[SPR_BOOKE_IVOR11] = sregs.u.e.ivor_low[11];
+ kvm_sync_excp(env, POWERPC_EXCP_FIT, SPR_BOOKE_IVOR11);
+ env->spr[SPR_BOOKE_IVOR12] = sregs.u.e.ivor_low[12];
+ kvm_sync_excp(env, POWERPC_EXCP_WDT, SPR_BOOKE_IVOR12);
+ env->spr[SPR_BOOKE_IVOR13] = sregs.u.e.ivor_low[13];
+ kvm_sync_excp(env, POWERPC_EXCP_DTLB, SPR_BOOKE_IVOR13);
+ env->spr[SPR_BOOKE_IVOR14] = sregs.u.e.ivor_low[14];
+ kvm_sync_excp(env, POWERPC_EXCP_ITLB, SPR_BOOKE_IVOR14);
+ env->spr[SPR_BOOKE_IVOR15] = sregs.u.e.ivor_low[15];
+ kvm_sync_excp(env, POWERPC_EXCP_DEBUG, SPR_BOOKE_IVOR15);
+
+ if (sregs.u.e.features & KVM_SREGS_E_SPE) {
+ env->spr[SPR_BOOKE_IVOR32] = sregs.u.e.ivor_high[0];
+ kvm_sync_excp(env, POWERPC_EXCP_SPEU, SPR_BOOKE_IVOR32);
+ env->spr[SPR_BOOKE_IVOR33] = sregs.u.e.ivor_high[1];
+ kvm_sync_excp(env, POWERPC_EXCP_EFPDI, SPR_BOOKE_IVOR33);
+ env->spr[SPR_BOOKE_IVOR34] = sregs.u.e.ivor_high[2];
+ kvm_sync_excp(env, POWERPC_EXCP_EFPRI, SPR_BOOKE_IVOR34);
+ }
+
+ if (sregs.u.e.features & KVM_SREGS_E_PM) {
+ env->spr[SPR_BOOKE_IVOR35] = sregs.u.e.ivor_high[3];
+ kvm_sync_excp(env, POWERPC_EXCP_EPERFM, SPR_BOOKE_IVOR35);
+ }
+
+ if (sregs.u.e.features & KVM_SREGS_E_PC) {
+ env->spr[SPR_BOOKE_IVOR36] = sregs.u.e.ivor_high[4];
+ kvm_sync_excp(env, POWERPC_EXCP_DOORI, SPR_BOOKE_IVOR36);
+ env->spr[SPR_BOOKE_IVOR37] = sregs.u.e.ivor_high[5];
+ kvm_sync_excp(env, POWERPC_EXCP_DOORCI, SPR_BOOKE_IVOR37);
+ }
+ }
+
+ if (sregs.u.e.features & KVM_SREGS_E_ARCH206_MMU) {
+ env->spr[SPR_BOOKE_MAS0] = sregs.u.e.mas0;
+ env->spr[SPR_BOOKE_MAS1] = sregs.u.e.mas1;
+ env->spr[SPR_BOOKE_MAS2] = sregs.u.e.mas2;
+ env->spr[SPR_BOOKE_MAS3] = sregs.u.e.mas7_3 & 0xffffffff;
+ env->spr[SPR_BOOKE_MAS4] = sregs.u.e.mas4;
+ env->spr[SPR_BOOKE_MAS6] = sregs.u.e.mas6;
+ env->spr[SPR_BOOKE_MAS7] = sregs.u.e.mas7_3 >> 32;
+ env->spr[SPR_MMUCFG] = sregs.u.e.mmucfg;
+ env->spr[SPR_BOOKE_TLB0CFG] = sregs.u.e.tlbcfg[0];
+ env->spr[SPR_BOOKE_TLB1CFG] = sregs.u.e.tlbcfg[1];
+ }
+
+ if (sregs.u.e.features & KVM_SREGS_EXP) {
+ env->spr[SPR_BOOKE_EPR] = sregs.u.e.epr;
+ }
+
+ if (sregs.u.e.features & KVM_SREGS_E_PD) {
+ env->spr[SPR_BOOKE_EPLC] = sregs.u.e.eplc;
+ env->spr[SPR_BOOKE_EPSC] = sregs.u.e.epsc;
+ }
+
+ if (sregs.u.e.impl_id == KVM_SREGS_E_IMPL_FSL) {
+ env->spr[SPR_E500_SVR] = sregs.u.e.impl.fsl.svr;
+ env->spr[SPR_Exxx_MCAR] = sregs.u.e.impl.fsl.mcar;
+ env->spr[SPR_HID0] = sregs.u.e.impl.fsl.hid0;
+
+ if (sregs.u.e.impl.fsl.features & KVM_SREGS_E_FSL_PIDn) {
+ env->spr[SPR_BOOKE_PID1] = sregs.u.e.impl.fsl.pid1;
+ env->spr[SPR_BOOKE_PID2] = sregs.u.e.impl.fsl.pid2;
+ }
+ }
+
+ return 0;
+}
+
+static int kvmppc_get_books_sregs(PowerPCCPU *cpu)
+{
+ CPUPPCState *env = &cpu->env;
+ struct kvm_sregs sregs;
+ int ret;
+ int i;
+
+ ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_SREGS, &sregs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (!env->external_htab) {
+ ppc_store_sdr1(env, sregs.u.s.sdr1);
+ }
+
+ /* Sync SLB */
+#ifdef TARGET_PPC64
+ /*
+ * The packed SLB array we get from KVM_GET_SREGS only contains
+ * information about valid entries. So we flush our internal copy
+ * to get rid of stale ones, then put all valid SLB entries back
+ * in.
+ */
+ memset(env->slb, 0, sizeof(env->slb));
+ for (i = 0; i < ARRAY_SIZE(env->slb); i++) {
+ target_ulong rb = sregs.u.s.ppc64.slb[i].slbe;
+ target_ulong rs = sregs.u.s.ppc64.slb[i].slbv;
+ /*
+ * Only restore valid entries
+ */
+ if (rb & SLB_ESID_V) {
+ ppc_store_slb(cpu, rb & 0xfff, rb & ~0xfffULL, rs);
+ }
+ }
+#endif
+
+ /* Sync SRs */
+ for (i = 0; i < 16; i++) {
+ env->sr[i] = sregs.u.s.ppc32.sr[i];
+ }
+
+ /* Sync BATs */
+ for (i = 0; i < 8; i++) {
+ env->DBAT[0][i] = sregs.u.s.ppc32.dbat[i] & 0xffffffff;
+ env->DBAT[1][i] = sregs.u.s.ppc32.dbat[i] >> 32;
+ env->IBAT[0][i] = sregs.u.s.ppc32.ibat[i] & 0xffffffff;
+ env->IBAT[1][i] = sregs.u.s.ppc32.ibat[i] >> 32;
+ }
+
+ return 0;
+}
+
int kvm_arch_get_registers(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
struct kvm_regs regs;
- struct kvm_sregs sregs;
uint32_t cr;
int i, ret;
@@ -1059,174 +1251,17 @@ int kvm_arch_get_registers(CPUState *cs)
kvm_get_fp(cs);
if (cap_booke_sregs) {
- ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs);
+ ret = kvmppc_get_booke_sregs(cpu);
if (ret < 0) {
return ret;
}
-
- if (sregs.u.e.features & KVM_SREGS_E_BASE) {
- env->spr[SPR_BOOKE_CSRR0] = sregs.u.e.csrr0;
- env->spr[SPR_BOOKE_CSRR1] = sregs.u.e.csrr1;
- env->spr[SPR_BOOKE_ESR] = sregs.u.e.esr;
- env->spr[SPR_BOOKE_DEAR] = sregs.u.e.dear;
- env->spr[SPR_BOOKE_MCSR] = sregs.u.e.mcsr;
- env->spr[SPR_BOOKE_TSR] = sregs.u.e.tsr;
- env->spr[SPR_BOOKE_TCR] = sregs.u.e.tcr;
- env->spr[SPR_DECR] = sregs.u.e.dec;
- env->spr[SPR_TBL] = sregs.u.e.tb & 0xffffffff;
- env->spr[SPR_TBU] = sregs.u.e.tb >> 32;
- env->spr[SPR_VRSAVE] = sregs.u.e.vrsave;
- }
-
- if (sregs.u.e.features & KVM_SREGS_E_ARCH206) {
- env->spr[SPR_BOOKE_PIR] = sregs.u.e.pir;
- env->spr[SPR_BOOKE_MCSRR0] = sregs.u.e.mcsrr0;
- env->spr[SPR_BOOKE_MCSRR1] = sregs.u.e.mcsrr1;
- env->spr[SPR_BOOKE_DECAR] = sregs.u.e.decar;
- env->spr[SPR_BOOKE_IVPR] = sregs.u.e.ivpr;
- }
-
- if (sregs.u.e.features & KVM_SREGS_E_64) {
- env->spr[SPR_BOOKE_EPCR] = sregs.u.e.epcr;
- }
-
- if (sregs.u.e.features & KVM_SREGS_E_SPRG8) {
- env->spr[SPR_BOOKE_SPRG8] = sregs.u.e.sprg8;
- }
-
- if (sregs.u.e.features & KVM_SREGS_E_IVOR) {
- env->spr[SPR_BOOKE_IVOR0] = sregs.u.e.ivor_low[0];
- kvm_sync_excp(env, POWERPC_EXCP_CRITICAL, SPR_BOOKE_IVOR0);
- env->spr[SPR_BOOKE_IVOR1] = sregs.u.e.ivor_low[1];
- kvm_sync_excp(env, POWERPC_EXCP_MCHECK, SPR_BOOKE_IVOR1);
- env->spr[SPR_BOOKE_IVOR2] = sregs.u.e.ivor_low[2];
- kvm_sync_excp(env, POWERPC_EXCP_DSI, SPR_BOOKE_IVOR2);
- env->spr[SPR_BOOKE_IVOR3] = sregs.u.e.ivor_low[3];
- kvm_sync_excp(env, POWERPC_EXCP_ISI, SPR_BOOKE_IVOR3);
- env->spr[SPR_BOOKE_IVOR4] = sregs.u.e.ivor_low[4];
- kvm_sync_excp(env, POWERPC_EXCP_EXTERNAL, SPR_BOOKE_IVOR4);
- env->spr[SPR_BOOKE_IVOR5] = sregs.u.e.ivor_low[5];
- kvm_sync_excp(env, POWERPC_EXCP_ALIGN, SPR_BOOKE_IVOR5);
- env->spr[SPR_BOOKE_IVOR6] = sregs.u.e.ivor_low[6];
- kvm_sync_excp(env, POWERPC_EXCP_PROGRAM, SPR_BOOKE_IVOR6);
- env->spr[SPR_BOOKE_IVOR7] = sregs.u.e.ivor_low[7];
- kvm_sync_excp(env, POWERPC_EXCP_FPU, SPR_BOOKE_IVOR7);
- env->spr[SPR_BOOKE_IVOR8] = sregs.u.e.ivor_low[8];
- kvm_sync_excp(env, POWERPC_EXCP_SYSCALL, SPR_BOOKE_IVOR8);
- env->spr[SPR_BOOKE_IVOR9] = sregs.u.e.ivor_low[9];
- kvm_sync_excp(env, POWERPC_EXCP_APU, SPR_BOOKE_IVOR9);
- env->spr[SPR_BOOKE_IVOR10] = sregs.u.e.ivor_low[10];
- kvm_sync_excp(env, POWERPC_EXCP_DECR, SPR_BOOKE_IVOR10);
- env->spr[SPR_BOOKE_IVOR11] = sregs.u.e.ivor_low[11];
- kvm_sync_excp(env, POWERPC_EXCP_FIT, SPR_BOOKE_IVOR11);
- env->spr[SPR_BOOKE_IVOR12] = sregs.u.e.ivor_low[12];
- kvm_sync_excp(env, POWERPC_EXCP_WDT, SPR_BOOKE_IVOR12);
- env->spr[SPR_BOOKE_IVOR13] = sregs.u.e.ivor_low[13];
- kvm_sync_excp(env, POWERPC_EXCP_DTLB, SPR_BOOKE_IVOR13);
- env->spr[SPR_BOOKE_IVOR14] = sregs.u.e.ivor_low[14];
- kvm_sync_excp(env, POWERPC_EXCP_ITLB, SPR_BOOKE_IVOR14);
- env->spr[SPR_BOOKE_IVOR15] = sregs.u.e.ivor_low[15];
- kvm_sync_excp(env, POWERPC_EXCP_DEBUG, SPR_BOOKE_IVOR15);
-
- if (sregs.u.e.features & KVM_SREGS_E_SPE) {
- env->spr[SPR_BOOKE_IVOR32] = sregs.u.e.ivor_high[0];
- kvm_sync_excp(env, POWERPC_EXCP_SPEU, SPR_BOOKE_IVOR32);
- env->spr[SPR_BOOKE_IVOR33] = sregs.u.e.ivor_high[1];
- kvm_sync_excp(env, POWERPC_EXCP_EFPDI, SPR_BOOKE_IVOR33);
- env->spr[SPR_BOOKE_IVOR34] = sregs.u.e.ivor_high[2];
- kvm_sync_excp(env, POWERPC_EXCP_EFPRI, SPR_BOOKE_IVOR34);
- }
-
- if (sregs.u.e.features & KVM_SREGS_E_PM) {
- env->spr[SPR_BOOKE_IVOR35] = sregs.u.e.ivor_high[3];
- kvm_sync_excp(env, POWERPC_EXCP_EPERFM, SPR_BOOKE_IVOR35);
- }
-
- if (sregs.u.e.features & KVM_SREGS_E_PC) {
- env->spr[SPR_BOOKE_IVOR36] = sregs.u.e.ivor_high[4];
- kvm_sync_excp(env, POWERPC_EXCP_DOORI, SPR_BOOKE_IVOR36);
- env->spr[SPR_BOOKE_IVOR37] = sregs.u.e.ivor_high[5];
- kvm_sync_excp(env, POWERPC_EXCP_DOORCI, SPR_BOOKE_IVOR37);
- }
- }
-
- if (sregs.u.e.features & KVM_SREGS_E_ARCH206_MMU) {
- env->spr[SPR_BOOKE_MAS0] = sregs.u.e.mas0;
- env->spr[SPR_BOOKE_MAS1] = sregs.u.e.mas1;
- env->spr[SPR_BOOKE_MAS2] = sregs.u.e.mas2;
- env->spr[SPR_BOOKE_MAS3] = sregs.u.e.mas7_3 & 0xffffffff;
- env->spr[SPR_BOOKE_MAS4] = sregs.u.e.mas4;
- env->spr[SPR_BOOKE_MAS6] = sregs.u.e.mas6;
- env->spr[SPR_BOOKE_MAS7] = sregs.u.e.mas7_3 >> 32;
- env->spr[SPR_MMUCFG] = sregs.u.e.mmucfg;
- env->spr[SPR_BOOKE_TLB0CFG] = sregs.u.e.tlbcfg[0];
- env->spr[SPR_BOOKE_TLB1CFG] = sregs.u.e.tlbcfg[1];
- }
-
- if (sregs.u.e.features & KVM_SREGS_EXP) {
- env->spr[SPR_BOOKE_EPR] = sregs.u.e.epr;
- }
-
- if (sregs.u.e.features & KVM_SREGS_E_PD) {
- env->spr[SPR_BOOKE_EPLC] = sregs.u.e.eplc;
- env->spr[SPR_BOOKE_EPSC] = sregs.u.e.epsc;
- }
-
- if (sregs.u.e.impl_id == KVM_SREGS_E_IMPL_FSL) {
- env->spr[SPR_E500_SVR] = sregs.u.e.impl.fsl.svr;
- env->spr[SPR_Exxx_MCAR] = sregs.u.e.impl.fsl.mcar;
- env->spr[SPR_HID0] = sregs.u.e.impl.fsl.hid0;
-
- if (sregs.u.e.impl.fsl.features & KVM_SREGS_E_FSL_PIDn) {
- env->spr[SPR_BOOKE_PID1] = sregs.u.e.impl.fsl.pid1;
- env->spr[SPR_BOOKE_PID2] = sregs.u.e.impl.fsl.pid2;
- }
- }
}
if (cap_segstate) {
- ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs);
+ ret = kvmppc_get_books_sregs(cpu);
if (ret < 0) {
return ret;
}
-
- if (!env->external_htab) {
- ppc_store_sdr1(env, sregs.u.s.sdr1);
- }
-
- /* Sync SLB */
-#ifdef TARGET_PPC64
- /*
- * The packed SLB array we get from KVM_GET_SREGS only contains
- * information about valid entries. So we flush our internal
- * copy to get rid of stale ones, then put all valid SLB entries
- * back in.
- */
- memset(env->slb, 0, sizeof(env->slb));
- for (i = 0; i < ARRAY_SIZE(env->slb); i++) {
- target_ulong rb = sregs.u.s.ppc64.slb[i].slbe;
- target_ulong rs = sregs.u.s.ppc64.slb[i].slbv;
- /*
- * Only restore valid entries
- */
- if (rb & SLB_ESID_V) {
- ppc_store_slb(cpu, rb & 0xfff, rb & ~0xfffULL, rs);
- }
- }
-#endif
-
- /* Sync SRs */
- for (i = 0; i < 16; i++) {
- env->sr[i] = sregs.u.s.ppc32.sr[i];
- }
-
- /* Sync BATs */
- for (i = 0; i < 8; i++) {
- env->DBAT[0][i] = sregs.u.s.ppc32.dbat[i] & 0xffffffff;
- env->DBAT[1][i] = sregs.u.s.ppc32.dbat[i] >> 32;
- env->IBAT[0][i] = sregs.u.s.ppc32.ibat[i] & 0xffffffff;
- env->IBAT[1][i] = sregs.u.s.ppc32.ibat[i] >> 32;
- }
}
if (cap_hior) {
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index fd64c44..fc79312 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -55,6 +55,7 @@ void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
target_ulong pte0, target_ulong pte1);
bool kvmppc_has_cap_fixup_hcalls(void);
int kvmppc_enable_hwrng(void);
+int kvmppc_put_books_sregs(PowerPCCPU *cpu);
#else
@@ -246,6 +247,11 @@ static inline int kvmppc_enable_hwrng(void)
{
return -1;
}
+
+static inline int kvmppc_put_books_sregs(PowerPCCPU *cpu)
+{
+ abort();
+}
#endif
#ifndef CONFIG_KVM
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 9c58fbf..d175fda 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -36,10 +36,11 @@
#endif
/*
- * Used to indicate whether we have allocated htab in the
- * host kernel
+ * Used to indicate that a CPU has its hash page table (HPT) managed
+ * within the host kernel
*/
-bool kvmppc_kern_htab;
+#define MMU_HASH64_KVM_MANAGED_HPT ((void *)-1)
+
/*
* SLB handling
*/
@@ -258,6 +259,53 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
/*
* 64-bit hash table MMU handling
*/
+void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
+ Error **errp)
+{
+ CPUPPCState *env = &cpu->env;
+ target_ulong htabsize = value & SDR_64_HTABSIZE;
+
+ env->spr[SPR_SDR1] = value;
+ if (htabsize > 28) {
+ error_setg(errp,
+ "Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1",
+ htabsize);
+ htabsize = 28;
+ }
+ env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
+ env->htab_base = value & SDR_64_HTABORG;
+}
+
+void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
+ Error **errp)
+{
+ CPUPPCState *env = &cpu->env;
+ Error *local_err = NULL;
+
+ cpu_synchronize_state(CPU(cpu));
+
+ if (hpt) {
+ env->external_htab = hpt;
+ } else {
+ env->external_htab = MMU_HASH64_KVM_MANAGED_HPT;
+ }
+ ppc_hash64_set_sdr1(cpu, (target_ulong)(uintptr_t)hpt | (shift - 18),
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* Not strictly necessary, but makes it clearer that an external
+ * htab is in use when debugging */
+ env->htab_base = -1;
+
+ if (kvm_enabled()) {
+ if (kvmppc_put_books_sregs(cpu) < 0) {
+ error_setg(errp, "Unable to update SDR1 in KVM");
+ }
+ }
+}
static int ppc_hash64_pte_prot(PowerPCCPU *cpu,
ppc_slb_t *slb, ppc_hash_pte64_t pte)
@@ -353,25 +401,16 @@ uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index)
hwaddr pte_offset;
pte_offset = pte_index * HASH_PTE_SIZE_64;
- if (kvmppc_kern_htab) {
+ if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
/*
* HTAB is controlled by KVM. Fetch the PTEG into a new buffer.
*/
token = kvmppc_hash64_read_pteg(cpu, pte_index);
- if (token) {
- return token;
- }
+ } else if (cpu->env.external_htab) {
/*
- * pteg read failed, even though we have allocated htab via
- * kvmppc_reset_htab.
+ * HTAB is controlled by QEMU. Just point to the internally
+ * accessible PTEG.
*/
- return 0;
- }
- /*
- * HTAB is controlled by QEMU. Just point to the internally
- * accessible PTEG.
- */
- if (cpu->env.external_htab) {
token = (uint64_t)(uintptr_t) cpu->env.external_htab + pte_offset;
} else if (cpu->env.htab_base) {
token = cpu->env.htab_base + pte_offset;
@@ -379,9 +418,9 @@ uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index)
return token;
}
-void ppc_hash64_stop_access(uint64_t token)
+void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token)
{
- if (kvmppc_kern_htab) {
+ if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
kvmppc_hash64_free_pteg(token);
}
}
@@ -410,11 +449,11 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
&& HPTE64_V_COMPARE(pte0, ptem)) {
pte->pte0 = pte0;
pte->pte1 = pte1;
- ppc_hash64_stop_access(token);
+ ppc_hash64_stop_access(cpu, token);
return (pte_index + i) * HASH_PTE_SIZE_64;
}
}
- ppc_hash64_stop_access(token);
+ ppc_hash64_stop_access(cpu, token);
/*
* We didn't find a valid entry.
*/
@@ -729,7 +768,7 @@ void ppc_hash64_store_hpte(PowerPCCPU *cpu,
{
CPUPPCState *env = &cpu->env;
- if (kvmppc_kern_htab) {
+ if (env->external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
return;
}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index e7d9925..9bf8b9b 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -90,10 +90,13 @@ unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
#define HPTE64_V_1TB_SEG 0x4000000000000000ULL
#define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL
+void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
+ Error **errp);
+void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
+ Error **errp);
-extern bool kvmppc_kern_htab;
uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index);
-void ppc_hash64_stop_access(uint64_t token);
+void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token);
static inline target_ulong ppc_hash64_load_hpte0(PowerPCCPU *cpu,
uint64_t token, int index)
@@ -102,7 +105,7 @@ static inline target_ulong ppc_hash64_load_hpte0(PowerPCCPU *cpu,
uint64_t addr;
addr = token + (index * HASH_PTE_SIZE_64);
- if (kvmppc_kern_htab || env->external_htab) {
+ if (env->external_htab) {
return ldq_p((const void *)(uintptr_t)addr);
} else {
return ldq_phys(CPU(cpu)->as, addr);
@@ -116,7 +119,7 @@ static inline target_ulong ppc_hash64_load_hpte1(PowerPCCPU *cpu,
uint64_t addr;
addr = token + (index * HASH_PTE_SIZE_64) + HASH_PTE_SIZE_64/2;
- if (kvmppc_kern_htab || env->external_htab) {
+ if (env->external_htab) {
return ldq_p((const void *)(uintptr_t)addr);
} else {
return ldq_phys(CPU(cpu)->as, addr);
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index e5ec8d6..fcb2cc5 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -2005,15 +2005,14 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
env->spr[SPR_SDR1] = value;
#if defined(TARGET_PPC64)
if (env->mmu_model & POWERPC_MMU_64) {
- target_ulong htabsize = value & SDR_64_HTABSIZE;
+ PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ Error *local_err = NULL;
- if (htabsize > 28) {
- fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
- " stored in SDR1\n", htabsize);
- htabsize = 28;
+ ppc_hash64_set_sdr1(cpu, value, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ error_free(local_err);
}
- env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
- env->htab_base = value & SDR_64_HTABORG;
} else
#endif /* defined(TARGET_PPC64) */
{
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index bd0cffc..fb206af 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -7603,6 +7603,30 @@ static void gen_spr_power8_pmu_sup(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_MMCRS, 0x00000000);
+ spr_register_kvm(env, SPR_POWER_SIER, "SIER",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_SIER, 0x00000000);
+ spr_register_kvm(env, SPR_POWER_SPMC1, "SPMC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_SPMC1, 0x00000000);
+ spr_register_kvm(env, SPR_POWER_SPMC2, "SPMC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_SPMC2, 0x00000000);
+ spr_register_kvm(env, SPR_TACR, "TACR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_TACR, 0x00000000);
+ spr_register_kvm(env, SPR_TCSCR, "TCSCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_TCSCR, 0x00000000);
+ spr_register_kvm(env, SPR_CSIGR, "CSIGR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_CSIGR, 0x00000000);
}
static void gen_spr_power8_pmu_user(CPUPPCState *env)
@@ -7611,6 +7635,10 @@ static void gen_spr_power8_pmu_user(CPUPPCState *env)
&spr_read_ureg, SPR_NOACCESS,
&spr_read_ureg, &spr_write_ureg,
0x00000000);
+ spr_register(env, SPR_POWER_USIER, "USIER",
+ &spr_read_generic, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
}
static void gen_spr_power5p_ear(CPUPPCState *env)
@@ -7714,10 +7742,10 @@ static void spr_write_tar(DisasContext *ctx, int sprn, int gprn)
static void gen_spr_power8_tce_address_control(CPUPPCState *env)
{
- spr_register(env, SPR_TAR, "TAR",
- &spr_read_tar, &spr_write_tar,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
+ spr_register_kvm(env, SPR_TAR, "TAR",
+ &spr_read_tar, &spr_write_tar,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_TAR, 0x00000000);
}
static void spr_read_tm(DisasContext *ctx, int gprn, int sprn)
@@ -7842,6 +7870,14 @@ static void gen_spr_power8_fscr(CPUPPCState *env)
KVM_REG_PPC_FSCR, initval);
}
+static void gen_spr_power8_pspb(CPUPPCState *env)
+{
+ spr_register_kvm(env, SPR_PSPB, "PSPB",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic32,
+ KVM_REG_PPC_PSPB, 0);
+}
+
static void init_proc_book3s_64(CPUPPCState *env, int version)
{
gen_spr_ne_601(env);
@@ -7892,6 +7928,7 @@ static void init_proc_book3s_64(CPUPPCState *env, int version)
gen_spr_power8_pmu_sup(env);
gen_spr_power8_pmu_user(env);
gen_spr_power8_tm(env);
+ gen_spr_power8_pspb(env);
gen_spr_vtb(env);
}
if (version < BOOK3S_CPU_POWER8) {
@@ -8219,6 +8256,9 @@ static void init_proc_POWER8(CPUPPCState *env)
static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr)
{
+ if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8NVL_BASE) {
+ return true;
+ }
if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8E_BASE) {
return true;
}