aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/mmu-hash64.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-03-07 16:36:37 +0000
committerPeter Maydell <peter.maydell@linaro.org>2014-03-07 16:36:38 +0000
commitbb2b04503497608cdc5fa4c990d26e936f9d2102 (patch)
tree6e04a6aba5e21207af95f7a9390e506959b9d0e5 /target-ppc/mmu-hash64.c
parentc3f8d28e455bff9bde2b81bd0c9b1d437b88c159 (diff)
parent0f20ba62c35e6a779ba4ea00616192ef2abb6896 (diff)
Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging
Patch queue for ppc - 2014-03-05 This pull request includes: - VSX emulation support - book3s pr/hv selection - some bug fixes - qdev stable numbering - eTSEC emulation # gpg: Signature made Wed 05 Mar 2014 02:14:19 GMT using RSA key ID 03FEDC60 # gpg: Can't check signature: public key not found * remotes/agraf/tags/signed-ppc-for-upstream: (130 commits) target-ppc: spapr: e500: fix to use cpu_dt_id target-ppc: add PowerPCCPU::cpu_dt_id target-ppc: Introduce hypervisor call H_GET_TCE target-ppc: Update ppc_hash64_store_hpte to support updating in-kernel htab target-ppc: Change the hpte store API target-ppc: Fix page table lookup with kvm enabled target-ppc: Fix htab_mask calculation target-ppc: Use Additional Temporary in stqcx Case target-ppc: Fix Compiler Warnings Due to 64-Bit Constants Declared as UL PPC: sPAPR: Only use getpagesize() when we run with kvm target-ppc/translate.c: Use ULL suffix for 64 bit constants spapr-vlan: flush queue whenever can_receive can go from false to true target-ppc: Altivec 2.07: Vector Permute and Exclusive OR target-ppc: Altivec 2.07: Vector SHA Sigma Instructions target-ppc: Altivec 2.07: AES Instructions target-ppc: Altivec 2.07: Binary Coded Decimal Instructions target-ppc: Altivec 2.07: Vector Polynomial Multiply Sum target-ppc: Altivec 2.07: Vector Gather Bits by Bytes target-ppc: Altivec 2.07: Doubleword Compares target-ppc: Altivec 2.07: vbpermq Instruction ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-ppc/mmu-hash64.c')
-rw-r--r--target-ppc/mmu-hash64.c117
1 files changed, 98 insertions, 19 deletions
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 67fc1b5dec..f2af4fbaa7 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -41,6 +41,11 @@
#endif
/*
+ * Used to indicate whether we have allocated htab in the
+ * host kernel
+ */
+bool kvmppc_kern_htab;
+/*
* SLB handling
*/
@@ -278,12 +283,12 @@ static int ppc_hash64_pte_prot(CPUPPCState *env,
static int ppc_hash64_amr_prot(CPUPPCState *env, ppc_hash_pte64_t pte)
{
int key, amrbits;
- int prot = PAGE_EXEC;
+ int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
/* Only recent MMUs implement Virtual Page Class Key Protection */
if (!(env->mmu_model & POWERPC_MMU_AMR)) {
- return PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return prot;
}
key = HPTE64_R_KEY(pte.pte1);
@@ -292,39 +297,94 @@ static int ppc_hash64_amr_prot(CPUPPCState *env, ppc_hash_pte64_t pte)
/* fprintf(stderr, "AMR protection: key=%d AMR=0x%" PRIx64 "\n", key, */
/* env->spr[SPR_AMR]); */
+ /*
+ * A store is permitted if the AMR bit is 0. Remove write
+ * protection if it is set.
+ */
if (amrbits & 0x2) {
- prot |= PAGE_WRITE;
+ prot &= ~PAGE_WRITE;
}
+ /*
+ * A load is permitted if the AMR bit is 0. Remove read
+ * protection if it is set.
+ */
if (amrbits & 0x1) {
- prot |= PAGE_READ;
+ prot &= ~PAGE_READ;
}
return prot;
}
-static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off,
+uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index)
+{
+ uint64_t token = 0;
+ hwaddr pte_offset;
+
+ pte_offset = pte_index * HASH_PTE_SIZE_64;
+ if (kvmppc_kern_htab) {
+ /*
+ * HTAB is controlled by KVM. Fetch the PTEG into a new buffer.
+ */
+ token = kvmppc_hash64_read_pteg(cpu, pte_index);
+ if (token) {
+ return token;
+ }
+ /*
+ * pteg read failed, even though we have allocated htab via
+ * kvmppc_reset_htab.
+ */
+ 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;
+ }
+ return token;
+}
+
+void ppc_hash64_stop_access(uint64_t token)
+{
+ if (kvmppc_kern_htab) {
+ return kvmppc_hash64_free_pteg(token);
+ }
+}
+
+static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr hash,
bool secondary, target_ulong ptem,
ppc_hash_pte64_t *pte)
{
- hwaddr pte_offset = pteg_off;
- target_ulong pte0, pte1;
int i;
+ uint64_t token;
+ target_ulong pte0, pte1;
+ target_ulong pte_index;
+ pte_index = (hash & env->htab_mask) * HPTES_PER_GROUP;
+ token = ppc_hash64_start_access(ppc_env_get_cpu(env), pte_index);
+ if (!token) {
+ return -1;
+ }
for (i = 0; i < HPTES_PER_GROUP; i++) {
- pte0 = ppc_hash64_load_hpte0(env, pte_offset);
- pte1 = ppc_hash64_load_hpte1(env, pte_offset);
+ pte0 = ppc_hash64_load_hpte0(env, token, i);
+ pte1 = ppc_hash64_load_hpte1(env, token, i);
if ((pte0 & HPTE64_V_VALID)
&& (secondary == !!(pte0 & HPTE64_V_SECONDARY))
&& HPTE64_V_COMPARE(pte0, ptem)) {
pte->pte0 = pte0;
pte->pte1 = pte1;
- return pte_offset;
+ ppc_hash64_stop_access(token);
+ return (pte_index + i) * HASH_PTE_SIZE_64;
}
-
- pte_offset += HASH_PTE_SIZE_64;
}
-
+ ppc_hash64_stop_access(token);
+ /*
+ * We didn't find a valid entry.
+ */
return -1;
}
@@ -332,7 +392,7 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
ppc_slb_t *slb, target_ulong eaddr,
ppc_hash_pte64_t *pte)
{
- hwaddr pteg_off, pte_offset;
+ hwaddr pte_offset;
hwaddr hash;
uint64_t vsid, epnshift, epnmask, epn, ptem;
@@ -367,8 +427,7 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
" vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n",
env->htab_base, env->htab_mask, vsid, ptem, hash);
- pteg_off = (hash * HASH_PTEG_SIZE_64) & env->htab_mask;
- pte_offset = ppc_hash64_pteg_search(env, pteg_off, 0, ptem, pte);
+ pte_offset = ppc_hash64_pteg_search(env, hash, 0, ptem, pte);
if (pte_offset == -1) {
/* Secondary PTEG lookup */
@@ -377,8 +436,7 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
" hash=" TARGET_FMT_plx "\n", env->htab_base,
env->htab_mask, vsid, ptem, ~hash);
- pteg_off = (~hash * HASH_PTEG_SIZE_64) & env->htab_mask;
- pte_offset = ppc_hash64_pteg_search(env, pteg_off, 1, ptem, pte);
+ pte_offset = ppc_hash64_pteg_search(env, ~hash, 1, ptem, pte);
}
return pte_offset;
@@ -508,7 +566,8 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr,
}
if (new_pte1 != pte.pte1) {
- ppc_hash64_store_hpte1(env, pte_offset, new_pte1);
+ ppc_hash64_store_hpte(env, pte_offset / HASH_PTE_SIZE_64,
+ pte.pte0, new_pte1);
}
/* 7. Determine the real address from the PTE */
@@ -544,3 +603,23 @@ hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
return ppc_hash64_pte_raddr(slb, pte, addr) & TARGET_PAGE_MASK;
}
+
+void ppc_hash64_store_hpte(CPUPPCState *env,
+ target_ulong pte_index,
+ target_ulong pte0, target_ulong pte1)
+{
+ CPUState *cs = ENV_GET_CPU(env);
+
+ if (kvmppc_kern_htab) {
+ return kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
+ }
+
+ pte_index *= HASH_PTE_SIZE_64;
+ if (env->external_htab) {
+ stq_p(env->external_htab + pte_index, pte0);
+ stq_p(env->external_htab + pte_index + HASH_PTE_SIZE_64/2, pte1);
+ } else {
+ stq_phys(cs->as, env->htab_base + pte_index, pte0);
+ stq_phys(cs->as, env->htab_base + pte_index + HASH_PTE_SIZE_64/2, pte1);
+ }
+}