aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/ppc/spapr.c60
-rw-r--r--hw/ppc/spapr_cpu_core.c17
-rw-r--r--hw/ppc/spapr_hcall.c3
-rw-r--r--target/ppc/cpu.h10
-rw-r--r--target/ppc/kvm.c2
-rw-r--r--target/ppc/machine.c4
-rw-r--r--target/ppc/mmu-hash32.h8
-rw-r--r--target/ppc/mmu-hash64.c99
-rw-r--r--target/ppc/mmu-hash64.h7
-rw-r--r--target/ppc/mmu_helper.c3
10 files changed, 125 insertions, 88 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 0b57aade3f..e0bb9bcb85 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1053,6 +1053,62 @@ static void close_htab_fd(sPAPRMachineState *spapr)
spapr->htab_fd = -1;
}
+static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+
+ return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
+}
+
+static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
+ hwaddr ptex, int n)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+ hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
+
+ if (!spapr->htab) {
+ /*
+ * HTAB is controlled by KVM. Fetch into temporary buffer
+ */
+ ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
+ kvmppc_read_hptes(hptes, ptex, n);
+ return hptes;
+ }
+
+ /*
+ * HTAB is controlled by QEMU. Just point to the internally
+ * accessible PTEG.
+ */
+ return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
+}
+
+static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
+ const ppc_hash_pte64_t *hptes,
+ hwaddr ptex, int n)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+
+ if (!spapr->htab) {
+ g_free((void *)hptes);
+ }
+
+ /* Nothing to do for qemu managed HPT */
+}
+
+static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex,
+ uint64_t pte0, uint64_t pte1)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+ hwaddr offset = ptex * HASH_PTE_SIZE_64;
+
+ if (!spapr->htab) {
+ kvmppc_write_hpte(ptex, pte0, pte1);
+ } else {
+ stq_p(spapr->htab + offset, pte0);
+ stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
+ }
+}
+
static int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
{
int shift;
@@ -2913,6 +2969,10 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
nc->nmi_monitor_handler = spapr_nmi;
smc->phb_placement = spapr_phb_placement;
vhc->hypercall = emulate_spapr_hypercall;
+ vhc->hpt_mask = spapr_hpt_mask;
+ vhc->map_hptes = spapr_map_hptes;
+ vhc->unmap_hptes = spapr_unmap_hptes;
+ vhc->store_hpte = spapr_store_hpte;
}
static const TypeInfo spapr_machine_info = {
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 76563c4182..ddb130f030 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -13,10 +13,12 @@
#include "hw/boards.h"
#include "qapi/error.h"
#include "sysemu/cpus.h"
+#include "sysemu/kvm.h"
#include "target/ppc/kvm_ppc.h"
#include "hw/ppc/ppc.h"
#include "target/ppc/mmu-hash64.h"
#include "sysemu/numa.h"
+#include "qemu/error-report.h"
static void spapr_cpu_reset(void *opaque)
{
@@ -34,8 +36,19 @@ static void spapr_cpu_reset(void *opaque)
env->spr[SPR_HIOR] = 0;
- ppc_hash64_set_external_hpt(cpu, spapr->htab, spapr->htab_shift,
- &error_fatal);
+ /*
+ * This is a hack for the benefit of KVM PR - it abuses the SDR1
+ * slot in kvm_sregs to communicate the userspace address of the
+ * HPT
+ */
+ if (kvm_enabled()) {
+ env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab
+ | (spapr->htab_shift - 18);
+ if (kvmppc_put_books_sregs(cpu) < 0) {
+ error_report("Unable to update SDR1 in KVM");
+ exit(1);
+ }
+ }
}
static void spapr_cpu_destroy(PowerPCCPU *cpu)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 85d96f6dc6..f05a90ed2c 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -326,7 +326,6 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- CPUPPCState *env = &cpu->env;
target_ulong flags = args[0];
target_ulong ptex = args[1];
uint8_t *hpte;
@@ -342,7 +341,7 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
n_entries = 4;
}
- hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64);
+ hpte = spapr->htab + (ptex * HASH_PTE_SIZE_64);
for (i = 0, ridx = 0; i < n_entries; i++) {
args[ridx++] = ldq_p(hpte);
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index aaf79f52b9..4e7fc2cfb6 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -999,8 +999,6 @@ struct CPUPPCState {
#endif
/* segment registers */
target_ulong sr[32];
- /* externally stored hash table */
- uint8_t *external_htab;
/* BATs */
uint32_t nb_BATs;
target_ulong DBAT[2][8];
@@ -1208,6 +1206,14 @@ struct PPCVirtualHypervisor {
struct PPCVirtualHypervisorClass {
InterfaceClass parent;
void (*hypercall)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu);
+ hwaddr (*hpt_mask)(PPCVirtualHypervisor *vhyp);
+ const ppc_hash_pte64_t *(*map_hptes)(PPCVirtualHypervisor *vhyp,
+ hwaddr ptex, int n);
+ void (*unmap_hptes)(PPCVirtualHypervisor *vhyp,
+ const ppc_hash_pte64_t *hptes,
+ hwaddr ptex, int n);
+ void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex,
+ uint64_t pte0, uint64_t pte1);
};
#define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor"
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 79c1da6638..acc40ece65 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -1251,7 +1251,7 @@ static int kvmppc_get_books_sregs(PowerPCCPU *cpu)
return ret;
}
- if (!env->external_htab) {
+ if (!cpu->vhyp) {
ppc_store_sdr1(env, sregs.u.s.sdr1);
}
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index 1ccbc8a960..6cb3a48db1 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -76,7 +76,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
qemu_get_betls(f, &env->pb[i]);
for (i = 0; i < 1024; i++)
qemu_get_betls(f, &env->spr[i]);
- if (!env->external_htab) {
+ if (!cpu->vhyp) {
ppc_store_sdr1(env, sdr1);
}
qemu_get_be32s(f, &env->vscr);
@@ -228,7 +228,7 @@ static int cpu_post_load(void *opaque, int version_id)
env->IBAT[1][i+4] = env->spr[SPR_IBAT4U + 2*i + 1];
}
- if (!env->external_htab) {
+ if (!cpu->vhyp) {
ppc_store_sdr1(env, env->spr[SPR_SDR1]);
}
diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
index 2ed4888a19..898021f0d8 100644
--- a/target/ppc/mmu-hash32.h
+++ b/target/ppc/mmu-hash32.h
@@ -80,10 +80,8 @@ static inline hwaddr ppc_hash32_hpt_mask(PowerPCCPU *cpu)
static inline target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu,
hwaddr pte_offset)
{
- CPUPPCState *env = &cpu->env;
target_ulong base = ppc_hash32_hpt_base(cpu);
- assert(!env->external_htab); /* Not supported on 32-bit for now */
return ldl_phys(CPU(cpu)->as, base + pte_offset);
}
@@ -91,29 +89,23 @@ static inline target_ulong ppc_hash32_load_hpte1(PowerPCCPU *cpu,
hwaddr pte_offset)
{
target_ulong base = ppc_hash32_hpt_base(cpu);
- CPUPPCState *env = &cpu->env;
- assert(!env->external_htab); /* Not supported on 32-bit for now */
return ldl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2);
}
static inline void ppc_hash32_store_hpte0(PowerPCCPU *cpu,
hwaddr pte_offset, target_ulong pte0)
{
- CPUPPCState *env = &cpu->env;
target_ulong base = ppc_hash32_hpt_base(cpu);
- assert(!env->external_htab); /* Not supported on 32-bit for now */
stl_phys(CPU(cpu)->as, base + pte_offset, pte0);
}
static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
hwaddr pte_offset, target_ulong pte1)
{
- CPUPPCState *env = &cpu->env;
target_ulong base = ppc_hash32_hpt_base(cpu);
- assert(!env->external_htab); /* Not supported on 32-bit for now */
stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
}
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index 38a6912203..8fe0e78e16 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -38,12 +38,6 @@
#endif
/*
- * Used to indicate that a CPU has its hash page table (HPT) managed
- * within the host kernel
- */
-#define MMU_HASH64_KVM_MANAGED_HPT ((void *)-1)
-
-/*
* SLB handling
*/
@@ -313,31 +307,6 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
env->spr[SPR_SDR1] = value;
}
-void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
- Error **errp)
-{
- CPUPPCState *env = &cpu->env;
- Error *local_err = NULL;
-
- 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;
- }
-
- 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)
{
@@ -429,29 +398,24 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
hwaddr ptex, int n)
{
- ppc_hash_pte64_t *hptes = NULL;
hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
+ hwaddr base = ppc_hash64_hpt_base(cpu);
+ hwaddr plen = n * HASH_PTE_SIZE_64;
+ const ppc_hash_pte64_t *hptes;
+
+ if (cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ return vhc->map_hptes(cpu->vhyp, ptex, n);
+ }
- if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
- /*
- * HTAB is controlled by KVM. Fetch into temporary buffer
- */
- hptes = g_malloc(HASH_PTEG_SIZE_64);
- kvmppc_read_hptes(hptes, ptex, n);
- } else if (cpu->env.external_htab) {
- /*
- * HTAB is controlled by QEMU. Just point to the internally
- * accessible PTEG.
- */
- hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset);
- } else if (ppc_hash64_hpt_base(cpu)) {
- hwaddr base = ppc_hash64_hpt_base(cpu);
- hwaddr plen = n * HASH_PTE_SIZE_64;
- hptes = address_space_map(CPU(cpu)->as, base + pte_offset,
- &plen, false);
- if (plen < (n * HASH_PTE_SIZE_64)) {
- hw_error("%s: Unable to map all requested HPTEs\n", __func__);
- }
+ if (!base) {
+ return NULL;
+ }
+
+ hptes = address_space_map(CPU(cpu)->as, base + pte_offset, &plen, false);
+ if (plen < (n * HASH_PTE_SIZE_64)) {
+ hw_error("%s: Unable to map all requested HPTEs\n", __func__);
}
return hptes;
}
@@ -459,12 +423,15 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
hwaddr ptex, int n)
{
- if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
- g_free((void *)hptes);
- } else if (!cpu->env.external_htab) {
- address_space_unmap(CPU(cpu)->as, (void *)hptes, n * HASH_PTE_SIZE_64,
- false, n * HASH_PTE_SIZE_64);
+ if (cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ vhc->unmap_hptes(cpu->vhyp, hptes, ptex, n);
+ return;
}
+
+ address_space_unmap(CPU(cpu)->as, (void *)hptes, n * HASH_PTE_SIZE_64,
+ false, n * HASH_PTE_SIZE_64);
}
static unsigned hpte_page_shift(const struct ppc_one_seg_page_size *sps,
@@ -916,22 +883,18 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
uint64_t pte0, uint64_t pte1)
{
- CPUPPCState *env = &cpu->env;
+ hwaddr base = ppc_hash64_hpt_base(cpu);
hwaddr offset = ptex * HASH_PTE_SIZE_64;
- if (env->external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
- kvmppc_write_hpte(ptex, pte0, pte1);
+ if (cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ vhc->store_hpte(cpu->vhyp, ptex, pte0, pte1);
return;
}
- if (env->external_htab) {
- stq_p(env->external_htab + offset, pte0);
- stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
- } else {
- hwaddr base = ppc_hash64_hpt_base(cpu);
- stq_phys(CPU(cpu)->as, base + offset, pte0);
- stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1);
- }
+ stq_phys(CPU(cpu)->as, base + offset, pte0);
+ stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1);
}
void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index 5914a08db7..c8d34584e8 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -101,13 +101,16 @@ static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
{
+ if (cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ return vhc->hpt_mask(cpu->vhyp);
+ }
return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18 - 7)) - 1;
}
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);
struct ppc_hash_pte64 {
uint64_t pte0, pte1;
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index 1381635d20..0176ab6095 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -2001,8 +2001,9 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
/* Special registers manipulation */
void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
{
+ PowerPCCPU *cpu = ppc_env_get_cpu(env);
qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
- assert(!env->external_htab);
+ assert(!cpu->vhyp);
#if defined(TARGET_PPC64)
if (env->mmu_model & POWERPC_MMU_64) {
PowerPCCPU *cpu = ppc_env_get_cpu(env);