target/hppa: Implement PROBE for system mode
authorRichard Henderson <richard.henderson@linaro.org>
Wed, 24 Jan 2018 23:03:25 +0000 (15:03 -0800)
committerRichard Henderson <richard.henderson@linaro.org>
Wed, 31 Jan 2018 13:30:50 +0000 (05:30 -0800)
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
target/hppa/helper.h
target/hppa/op_helper.c
target/hppa/translate.c

index 0e569cba319fcacb7fddda7f3b05a8a82e6caaf3..bfe0dd1db12efba4127f1c816517a50dd27eed5c 100644 (file)
@@ -17,8 +17,7 @@ DEF_HELPER_FLAGS_3(stby_b_parallel, TCG_CALL_NO_WG, void, env, tl, tr)
 DEF_HELPER_FLAGS_3(stby_e, TCG_CALL_NO_WG, void, env, tl, tr)
 DEF_HELPER_FLAGS_3(stby_e_parallel, TCG_CALL_NO_WG, void, env, tl, tr)
 
-DEF_HELPER_FLAGS_1(probe_r, TCG_CALL_NO_RWG_SE, tr, tl)
-DEF_HELPER_FLAGS_1(probe_w, TCG_CALL_NO_RWG_SE, tr, tl)
+DEF_HELPER_FLAGS_4(probe, TCG_CALL_NO_WG, tr, env, tl, i32, i32)
 
 DEF_HELPER_FLAGS_1(loaded_fr0, TCG_CALL_NO_RWG, void, env)
 
index 0daa7511f492a75ac5dae6e02db6ff59adb9b5aa..4ee936bf86a591bd956637c3dcc6cac77b51e5d7 100644 (file)
@@ -160,21 +160,33 @@ void HELPER(stby_e_parallel)(CPUHPPAState *env, target_ulong addr,
     do_stby_e(env, addr, val, true);
 }
 
-target_ureg HELPER(probe_r)(target_ulong addr)
+target_ureg HELPER(probe)(CPUHPPAState *env, target_ulong addr,
+                          uint32_t level, uint32_t want)
 {
 #ifdef CONFIG_USER_ONLY
-    return page_check_range(addr, 1, PAGE_READ);
+    return page_check_range(addr, 1, want);
 #else
-    return 1; /* FIXME */
-#endif
-}
+    int prot, excp;
+    hwaddr phys;
 
-target_ureg HELPER(probe_w)(target_ulong addr)
-{
-#ifdef CONFIG_USER_ONLY
-    return page_check_range(addr, 1, PAGE_WRITE);
-#else
-    return 1; /* FIXME */
+    /* Fail if the requested privilege level is higher than current.  */
+    if (level < (env->iaoq_f & 3)) {
+        return 0;
+    }
+
+    excp = hppa_get_physical_address(env, addr, level, 0, &phys, &prot);
+    if (excp >= 0) {
+        if (env->psw & PSW_Q) {
+            /* ??? Needs tweaking for hppa64.  */
+            env->cr[CR_IOR] = addr;
+            env->cr[CR_ISR] = addr >> 32;
+        }
+        if (excp == EXCP_DTLB_MISS) {
+            excp = EXCP_NA_DTLB_MISS;
+        }
+        hppa_dynamic_excp(env, excp, GETPC());
+    }
+    return (want & prot) != 0;
 #endif
 }
 
index 842f74ea5bbde3e72e86199ac01903776408a0b1..6499b392f9e273d5c628a1c1c0c7d2371fb43b60 100644 (file)
@@ -2380,21 +2380,33 @@ static DisasJumpType trans_probe(DisasContext *ctx, uint32_t insn,
 {
     unsigned rt = extract32(insn, 0, 5);
     unsigned sp = extract32(insn, 14, 2);
+    unsigned rr = extract32(insn, 16, 5);
     unsigned rb = extract32(insn, 21, 5);
     unsigned is_write = extract32(insn, 6, 1);
+    unsigned is_imm = extract32(insn, 13, 1);
     TCGv_reg dest, ofs;
+    TCGv_i32 level, want;
     TCGv_tl addr;
 
     nullify_over(ctx);
 
-    /* ??? Do something with priv level operand.  */
     dest = dest_gpr(ctx, rt);
     form_gva(ctx, &addr, &ofs, rb, 0, 0, 0, sp, 0, false);
-    if (is_write) {
-        gen_helper_probe_w(dest, addr);
+
+    if (is_imm) {
+        level = tcg_const_i32(extract32(insn, 16, 2));
     } else {
-        gen_helper_probe_r(dest, addr);
+        level = tcg_temp_new_i32();
+        tcg_gen_trunc_reg_i32(level, load_gpr(ctx, rr));
+        tcg_gen_andi_i32(level, level, 3);
     }
+    want = tcg_const_i32(is_write ? PAGE_WRITE : PAGE_READ);
+
+    gen_helper_probe(dest, cpu_env, addr, level, want);
+
+    tcg_temp_free_i32(want);
+    tcg_temp_free_i32(level);
+
     save_gpr(ctx, rt, dest);
     return nullify_end(ctx, DISAS_NEXT);
 }