* [PATCH v2] target/hppa: Implement CPU diagnose registers for 64-bit HP-UX
@ 2025-01-28 22:45 deller
2025-01-28 22:45 ` [PATCH 1/4] target/hppa: Add CPU diagnose registers deller
` (3 more replies)
0 siblings, 4 replies; 15+ messages in thread
From: deller @ 2025-01-28 22:45 UTC (permalink / raw)
To: richard.henderson, qemu-devel; +Cc: deller
This series of 4 patches incorporates the changes as suggested by
Richard regarding PATCH #3 from my previous series.
Please review.
Helge
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/4] target/hppa: Add CPU diagnose registers
2025-01-28 22:45 [PATCH v2] target/hppa: Implement CPU diagnose registers for 64-bit HP-UX deller
@ 2025-01-28 22:45 ` deller
2025-01-29 1:43 ` Richard Henderson
2025-01-28 22:45 ` [PATCH 2/4] target/hppa: Add instruction decoding for mfdiag and mtdiag deller
` (2 subsequent siblings)
3 siblings, 1 reply; 15+ messages in thread
From: deller @ 2025-01-28 22:45 UTC (permalink / raw)
To: richard.henderson, qemu-devel; +Cc: deller
From: Helge Deller <deller@gmx.de>
Add the diagnose registers (%dr) to the CPUArchState. Those are mostly
undocumented and control cache behaviour, memory behaviour, reset button
management and many other related internal CPU things.
Signed-off-by: Helge Deller <deller@gmx.de>
---
target/hppa/cpu.h | 1 +
target/hppa/machine.c | 5 +++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index beea42d105..b858986c41 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -232,6 +232,7 @@ typedef struct CPUArchState {
target_ulong cr[32]; /* control registers */
target_ulong cr_back[2]; /* back of cr17/cr18 */
target_ulong shadow[7]; /* shadow registers */
+ target_ulong dr[32]; /* diagnose registers */
/*
* During unwind of a memory insn, the base register of the address.
diff --git a/target/hppa/machine.c b/target/hppa/machine.c
index 211bfcf640..bb47a2e689 100644
--- a/target/hppa/machine.c
+++ b/target/hppa/machine.c
@@ -198,6 +198,7 @@ static const VMStateField vmstate_env_fields[] = {
VMSTATE_UINT64(iasq_b, CPUHPPAState),
VMSTATE_UINT32(fr0_shadow, CPUHPPAState),
+ VMSTATE_UINT64_ARRAY(dr, CPUHPPAState, 32),
VMSTATE_END_OF_LIST()
};
@@ -208,8 +209,8 @@ static const VMStateDescription * const vmstate_env_subsections[] = {
static const VMStateDescription vmstate_env = {
.name = "env",
- .version_id = 3,
- .minimum_version_id = 3,
+ .version_id = 4,
+ .minimum_version_id = 4,
.fields = vmstate_env_fields,
.subsections = vmstate_env_subsections,
};
--
2.47.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/4] target/hppa: Add instruction decoding for mfdiag and mtdiag
2025-01-28 22:45 [PATCH v2] target/hppa: Implement CPU diagnose registers for 64-bit HP-UX deller
2025-01-28 22:45 ` [PATCH 1/4] target/hppa: Add CPU diagnose registers deller
@ 2025-01-28 22:45 ` deller
2025-01-29 1:46 ` Richard Henderson
2025-01-28 22:45 ` [PATCH 3/4] target/hppa: 64-bit CPUs start with space register hashing enabled deller
2025-01-28 22:45 ` [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX deller
3 siblings, 1 reply; 15+ messages in thread
From: deller @ 2025-01-28 22:45 UTC (permalink / raw)
To: richard.henderson, qemu-devel; +Cc: deller
From: Helge Deller <deller@gmx.de>
Add 32- and 64-bit instruction decoding of the mfdiag and mtdiag
instructions which modify the diagnose registers.
diag_getshadowregs_pa2() and diag_putshadowregs_pa2() were added in
commit 3bdf20819e68 based on some analysis of ODE code, but now they
conflict with the generic mfdiag/mtdiag instructions. I believe the
former analysis was wrong, so remove them again. Note that all diag
instructions are badly documented, so most things are based on reverse
engineering and thus may be wrong.
Signed-off-by: Helge Deller <deller@gmx.de>
Fixes: 3bdf20819e68 ("target/hppa: Add diag instructions to set/restore shadow registers")
---
target/hppa/insns.decode | 6 ++++--
target/hppa/translate.c | 22 ++++++++++++++++------
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/target/hppa/insns.decode b/target/hppa/insns.decode
index 71074a64c1..4eaac750ea 100644
--- a/target/hppa/insns.decode
+++ b/target/hppa/insns.decode
@@ -644,10 +644,12 @@ xmpyu 001110 ..... ..... 010 .0111 .00 t:5 r1=%ra64 r2=%rb64
# For 32-bit PA-7300LC (PCX-L2)
diag_getshadowregs_pa1 000101 00 0000 0000 0001 1010 0000 0000
diag_putshadowregs_pa1 000101 00 0000 0000 0001 1010 0100 0000
+ diag_mfdiag 000101 dr:5 rt:5 0000 0110 0000 0000
+ diag_mtdiag 000101 dr:5 r1:5 0001 0110 0000 0000
# For 64-bit PA8700 (PCX-W2)
- diag_getshadowregs_pa2 000101 00 0111 1000 0001 1000 0100 0000
- diag_putshadowregs_pa2 000101 00 0111 0000 0001 1000 0100 0000
+ diag_mfdiag 000101 dr:5 0 0000 0000 1000 101 rt:5
+ diag_mtdiag 000101 dr:5 r1:5 0001 1000 0100 0000
]
diag_unimp 000101 i:26
}
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index dc04f9f3c0..7b9d3deb39 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -4593,19 +4593,29 @@ static bool trans_diag_getshadowregs_pa1(DisasContext *ctx, arg_empty *a)
return !ctx->is_pa20 && do_getshadowregs(ctx);
}
-static bool trans_diag_getshadowregs_pa2(DisasContext *ctx, arg_empty *a)
+static bool trans_diag_putshadowregs_pa1(DisasContext *ctx, arg_empty *a)
{
- return ctx->is_pa20 && do_getshadowregs(ctx);
+ return !ctx->is_pa20 && do_putshadowregs(ctx);
}
-static bool trans_diag_putshadowregs_pa1(DisasContext *ctx, arg_empty *a)
+static bool trans_diag_mfdiag(DisasContext *ctx, arg_diag_mfdiag *a)
{
- return !ctx->is_pa20 && do_putshadowregs(ctx);
+ CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
+ nullify_over(ctx);
+ TCGv_i64 dest = dest_gpr(ctx, a->rt);
+ tcg_gen_ld_i64(dest, tcg_env,
+ offsetof(CPUHPPAState, dr[a->dr]));
+ save_gpr(ctx, a->rt, dest);
+ return nullify_end(ctx);
}
-static bool trans_diag_putshadowregs_pa2(DisasContext *ctx, arg_empty *a)
+static bool trans_diag_mtdiag(DisasContext *ctx, arg_diag_mtdiag *a)
{
- return ctx->is_pa20 && do_putshadowregs(ctx);
+ CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
+ nullify_over(ctx);
+ tcg_gen_st_i64(load_gpr(ctx, a->r1), tcg_env,
+ offsetof(CPUHPPAState, dr[a->dr]));
+ return nullify_end(ctx);
}
static bool trans_diag_unimp(DisasContext *ctx, arg_diag_unimp *a)
--
2.47.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 3/4] target/hppa: 64-bit CPUs start with space register hashing enabled
2025-01-28 22:45 [PATCH v2] target/hppa: Implement CPU diagnose registers for 64-bit HP-UX deller
2025-01-28 22:45 ` [PATCH 1/4] target/hppa: Add CPU diagnose registers deller
2025-01-28 22:45 ` [PATCH 2/4] target/hppa: Add instruction decoding for mfdiag and mtdiag deller
@ 2025-01-28 22:45 ` deller
2025-01-29 1:46 ` Richard Henderson
2025-01-28 22:45 ` [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX deller
3 siblings, 1 reply; 15+ messages in thread
From: deller @ 2025-01-28 22:45 UTC (permalink / raw)
To: richard.henderson, qemu-devel; +Cc: deller
From: Helge Deller <deller@gmx.de>
Turn on space register hashing for 64-bit CPUs when reset.
Signed-off-by: Helge Deller <deller@gmx.de>
---
target/hppa/cpu.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index b0bc9d35e4..c86f9190d2 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -28,6 +28,7 @@
#include "exec/translation-block.h"
#include "fpu/softfloat.h"
#include "tcg/tcg.h"
+#include "hw/hppa/hppa_hardware.h"
static void hppa_cpu_set_pc(CPUState *cs, vaddr value)
{
@@ -217,6 +218,10 @@ static void hppa_cpu_reset_hold(Object *obj, ResetType type)
memset(env, 0, offsetof(CPUHPPAState, end_reset_fields));
cpu_hppa_loaded_fr0(env);
+
+ /* 64-bit machines start with space-register hashing enabled in %dr2 */
+ env->dr[2] = hppa_is_pa20(env) ? HPPA64_DIAG_SPHASH_ENABLE : 0;
+
cpu_hppa_put_psw(env, PSW_M);
}
--
2.47.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX
2025-01-28 22:45 [PATCH v2] target/hppa: Implement CPU diagnose registers for 64-bit HP-UX deller
` (2 preceding siblings ...)
2025-01-28 22:45 ` [PATCH 3/4] target/hppa: 64-bit CPUs start with space register hashing enabled deller
@ 2025-01-28 22:45 ` deller
2025-01-29 1:50 ` Richard Henderson
2025-01-29 1:52 ` Richard Henderson
3 siblings, 2 replies; 15+ messages in thread
From: deller @ 2025-01-28 22:45 UTC (permalink / raw)
To: richard.henderson, qemu-devel; +Cc: deller
From: Helge Deller <deller@gmx.de>
The Linux kernel turns space-register hashing off unconditionally at
bootup. That code was provided by HP at the beginning of the PA-RISC
Linux porting effort, and I don't know why it was decided then why Linux
should not use space register hashing.
32-bit HP-UX versions seem to not use space register hashing either.
But for 64-bit HP-UX versions, Sven Schnelle noticed that space register
hashing needs to be enabled and is required, otherwise the HP-UX kernel
will crash badly.
On 64-bit CPUs space register hashing is controlled by a bit in diagnose
register %dr2. Since we want to support Linux and 32- and 64-bit HP-UX,
we need to fully emulate the diagnose registers and handle specifically
the bit in %dr2.
This patch adds the code to calculate the gva memory mask based on the
space-register hashing bit in %dr2 and the PSW_W (64-bit) flag.
The value is cached in the gva_offset_mask variable in CPUArchState
and recalculated at every modification of the CPU PSW or %dr2.
Signed-off-by: Helge Deller <deller@gmx.de>
Suggested-by: Richard Henderson <richard.henderson@linaro.org>
Suggested-by: Sven Schnelle <svens@stackframe.org>
---
target/hppa/cpu.c | 5 +++--
target/hppa/cpu.h | 19 +++++++------------
target/hppa/helper.c | 25 +++++++++++++++++++++++--
target/hppa/int_helper.c | 10 ++++++----
target/hppa/sys_helper.c | 4 ++--
target/hppa/translate.c | 8 +++++++-
6 files changed, 48 insertions(+), 23 deletions(-)
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index c86f9190d2..c64495332f 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -45,8 +45,9 @@ static vaddr hppa_cpu_get_pc(CPUState *cs)
{
CPUHPPAState *env = cpu_env(cs);
- return hppa_form_gva_psw(env->psw, (env->psw & PSW_C ? env->iasq_f : 0),
- env->iaoq_f & -4);
+ return hppa_form_gva_mask(env->gva_offset_mask,
+ (env->psw & PSW_C ? env->iasq_f : 0),
+ env->iaoq_f & -4);
}
void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index b858986c41..52dc6ec700 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -223,6 +223,7 @@ typedef struct CPUArchState {
target_ulong psw_cb; /* in least significant bit of next nibble */
target_ulong psw_cb_msb; /* boolean */
+ uint64_t gva_offset_mask; /* cached address mask based on PSW and %dr2 */
uint64_t iasq_f;
uint64_t iasq_b;
@@ -320,27 +321,20 @@ void hppa_translate_code(CPUState *cs, TranslationBlock *tb,
#define CPU_RESOLVING_TYPE TYPE_HPPA_CPU
-static inline uint64_t gva_offset_mask(target_ulong psw)
-{
- return (psw & PSW_W
- ? MAKE_64BIT_MASK(0, 62)
- : MAKE_64BIT_MASK(0, 32));
-}
-
-static inline target_ulong hppa_form_gva_psw(target_ulong psw, uint64_t spc,
- target_ulong off)
+static inline target_ulong hppa_form_gva_mask(uint64_t gva_offset_mask,
+ uint64_t spc, target_ulong off)
{
#ifdef CONFIG_USER_ONLY
- return off & gva_offset_mask(psw);
+ return off & gva_offset_mask;
#else
- return spc | (off & gva_offset_mask(psw));
+ return spc | (off & gva_offset_mask);
#endif
}
static inline target_ulong hppa_form_gva(CPUHPPAState *env, uint64_t spc,
target_ulong off)
{
- return hppa_form_gva_psw(env->psw, spc, off);
+ return hppa_form_gva_mask(env->gva_offset_mask, spc, off);
}
hwaddr hppa_abs_to_phys_pa2_w0(vaddr addr);
@@ -362,6 +356,7 @@ void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
target_ulong cpu_hppa_get_psw(CPUHPPAState *env);
void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong);
+void update_gva_offset_mask(CPUHPPAState *env);
void cpu_hppa_loaded_fr0(CPUHPPAState *env);
#ifdef CONFIG_USER_ONLY
diff --git a/target/hppa/helper.c b/target/hppa/helper.c
index d4b1a3cd5a..ac7f58f0af 100644
--- a/target/hppa/helper.c
+++ b/target/hppa/helper.c
@@ -24,6 +24,7 @@
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "qemu/qemu-print.h"
+#include "hw/hppa/hppa_hardware.h"
target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
{
@@ -59,6 +60,22 @@ target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
return psw;
}
+void update_gva_offset_mask(CPUHPPAState *env)
+{
+ uint64_t gom;
+
+ if (env->psw & PSW_W) {
+ gom = (env->dr[2] & HPPA64_DIAG_SPHASH_ENABLE)
+ ? MAKE_64BIT_MASK(0, 62) &
+ ~((uint64_t)HPPA64_PDC_CACHE_RET_SPID_VAL << 48)
+ : MAKE_64BIT_MASK(0, 62);
+ } else {
+ gom = MAKE_64BIT_MASK(0, 32);
+ }
+
+ env->gva_offset_mask = gom;
+}
+
void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
{
uint64_t reserved;
@@ -98,6 +115,8 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
cb |= ((psw >> 9) & 1) << 8;
cb |= ((psw >> 8) & 1) << 4;
env->psw_cb = cb;
+
+ update_gva_offset_mask(env);
}
void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
@@ -133,9 +152,11 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
qemu_fprintf(f, "IA_F %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n"
"IA_B %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n",
env->iasq_f >> 32, w, m & env->iaoq_f,
- hppa_form_gva_psw(psw, env->iasq_f, env->iaoq_f),
+ hppa_form_gva_mask(env->gva_offset_mask, env->iasq_f,
+ env->iaoq_f),
env->iasq_b >> 32, w, m & env->iaoq_b,
- hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b));
+ hppa_form_gva_mask(env->gva_offset_mask, env->iasq_b,
+ env->iaoq_b));
psw_c[0] = (psw & PSW_W ? 'W' : '-');
psw_c[1] = (psw & PSW_E ? 'E' : '-');
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 58695def82..7d48643bb6 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -94,11 +94,12 @@ void hppa_cpu_do_interrupt(CPUState *cs)
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = &cpu->env;
int i = cs->exception_index;
- uint64_t old_psw;
+ uint64_t old_psw, old_gva_offset_mask;
/* As documented in pa2.0 -- interruption handling. */
/* step 1 */
env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env);
+ old_gva_offset_mask = env->gva_offset_mask;
/* step 2 -- Note PSW_W is masked out again for pa1.x */
cpu_hppa_put_psw(env,
@@ -112,9 +113,9 @@ void hppa_cpu_do_interrupt(CPUState *cs)
*/
if (old_psw & PSW_C) {
env->cr[CR_IIASQ] =
- hppa_form_gva_psw(old_psw, env->iasq_f, env->iaoq_f) >> 32;
+ hppa_form_gva_mask(old_gva_offset_mask, env->iasq_f, env->iaoq_f) >> 32;
env->cr_back[0] =
- hppa_form_gva_psw(old_psw, env->iasq_b, env->iaoq_b) >> 32;
+ hppa_form_gva_mask(old_gva_offset_mask, env->iasq_b, env->iaoq_b) >> 32;
} else {
env->cr[CR_IIASQ] = 0;
env->cr_back[0] = 0;
@@ -165,7 +166,8 @@ void hppa_cpu_do_interrupt(CPUState *cs)
if (old_psw & PSW_C) {
int prot, t;
- vaddr = hppa_form_gva_psw(old_psw, env->iasq_f, vaddr);
+ vaddr = hppa_form_gva_mask(old_gva_offset_mask,
+ env->iasq_f, vaddr);
t = hppa_get_physical_address(env, vaddr, MMU_KERNEL_IDX,
0, 0, &paddr, &prot);
if (t >= 0) {
diff --git a/target/hppa/sys_helper.c b/target/hppa/sys_helper.c
index da5b569de8..052a6a88a2 100644
--- a/target/hppa/sys_helper.c
+++ b/target/hppa/sys_helper.c
@@ -73,7 +73,7 @@ target_ulong HELPER(swap_system_mask)(CPUHPPAState *env, target_ulong nsm)
* machines set the Q bit from 0 to 1 without an exception,
* so let this go without comment.
*/
- env->psw = (psw & ~PSW_SM) | (nsm & PSW_SM);
+ cpu_hppa_put_psw(env, (psw & ~PSW_SM) | (nsm & PSW_SM));
return psw & PSW_SM;
}
@@ -88,7 +88,7 @@ void HELPER(rfi)(CPUHPPAState *env)
* To recreate the space identifier, remove the offset bits.
* For pa1.x, the mask reduces to no change to space.
*/
- mask = gva_offset_mask(env->psw);
+ mask = env->gva_offset_mask;
env->iaoq_f = env->cr[CR_IIAOQ];
env->iaoq_b = env->cr_back[1];
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 7b9d3deb39..6c68f98651 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -73,6 +73,7 @@ typedef struct DisasContext {
/* IAOQ_Front at entry to TB. */
uint64_t iaoq_first;
+ uint64_t gva_offset_mask;
DisasCond null_cond;
TCGLabel *null_lab;
@@ -1577,7 +1578,7 @@ static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
*pofs = ofs;
*pgva = addr = tcg_temp_new_i64();
tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base,
- gva_offset_mask(ctx->tb_flags));
+ ctx->gva_offset_mask);
#ifndef CONFIG_USER_ONLY
if (!is_phys) {
tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
@@ -4615,6 +4616,10 @@ static bool trans_diag_mtdiag(DisasContext *ctx, arg_diag_mtdiag *a)
nullify_over(ctx);
tcg_gen_st_i64(load_gpr(ctx, a->r1), tcg_env,
offsetof(CPUHPPAState, dr[a->dr]));
+ if (ctx->is_pa20 && (a->dr == 2)) {
+ /* Exit TB to recalculate gva_offset_mask on %dr2 */
+ ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
+ }
return nullify_end(ctx);
}
@@ -4635,6 +4640,7 @@ static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->tb_flags = ctx->base.tb->flags;
ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
ctx->psw_xb = ctx->tb_flags & (PSW_X | PSW_B);
+ ctx->gva_offset_mask = cpu_env(cs)->gva_offset_mask;
#ifdef CONFIG_USER_ONLY
ctx->privilege = PRIV_USER;
--
2.47.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 1/4] target/hppa: Add CPU diagnose registers
2025-01-28 22:45 ` [PATCH 1/4] target/hppa: Add CPU diagnose registers deller
@ 2025-01-29 1:43 ` Richard Henderson
0 siblings, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2025-01-29 1:43 UTC (permalink / raw)
To: deller, qemu-devel; +Cc: deller
On 1/28/25 14:45, deller@kernel.org wrote:
> From: Helge Deller<deller@gmx.de>
>
> Add the diagnose registers (%dr) to the CPUArchState. Those are mostly
> undocumented and control cache behaviour, memory behaviour, reset button
> management and many other related internal CPU things.
>
> Signed-off-by: Helge Deller<deller@gmx.de>
> ---
> target/hppa/cpu.h | 1 +
> target/hppa/machine.c | 5 +++--
> 2 files changed, 4 insertions(+), 2 deletions(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/4] target/hppa: Add instruction decoding for mfdiag and mtdiag
2025-01-28 22:45 ` [PATCH 2/4] target/hppa: Add instruction decoding for mfdiag and mtdiag deller
@ 2025-01-29 1:46 ` Richard Henderson
0 siblings, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2025-01-29 1:46 UTC (permalink / raw)
To: deller, qemu-devel; +Cc: deller
On 1/28/25 14:45, deller@kernel.org wrote:
> From: Helge Deller <deller@gmx.de>
>
> Add 32- and 64-bit instruction decoding of the mfdiag and mtdiag
> instructions which modify the diagnose registers.
>
> diag_getshadowregs_pa2() and diag_putshadowregs_pa2() were added in
> commit 3bdf20819e68 based on some analysis of ODE code, but now they
> conflict with the generic mfdiag/mtdiag instructions. I believe the
> former analysis was wrong, so remove them again. Note that all diag
> instructions are badly documented, so most things are based on reverse
> engineering and thus may be wrong.
>
> Signed-off-by: Helge Deller <deller@gmx.de>
> Fixes: 3bdf20819e68 ("target/hppa: Add diag instructions to set/restore shadow registers")
> ---
> target/hppa/insns.decode | 6 ++++--
> target/hppa/translate.c | 22 ++++++++++++++++------
> 2 files changed, 20 insertions(+), 8 deletions(-)
>
> diff --git a/target/hppa/insns.decode b/target/hppa/insns.decode
> index 71074a64c1..4eaac750ea 100644
> --- a/target/hppa/insns.decode
> +++ b/target/hppa/insns.decode
> @@ -644,10 +644,12 @@ xmpyu 001110 ..... ..... 010 .0111 .00 t:5 r1=%ra64 r2=%rb64
> # For 32-bit PA-7300LC (PCX-L2)
> diag_getshadowregs_pa1 000101 00 0000 0000 0001 1010 0000 0000
> diag_putshadowregs_pa1 000101 00 0000 0000 0001 1010 0100 0000
> + diag_mfdiag 000101 dr:5 rt:5 0000 0110 0000 0000
> + diag_mtdiag 000101 dr:5 r1:5 0001 0110 0000 0000
>
> # For 64-bit PA8700 (PCX-W2)
> - diag_getshadowregs_pa2 000101 00 0111 1000 0001 1000 0100 0000
> - diag_putshadowregs_pa2 000101 00 0111 0000 0001 1000 0100 0000
> + diag_mfdiag 000101 dr:5 0 0000 0000 1000 101 rt:5
> + diag_mtdiag 000101 dr:5 r1:5 0001 1000 0100 0000
Remove diag_get/putshadowregs_pa2 as a separate patch.
Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/4] target/hppa: 64-bit CPUs start with space register hashing enabled
2025-01-28 22:45 ` [PATCH 3/4] target/hppa: 64-bit CPUs start with space register hashing enabled deller
@ 2025-01-29 1:46 ` Richard Henderson
0 siblings, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2025-01-29 1:46 UTC (permalink / raw)
To: deller, qemu-devel; +Cc: deller
On 1/28/25 14:45, deller@kernel.org wrote:
> From: Helge Deller<deller@gmx.de>
>
> Turn on space register hashing for 64-bit CPUs when reset.
>
> Signed-off-by: Helge Deller<deller@gmx.de>
> ---
> target/hppa/cpu.c | 5 +++++
> 1 file changed, 5 insertions(+)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX
2025-01-28 22:45 ` [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX deller
@ 2025-01-29 1:50 ` Richard Henderson
2025-01-29 1:52 ` Richard Henderson
1 sibling, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2025-01-29 1:50 UTC (permalink / raw)
To: deller, qemu-devel; +Cc: deller
On 1/28/25 14:45, deller@kernel.org wrote:
> @@ -4635,6 +4640,7 @@ static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
> ctx->tb_flags = ctx->base.tb->flags;
> ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
> ctx->psw_xb = ctx->tb_flags & (PSW_X | PSW_B);
> + ctx->gva_offset_mask = cpu_env(cs)->gva_offset_mask;
This is invalid because no portion of ds2 affects tb_flags.
You can't just read from env.
r~
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX
2025-01-28 22:45 ` [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX deller
2025-01-29 1:50 ` Richard Henderson
@ 2025-01-29 1:52 ` Richard Henderson
2025-01-29 2:00 ` Richard Henderson
1 sibling, 1 reply; 15+ messages in thread
From: Richard Henderson @ 2025-01-29 1:52 UTC (permalink / raw)
To: deller, qemu-devel; +Cc: deller
On 1/28/25 14:45, deller@kernel.org wrote:
> + if (ctx->is_pa20 && (a->dr == 2)) {
> + /* Exit TB to recalculate gva_offset_mask on %dr2 */
> + ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
> + }
Where does this update happen? I think you've missed that step.
r~
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX
2025-01-29 1:52 ` Richard Henderson
@ 2025-01-29 2:00 ` Richard Henderson
2025-01-29 4:07 ` Helge Deller
0 siblings, 1 reply; 15+ messages in thread
From: Richard Henderson @ 2025-01-29 2:00 UTC (permalink / raw)
To: deller, qemu-devel; +Cc: deller
On 1/28/25 17:52, Richard Henderson wrote:
> On 1/28/25 14:45, deller@kernel.org wrote:
>> + if (ctx->is_pa20 && (a->dr == 2)) {
>> + /* Exit TB to recalculate gva_offset_mask on %dr2 */
>> + ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
>> + }
>
> Where does this update happen? I think you've missed that step.
To expand on this, I believe you want a new helper, invoked here, which calls
update_gva_offset_mask(). Then exit the tb as you do above.
We don't really have to go back to the main loop, but we can't chain with
DISAS_IAQ_N_STALE either. We'd have to invent another DISAS thingy for an exact fit. For
something that's probably called once at boot and never again, it hardly seems worth the
effort.
r~
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX
2025-01-29 2:00 ` Richard Henderson
@ 2025-01-29 4:07 ` Helge Deller
2025-01-29 5:33 ` Richard Henderson
0 siblings, 1 reply; 15+ messages in thread
From: Helge Deller @ 2025-01-29 4:07 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel, deller
* Richard Henderson <richard.henderson@linaro.org>:
> On 1/28/25 17:52, Richard Henderson wrote:
> > On 1/28/25 14:45, deller@kernel.org wrote:
> > > + if (ctx->is_pa20 && (a->dr == 2)) {
> > > + /* Exit TB to recalculate gva_offset_mask on %dr2 */
> > > + ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
> > > + }
> >
> > Where does this update happen? I think you've missed that step.
>
> To expand on this, I believe you want a new helper, invoked here, which
> calls update_gva_offset_mask(). Then exit the tb as you do above.
>
> We don't really have to go back to the main loop, but we can't chain with
> DISAS_IAQ_N_STALE either. We'd have to invent another DISAS thingy for an
> exact fit. For something that's probably called once at boot and never
> again, it hardly seems worth the effort.
I adjusted it, please see current patch version at the end of the mail.
What I'm not sure about is gva_offset_mask in those hunks and where you
said I can't read from env:
+++ b/target/hppa/translate.c
@@ -73,6 +73,7 @@ typedef struct DisasContext {
/* IAOQ_Front at entry to TB. */
uint64_t iaoq_first;
+ uint64_t gva_offset_mask;
DisasCond null_cond;
TCGLabel *null_lab;
@@ -1577,7 +1578,7 @@ static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
*pofs = ofs;
*pgva = addr = tcg_temp_new_i64();
tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base,
- gva_offset_mask(ctx->tb_flags));
+ ctx->gva_offset_mask);
#ifndef CONFIG_USER_ONLY
if (!is_phys) {
tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
@@ -4635,6 +4641,7 @@ static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->tb_flags = ctx->base.tb->flags;
ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
ctx->psw_xb = ctx->tb_flags & (PSW_X | PSW_B);
+ ctx->gva_offset_mask = cpu_env(cs)->gva_offset_mask;
Do I need to change the code in form_gva() to read at runtime from env
instead?
Helge
Current patch:
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index c86f9190d2..c64495332f 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -45,8 +45,9 @@ static vaddr hppa_cpu_get_pc(CPUState *cs)
{
CPUHPPAState *env = cpu_env(cs);
- return hppa_form_gva_psw(env->psw, (env->psw & PSW_C ? env->iasq_f : 0),
- env->iaoq_f & -4);
+ return hppa_form_gva_mask(env->gva_offset_mask,
+ (env->psw & PSW_C ? env->iasq_f : 0),
+ env->iaoq_f & -4);
}
void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index b858986c41..52dc6ec700 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -223,6 +223,7 @@ typedef struct CPUArchState {
target_ulong psw_cb; /* in least significant bit of next nibble */
target_ulong psw_cb_msb; /* boolean */
+ uint64_t gva_offset_mask; /* cached address mask based on PSW and %dr2 */
uint64_t iasq_f;
uint64_t iasq_b;
@@ -320,27 +321,20 @@ void hppa_translate_code(CPUState *cs, TranslationBlock *tb,
#define CPU_RESOLVING_TYPE TYPE_HPPA_CPU
-static inline uint64_t gva_offset_mask(target_ulong psw)
-{
- return (psw & PSW_W
- ? MAKE_64BIT_MASK(0, 62)
- : MAKE_64BIT_MASK(0, 32));
-}
-
-static inline target_ulong hppa_form_gva_psw(target_ulong psw, uint64_t spc,
- target_ulong off)
+static inline target_ulong hppa_form_gva_mask(uint64_t gva_offset_mask,
+ uint64_t spc, target_ulong off)
{
#ifdef CONFIG_USER_ONLY
- return off & gva_offset_mask(psw);
+ return off & gva_offset_mask;
#else
- return spc | (off & gva_offset_mask(psw));
+ return spc | (off & gva_offset_mask);
#endif
}
static inline target_ulong hppa_form_gva(CPUHPPAState *env, uint64_t spc,
target_ulong off)
{
- return hppa_form_gva_psw(env->psw, spc, off);
+ return hppa_form_gva_mask(env->gva_offset_mask, spc, off);
}
hwaddr hppa_abs_to_phys_pa2_w0(vaddr addr);
@@ -362,6 +356,7 @@ void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
target_ulong cpu_hppa_get_psw(CPUHPPAState *env);
void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong);
+void update_gva_offset_mask(CPUHPPAState *env);
void cpu_hppa_loaded_fr0(CPUHPPAState *env);
#ifdef CONFIG_USER_ONLY
diff --git a/target/hppa/helper.c b/target/hppa/helper.c
index d4b1a3cd5a..ac7f58f0af 100644
--- a/target/hppa/helper.c
+++ b/target/hppa/helper.c
@@ -24,6 +24,7 @@
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "qemu/qemu-print.h"
+#include "hw/hppa/hppa_hardware.h"
target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
{
@@ -59,6 +60,22 @@ target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
return psw;
}
+void update_gva_offset_mask(CPUHPPAState *env)
+{
+ uint64_t gom;
+
+ if (env->psw & PSW_W) {
+ gom = (env->dr[2] & HPPA64_DIAG_SPHASH_ENABLE)
+ ? MAKE_64BIT_MASK(0, 62) &
+ ~((uint64_t)HPPA64_PDC_CACHE_RET_SPID_VAL << 48)
+ : MAKE_64BIT_MASK(0, 62);
+ } else {
+ gom = MAKE_64BIT_MASK(0, 32);
+ }
+
+ env->gva_offset_mask = gom;
+}
+
void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
{
uint64_t reserved;
@@ -98,6 +115,8 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
cb |= ((psw >> 9) & 1) << 8;
cb |= ((psw >> 8) & 1) << 4;
env->psw_cb = cb;
+
+ update_gva_offset_mask(env);
}
void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
@@ -133,9 +152,11 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
qemu_fprintf(f, "IA_F %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n"
"IA_B %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n",
env->iasq_f >> 32, w, m & env->iaoq_f,
- hppa_form_gva_psw(psw, env->iasq_f, env->iaoq_f),
+ hppa_form_gva_mask(env->gva_offset_mask, env->iasq_f,
+ env->iaoq_f),
env->iasq_b >> 32, w, m & env->iaoq_b,
- hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b));
+ hppa_form_gva_mask(env->gva_offset_mask, env->iasq_b,
+ env->iaoq_b));
psw_c[0] = (psw & PSW_W ? 'W' : '-');
psw_c[1] = (psw & PSW_E ? 'E' : '-');
diff --git a/target/hppa/helper.h b/target/hppa/helper.h
index de411923d9..8369855d78 100644
--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -99,6 +99,7 @@ DEF_HELPER_FLAGS_2(ptlb_l, 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, tl, env, tl)
DEF_HELPER_FLAGS_1(change_prot_id, TCG_CALL_NO_RWG, void, env)
+DEF_HELPER_FLAGS_1(update_gva_offset_mask, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_1(diag_btlb, void, env)
DEF_HELPER_1(diag_console_output, void, env)
#endif
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 58695def82..7d48643bb6 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -94,11 +94,12 @@ void hppa_cpu_do_interrupt(CPUState *cs)
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = &cpu->env;
int i = cs->exception_index;
- uint64_t old_psw;
+ uint64_t old_psw, old_gva_offset_mask;
/* As documented in pa2.0 -- interruption handling. */
/* step 1 */
env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env);
+ old_gva_offset_mask = env->gva_offset_mask;
/* step 2 -- Note PSW_W is masked out again for pa1.x */
cpu_hppa_put_psw(env,
@@ -112,9 +113,9 @@ void hppa_cpu_do_interrupt(CPUState *cs)
*/
if (old_psw & PSW_C) {
env->cr[CR_IIASQ] =
- hppa_form_gva_psw(old_psw, env->iasq_f, env->iaoq_f) >> 32;
+ hppa_form_gva_mask(old_gva_offset_mask, env->iasq_f, env->iaoq_f) >> 32;
env->cr_back[0] =
- hppa_form_gva_psw(old_psw, env->iasq_b, env->iaoq_b) >> 32;
+ hppa_form_gva_mask(old_gva_offset_mask, env->iasq_b, env->iaoq_b) >> 32;
} else {
env->cr[CR_IIASQ] = 0;
env->cr_back[0] = 0;
@@ -165,7 +166,8 @@ void hppa_cpu_do_interrupt(CPUState *cs)
if (old_psw & PSW_C) {
int prot, t;
- vaddr = hppa_form_gva_psw(old_psw, env->iasq_f, vaddr);
+ vaddr = hppa_form_gva_mask(old_gva_offset_mask,
+ env->iasq_f, vaddr);
t = hppa_get_physical_address(env, vaddr, MMU_KERNEL_IDX,
0, 0, &paddr, &prot);
if (t >= 0) {
diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c
index b8c3e55170..304f0b61e2 100644
--- a/target/hppa/mem_helper.c
+++ b/target/hppa/mem_helper.c
@@ -824,3 +824,8 @@ uint64_t HELPER(b_gate_priv)(CPUHPPAState *env, uint64_t iaoq_f)
}
return iaoq_f;
}
+
+void HELPER(update_gva_offset_mask)(CPUHPPAState *env)
+{
+ update_gva_offset_mask(env);
+}
diff --git a/target/hppa/sys_helper.c b/target/hppa/sys_helper.c
index da5b569de8..052a6a88a2 100644
--- a/target/hppa/sys_helper.c
+++ b/target/hppa/sys_helper.c
@@ -73,7 +73,7 @@ target_ulong HELPER(swap_system_mask)(CPUHPPAState *env, target_ulong nsm)
* machines set the Q bit from 0 to 1 without an exception,
* so let this go without comment.
*/
- env->psw = (psw & ~PSW_SM) | (nsm & PSW_SM);
+ cpu_hppa_put_psw(env, (psw & ~PSW_SM) | (nsm & PSW_SM));
return psw & PSW_SM;
}
@@ -88,7 +88,7 @@ void HELPER(rfi)(CPUHPPAState *env)
* To recreate the space identifier, remove the offset bits.
* For pa1.x, the mask reduces to no change to space.
*/
- mask = gva_offset_mask(env->psw);
+ mask = env->gva_offset_mask;
env->iaoq_f = env->cr[CR_IIAOQ];
env->iaoq_b = env->cr_back[1];
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 7b9d3deb39..5508c55378 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -73,6 +73,7 @@ typedef struct DisasContext {
/* IAOQ_Front at entry to TB. */
uint64_t iaoq_first;
+ uint64_t gva_offset_mask;
DisasCond null_cond;
TCGLabel *null_lab;
@@ -1577,7 +1578,7 @@ static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
*pofs = ofs;
*pgva = addr = tcg_temp_new_i64();
tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base,
- gva_offset_mask(ctx->tb_flags));
+ ctx->gva_offset_mask);
#ifndef CONFIG_USER_ONLY
if (!is_phys) {
tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
@@ -4615,6 +4616,11 @@ static bool trans_diag_mtdiag(DisasContext *ctx, arg_diag_mtdiag *a)
nullify_over(ctx);
tcg_gen_st_i64(load_gpr(ctx, a->r1), tcg_env,
offsetof(CPUHPPAState, dr[a->dr]));
+ if (ctx->is_pa20 && (a->dr == 2)) {
+ gen_helper_update_gva_offset_mask(tcg_env);
+ /* Exit TB to recalculate gva_offset_mask on %dr2 */
+ ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
+ }
return nullify_end(ctx);
}
@@ -4635,6 +4641,7 @@ static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->tb_flags = ctx->base.tb->flags;
ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
ctx->psw_xb = ctx->tb_flags & (PSW_X | PSW_B);
+ ctx->gva_offset_mask = cpu_env(cs)->gva_offset_mask;
#ifdef CONFIG_USER_ONLY
ctx->privilege = PRIV_USER;
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX
2025-01-29 4:07 ` Helge Deller
@ 2025-01-29 5:33 ` Richard Henderson
2025-01-29 15:30 ` Helge Deller
0 siblings, 1 reply; 15+ messages in thread
From: Richard Henderson @ 2025-01-29 5:33 UTC (permalink / raw)
To: Helge Deller; +Cc: qemu-devel, deller
On 1/28/25 20:07, Helge Deller wrote:
> What I'm not sure about is gva_offset_mask in those hunks and where you
> said I can't read from env:
...
> @@ -4635,6 +4641,7 @@ static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
> ctx->tb_flags = ctx->base.tb->flags;
> ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
> ctx->psw_xb = ctx->tb_flags & (PSW_X | PSW_B);
> + ctx->gva_offset_mask = cpu_env(cs)->gva_offset_mask;
>
> Do I need to change the code in form_gva() to read at runtime from env
> instead?
That's one way to do it, sure. But it's not so hard:
#define TB_FLAG_SPHASH 0x800
void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
uint64_t *pcsbase, uint32_t *pflags)
{
...
#ifdef CONFIG_USER_ONLY
flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus;
#else
if ((env->sr[4] == env->sr[5])
& (env->sr[4] == env->sr[6])
& (env->sr[4] == env->sr[7])) {
flags |= TB_FLAG_SR_SAME;
}
if ((flags & PSW_W) &&
(env->dr[2] & HPPA64_DIAG_SPHASH_ENABLE)) {
flags |= TB_FLAG_SPHASH;
}
#endif
...
}
Now tb_flags is constrained by both inputs to update_gva_offset_mask, and you *can* read
from env->gva_offset_mask. It's guaranteed to be the same every time.
> nullify_over(ctx);
> tcg_gen_st_i64(load_gpr(ctx, a->r1), tcg_env,
> offsetof(CPUHPPAState, dr[a->dr]));
> + if (ctx->is_pa20 && (a->dr == 2)) {
> + gen_helper_update_gva_offset_mask(tcg_env);
> + /* Exit TB to recalculate gva_offset_mask on %dr2 */
> + ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
> + }
Better comment:
/* Update gva_offset_mask from the new value of %dr2 */
gen_helper_update_gva_offset_mask(tcg_env);
/* Exit to capture the new value for the next TB. */
ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
r~
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX
2025-01-29 5:33 ` Richard Henderson
@ 2025-01-29 15:30 ` Helge Deller
2025-01-30 1:10 ` Richard Henderson
0 siblings, 1 reply; 15+ messages in thread
From: Helge Deller @ 2025-01-29 15:30 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel, deller
Richard, thanks for your feedback!
Can you please review the updated patch below which includes your
suggestions.
Additionally I've successfully tested it.
Thanks in advance,
Helge
-------------
Subject: [PATCH] target/hppa: Implement space register hashing for 64-bit HP-UX
The Linux kernel turns space-register hashing off unconditionally at
bootup. That code was provided by HP at the beginning of the PA-RISC
Linux porting effort, and I don't know why it was decided then why Linux
should not use space register hashing.
32-bit HP-UX versions seem to not use space register hashing either.
But for 64-bit HP-UX versions, Sven Schnelle noticed that space register
hashing needs to be enabled and is required, otherwise the HP-UX kernel
will crash badly.
On 64-bit CPUs space register hashing is controlled by a bit in diagnose
register %dr2. Since we want to support Linux and 32- and 64-bit HP-UX,
we need to fully emulate the diagnose registers and handle specifically
the bit in %dr2.
This patch adds the code to calculate the gva memory mask based on the
space-register hashing bit in %dr2 and the PSW_W (64-bit) flag.
The value is cached in the gva_offset_mask variable in CPUArchState
and recalculated at every modification of the CPU PSW or %dr2.
Signed-off-by: Helge Deller <deller@gmx.de>
Suggested-by: Richard Henderson <richard.henderson@linaro.org>
Suggested-by: Sven Schnelle <svens@stackframe.org>
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index c86f9190d2..5655677431 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -45,8 +45,9 @@ static vaddr hppa_cpu_get_pc(CPUState *cs)
{
CPUHPPAState *env = cpu_env(cs);
- return hppa_form_gva_psw(env->psw, (env->psw & PSW_C ? env->iasq_f : 0),
- env->iaoq_f & -4);
+ return hppa_form_gva_mask(env->gva_offset_mask,
+ (env->psw & PSW_C ? env->iasq_f : 0),
+ env->iaoq_f & -4);
}
void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
@@ -91,6 +92,10 @@ void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
& (env->sr[4] == env->sr[7])) {
flags |= TB_FLAG_SR_SAME;
}
+ if ((env->psw & PSW_W) &&
+ (env->dr[2] & HPPA64_DIAG_SPHASH_ENABLE)) {
+ flags |= TB_FLAG_SPHASH;
+ }
#endif
*pcsbase = cs_base;
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index b858986c41..7be4a1d380 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -223,6 +223,7 @@ typedef struct CPUArchState {
target_ulong psw_cb; /* in least significant bit of next nibble */
target_ulong psw_cb_msb; /* boolean */
+ uint64_t gva_offset_mask; /* cached address mask based on PSW and %dr2 */
uint64_t iasq_f;
uint64_t iasq_b;
@@ -320,27 +321,20 @@ void hppa_translate_code(CPUState *cs, TranslationBlock *tb,
#define CPU_RESOLVING_TYPE TYPE_HPPA_CPU
-static inline uint64_t gva_offset_mask(target_ulong psw)
-{
- return (psw & PSW_W
- ? MAKE_64BIT_MASK(0, 62)
- : MAKE_64BIT_MASK(0, 32));
-}
-
-static inline target_ulong hppa_form_gva_psw(target_ulong psw, uint64_t spc,
- target_ulong off)
+static inline target_ulong hppa_form_gva_mask(uint64_t gva_offset_mask,
+ uint64_t spc, target_ulong off)
{
#ifdef CONFIG_USER_ONLY
- return off & gva_offset_mask(psw);
+ return off & gva_offset_mask;
#else
- return spc | (off & gva_offset_mask(psw));
+ return spc | (off & gva_offset_mask);
#endif
}
static inline target_ulong hppa_form_gva(CPUHPPAState *env, uint64_t spc,
target_ulong off)
{
- return hppa_form_gva_psw(env->psw, spc, off);
+ return hppa_form_gva_mask(env->gva_offset_mask, spc, off);
}
hwaddr hppa_abs_to_phys_pa2_w0(vaddr addr);
@@ -354,6 +348,7 @@ hwaddr hppa_abs_to_phys_pa2_w1(vaddr addr);
#define TB_FLAG_SR_SAME PSW_I
#define TB_FLAG_PRIV_SHIFT 8
#define TB_FLAG_UNALIGN 0x400
+#define TB_FLAG_SPHASH 0x800
#define CS_BASE_DIFFPAGE (1 << 12)
#define CS_BASE_DIFFSPACE (1 << 13)
@@ -362,6 +357,7 @@ void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
target_ulong cpu_hppa_get_psw(CPUHPPAState *env);
void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong);
+void update_gva_offset_mask(CPUHPPAState *env);
void cpu_hppa_loaded_fr0(CPUHPPAState *env);
#ifdef CONFIG_USER_ONLY
diff --git a/target/hppa/helper.c b/target/hppa/helper.c
index d4b1a3cd5a..ac7f58f0af 100644
--- a/target/hppa/helper.c
+++ b/target/hppa/helper.c
@@ -24,6 +24,7 @@
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "qemu/qemu-print.h"
+#include "hw/hppa/hppa_hardware.h"
target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
{
@@ -59,6 +60,22 @@ target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
return psw;
}
+void update_gva_offset_mask(CPUHPPAState *env)
+{
+ uint64_t gom;
+
+ if (env->psw & PSW_W) {
+ gom = (env->dr[2] & HPPA64_DIAG_SPHASH_ENABLE)
+ ? MAKE_64BIT_MASK(0, 62) &
+ ~((uint64_t)HPPA64_PDC_CACHE_RET_SPID_VAL << 48)
+ : MAKE_64BIT_MASK(0, 62);
+ } else {
+ gom = MAKE_64BIT_MASK(0, 32);
+ }
+
+ env->gva_offset_mask = gom;
+}
+
void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
{
uint64_t reserved;
@@ -98,6 +115,8 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
cb |= ((psw >> 9) & 1) << 8;
cb |= ((psw >> 8) & 1) << 4;
env->psw_cb = cb;
+
+ update_gva_offset_mask(env);
}
void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
@@ -133,9 +152,11 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
qemu_fprintf(f, "IA_F %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n"
"IA_B %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n",
env->iasq_f >> 32, w, m & env->iaoq_f,
- hppa_form_gva_psw(psw, env->iasq_f, env->iaoq_f),
+ hppa_form_gva_mask(env->gva_offset_mask, env->iasq_f,
+ env->iaoq_f),
env->iasq_b >> 32, w, m & env->iaoq_b,
- hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b));
+ hppa_form_gva_mask(env->gva_offset_mask, env->iasq_b,
+ env->iaoq_b));
psw_c[0] = (psw & PSW_W ? 'W' : '-');
psw_c[1] = (psw & PSW_E ? 'E' : '-');
diff --git a/target/hppa/helper.h b/target/hppa/helper.h
index de411923d9..8369855d78 100644
--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -99,6 +99,7 @@ DEF_HELPER_FLAGS_2(ptlb_l, 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, tl, env, tl)
DEF_HELPER_FLAGS_1(change_prot_id, TCG_CALL_NO_RWG, void, env)
+DEF_HELPER_FLAGS_1(update_gva_offset_mask, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_1(diag_btlb, void, env)
DEF_HELPER_1(diag_console_output, void, env)
#endif
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 58695def82..7d48643bb6 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -94,11 +94,12 @@ void hppa_cpu_do_interrupt(CPUState *cs)
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = &cpu->env;
int i = cs->exception_index;
- uint64_t old_psw;
+ uint64_t old_psw, old_gva_offset_mask;
/* As documented in pa2.0 -- interruption handling. */
/* step 1 */
env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env);
+ old_gva_offset_mask = env->gva_offset_mask;
/* step 2 -- Note PSW_W is masked out again for pa1.x */
cpu_hppa_put_psw(env,
@@ -112,9 +113,9 @@ void hppa_cpu_do_interrupt(CPUState *cs)
*/
if (old_psw & PSW_C) {
env->cr[CR_IIASQ] =
- hppa_form_gva_psw(old_psw, env->iasq_f, env->iaoq_f) >> 32;
+ hppa_form_gva_mask(old_gva_offset_mask, env->iasq_f, env->iaoq_f) >> 32;
env->cr_back[0] =
- hppa_form_gva_psw(old_psw, env->iasq_b, env->iaoq_b) >> 32;
+ hppa_form_gva_mask(old_gva_offset_mask, env->iasq_b, env->iaoq_b) >> 32;
} else {
env->cr[CR_IIASQ] = 0;
env->cr_back[0] = 0;
@@ -165,7 +166,8 @@ void hppa_cpu_do_interrupt(CPUState *cs)
if (old_psw & PSW_C) {
int prot, t;
- vaddr = hppa_form_gva_psw(old_psw, env->iasq_f, vaddr);
+ vaddr = hppa_form_gva_mask(old_gva_offset_mask,
+ env->iasq_f, vaddr);
t = hppa_get_physical_address(env, vaddr, MMU_KERNEL_IDX,
0, 0, &paddr, &prot);
if (t >= 0) {
diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c
index b8c3e55170..304f0b61e2 100644
--- a/target/hppa/mem_helper.c
+++ b/target/hppa/mem_helper.c
@@ -824,3 +824,8 @@ uint64_t HELPER(b_gate_priv)(CPUHPPAState *env, uint64_t iaoq_f)
}
return iaoq_f;
}
+
+void HELPER(update_gva_offset_mask)(CPUHPPAState *env)
+{
+ update_gva_offset_mask(env);
+}
diff --git a/target/hppa/sys_helper.c b/target/hppa/sys_helper.c
index da5b569de8..052a6a88a2 100644
--- a/target/hppa/sys_helper.c
+++ b/target/hppa/sys_helper.c
@@ -73,7 +73,7 @@ target_ulong HELPER(swap_system_mask)(CPUHPPAState *env, target_ulong nsm)
* machines set the Q bit from 0 to 1 without an exception,
* so let this go without comment.
*/
- env->psw = (psw & ~PSW_SM) | (nsm & PSW_SM);
+ cpu_hppa_put_psw(env, (psw & ~PSW_SM) | (nsm & PSW_SM));
return psw & PSW_SM;
}
@@ -88,7 +88,7 @@ void HELPER(rfi)(CPUHPPAState *env)
* To recreate the space identifier, remove the offset bits.
* For pa1.x, the mask reduces to no change to space.
*/
- mask = gva_offset_mask(env->psw);
+ mask = env->gva_offset_mask;
env->iaoq_f = env->cr[CR_IIAOQ];
env->iaoq_b = env->cr_back[1];
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 7b9d3deb39..e9ef171418 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -73,6 +73,7 @@ typedef struct DisasContext {
/* IAOQ_Front at entry to TB. */
uint64_t iaoq_first;
+ uint64_t gva_offset_mask;
DisasCond null_cond;
TCGLabel *null_lab;
@@ -1577,7 +1578,7 @@ static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
*pofs = ofs;
*pgva = addr = tcg_temp_new_i64();
tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base,
- gva_offset_mask(ctx->tb_flags));
+ ctx->gva_offset_mask);
#ifndef CONFIG_USER_ONLY
if (!is_phys) {
tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
@@ -4615,6 +4616,12 @@ static bool trans_diag_mtdiag(DisasContext *ctx, arg_diag_mtdiag *a)
nullify_over(ctx);
tcg_gen_st_i64(load_gpr(ctx, a->r1), tcg_env,
offsetof(CPUHPPAState, dr[a->dr]));
+ if (ctx->is_pa20 && (a->dr == 2)) {
+ /* Update gva_offset_mask from the new value of %dr2 */
+ gen_helper_update_gva_offset_mask(tcg_env);
+ /* Exit to capture the new value for the next TB. */
+ ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
+ }
return nullify_end(ctx);
}
@@ -4635,6 +4642,7 @@ static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->tb_flags = ctx->base.tb->flags;
ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
ctx->psw_xb = ctx->tb_flags & (PSW_X | PSW_B);
+ ctx->gva_offset_mask = cpu_env(cs)->gva_offset_mask;
#ifdef CONFIG_USER_ONLY
ctx->privilege = PRIV_USER;
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX
2025-01-29 15:30 ` Helge Deller
@ 2025-01-30 1:10 ` Richard Henderson
0 siblings, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2025-01-30 1:10 UTC (permalink / raw)
To: Helge Deller; +Cc: qemu-devel, deller
On 1/29/25 07:30, Helge Deller wrote:
> Subject: [PATCH] target/hppa: Implement space register hashing for 64-bit HP-UX
>
> The Linux kernel turns space-register hashing off unconditionally at
> bootup. That code was provided by HP at the beginning of the PA-RISC
> Linux porting effort, and I don't know why it was decided then why Linux
> should not use space register hashing.
> 32-bit HP-UX versions seem to not use space register hashing either.
>
> But for 64-bit HP-UX versions, Sven Schnelle noticed that space register
> hashing needs to be enabled and is required, otherwise the HP-UX kernel
> will crash badly.
>
> On 64-bit CPUs space register hashing is controlled by a bit in diagnose
> register %dr2. Since we want to support Linux and 32- and 64-bit HP-UX,
> we need to fully emulate the diagnose registers and handle specifically
> the bit in %dr2.
>
> This patch adds the code to calculate the gva memory mask based on the
> space-register hashing bit in %dr2 and the PSW_W (64-bit) flag.
> The value is cached in the gva_offset_mask variable in CPUArchState
> and recalculated at every modification of the CPU PSW or %dr2.
>
> Signed-off-by: Helge Deller<deller@gmx.de>
> Suggested-by: Richard Henderson<richard.henderson@linaro.org>
> Suggested-by: Sven Schnelle<svens@stackframe.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2025-01-30 1:11 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-28 22:45 [PATCH v2] target/hppa: Implement CPU diagnose registers for 64-bit HP-UX deller
2025-01-28 22:45 ` [PATCH 1/4] target/hppa: Add CPU diagnose registers deller
2025-01-29 1:43 ` Richard Henderson
2025-01-28 22:45 ` [PATCH 2/4] target/hppa: Add instruction decoding for mfdiag and mtdiag deller
2025-01-29 1:46 ` Richard Henderson
2025-01-28 22:45 ` [PATCH 3/4] target/hppa: 64-bit CPUs start with space register hashing enabled deller
2025-01-29 1:46 ` Richard Henderson
2025-01-28 22:45 ` [PATCH 4/4] target/hppa: Implement space register hashing for 64-bit HP-UX deller
2025-01-29 1:50 ` Richard Henderson
2025-01-29 1:52 ` Richard Henderson
2025-01-29 2:00 ` Richard Henderson
2025-01-29 4:07 ` Helge Deller
2025-01-29 5:33 ` Richard Henderson
2025-01-29 15:30 ` Helge Deller
2025-01-30 1:10 ` Richard Henderson
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.