[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-ppc] [PATCH 45/48] mmu-hash64: Implement Virtual Page Class Key Pr
From: |
David Gibson |
Subject: |
[Qemu-ppc] [PATCH 45/48] mmu-hash64: Implement Virtual Page Class Key Protection |
Date: |
Tue, 12 Mar 2013 21:31:47 +1100 |
Version 2.06 of the Power architecture describes an additional page
protection mechanism. Each virtual page has a "class" (0-31) recorded in
the PTE. The AMR register contains bits which can prohibit reads and/or
writes on a class by class basis. Interestingly, the AMR is userspace
readable and writable, however user mode writes are masked by the contents
of the UAMOR which is privileged.
This patch implements this protection mechanism, along with the AMR and
UAMOR SPRs. The architecture also specifies a hypervisor-privileged AMOR
register which masks user and supervisor writes to the AMR and UAMOR. We
leave this out for now, since we don't at present model hypervisor mode
correctly in any case.
Signed-off-by: David Gibson <address@hidden>
---
target-ppc/cpu.h | 8 +++++--
target-ppc/mmu-hash64.c | 46 +++++++++++++++++++++++++++++++++++-----
target-ppc/mmu-hash64.h | 2 ++
target-ppc/translate_init.c | 49 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 98 insertions(+), 7 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 696551a..f42e184 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -113,11 +113,13 @@ enum powerpc_mmu_t {
#if defined(TARGET_PPC64)
#define POWERPC_MMU_64 0x00010000
#define POWERPC_MMU_1TSEG 0x00020000
+#define POWERPC_MMU_AMR 0x00040000
/* 64 bits PowerPC MMU */
POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001,
/* Architecture 2.06 variant */
- POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003,
- /* Architecture 2.06 "degraded" (no 1T segments) */
+ POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
+ | POWERPC_MMU_AMR | 0x00000003,
+ /* Architecture 2.06 "degraded" (no 1T segments or AMR) */
POWERPC_MMU_2_06d = POWERPC_MMU_64 | 0x00000003,
#endif /* defined(TARGET_PPC64) */
};
@@ -1222,6 +1224,7 @@ static inline void cpu_clone_regs(CPUPPCState *env,
target_ulong newsp)
#define SPR_601_UDECR (0x006)
#define SPR_LR (0x008)
#define SPR_CTR (0x009)
+#define SPR_UAMR (0x00C)
#define SPR_DSCR (0x011)
#define SPR_DSISR (0x012)
#define SPR_DAR (0x013) /* DAE for PowerPC 601 */
@@ -1259,6 +1262,7 @@ static inline void cpu_clone_regs(CPUPPCState *env,
target_ulong newsp)
#define SPR_MPC_CMPH (0x09B)
#define SPR_MPC_LCTRL1 (0x09C)
#define SPR_MPC_LCTRL2 (0x09D)
+#define SPR_UAMOR (0x09D)
#define SPR_MPC_ICTRL (0x09E)
#define SPR_MPC_BAR (0x09F)
#define SPR_VRSAVE (0x100)
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index f18c98f..43ccf45 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -275,6 +275,33 @@ static int ppc_hash64_pte_prot(CPUPPCState *env,
return prot;
}
+static int ppc_hash64_amr_prot(CPUPPCState *env, ppc_hash_pte64_t pte)
+{
+ int key, amrbits;
+ int prot = 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;
+ }
+
+ key = HPTE64_R_KEY(pte.pte1);
+ amrbits = (env->spr[SPR_AMR] >> 2*(31 - key)) & 0x3;
+
+ /* fprintf(stderr, "AMR protection: key=%d AMR=0x%" PRIx64 "\n", key, */
+ /* env->spr[SPR_AMR]); */
+
+ if (amrbits & 0x2) {
+ prot |= PAGE_WRITE;
+ }
+ if (amrbits & 0x1) {
+ prot |= PAGE_READ;
+ }
+
+ return prot;
+}
+
static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off,
bool secondary, target_ulong ptem,
ppc_hash_pte64_t *pte)
@@ -375,7 +402,7 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env,
target_ulong eaddr,
ppc_slb_t *slb;
hwaddr pte_offset;
ppc_hash_pte64_t pte;
- int prot;
+ int pp_prot, amr_prot, prot;
uint64_t new_pte1;
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
hwaddr raddr;
@@ -437,7 +464,9 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env,
target_ulong eaddr,
/* 5. Check access permissions */
- prot = ppc_hash64_pte_prot(env, slb, pte);
+ pp_prot = ppc_hash64_pte_prot(env, slb, pte);
+ amr_prot = ppc_hash64_amr_prot(env, pte);
+ prot = pp_prot & amr_prot;
if ((need_prot[rwx] & ~prot) != 0) {
/* Access right violation */
@@ -446,14 +475,21 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env,
target_ulong eaddr,
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x08000000;
} else {
+ target_ulong dsisr = 0;
+
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
+ if (need_prot[rwx] & ~pp_prot) {
+ dsisr |= 0x08000000;
+ }
if (rwx == 1) {
- env->spr[SPR_DSISR] = 0x0A000000;
- } else {
- env->spr[SPR_DSISR] = 0x08000000;
+ dsisr |= 0x02000000;
+ }
+ if (need_prot[rwx] & ~amr_prot) {
+ dsisr |= 0x00200000;
}
+ env->spr[SPR_DSISR] = dsisr;
}
return 1;
}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index 1ce6e5b..5e6e506 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -69,6 +69,8 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env,
target_ulong address, int rw,
#define HPTE64_R_C 0x0000000000000080ULL
#define HPTE64_R_R 0x0000000000000100ULL
#define HPTE64_R_KEY_LO 0x0000000000000e00ULL
+#define HPTE64_R_KEY(x) ((((x) & HPTE64_R_KEY_HI) >> 60) | \
+ (((x) & HPTE64_R_KEY_LO) >> 9))
#define HPTE64_V_1TB_SEG 0x4000000000000000ULL
#define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index c580d62..b2a76d0 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -1017,6 +1017,54 @@ static void gen_spr_7xx (CPUPPCState *env)
0x00000000);
}
+#ifdef TARGET_PPC64
+#ifndef CONFIG_USER_ONLY
+static void spr_read_uamr (void *opaque, int gprn, int sprn)
+{
+ gen_load_spr(cpu_gpr[gprn], SPR_AMR);
+ spr_load_dump_spr(SPR_AMR);
+}
+
+static void spr_write_uamr (void *opaque, int sprn, int gprn)
+{
+ gen_store_spr(SPR_AMR, cpu_gpr[gprn]);
+ spr_store_dump_spr(SPR_AMR);
+}
+
+static void spr_write_uamr_pr (void *opaque, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+
+ gen_load_spr(t0, SPR_UAMOR);
+ tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
+ gen_store_spr(SPR_AMR, t0);
+ spr_store_dump_spr(SPR_AMR);
+}
+#endif /* CONFIG_USER_ONLY */
+
+static void gen_spr_amr (CPUPPCState *env)
+{
+#ifndef CONFIG_USER_ONLY
+ /* Virtual Page Class Key protection */
+ /* The AMR is accessible either via SPR 13 or SPR 29. 13 is
+ * userspace accessible, 29 is privileged. So we only need to set
+ * the kvm ONE_REG id on one of them, we use 29 */
+ spr_register(env, SPR_UAMR, "UAMR",
+ &spr_read_uamr, &spr_write_uamr_pr,
+ &spr_read_uamr, &spr_write_uamr,
+ 0);
+ spr_register_kvm(env, SPR_AMR, "AMR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_AMR, 0xffffffffffffffff);
+ spr_register_kvm(env, SPR_UAMOR, "UAMOR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_UAMOR, 0);
+#endif /* !CONFIG_USER_ONLY */
+}
+#endif /* TARGET_PPC64 */
+
static void gen_spr_thrm (CPUPPCState *env)
{
/* Thermal management */
@@ -6872,6 +6920,7 @@ static void init_proc_POWER7 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000); /* TOFIX */
+ gen_spr_amr(env);
/* XXX : not implemented */
spr_register(env, SPR_CTRL, "SPR_CTRLT",
SPR_NOACCESS, SPR_NOACCESS,
--
1.7.10.4
- [Qemu-ppc] [PATCH 05/48] target-ppc: Disentangle pte_check(), (continued)
- [Qemu-ppc] [PATCH 05/48] target-ppc: Disentangle pte_check(), David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 20/48] mmu-hash*: Remove eaddr field from mmu_ctx_hash{32, 64}, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 43/48] mmu-hash*: Don't use full ppc_hash{32, 64}_translate() path for get_phys_page_debug(), David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 27/48] mmu-hash*: Make find_pte{32, 64} do more of the job of finding ptes, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 10/48] target-ppc: Disentangle hash mmu paths for cpu_ppc_handle_mmu_fault, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 12/48] target-ppc: Disentangle hash mmu helper functions, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 31/48] mmu-hash32: Remove odd pointer usage from BAT code, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 21/48] mmu-hash*: Combine ppc_hash{32, 64}_get_physical_address and get_segment{32, 64}(), David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 13/48] target-ppc: Don't share get_pteg_offset() between 32 and 64-bit, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 06/48] target-ppc: Disentangle find_pte(), David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 45/48] mmu-hash64: Implement Virtual Page Class Key Protection,
David Gibson <=
- [Qemu-ppc] [PATCH 09/48] target-ppc: Disentangle get_physical_address() paths, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 26/48] mmu-hash*: Separate PTEG searching from permissions checking, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 41/48] mmu-hash*: Clean up real address calculation, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 04/48] target-ppc: Move SLB handling into a mmu-hash64.c, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 36/48] mmu-hash*: Don't update PTE flags when permission is denied, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 47/48] target-ppc: Move ppc tlb_fill implementation into mmu_helper.c, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 44/48] mmu-hash*: Merge translate and fault handling functions, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 48/48] target-ppc: Use QOM method dispatch for MMU fault handling, David Gibson, 2013/03/12
- [Qemu-ppc] [PATCH 15/48] target-ppc: mmu_ctx_t should not be a global type, David Gibson, 2013/03/12