Skip to content

Commit 644ce5d

Browse files
committed
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 <[email protected]> Suggested-by: Sven Schnelle <[email protected]> Suggested-by: Richard Henderson <[email protected]> Reviewed-by: Richard Henderson <[email protected]>
1 parent 75f73d5 commit 644ce5d

File tree

8 files changed

+63
-23
lines changed

8 files changed

+63
-23
lines changed

target/hppa/cpu.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ static vaddr hppa_cpu_get_pc(CPUState *cs)
4545
{
4646
CPUHPPAState *env = cpu_env(cs);
4747

48-
return hppa_form_gva_psw(env->psw, (env->psw & PSW_C ? env->iasq_f : 0),
49-
env->iaoq_f & -4);
48+
return hppa_form_gva_mask(env->gva_offset_mask,
49+
(env->psw & PSW_C ? env->iasq_f : 0),
50+
env->iaoq_f & -4);
5051
}
5152

5253
void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
@@ -91,6 +92,10 @@ void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
9192
& (env->sr[4] == env->sr[7])) {
9293
flags |= TB_FLAG_SR_SAME;
9394
}
95+
if ((env->psw & PSW_W) &&
96+
(env->dr[2] & HPPA64_DIAG_SPHASH_ENABLE)) {
97+
flags |= TB_FLAG_SPHASH;
98+
}
9499
#endif
95100

96101
*pcsbase = cs_base;

target/hppa/cpu.h

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ typedef struct CPUArchState {
223223
target_ulong psw_cb; /* in least significant bit of next nibble */
224224
target_ulong psw_cb_msb; /* boolean */
225225

226+
uint64_t gva_offset_mask; /* cached address mask based on PSW and %dr2 */
226227
uint64_t iasq_f;
227228
uint64_t iasq_b;
228229

@@ -320,27 +321,20 @@ void hppa_translate_code(CPUState *cs, TranslationBlock *tb,
320321

321322
#define CPU_RESOLVING_TYPE TYPE_HPPA_CPU
322323

323-
static inline uint64_t gva_offset_mask(target_ulong psw)
324-
{
325-
return (psw & PSW_W
326-
? MAKE_64BIT_MASK(0, 62)
327-
: MAKE_64BIT_MASK(0, 32));
328-
}
329-
330-
static inline target_ulong hppa_form_gva_psw(target_ulong psw, uint64_t spc,
331-
target_ulong off)
324+
static inline target_ulong hppa_form_gva_mask(uint64_t gva_offset_mask,
325+
uint64_t spc, target_ulong off)
332326
{
333327
#ifdef CONFIG_USER_ONLY
334-
return off & gva_offset_mask(psw);
328+
return off & gva_offset_mask;
335329
#else
336-
return spc | (off & gva_offset_mask(psw));
330+
return spc | (off & gva_offset_mask);
337331
#endif
338332
}
339333

340334
static inline target_ulong hppa_form_gva(CPUHPPAState *env, uint64_t spc,
341335
target_ulong off)
342336
{
343-
return hppa_form_gva_psw(env->psw, spc, off);
337+
return hppa_form_gva_mask(env->gva_offset_mask, spc, off);
344338
}
345339

346340
hwaddr hppa_abs_to_phys_pa2_w0(vaddr addr);
@@ -354,6 +348,7 @@ hwaddr hppa_abs_to_phys_pa2_w1(vaddr addr);
354348
#define TB_FLAG_SR_SAME PSW_I
355349
#define TB_FLAG_PRIV_SHIFT 8
356350
#define TB_FLAG_UNALIGN 0x400
351+
#define TB_FLAG_SPHASH 0x800
357352
#define CS_BASE_DIFFPAGE (1 << 12)
358353
#define CS_BASE_DIFFSPACE (1 << 13)
359354

@@ -362,6 +357,7 @@ void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
362357

363358
target_ulong cpu_hppa_get_psw(CPUHPPAState *env);
364359
void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong);
360+
void update_gva_offset_mask(CPUHPPAState *env);
365361
void cpu_hppa_loaded_fr0(CPUHPPAState *env);
366362

367363
#ifdef CONFIG_USER_ONLY

target/hppa/helper.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "exec/exec-all.h"
2525
#include "exec/helper-proto.h"
2626
#include "qemu/qemu-print.h"
27+
#include "hw/hppa/hppa_hardware.h"
2728

2829
target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
2930
{
@@ -59,6 +60,22 @@ target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
5960
return psw;
6061
}
6162

63+
void update_gva_offset_mask(CPUHPPAState *env)
64+
{
65+
uint64_t gom;
66+
67+
if (env->psw & PSW_W) {
68+
gom = (env->dr[2] & HPPA64_DIAG_SPHASH_ENABLE)
69+
? MAKE_64BIT_MASK(0, 62) &
70+
~((uint64_t)HPPA64_PDC_CACHE_RET_SPID_VAL << 48)
71+
: MAKE_64BIT_MASK(0, 62);
72+
} else {
73+
gom = MAKE_64BIT_MASK(0, 32);
74+
}
75+
76+
env->gva_offset_mask = gom;
77+
}
78+
6279
void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
6380
{
6481
uint64_t reserved;
@@ -98,6 +115,8 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
98115
cb |= ((psw >> 9) & 1) << 8;
99116
cb |= ((psw >> 8) & 1) << 4;
100117
env->psw_cb = cb;
118+
119+
update_gva_offset_mask(env);
101120
}
102121

103122
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)
133152
qemu_fprintf(f, "IA_F %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n"
134153
"IA_B %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n",
135154
env->iasq_f >> 32, w, m & env->iaoq_f,
136-
hppa_form_gva_psw(psw, env->iasq_f, env->iaoq_f),
155+
hppa_form_gva_mask(env->gva_offset_mask, env->iasq_f,
156+
env->iaoq_f),
137157
env->iasq_b >> 32, w, m & env->iaoq_b,
138-
hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b));
158+
hppa_form_gva_mask(env->gva_offset_mask, env->iasq_b,
159+
env->iaoq_b));
139160

