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:
commit
9298a4e8a6
@ -182,6 +182,7 @@ trace-events-subdirs += qapi
|
|||||||
trace-events-subdirs += qom
|
trace-events-subdirs += qom
|
||||||
trace-events-subdirs += scsi
|
trace-events-subdirs += scsi
|
||||||
trace-events-subdirs += target/arm
|
trace-events-subdirs += target/arm
|
||||||
|
trace-events-subdirs += target/hppa
|
||||||
trace-events-subdirs += target/i386
|
trace-events-subdirs += target/i386
|
||||||
trace-events-subdirs += target/mips
|
trace-events-subdirs += target/mips
|
||||||
trace-events-subdirs += target/ppc
|
trace-events-subdirs += target/ppc
|
||||||
|
@ -143,6 +143,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CR_RC 0
|
#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_SCRCCR 10
|
||||||
#define CR_SAR 11
|
#define CR_SAR 11
|
||||||
#define CR_IVA 14
|
#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_put_psw(CPUHPPAState *env, target_ureg);
|
||||||
void cpu_hppa_loaded_fr0(CPUHPPAState *env);
|
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
|
#define cpu_signal_handler cpu_hppa_signal_handler
|
||||||
|
|
||||||
int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
|
int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
|
||||||
|
@ -93,19 +93,19 @@ int hppa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
|||||||
val = env->cr[CR_RC];
|
val = env->cr[CR_RC];
|
||||||
break;
|
break;
|
||||||
case 52:
|
case 52:
|
||||||
val = env->cr[8];
|
val = env->cr[CR_PID1];
|
||||||
break;
|
break;
|
||||||
case 53:
|
case 53:
|
||||||
val = env->cr[9];
|
val = env->cr[CR_PID2];
|
||||||
break;
|
break;
|
||||||
case 54:
|
case 54:
|
||||||
val = env->cr[CR_SCRCCR];
|
val = env->cr[CR_SCRCCR];
|
||||||
break;
|
break;
|
||||||
case 55:
|
case 55:
|
||||||
val = env->cr[12];
|
val = env->cr[CR_PID3];
|
||||||
break;
|
break;
|
||||||
case 56:
|
case 56:
|
||||||
val = env->cr[13];
|
val = env->cr[CR_PID4];
|
||||||
break;
|
break;
|
||||||
case 57:
|
case 57:
|
||||||
val = env->cr[24];
|
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;
|
env->cr[CR_RC] = val;
|
||||||
break;
|
break;
|
||||||
case 52:
|
case 52:
|
||||||
env->cr[8] = val;
|
env->cr[CR_PID1] = val;
|
||||||
|
cpu_hppa_change_prot_id(env);
|
||||||
break;
|
break;
|
||||||
case 53:
|
case 53:
|
||||||
env->cr[9] = val;
|
env->cr[CR_PID2] = val;
|
||||||
|
cpu_hppa_change_prot_id(env);
|
||||||
break;
|
break;
|
||||||
case 54:
|
case 54:
|
||||||
env->cr[CR_SCRCCR] = val;
|
env->cr[CR_SCRCCR] = val;
|
||||||
break;
|
break;
|
||||||
case 55:
|
case 55:
|
||||||
env->cr[12] = val;
|
env->cr[CR_PID3] = val;
|
||||||
|
cpu_hppa_change_prot_id(env);
|
||||||
break;
|
break;
|
||||||
case 56:
|
case 56:
|
||||||
env->cr[13] = val;
|
env->cr[CR_PID4] = val;
|
||||||
|
cpu_hppa_change_prot_id(env);
|
||||||
break;
|
break;
|
||||||
case 57:
|
case 57:
|
||||||
env->cr[24] = val;
|
env->cr[24] = val;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "fpu/softfloat.h"
|
#include "fpu/softfloat.h"
|
||||||
|
#include "exec/exec-all.h"
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
|
|
||||||
target_ureg cpu_hppa_get_psw(CPUHPPAState *env)
|
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)
|
void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw)
|
||||||
{
|
{
|
||||||
|
target_ureg old_psw = env->psw;
|
||||||
target_ureg cb = 0;
|
target_ureg cb = 0;
|
||||||
|
|
||||||
env->psw = psw & ~(PSW_N | PSW_V | PSW_CB);
|
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 >> 9) & 1) << 8;
|
||||||
cb |= ((psw >> 8) & 1) << 4;
|
cb |= ((psw >> 8) & 1) << 4;
|
||||||
env->psw_cb = cb;
|
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,
|
void hppa_cpu_dump_state(CPUState *cs, FILE *f,
|
||||||
|
@ -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_2(ptlb, TCG_CALL_NO_RWG, void, env, tl)
|
||||||
DEF_HELPER_FLAGS_1(ptlbe, TCG_CALL_NO_RWG, void, env)
|
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_2(lpa, TCG_CALL_NO_WG, tr, env, tl)
|
||||||
|
DEF_HELPER_FLAGS_1(change_prot_id, TCG_CALL_NO_RWG, void, env)
|
||||||
#endif
|
#endif
|
||||||
|
@ -525,3 +525,6 @@ fmpy_d 001110 ..... ..... 010 ..... ... ..... @f0e_d_3
|
|||||||
fdiv_d 001110 ..... ..... 011 ..... ... ..... @f0e_d_3
|
fdiv_d 001110 ..... ..... 011 ..... ... ..... @f0e_d_3
|
||||||
|
|
||||||
xmpyu 001110 ..... ..... 010 .0111 .00 t:5 r1=%ra64 r2=%rb64
|
xmpyu 001110 ..... ..... 010 .0111 .00 t:5 r1=%ra64 r2=%rb64
|
||||||
|
|
||||||
|
# diag
|
||||||
|
diag 000101 ----- ----- ---- ---- ---- ----
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "qom/cpu.h"
|
#include "qom/cpu.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
int hppa_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
|
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) {
|
for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
|
||||||
hppa_tlb_entry *ent = &env->tlb[i];
|
hppa_tlb_entry *ent = &env->tlb[i];
|
||||||
if (ent->va_b <= addr && addr <= ent->va_e) {
|
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;
|
return ent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
trace_hppa_tlb_find_entry_not_found(env, addr);
|
||||||
return NULL;
|
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);
|
unsigned i, n = 1 << (2 * ent->page_size);
|
||||||
uint64_t addr = ent->va_b;
|
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) {
|
for (i = 0; i < n; ++i, addr += TARGET_PAGE_SIZE) {
|
||||||
/* Do not flush MMU_PHYS_IDX. */
|
/* Do not flush MMU_PHYS_IDX. */
|
||||||
tlb_flush_page_by_mmuidx(cs, addr, 0xf);
|
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) {
|
if (ent == NULL || !ent->entry_valid) {
|
||||||
phys = 0;
|
phys = 0;
|
||||||
prot = 0;
|
prot = 0;
|
||||||
/* ??? Unconditionally report data tlb miss,
|
ret = (type == PAGE_EXEC) ? EXCP_ITLB_MISS : EXCP_DTLB_MISS;
|
||||||
even if this is an instruction fetch. */
|
|
||||||
ret = EXCP_DTLB_MISS;
|
|
||||||
goto egress;
|
goto egress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +131,20 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
|
|||||||
break;
|
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
|
/* No guest access type indicates a non-architectural access from
|
||||||
within QEMU. Bypass checks for access, D, B and T bits. */
|
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:
|
egress:
|
||||||
*pphys = phys;
|
*pphys = phys;
|
||||||
*pprot = prot;
|
*pprot = prot;
|
||||||
|
trace_hppa_tlb_get_physical_address(env, ret, prot, addr, phys);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +218,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size,
|
|||||||
MMUAccessType type, int mmu_idx, uintptr_t retaddr)
|
MMUAccessType type, int mmu_idx, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
HPPACPU *cpu = HPPA_CPU(cs);
|
HPPACPU *cpu = HPPA_CPU(cs);
|
||||||
|
CPUHPPAState *env = &cpu->env;
|
||||||
int prot, excp, a_prot;
|
int prot, excp, a_prot;
|
||||||
hwaddr phys;
|
hwaddr phys;
|
||||||
|
|
||||||
@ -215,9 +234,10 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
excp = hppa_get_physical_address(&cpu->env, addr, mmu_idx,
|
excp = hppa_get_physical_address(env, addr, mmu_idx,
|
||||||
a_prot, &phys, &prot);
|
a_prot, &phys, &prot);
|
||||||
if (unlikely(excp >= 0)) {
|
if (unlikely(excp >= 0)) {
|
||||||
|
trace_hppa_tlb_fill_excp(env, addr, size, type, mmu_idx);
|
||||||
/* Failure. Raise the indicated exception. */
|
/* Failure. Raise the indicated exception. */
|
||||||
cs->exception_index = excp;
|
cs->exception_index = excp;
|
||||||
if (cpu->env.psw & PSW_Q) {
|
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);
|
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. */
|
/* Success! Store the translation into the QEMU TLB. */
|
||||||
tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
|
tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
|
||||||
prot, mmu_idx, TARGET_PAGE_SIZE);
|
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. */
|
/* Zap any old entries covering ADDR; notice empty entries on the way. */
|
||||||
for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
|
for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
|
||||||
hppa_tlb_entry *ent = &env->tlb[i];
|
hppa_tlb_entry *ent = &env->tlb[i];
|
||||||
if (!ent->entry_valid) {
|
if (ent->va_b <= addr && addr <= ent->va_e) {
|
||||||
empty = ent;
|
if (ent->entry_valid) {
|
||||||
} else if (ent->va_b <= addr && addr <= ent->va_e) {
|
hppa_flush_tlb_ent(env, ent);
|
||||||
hppa_flush_tlb_ent(env, ent);
|
}
|
||||||
empty = 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_b = addr & TARGET_PAGE_MASK;
|
||||||
empty->va_e = empty->va_b + TARGET_PAGE_SIZE - 1;
|
empty->va_e = empty->va_b + TARGET_PAGE_SIZE - 1;
|
||||||
empty->pa = extract32(reg, 5, 20) << TARGET_PAGE_BITS;
|
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. */
|
/* 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);
|
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");
|
qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -280,6 +305,8 @@ void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
|
|||||||
ent->d = extract32(reg, 28, 1);
|
ent->d = extract32(reg, 28, 1);
|
||||||
ent->t = extract32(reg, 29, 1);
|
ent->t = extract32(reg, 29, 1);
|
||||||
ent->entry_valid = 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
|
/* 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 *src = CPU(hppa_env_get_cpu(env));
|
||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
|
trace_hppa_tlb_ptlb(env);
|
||||||
run_on_cpu_data data = RUN_ON_CPU_TARGET_PTR(addr);
|
run_on_cpu_data data = RUN_ON_CPU_TARGET_PTR(addr);
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
@ -314,11 +342,24 @@ void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr)
|
|||||||
void HELPER(ptlbe)(CPUHPPAState *env)
|
void HELPER(ptlbe)(CPUHPPAState *env)
|
||||||
{
|
{
|
||||||
CPUState *src = CPU(hppa_env_get_cpu(env));
|
CPUState *src = CPU(hppa_env_get_cpu(env));
|
||||||
|
trace_hppa_tlb_ptlbe(env);
|
||||||
memset(env->tlb, 0, sizeof(env->tlb));
|
memset(env->tlb, 0, sizeof(env->tlb));
|
||||||
tlb_flush_by_mmuidx(src, 0xf);
|
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)
|
target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
|
||||||
{
|
{
|
||||||
hwaddr phys;
|
hwaddr phys;
|
||||||
@ -335,8 +376,10 @@ target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
|
|||||||
if (excp == EXCP_DTLB_MISS) {
|
if (excp == EXCP_DTLB_MISS) {
|
||||||
excp = EXCP_NA_DTLB_MISS;
|
excp = EXCP_NA_DTLB_MISS;
|
||||||
}
|
}
|
||||||
|
trace_hppa_tlb_lpa_failed(env, addr);
|
||||||
hppa_dynamic_excp(env, excp, GETPC());
|
hppa_dynamic_excp(env, excp, GETPC());
|
||||||
}
|
}
|
||||||
|
trace_hppa_tlb_lpa_success(env, addr, phys);
|
||||||
return phys;
|
return phys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
#include "fpu/softfloat.h"
|
#include "fpu/softfloat.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
void QEMU_NORETURN HELPER(excp)(CPUHPPAState *env, int excp)
|
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;
|
int prot, excp;
|
||||||
hwaddr phys;
|
hwaddr phys;
|
||||||
|
|
||||||
|
trace_hppa_tlb_probe(addr, level, want);
|
||||||
/* Fail if the requested privilege level is higher than current. */
|
/* Fail if the requested privilege level is higher than current. */
|
||||||
if (level < (env->iaoq_f & 3)) {
|
if (level < (env->iaoq_f & 3)) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -676,11 +678,6 @@ target_ureg HELPER(swap_system_mask)(CPUHPPAState *env, target_ureg nsm)
|
|||||||
|
|
||||||
void HELPER(rfi)(CPUHPPAState *env)
|
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_f = (uint64_t)env->cr[CR_IIASQ] << 32;
|
||||||
env->iasq_b = (uint64_t)env->cr_back[0] << 32;
|
env->iasq_b = (uint64_t)env->cr_back[0] << 32;
|
||||||
env->iaoq_f = env->cr[CR_IIAOQ];
|
env->iaoq_f = env->cr[CR_IIAOQ];
|
||||||
|
18
target/hppa/trace-events
Normal file
18
target/hppa/trace-events
Normal 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"
|
@ -816,12 +816,10 @@ static bool gen_illegal(DisasContext *ctx)
|
|||||||
|
|
||||||
static bool use_goto_tb(DisasContext *ctx, target_ureg dest)
|
static bool use_goto_tb(DisasContext *ctx, target_ureg dest)
|
||||||
{
|
{
|
||||||
/* Suppress goto_tb in the case of single-steping and IO. */
|
/* Suppress goto_tb for page crossing, IO, or single-steping. */
|
||||||
if ((tb_cflags(ctx->base.tb) & CF_LAST_IO)
|
return !(((ctx->base.pc_first ^ dest) & TARGET_PAGE_MASK)
|
||||||
|| ctx->base.singlestep_enabled) {
|
|| (tb_cflags(ctx->base.tb) & CF_LAST_IO)
|
||||||
return false;
|
|| ctx->base.singlestep_enabled);
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the next insn is to be nullified, and it's on the same page,
|
/* 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]));
|
offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
|
||||||
break;
|
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:
|
default:
|
||||||
tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
|
tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
|
||||||
break;
|
break;
|
||||||
@ -2474,9 +2482,8 @@ static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
|
|||||||
gen_helper_itlbp(cpu_env, addr, reg);
|
gen_helper_itlbp(cpu_env, addr, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exit TB for ITLB change if mmu is enabled. This *should* not be
|
/* Exit TB for TLB change if mmu is enabled. */
|
||||||
the case, since the OS TLB fill handler runs with mmu disabled. */
|
if (ctx->tb_flags & PSW_C) {
|
||||||
if (!a->data && (ctx->tb_flags & PSW_C)) {
|
|
||||||
ctx->base.is_jmp = DISAS_IAQ_N_STALE;
|
ctx->base.is_jmp = DISAS_IAQ_N_STALE;
|
||||||
}
|
}
|
||||||
return nullify_end(ctx);
|
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. */
|
/* 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;
|
ctx->base.is_jmp = DISAS_IAQ_N_STALE;
|
||||||
}
|
}
|
||||||
return nullify_end(ctx);
|
return nullify_end(ctx);
|
||||||
@ -3033,7 +3040,7 @@ static bool do_addb(DisasContext *ctx, unsigned r, TCGv_reg in1,
|
|||||||
DisasCond cond;
|
DisasCond cond;
|
||||||
|
|
||||||
in2 = load_gpr(ctx, r);
|
in2 = load_gpr(ctx, r);
|
||||||
dest = dest_gpr(ctx, r);
|
dest = tcg_temp_new();
|
||||||
sv = NULL;
|
sv = NULL;
|
||||||
cb_msb = 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);
|
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);
|
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);
|
target_ureg dest = iaoq_dest(ctx, a->disp);
|
||||||
|
|
||||||
|
nullify_over(ctx);
|
||||||
|
|
||||||
/* Make sure the caller hasn't done something weird with the queue.
|
/* 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
|
* ??? This is not quite the same as the PSW[B] bit, which would be
|
||||||
* expensive to track. Real hardware will trap for
|
* expensive to track. Real hardware will trap for
|
||||||
@ -3483,7 +3494,16 @@ static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
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);
|
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)
|
static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
||||||
{
|
{
|
||||||
DisasContext *ctx = container_of(dcbase, DisasContext, base);
|
DisasContext *ctx = container_of(dcbase, DisasContext, base);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user