aboutsummaryrefslogtreecommitdiff
path: root/target/hppa
diff options
context:
space:
mode:
authorSven Schnelle <svens@stackframe.org>2019-03-11 20:16:00 +0100
committerRichard Henderson <richard.henderson@linaro.org>2019-03-12 09:13:43 -0700
commitd5de20bd84ae3a6f6c194f0088cfcb4d4f6af602 (patch)
treeee63c5d833b5d74e4d11098d30da525d55c29691 /target/hppa
parent38188fd216cf139e88459296cb42400b5a039f79 (diff)
target/hppa: add TLB protection id check
Signed-off-by: Sven Schnelle <svens@stackframe.org> Message-Id: <20190311191602.25796-10-svens@stackframe.org> [rth: Add required tlb flushing when prot id registers change.] Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target/hppa')
-rw-r--r--target/hppa/cpu.h10
-rw-r--r--target/hppa/gdbstub.c20
-rw-r--r--target/hppa/helper.c10
-rw-r--r--target/hppa/helper.h1
-rw-r--r--target/hppa/mem_helper.c28
-rw-r--r--target/hppa/translate.c10
6 files changed, 70 insertions, 9 deletions
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index 861bbb1f16..c062c7969c 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -143,6 +143,10 @@
#endif
#define CR_RC 0
+#define CR_PID1 8
+#define CR_PID2 9
+#define CR_PID3 12
+#define CR_PID4 13
#define CR_SCRCCR 10
#define CR_SAR 11
#define CR_IVA 14
@@ -341,6 +345,12 @@ target_ureg cpu_hppa_get_psw(CPUHPPAState *env);
void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg);
void cpu_hppa_loaded_fr0(CPUHPPAState *env);
+#ifdef CONFIG_USER_ONLY
+static inline void cpu_hppa_change_prot_id(CPUHPPAState *env) { }
+#else
+void cpu_hppa_change_prot_id(CPUHPPAState *env);
+#endif
+
#define cpu_signal_handler cpu_hppa_signal_handler
int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
diff --git a/target/hppa/gdbstub.c b/target/hppa/gdbstub.c
index 3157a690f2..983bf92aaf 100644
--- a/target/hppa/gdbstub.c
+++ b/target/hppa/gdbstub.c
@@ -93,19 +93,19 @@ int hppa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
val = env->cr[CR_RC];
break;
case 52:
- val = env->cr[8];
+ val = env->cr[CR_PID1];
break;
case 53:
- val = env->cr[9];
+ val = env->cr[CR_PID2];
break;
case 54:
val = env->cr[CR_SCRCCR];
break;
case 55:
- val = env->cr[12];
+ val = env->cr[CR_PID3];
break;
case 56:
- val = env->cr[13];
+ val = env->cr[CR_PID4];
break;
case 57:
val = env->cr[24];
@@ -224,19 +224,23 @@ int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
env->cr[CR_RC] = val;
break;
case 52:
- env->cr[8] = val;
+ env->cr[CR_PID1] = val;
+ cpu_hppa_change_prot_id(env);
break;
case 53:
- env->cr[9] = val;
+ env->cr[CR_PID2] = val;
+ cpu_hppa_change_prot_id(env);
break;
case 54:
env->cr[CR_SCRCCR] = val;
break;
case 55:
- env->cr[12] = val;
+ env->cr[CR_PID3] = val;
+ cpu_hppa_change_prot_id(env);
break;
case 56:
- env->cr[13] = val;
+ env->cr[CR_PID4] = val;
+ cpu_hppa_change_prot_id(env);
break;
case 57:
env->cr[24] = val;
diff --git a/target/hppa/helper.c b/target/hppa/helper.c
index 6539061e52..ac750b62ef 100644
--- a/target/hppa/helper.c
+++ b/target/hppa/helper.c
@@ -21,6 +21,7 @@
#include "cpu.h"
#include "fpu/softfloat.h"
+#include "exec/exec-all.h"
#include "exec/helper-proto.h"
target_ureg cpu_hppa_get_psw(CPUHPPAState *env)
@@ -49,6 +50,7 @@ target_ureg cpu_hppa_get_psw(CPUHPPAState *env)
void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw)
{
+ target_ureg old_psw = env->psw;
target_ureg cb = 0;
env->psw = psw & ~(PSW_N | PSW_V | PSW_CB);
@@ -64,6 +66,14 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw)
cb |= ((psw >> 9) & 1) << 8;
cb |= ((psw >> 8) & 1) << 4;
env->psw_cb = cb;
+
+ /* If PSW_P changes, it affects how we translate addresses. */
+ if ((psw ^ old_psw) & PSW_P) {
+#ifndef CONFIG_USER_ONLY
+ CPUState *src = CPU(hppa_env_get_cpu(env));
+ tlb_flush_by_mmuidx(src, 0xf);
+#endif
+ }
}
void hppa_cpu_dump_state(CPUState *cs, FILE *f,
diff --git a/target/hppa/helper.h b/target/hppa/helper.h
index bfe0dd1db1..38d834ef6b 100644
--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -92,4 +92,5 @@ DEF_HELPER_FLAGS_3(itlbp, TCG_CALL_NO_RWG, void, env, tl, tr)
DEF_HELPER_FLAGS_2(ptlb, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_1(ptlbe, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_2(lpa, TCG_CALL_NO_WG, tr, env, tl)
+DEF_HELPER_FLAGS_1(change_prot_id, TCG_CALL_NO_RWG, void, env)
#endif
diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c
index a69cca9c5d..c9b57d07c3 100644
--- a/target/hppa/mem_helper.c
+++ b/target/hppa/mem_helper.c
@@ -131,7 +131,20 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
break;
}
- /* ??? Check PSW_P and ent->access_prot. This can remove PAGE_WRITE. */
+ /* access_id == 0 means public page and no check is performed */
+ if ((env->psw & PSW_P) && ent->access_id) {
+ /* If bits [31:1] match, and bit 0 is set, suppress write. */
+ int match = ent->access_id * 2 + 1;
+
+ if (match == env->cr[CR_PID1] || match == env->cr[CR_PID2] ||
+ match == env->cr[CR_PID3] || match == env->cr[CR_PID4]) {
+ prot &= PAGE_READ | PAGE_EXEC;
+ if (type == PAGE_WRITE) {
+ ret = EXCP_DMPI;
+ goto egress;
+ }
+ }
+ }
/* No guest access type indicates a non-architectural access from
within QEMU. Bypass checks for access, D, B and T bits. */
@@ -334,6 +347,19 @@ void HELPER(ptlbe)(CPUHPPAState *env)
tlb_flush_by_mmuidx(src, 0xf);
}
+void cpu_hppa_change_prot_id(CPUHPPAState *env)
+{
+ if (env->psw & PSW_P) {
+ CPUState *src = CPU(hppa_env_get_cpu(env));
+ tlb_flush_by_mmuidx(src, 0xf);
+ }
+}
+
+void HELPER(change_prot_id)(CPUHPPAState *env)
+{
+ cpu_hppa_change_prot_id(env);
+}
+
target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
{
hwaddr phys;
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 6ac196804b..70a7cd4a89 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -2256,6 +2256,16 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
break;
+ case CR_PID1:
+ case CR_PID2:
+ case CR_PID3:
+ case CR_PID4:
+ tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
+#ifndef CONFIG_USER_ONLY
+ gen_helper_change_prot_id(cpu_env);
+#endif
+ break;
+
default:
tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
break;