140161
psw_c[0] = (psw & PSW_W ? 'W' : '-');
141162
psw_c[1] = (psw & PSW_E ? 'E' : '-');

target/hppa/helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ DEF_HELPER_FLAGS_2(ptlb_l, TCG_CALL_NO_RWG, void, env, tl)
9999
DEF_HELPER_FLAGS_1(ptlbe, TCG_CALL_NO_RWG, void, env)
100100
DEF_HELPER_FLAGS_2(lpa, TCG_CALL_NO_WG, tl, env, tl)
101101
DEF_HELPER_FLAGS_1(change_prot_id, TCG_CALL_NO_RWG, void, env)
102+
DEF_HELPER_FLAGS_1(update_gva_offset_mask, TCG_CALL_NO_RWG, void, env)
102103
DEF_HELPER_1(diag_btlb, void, env)
103104
DEF_HELPER_1(diag_console_output, void, env)
104105
#endif

target/hppa/int_helper.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,12 @@ void hppa_cpu_do_interrupt(CPUState *cs)
9494
HPPACPU *cpu = HPPA_CPU(cs);
9595
CPUHPPAState *env = &cpu->env;
9696
int i = cs->exception_index;
97-
uint64_t old_psw;
97+
uint64_t old_psw, old_gva_offset_mask;
9898

9999
/* As documented in pa2.0 -- interruption handling. */
100100
/* step 1 */
101101
env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env);
102+
old_gva_offset_mask = env->gva_offset_mask;
102103

