Misc fixes affecting HP-UX 10.20.

-----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJch9tgAAoJEGTfOOivfiFfKtoH/RzN42QeTfH60VrqsxIcOQ3t
 6vuDzO071zCPUMWLpIizhGH2FDRbUS2H4oihtoaoZza0IllewdhjXr4EabmXBlbz
 GD1louz73+AvOJ88dmfCC8tvEVW0Ga+MgljDBGwNAPPTEXlYUZGYGq8r4Mv9sxHu
 TGNkb4Q/nSsIXeaSaXUHECVJNJ43o+naCgoO6odTgjcN5Dr99t5Uk8GK2wgfLMaE
 iz+c9EsEDPtPnJ7vmwbS/sJuS5D6fqBX2Ag0UNvNlJObImZfkxDi6g4h/VKDHrpa
 Ycxoog+EaCBV1iVkHhl8GV8hwzNFJ0EMFcK95Bf0KxcOVbL6jh59uINR2zVjS7M=
 =pjDE
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/rth/tags/pull-hppa-20190312' into staging

Misc fixes affecting HP-UX 10.20.

# gpg: Signature made Tue 12 Mar 2019 16:16:32 GMT
# gpg:                using RSA key 64DF38E8AF7E215F
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full]
# Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A  05C0 64DF 38E8 AF7E 215F

* remotes/rth/tags/pull-hppa-20190312:
  target/hppa: exit TB if either Data or Instruction TLB changes
  target/hppa: add TLB protection id check
  target/hppa: allow multiple itlbp without itlba
  target/hppa: fix b,gate instruction
  target/hppa: ignore DIAG opcode
  target/hppa: remove PSW I/R/Q bit check
  target/hppa: add TLB trace events
  target/hppa: report ITLB_EXCP_MISS for ITLB misses
  target/hppa: fix TLB handling for page 0
  target/hppa: fix overwriting source reg in addb
  target/hppa: Check for page crossings in use_goto_tb

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-03-13 09:33:41 +00:00
commit 9298a4e8a6
10 changed files with 151 additions and 37 deletions

View File

@ -182,6 +182,7 @@ trace-events-subdirs += qapi
trace-events-subdirs += qom
trace-events-subdirs += scsi
trace-events-subdirs += target/arm
trace-events-subdirs += target/hppa
trace-events-subdirs += target/i386
trace-events-subdirs += target/mips
trace-events-subdirs += target/ppc

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -525,3 +525,6 @@ fmpy_d 001110 ..... ..... 010 ..... ... ..... @f0e_d_3
fdiv_d 001110 ..... ..... 011 ..... ... ..... @f0e_d_3
xmpyu 001110 ..... ..... 010 .0111 .00 t:5 r1=%ra64 r2=%rb64
# diag
diag 000101 ----- ----- ---- ---- ---- ----

View File

@ -22,6 +22,7 @@
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "qom/cpu.h"
#include "trace.h"
#ifdef CONFIG_USER_ONLY
int hppa_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
@ -43,9 +44,12 @@ static hppa_tlb_entry *hppa_find_tlb(CPUHPPAState *env, vaddr addr)
for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
hppa_tlb_entry *ent = &env->tlb[i];
if (ent->va_b <= addr && addr <= ent->va_e) {
trace_hppa_tlb_find_entry(env, ent + i, ent->entry_valid,
ent->va_b, ent->va_e, ent->pa);
return ent;
}
}
trace_hppa_tlb_find_entry_not_found(env, addr);
return NULL;
}
@ -55,6 +59,8 @@ static void hppa_flush_tlb_ent(CPUHPPAState *env, hppa_tlb_entry *ent)
unsigned i, n = 1 << (2 * ent->page_size);
uint64_t addr = ent->va_b;
trace_hppa_tlb_flush_ent(env, ent, ent->va_b, ent->va_e, ent->pa);
for (i = 0; i < n; ++i, addr += TARGET_PAGE_SIZE) {
/* Do not flush MMU_PHYS_IDX. */
tlb_flush_page_by_mmuidx(cs, addr, 0xf);
@ -96,9 +102,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
if (ent == NULL || !ent->entry_valid) {
phys = 0;
prot = 0;
/* ??? Unconditionally report data tlb miss,
even if this is an instruction fetch. */
ret = EXCP_DTLB_MISS;
ret = (type == PAGE_EXEC) ? EXCP_ITLB_MISS : EXCP_DTLB_MISS;
goto egress;
}
@ -127,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. */
@ -171,6 +188,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
egress:
*pphys = phys;
*pprot = prot;
trace_hppa_tlb_get_physical_address(env, ret, prot, addr, phys);
return ret;
}
@ -200,6 +218,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size,
MMUAccessType type, int mmu_idx, uintptr_t retaddr)
{
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = &cpu->env;
int prot, excp, a_prot;
hwaddr phys;
@ -215,9 +234,10 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size,
break;
}
excp = hppa_get_physical_address(&cpu->env, addr, mmu_idx,
excp = hppa_get_physical_address(env, addr, mmu_idx,
a_prot, &phys, &prot);
if (unlikely(excp >= 0)) {
trace_hppa_tlb_fill_excp(env, addr, size, type, mmu_idx);
/* Failure. Raise the indicated exception. */
cs->exception_index = excp;
if (cpu->env.psw & PSW_Q) {
@ -228,6 +248,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size,
cpu_loop_exit_restore(cs, retaddr);
}
trace_hppa_tlb_fill_success(env, addr & TARGET_PAGE_MASK,
phys & TARGET_PAGE_MASK, size, type, mmu_idx);
/* Success! Store the translation into the QEMU TLB. */
tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
prot, mmu_idx, TARGET_PAGE_SIZE);
@ -242,11 +264,13 @@ void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
/* Zap any old entries covering ADDR; notice empty entries on the way. */
for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
hppa_tlb_entry *ent = &env->tlb[i];
if (!ent->entry_valid) {
empty = ent;
} else if (ent->va_b <= addr && addr <= ent->va_e) {
hppa_flush_tlb_ent(env, ent);
empty = ent;
if (ent->va_b <= addr && addr <= ent->va_e) {
if (ent->entry_valid) {
hppa_flush_tlb_ent(env, ent);
}
if (!empty) {
empty = ent;
}
}
}
@ -259,6 +283,7 @@ void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
empty->va_b = addr & TARGET_PAGE_MASK;
empty->va_e = empty->va_b + TARGET_PAGE_SIZE - 1;
empty->pa = extract32(reg, 5, 20) << TARGET_PAGE_BITS;
trace_hppa_tlb_itlba(env, empty, empty->va_b, empty->va_e, empty->pa);
}
/* Insert (Insn/Data) TLB Protection. Note this is PA 1.1 only. */
@ -266,7 +291,7 @@ void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
{
hppa_tlb_entry *ent = hppa_find_tlb(env, addr);
if (unlikely(ent == NULL || ent->entry_valid)) {
if (unlikely(ent == NULL)) {
qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n");
return;
}
@ -280,6 +305,8 @@ void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
ent->d = extract32(reg, 28, 1);
ent->t = extract32(reg, 29, 1);
ent->entry_valid = 1;
trace_hppa_tlb_itlbp(env, ent, ent->access_id, ent->u, ent->ar_pl2,
ent->ar_pl1, ent->ar_type, ent->b, ent->d, ent->t);
}
/* Purge (Insn/Data) TLB. This is explicitly page-based, and is
@ -299,6 +326,7 @@ void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr)
{
CPUState *src = CPU(hppa_env_get_cpu(env));
CPUState *cpu;
trace_hppa_tlb_ptlb(env);
run_on_cpu_data data = RUN_ON_CPU_TARGET_PTR(addr);
CPU_FOREACH(cpu) {
@ -314,11 +342,24 @@ void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr)
void HELPER(ptlbe)(CPUHPPAState *env)
{
CPUState *src = CPU(hppa_env_get_cpu(env));
trace_hppa_tlb_ptlbe(env);
memset(env->tlb, 0, sizeof(env->tlb));
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;
@ -335,8 +376,10 @@ target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
if (excp == EXCP_DTLB_MISS) {
excp = EXCP_NA_DTLB_MISS;
}
trace_hppa_tlb_lpa_failed(env, addr);
hppa_dynamic_excp(env, excp, GETPC());
}
trace_hppa_tlb_lpa_success(env, addr, phys);
return phys;
}

View File

@ -25,6 +25,7 @@
#include "sysemu/sysemu.h"
#include "qemu/timer.h"
#include "fpu/softfloat.h"
#include "trace.h"
void QEMU_NORETURN HELPER(excp)(CPUHPPAState *env, int excp)
{
@ -165,6 +166,7 @@ target_ureg HELPER(probe)(CPUHPPAState *env, target_ulong addr,
int prot, excp;
hwaddr phys;
trace_hppa_tlb_probe(addr, level, want);
/* Fail if the requested privilege level is higher than current. */
if (level < (env->iaoq_f & 3)) {
return 0;
@ -676,11 +678,6 @@ target_ureg HELPER(swap_system_mask)(CPUHPPAState *env, target_ureg nsm)
void HELPER(rfi)(CPUHPPAState *env)
{
/* ??? On second reading this condition simply seems
to be undefined rather than a diagnosed trap. */
if (env->psw & (PSW_I | PSW_R | PSW_Q)) {
helper_excp(env, EXCP_ILL);
}
env->iasq_f = (uint64_t)env->cr[CR_IIASQ] << 32;
env->iasq_b = (uint64_t)env->cr_back[0] << 32;
env->iaoq_f = env->cr[CR_IIAOQ];

18
target/hppa/trace-events Normal file
View File

@ -0,0 +1,18 @@
# See docs/devel/tracing.txt for syntax documentation.
# target/hppa/mem_helper.c
disable hppa_tlb_flush_ent(void *env, void *ent, uint64_t va_b, uint64_t va_e, uint64_t pa) "env=%p ent=%p va_b=0x%lx va_e=0x%lx pa=0x%lx"
disable hppa_tlb_find_entry(void *env, void *ent, int valid, uint64_t va_b, uint64_t va_e, uint64_t pa) "env=%p ent=%p valid=%d va_b=0x%lx va_e=0x%lx pa=0x%lx"
disable hppa_tlb_find_entry_not_found(void *env, uint64_t addr) "env=%p addr=%08lx"
disable hppa_tlb_get_physical_address(void *env, int ret, int prot, uint64_t addr, uint64_t phys) "env=%p ret=%d prot=%d addr=0x%lx phys=0x%lx"
disable hppa_tlb_fill_excp(void *env, uint64_t addr, int size, int type, int mmu_idx) "env=%p addr=0x%lx size=%d type=%d mmu_idx=%d"
disable hppa_tlb_fill_success(void *env, uint64_t addr, uint64_t phys, int size, int type, int mmu_idx) "env=%p addr=0x%lx phys=0x%lx size=%d type=%d mmu_idx=%d"
disable hppa_tlb_itlba(void *env, void *ent, uint64_t va_b, uint64_t va_e, uint64_t pa) "env=%p ent=%p va_b=0x%lx va_e=0x%lx pa=0x%lx"
disable hppa_tlb_itlbp(void *env, void *ent, int access_id, int u, int pl2, int pl1, int type, int b, int d, int t) "env=%p ent=%p access_id=%x u=%d pl2=%d pl1=%d type=%d b=%d d=%d t=%d"
disable hppa_tlb_ptlb(void *env) "env=%p"
disable hppa_tlb_ptlbe(void *env) "env=%p"
disable hppa_tlb_lpa_success(void *env, uint64_t addr, uint64_t phys) "env=%p addr=0x%lx phys=0x%lx"
disable hppa_tlb_lpa_failed(void *env, uint64_t addr) "env=%p addr=0x%lx"
# target/hppa/op_helper.c
disable hppa_tlb_probe(uint64_t addr, int level, int want) "addr=0x%lx level=%d want=%d"

View File

@ -816,12 +816,10 @@ static bool gen_illegal(DisasContext *ctx)
static bool use_goto_tb(DisasContext *ctx, target_ureg dest)
{
/* Suppress goto_tb in the case of single-steping and IO. */
if ((tb_cflags(ctx->base.tb) & CF_LAST_IO)
|| ctx->base.singlestep_enabled) {
return false;
}
return true;
/* Suppress goto_tb for page crossing, IO, or single-steping. */
return !(((ctx->base.pc_first ^ dest) & TARGET_PAGE_MASK)
|| (tb_cflags(ctx->base.tb) & CF_LAST_IO)
|| ctx->base.singlestep_enabled);
}
/* If the next insn is to be nullified, and it's on the same page,
@ -2258,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;
@ -2474,9 +2482,8 @@ static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
gen_helper_itlbp(cpu_env, addr, reg);
}
/* Exit TB for ITLB change if mmu is enabled. This *should* not be
the case, since the OS TLB fill handler runs with mmu disabled. */
if (!a->data && (ctx->tb_flags & PSW_C)) {
/* Exit TB for TLB change if mmu is enabled. */
if (ctx->tb_flags & PSW_C) {
ctx->base.is_jmp = DISAS_IAQ_N_STALE;
}
return nullify_end(ctx);
@ -2503,7 +2510,7 @@ static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a)
}
/* Exit TB for TLB change if mmu is enabled. */
if (!a->data && (ctx->tb_flags & PSW_C)) {
if (ctx->tb_flags & PSW_C) {
ctx->base.is_jmp = DISAS_IAQ_N_STALE;
}
return nullify_end(ctx);
@ -3033,7 +3040,7 @@ static bool do_addb(DisasContext *ctx, unsigned r, TCGv_reg in1,
DisasCond cond;
in2 = load_gpr(ctx, r);
dest = dest_gpr(ctx, r);
dest = tcg_temp_new();
sv = NULL;
cb_msb = NULL;
@ -3049,6 +3056,8 @@ static bool do_addb(DisasContext *ctx, unsigned r, TCGv_reg in1,
}
cond = do_cond(c * 2 + f, dest, cb_msb, sv);
save_gpr(ctx, r, dest);
tcg_temp_free(dest);
return do_cbranch(ctx, disp, n, &cond);
}
@ -3446,6 +3455,8 @@ static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
{
target_ureg dest = iaoq_dest(ctx, a->disp);
nullify_over(ctx);
/* Make sure the caller hasn't done something weird with the queue.
* ??? This is not quite the same as the PSW[B] bit, which would be
* expensive to track. Real hardware will trap for
@ -3483,7 +3494,16 @@ static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
}
#endif
return do_dbranch(ctx, dest, a->l, a->n);
if (a->l) {
TCGv_reg tmp = dest_gpr(ctx, a->l);
if (ctx->privilege < 3) {
tcg_gen_andi_reg(tmp, tmp, -4);
}
tcg_gen_ori_reg(tmp, tmp, ctx->privilege);
save_gpr(ctx, a->l, tmp);
}
return do_dbranch(ctx, dest, 0, a->n);
}
static bool trans_blr(DisasContext *ctx, arg_blr *a)
@ -4048,6 +4068,13 @@ static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
return nullify_end(ctx);
}
static bool trans_diag(DisasContext *ctx, arg_diag *a)
{
qemu_log_mask(LOG_UNIMP, "DIAG opcode ignored\n");
cond_free(&ctx->null_cond);
return true;
}
static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);