103104
/* step 2 -- Note PSW_W is masked out again for pa1.x */
104105
cpu_hppa_put_psw(env,
@@ -112,9 +113,9 @@ void hppa_cpu_do_interrupt(CPUState *cs)
112113
*/
113114
if (old_psw & PSW_C) {
114115
env->cr[CR_IIASQ] =
115-
hppa_form_gva_psw(old_psw, env->iasq_f, env->iaoq_f) >> 32;
116+
hppa_form_gva_mask(old_gva_offset_mask, env->iasq_f, env->iaoq_f) >> 32;
116117
env->cr_back[0] =
117-
hppa_form_gva_psw(old_psw, env->iasq_b, env->iaoq_b) >> 32;
118+
hppa_form_gva_mask(old_gva_offset_mask, env->iasq_b, env->iaoq_b) >> 32;
118119
} else {
119120
env->cr[CR_IIASQ] = 0;
120121
env->cr_back[0] = 0;
@@ -165,7 +166,8 @@ void hppa_cpu_do_interrupt(CPUState *cs)
165166
if (old_psw & PSW_C) {
166167
int prot, t;
167168

168-
vaddr = hppa_form_gva_psw(old_psw, env->iasq_f, vaddr);
169+
vaddr = hppa_form_gva_mask(old_gva_offset_mask,
170+
env->iasq_f, vaddr);
169171
t = hppa_get_physical_address(env, vaddr, MMU_KERNEL_IDX,
170172
0, 0, &paddr, &prot);
171173
if (t >= 0) {

target/hppa/mem_helper.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,3 +824,8 @@ uint64_t HELPER(b_gate_priv)(CPUHPPAState *env, uint64_t iaoq_f)
824824
}
825825
return iaoq_f;
826826
}
827+
828+
void HELPER(update_gva_offset_mask)(CPUHPPAState *env)
829+
{
830+
update_gva_offset_mask(env);
831+
}

target/hppa/sys_helper.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ target_ulong HELPER(swap_system_mask)(CPUHPPAState *env, target_ulong nsm)
7373
* machines set the Q bit from 0 to 1 without an exception,
7474
* so let this go without comment.
7575
*/
76-
env->psw = (psw & ~PSW_SM) | (nsm & PSW_SM);
76+
cpu_hppa_put_psw(env, (psw & ~PSW_SM) | (nsm & PSW_SM));
7777
return psw & PSW_SM;
7878
}
7979

@@ -88,7 +88,7 @@ void HELPER(rfi)(CPUHPPAState *env)
8888
* To recreate the space identifier, remove the offset bits.
8989
* For pa1.x, the mask reduces to no change to space.
9090
*/
91-
mask = gva_offset_mask(env->psw);
91+
mask = env->gva_offset_mask;
9292

9393
env->iaoq_f = env->cr[CR_IIAOQ];
9494
env->iaoq_b = env->cr_back[1];

target/hppa/translate.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ typedef struct DisasContext {
7373

7474
/* IAOQ_Front at entry to TB. */
7575
uint64_t iaoq_first;
76+
uint64_t gva_offset_mask;
7677

7778
DisasCond null_cond;
7879
TCGLabel *null_lab;
@@ -1577,7 +1578,7 @@ static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
15771578
*pofs = ofs;
15781579
*pgva = addr = tcg_temp_new_i64();
15791580
tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base,
1580-
gva_offset_mask(ctx->tb_flags));
1581+
ctx->gva_offset_mask);
15811582
#ifndef CONFIG_USER_ONLY
15821583
if (!is_phys) {
15831584
tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
@@ -4615,6 +4616,14 @@ static bool trans_diag_mtdiag(DisasContext *ctx, arg_diag_mtdiag *a)
46154616
nullify_over(ctx);
46164617
tcg_gen_st_i64(load_gpr(ctx, a->r1), tcg_env,
46174618
offsetof(CPUHPPAState, dr[a->dr]));
4619+
#ifndef CONFIG_USER_ONLY
4620+
if (ctx->is_pa20 && (a->dr == 2)) {
4621+
/* Update gva_offset_mask from the new value of %dr2 */
4622+
gen_helper_update_gva_offset_mask(tcg_env);
4623+
/* Exit to capture the new value for the next TB. */
4624+
ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
4625+
}
4626+
#endif
46184627
return nullify_end(ctx);
46194628
}
46204629

@@ -4635,6 +4644,7 @@ static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
46354644
ctx->tb_flags = ctx->base.tb->flags;
46364645
ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
46374646
ctx->psw_xb = ctx->tb_flags & (PSW_X | PSW_B);
4647+
ctx->gva_offset_mask = cpu_env(cs)->gva_offset_mask;
46384648

46394649
#ifdef CONFIG_USER_ONLY
46404650
ctx->privilege = PRIV_USER;

0 commit comments

Comments
 (0)