1
0
mirror of https://gitlab.com/qemu-project/qemu synced 2024-07-01 07:14:48 +00:00

target/hppa:

- Use TCG_COND_TST where applicable.
   - Use CF_BP_PAGE instead of a local breakpoint search.
   - Clean up IAOQ handling during translation.
   - Implement CF_PCREL.
   - Implement PSW.B.
   - Implement PSW.X.
   - Log cpu state on interrupt and rfi.
 -----BEGIN PGP SIGNATURE-----
 
 iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmZEgnwdHHJpY2hhcmQu
 aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV+43gf8CakQdMSqfGV2nGP+
 7wWZOAV04IyfkJ38F/CH0ihUkblEOzXJ1shTFkrHEw257j0D10MctSSbjrqz5BwU
 obQcwoVlxzTGXqzhkZ6wagkcqjv3TtlPtznZIk6JssdlrtwIKDmE2/3t1dzHnyBD
 WTrS0SK3YvVRovq/ai51raUbiBsNq7XG3skHEsMKsFxp4EaDP5JTbputdQWdffjh
 TBmXImhHC3gm09KWIUZwfEBHlaa7YXk2orzB8kBE8S2kQj9vrGXEaC4jYnBcQLPw
 NDDkBYRqxHYQr0vIAHee+5cUgt1jDBr5rXnAnJwzK0wyEEc4Mi4OTPhNE604iu2y
 SDxS8Q==
 =A4Qf
 -----END PGP SIGNATURE-----

Merge tag 'pull-hppa-20240515' of https://gitlab.com/rth7680/qemu into staging

target/hppa:
  - Use TCG_COND_TST where applicable.
  - Use CF_BP_PAGE instead of a local breakpoint search.
  - Clean up IAOQ handling during translation.
  - Implement CF_PCREL.
  - Implement PSW.B.
  - Implement PSW.X.
  - Log cpu state on interrupt and rfi.

# -----BEGIN PGP SIGNATURE-----
#
# iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmZEgnwdHHJpY2hhcmQu
# aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV+43gf8CakQdMSqfGV2nGP+
# 7wWZOAV04IyfkJ38F/CH0ihUkblEOzXJ1shTFkrHEw257j0D10MctSSbjrqz5BwU
# obQcwoVlxzTGXqzhkZ6wagkcqjv3TtlPtznZIk6JssdlrtwIKDmE2/3t1dzHnyBD
# WTrS0SK3YvVRovq/ai51raUbiBsNq7XG3skHEsMKsFxp4EaDP5JTbputdQWdffjh
# TBmXImhHC3gm09KWIUZwfEBHlaa7YXk2orzB8kBE8S2kQj9vrGXEaC4jYnBcQLPw
# NDDkBYRqxHYQr0vIAHee+5cUgt1jDBr5rXnAnJwzK0wyEEc4Mi4OTPhNE604iu2y
# SDxS8Q==
# =A4Qf
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 15 May 2024 11:38:04 AM CEST
# gpg:                using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg:                issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate]

* tag 'pull-hppa-20240515' of https://gitlab.com/rth7680/qemu: (43 commits)
  target/hppa: Log cpu state on return-from-interrupt
  target/hppa: Log cpu state at interrupt
  target/hppa: Implement CF_PCREL
  target/hppa: Adjust priv for B,GATE at runtime
  target/hppa: Drop tlb_entry return from hppa_get_physical_address
  target/hppa: Implement PSW_X
  target/hppa: Implement PSW_B
  target/hppa: Manage PSW_X and PSW_B in translator
  target/hppa: Split PSW X and B into their own field
  target/hppa: Improve hppa_cpu_dump_state
  target/hppa: Do not mask in copy_iaoq_entry
  target/hppa: Store full iaoq_f and page offset of iaoq_b in TB
  linux-user/hppa: Force all code addresses to PRIV_USER
  target/hppa: Use delay_excp for conditional trap on overflow
  target/hppa: Use delay_excp for conditional traps
  target/hppa: Introduce DisasDelayException
  target/hppa: Remove cond_free
  target/hppa: Use TCG_COND_TST* in trans_ftest
  target/hppa: Use registerfields.h for FPSR
  target/hppa: Use TCG_COND_TST* in trans_bb_imm
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2024-05-15 11:46:58 +02:00
commit 922582ace2
15 changed files with 868 additions and 752 deletions

View File

@ -1887,8 +1887,8 @@ static inline void init_thread(struct target_pt_regs *regs,
static inline void init_thread(struct target_pt_regs *regs,
struct image_info *infop)
{
regs->iaoq[0] = infop->entry;
regs->iaoq[1] = infop->entry + 4;
regs->iaoq[0] = infop->entry | PRIV_USER;
regs->iaoq[1] = regs->iaoq[0] + 4;
regs->gr[23] = 0;
regs->gr[24] = infop->argv;
regs->gr[25] = infop->argc;

View File

@ -129,8 +129,8 @@ void cpu_loop(CPUHPPAState *env)
default:
env->gr[28] = ret;
/* We arrived here by faking the gateway page. Return. */
env->iaoq_f = env->gr[31];
env->iaoq_b = env->gr[31] + 4;
env->iaoq_f = env->gr[31] | PRIV_USER;
env->iaoq_b = env->iaoq_f + 4;
break;
case -QEMU_ERESTARTSYS:
case -QEMU_ESIGRETURN:
@ -140,8 +140,8 @@ void cpu_loop(CPUHPPAState *env)
case EXCP_SYSCALL_LWS:
env->gr[21] = hppa_lws(env);
/* We arrived here by faking the gateway page. Return. */
env->iaoq_f = env->gr[31];
env->iaoq_b = env->gr[31] + 4;
env->iaoq_f = env->gr[31] | PRIV_USER;
env->iaoq_b = env->iaoq_f + 4;
break;
case EXCP_IMP:
force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->iaoq_f);
@ -152,9 +152,9 @@ void cpu_loop(CPUHPPAState *env)
case EXCP_PRIV_OPR:
/* check for glibc ABORT_INSTRUCTION "iitlbp %r0,(%sr0, %r0)" */
if (env->cr[CR_IIR] == 0x04000000) {
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f);
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f);
} else {
force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->iaoq_f);
force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->iaoq_f);
}
break;
case EXCP_PRIV_REG:
@ -170,7 +170,7 @@ void cpu_loop(CPUHPPAState *env)
force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f);
break;
case EXCP_BREAK:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f & ~3);
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f);
break;
case EXCP_DEBUG:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f);

View File

@ -101,7 +101,9 @@ static void restore_sigcontext(CPUArchState *env, struct target_sigcontext *sc)
cpu_hppa_loaded_fr0(env);
__get_user(env->iaoq_f, &sc->sc_iaoq[0]);
env->iaoq_f |= PRIV_USER;
__get_user(env->iaoq_b, &sc->sc_iaoq[1]);
env->iaoq_b |= PRIV_USER;
__get_user(env->cr[CR_SAR], &sc->sc_sar);
}
@ -162,8 +164,8 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
unlock_user(fdesc, haddr, 0);
haddr = dest;
}
env->iaoq_f = haddr;
env->iaoq_b = haddr + 4;
env->iaoq_f = haddr | PRIV_USER;
env->iaoq_b = env->iaoq_f + 4;
env->psw_n = 0;
return;

View File

@ -28,8 +28,8 @@ static inline void cpu_clone_regs_child(CPUHPPAState *env, target_ulong newsp,
/* Indicate child in return value. */
env->gr[28] = 0;
/* Return from the syscall. */
env->iaoq_f = env->gr[31];
env->iaoq_b = env->gr[31] + 4;
env->iaoq_f = env->gr[31] | PRIV_USER;
env->iaoq_b = env->iaoq_f + 4;
}
static inline void cpu_clone_regs_parent(CPUHPPAState *env, unsigned flags)

View File

@ -32,15 +32,67 @@ static void hppa_cpu_set_pc(CPUState *cs, vaddr value)
{
HPPACPU *cpu = HPPA_CPU(cs);
#ifdef CONFIG_USER_ONLY
value |= PRIV_USER;
#endif
cpu->env.iaoq_f = value;
cpu->env.iaoq_b = value + 4;
}
static vaddr hppa_cpu_get_pc(CPUState *cs)
{
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = cpu_env(cs);
return cpu->env.iaoq_f;
return hppa_form_gva_psw(env->psw, (env->psw & PSW_C ? env->iasq_f : 0),
env->iaoq_f & -4);
}
void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
uint64_t *pcsbase, uint32_t *pflags)
{
uint32_t flags = 0;
uint64_t cs_base = 0;
/*
* TB lookup assumes that PC contains the complete virtual address.
* If we leave space+offset separate, we'll get ITLB misses to an
* incomplete virtual address. This also means that we must separate
* out current cpu privilege from the low bits of IAOQ_F.
*/
*pc = hppa_cpu_get_pc(env_cpu(env));
flags |= (env->iaoq_f & 3) << TB_FLAG_PRIV_SHIFT;
/*
* The only really interesting case is if IAQ_Back is on the same page
* as IAQ_Front, so that we can use goto_tb between the blocks. In all
* other cases, we'll be ending the TranslationBlock with one insn and
* not linking between them.
*/
if (env->iasq_f != env->iasq_b) {
cs_base |= CS_BASE_DIFFSPACE;
} else if ((env->iaoq_f ^ env->iaoq_b) & TARGET_PAGE_MASK) {
cs_base |= CS_BASE_DIFFPAGE;
} else {
cs_base |= env->iaoq_b & ~TARGET_PAGE_MASK;
}
/* ??? E, T, H, L bits need to be here, when implemented. */
flags |= env->psw_n * PSW_N;
flags |= env->psw_xb;
flags |= env->psw & (PSW_W | PSW_C | PSW_D | PSW_P);
#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;
}
#endif
*pcsbase = cs_base;
*pflags = flags;
}
static void hppa_cpu_synchronize_from_tb(CPUState *cs,
@ -48,45 +100,28 @@ static void hppa_cpu_synchronize_from_tb(CPUState *cs,
{
HPPACPU *cpu = HPPA_CPU(cs);
tcg_debug_assert(!tcg_cflags_has(cs, CF_PCREL));
#ifdef CONFIG_USER_ONLY
cpu->env.iaoq_f = tb->pc;
cpu->env.iaoq_b = tb->cs_base;
#else
/* Recover the IAOQ values from the GVA + PRIV. */
uint32_t priv = (tb->flags >> TB_FLAG_PRIV_SHIFT) & 3;
target_ulong cs_base = tb->cs_base;
target_ulong iasq_f = cs_base & ~0xffffffffull;
int32_t diff = cs_base;
cpu->env.iasq_f = iasq_f;
cpu->env.iaoq_f = (tb->pc & ~iasq_f) + priv;
if (diff) {
cpu->env.iaoq_b = cpu->env.iaoq_f + diff;
}
#endif
/* IAQ is always up-to-date before goto_tb. */
cpu->env.psw_n = (tb->flags & PSW_N) != 0;
cpu->env.psw_xb = tb->flags & (PSW_X | PSW_B);
}
static void hppa_restore_state_to_opc(CPUState *cs,
const TranslationBlock *tb,
const uint64_t *data)
{
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = cpu_env(cs);
cpu->env.iaoq_f = data[0];
if (data[1] != (target_ulong)-1) {
cpu->env.iaoq_b = data[1];
env->iaoq_f = (env->iaoq_f & TARGET_PAGE_MASK) | data[0];
if (data[1] != INT32_MIN) {
env->iaoq_b = env->iaoq_f + data[1];
}
cpu->env.unwind_breg = data[2];
env->unwind_breg = data[2];
/*
* Since we were executing the instruction at IAOQ_F, and took some
* sort of action that provoked the cpu_restore_state, we can infer
* that the instruction was not nullified.
*/
cpu->env.psw_n = 0;
env->psw_n = 0;
}
static bool hppa_cpu_has_work(CPUState *cs)
@ -152,6 +187,9 @@ static void hppa_cpu_realizefn(DeviceState *dev, Error **errp)
hppa_ptlbe(&cpu->env);
}
#endif
/* Use pc-relative instructions always to simplify the translator. */
tcg_cflags_set(cs, CF_PCREL);
}
static void hppa_cpu_initfn(Object *obj)

View File

@ -24,6 +24,7 @@
#include "exec/cpu-defs.h"
#include "qemu/cpu-float.h"
#include "qemu/interval-tree.h"
#include "hw/registerfields.h"
#define MMU_ABS_W_IDX 6
#define MMU_ABS_IDX 7
@ -41,6 +42,9 @@
#define MMU_IDX_TO_P(MIDX) (((MIDX) - MMU_KERNEL_IDX) & 1)
#define PRIV_P_TO_MMU_IDX(PRIV, P) ((PRIV) * 2 + !!(P) + MMU_KERNEL_IDX)
#define PRIV_KERNEL 0
#define PRIV_USER 3
#define TARGET_INSN_START_EXTRA_WORDS 2
/* No need to flush MMU_ABS*_IDX */
@ -152,6 +156,30 @@
#define CR_IPSW 22
#define CR_EIRR 23
FIELD(FPSR, ENA_I, 0, 1)
FIELD(FPSR, ENA_U, 1, 1)
FIELD(FPSR, ENA_O, 2, 1)
FIELD(FPSR, ENA_Z, 3, 1)
FIELD(FPSR, ENA_V, 4, 1)
FIELD(FPSR, ENABLES, 0, 5)
FIELD(FPSR, D, 5, 1)
FIELD(FPSR, T, 6, 1)
FIELD(FPSR, RM, 9, 2)
FIELD(FPSR, CQ, 11, 11)
FIELD(FPSR, CQ0_6, 15, 7)
FIELD(FPSR, CQ0_4, 17, 5)
FIELD(FPSR, CQ0_2, 19, 3)
FIELD(FPSR, CQ0, 21, 1)
FIELD(FPSR, CA, 15, 7)
FIELD(FPSR, CA0, 21, 1)
FIELD(FPSR, C, 26, 1)
FIELD(FPSR, FLG_I, 27, 1)
FIELD(FPSR, FLG_U, 28, 1)
FIELD(FPSR, FLG_O, 29, 1)
FIELD(FPSR, FLG_Z, 30, 1)
FIELD(FPSR, FLG_V, 31, 1)
FIELD(FPSR, FLAGS, 27, 5)
typedef struct HPPATLBEntry {
union {
IntervalTreeNode itree;
@ -180,7 +208,8 @@ typedef struct CPUArchState {
uint64_t fr[32];
uint64_t sr[8]; /* stored shifted into place for gva */
target_ulong psw; /* All psw bits except the following: */
uint32_t psw; /* All psw bits except the following: */
uint32_t psw_xb; /* X and B, in their normal positions */
target_ulong psw_n; /* boolean */
target_long psw_v; /* in most significant bit */
@ -313,48 +342,11 @@ 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 CS_BASE_DIFFPAGE (1 << 12)
#define CS_BASE_DIFFSPACE (1 << 13)
static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
uint64_t *cs_base, uint32_t *pflags)
{
uint32_t flags = env->psw_n * PSW_N;
/* TB lookup assumes that PC contains the complete virtual address.
If we leave space+offset separate, we'll get ITLB misses to an
incomplete virtual address. This also means that we must separate
out current cpu privilege from the low bits of IAOQ_F. */
#ifdef CONFIG_USER_ONLY
*pc = env->iaoq_f & -4;
*cs_base = env->iaoq_b & -4;
flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus;
#else
/* ??? E, T, H, L, B bits need to be here, when implemented. */
flags |= env->psw & (PSW_W | PSW_C | PSW_D | PSW_P);
flags |= (env->iaoq_f & 3) << TB_FLAG_PRIV_SHIFT;
*pc = hppa_form_gva_psw(env->psw, (env->psw & PSW_C ? env->iasq_f : 0),
env->iaoq_f & -4);
*cs_base = env->iasq_f;
/* Insert a difference between IAOQ_B and IAOQ_F within the otherwise zero
low 32-bits of CS_BASE. This will succeed for all direct branches,
which is the primary case we care about -- using goto_tb within a page.
Failure is indicated by a zero difference. */
if (env->iasq_f == env->iasq_b) {
target_long diff = env->iaoq_b - env->iaoq_f;
if (diff == (int32_t)diff) {
*cs_base |= (uint32_t)diff;
}
}
if ((env->sr[4] == env->sr[5])
& (env->sr[4] == env->sr[6])
& (env->sr[4] == env->sr[7])) {
flags |= TB_FLAG_SR_SAME;
}
#endif
*pflags = flags;
}
void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
uint64_t *cs_base, uint32_t *pflags);
target_ulong cpu_hppa_get_psw(CPUHPPAState *env);
void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong);
@ -379,8 +371,7 @@ bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
void hppa_cpu_do_interrupt(CPUState *cpu);
bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
int type, hwaddr *pphys, int *pprot,
HPPATLBEntry **tlb_entry);
int type, hwaddr *pphys, int *pprot);
void hppa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
vaddr addr, unsigned size,
MMUAccessType access_type,
@ -389,7 +380,6 @@ void hppa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
extern const MemoryRegionOps hppa_io_eir_ops;
extern const VMStateDescription vmstate_hppa_cpu;
void hppa_cpu_alarm_timer(void *);
int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr);
#endif
G_NORETURN void hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra);

View File

@ -30,7 +30,7 @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
env->fr0_shadow = shadow;
switch (extract32(shadow, 9, 2)) {
switch (FIELD_EX32(shadow, FPSR, RM)) {
default:
rm = float_round_nearest_even;
break;
@ -46,7 +46,7 @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
}
set_float_rounding_mode(rm, &env->fp_status);
d = extract32(shadow, 5, 1);
d = FIELD_EX32(shadow, FPSR, D);
set_flush_to_zero(d, &env->fp_status);
set_flush_inputs_to_zero(d, &env->fp_status);
}
@ -57,7 +57,7 @@ void cpu_hppa_loaded_fr0(CPUHPPAState *env)
}
#define CONVERT_BIT(X, SRC, DST) \
((SRC) > (DST) \
((unsigned)(SRC) > (unsigned)(DST) \
? (X) / ((SRC) / (DST)) & (DST) \
: ((X) & (SRC)) * ((DST) / (SRC)))
@ -73,12 +73,12 @@ static void update_fr0_op(CPUHPPAState *env, uintptr_t ra)
}
set_float_exception_flags(0, &env->fp_status);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_inexact, 1u << 0);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_underflow, 1u << 1);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow, 1u << 2);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, 1u << 3);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid, 1u << 4);
shadow |= hard_exp << (32 - 5);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_inexact, R_FPSR_ENA_I_MASK);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_underflow, R_FPSR_ENA_U_MASK);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow, R_FPSR_ENA_O_MASK);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, R_FPSR_ENA_Z_MASK);
hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid, R_FPSR_ENA_V_MASK);
shadow |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT);
env->fr0_shadow = shadow;
env->fr[0] = (uint64_t)shadow << 32;
@ -378,15 +378,15 @@ static void update_fr0_cmp(CPUHPPAState *env, uint32_t y,
if (y) {
/* targeted comparison */
/* set fpsr[ca[y - 1]] to current compare */
shadow = deposit32(shadow, 21 - (y - 1), 1, c);
shadow = deposit32(shadow, R_FPSR_CA0_SHIFT - (y - 1), 1, c);
} else {
/* queued comparison */
/* shift cq right by one place */
shadow = deposit32(shadow, 11, 10, extract32(shadow, 12, 10));
shadow = (shadow & ~R_FPSR_CQ_MASK) | ((shadow >> 1) & R_FPSR_CQ_MASK);
/* move fpsr[c] to fpsr[cq[0]] */
shadow = deposit32(shadow, 21, 1, extract32(shadow, 26, 1));
shadow = FIELD_DP32(shadow, FPSR, CQ0, FIELD_EX32(shadow, FPSR, C));
/* set fpsr[c] to current compare */
shadow = deposit32(shadow, 26, 1, c);
shadow = FIELD_DP32(shadow, FPSR, C, c);
}
env->fr0_shadow = shadow;

View File

@ -163,12 +163,18 @@ int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
env->cr[CR_SAR] = val & (hppa_is_pa20(env) ? 63 : 31);
break;
case 33:
#ifdef CONFIG_USER_ONLY
val |= PRIV_USER;
#endif
env->iaoq_f = val;
break;
case 34:
env->iasq_f = (uint64_t)val << 32;
break;
case 35:
#ifdef CONFIG_USER_ONLY
val |= PRIV_USER;
#endif
env->iaoq_b = val;
break;
case 36:

View File

@ -54,7 +54,7 @@ target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
psw |= env->psw_n * PSW_N;
psw |= (env->psw_v < 0) * PSW_V;
psw |= env->psw;
psw |= env->psw | env->psw_xb;
return psw;
}
@ -76,8 +76,8 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
}
psw &= ~reserved;
env->psw = psw & (uint32_t)~(PSW_N | PSW_V | PSW_CB);
env->psw = psw & (uint32_t)~(PSW_B | PSW_N | PSW_V | PSW_X | PSW_CB);
env->psw_xb = psw & (PSW_X | PSW_B);
env->psw_n = (psw / PSW_N) & 1;
env->psw_v = -((psw / PSW_V) & 1);
@ -102,6 +102,19 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
{
#ifndef CONFIG_USER_ONLY
static const char cr_name[32][5] = {
"RC", "CR1", "CR2", "CR3",
"CR4", "CR5", "CR6", "CR7",
"PID1", "PID2", "CCR", "SAR",
"PID3", "PID4", "IVA", "EIEM",
"ITMR", "ISQF", "IOQF", "IIR",
"ISR", "IOR", "IPSW", "EIRR",
"TR0", "TR1", "TR2", "TR3",
"TR4", "TR5", "TR6", "TR7",
};
#endif
CPUHPPAState *env = cpu_env(cs);
target_ulong psw = cpu_hppa_get_psw(env);
target_ulong psw_cb;
@ -117,11 +130,12 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
m = UINT32_MAX;
}
qemu_fprintf(f, "IA_F " TARGET_FMT_lx " IA_B " TARGET_FMT_lx
" IIR %0*" PRIx64 "\n",
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_psw(psw, env->iasq_b, env->iaoq_b),
w, m & env->cr[CR_IIR]);
env->iasq_b >> 32, w, m & env->iaoq_b,
hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b));
psw_c[0] = (psw & PSW_W ? 'W' : '-');
psw_c[1] = (psw & PSW_E ? 'E' : '-');
@ -154,12 +168,46 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
(i & 3) == 3 ? '\n' : ' ');
}
#ifndef CONFIG_USER_ONLY
for (i = 0; i < 32; i++) {
qemu_fprintf(f, "%-4s %0*" PRIx64 "%c",
cr_name[i], w, m & env->cr[i],
(i & 3) == 3 ? '\n' : ' ');
}
qemu_fprintf(f, "ISQB %0*" PRIx64 " IOQB %0*" PRIx64 "\n",
w, m & env->cr_back[0], w, m & env->cr_back[1]);
for (i = 0; i < 8; i++) {
qemu_fprintf(f, "SR%02d %08x%c", i, (uint32_t)(env->sr[i] >> 32),
(i & 3) == 3 ? '\n' : ' ');
}
#endif
qemu_fprintf(f, "\n");
/* ??? FR */
if (flags & CPU_DUMP_FPU) {
static const char rm[4][4] = { "RN", "RZ", "R+", "R-" };
char flg[6], ena[6];
uint32_t fpsr = env->fr0_shadow;
flg[0] = (fpsr & R_FPSR_FLG_V_MASK ? 'V' : '-');
flg[1] = (fpsr & R_FPSR_FLG_Z_MASK ? 'Z' : '-');
flg[2] = (fpsr & R_FPSR_FLG_O_MASK ? 'O' : '-');
flg[3] = (fpsr & R_FPSR_FLG_U_MASK ? 'U' : '-');
flg[4] = (fpsr & R_FPSR_FLG_I_MASK ? 'I' : '-');
flg[5] = '\0';
ena[0] = (fpsr & R_FPSR_ENA_V_MASK ? 'V' : '-');
ena[1] = (fpsr & R_FPSR_ENA_Z_MASK ? 'Z' : '-');
ena[2] = (fpsr & R_FPSR_ENA_O_MASK ? 'O' : '-');
ena[3] = (fpsr & R_FPSR_ENA_U_MASK ? 'U' : '-');
ena[4] = (fpsr & R_FPSR_ENA_I_MASK ? 'I' : '-');
ena[5] = '\0';
qemu_fprintf(f, "FPSR %08x flag %s enable %s %s\n",
fpsr, flg, ena, rm[FIELD_EX32(fpsr, FPSR, RM)]);
for (i = 0; i < 32; i++) {
qemu_fprintf(f, "FR%02d %016" PRIx64 "%c",
i, env->fr[i], (i & 3) == 3 ? '\n' : ' ');
}
}
qemu_fprintf(f, "\n");
}

View File

@ -1,6 +1,4 @@
DEF_HELPER_2(excp, noreturn, env, int)
DEF_HELPER_FLAGS_2(tsv, TCG_CALL_NO_WG, void, env, tl)
DEF_HELPER_FLAGS_2(tcond, TCG_CALL_NO_WG, void, env, tl)
DEF_HELPER_FLAGS_3(stby_b, TCG_CALL_NO_WG, void, env, tl, tl)
DEF_HELPER_FLAGS_3(stby_b_parallel, TCG_CALL_NO_WG, void, env, tl, tl)
@ -88,6 +86,7 @@ DEF_HELPER_1(halt, noreturn, env)
DEF_HELPER_1(reset, noreturn, env)
DEF_HELPER_1(rfi, void, env)
DEF_HELPER_1(rfi_r, void, env)
DEF_HELPER_FLAGS_2(b_gate_priv, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_2(write_interval_timer, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(write_eirr, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(swap_system_mask, TCG_CALL_NO_RWG, tl, env, tl)

View File

@ -134,13 +134,13 @@ void hppa_cpu_do_interrupt(CPUState *cs)
switch (i) {
case EXCP_ILL:
case EXCP_BREAK:
case EXCP_OVERFLOW:
case EXCP_COND:
case EXCP_PRIV_REG:
case EXCP_PRIV_OPR:
/* IIR set via translate.c. */
break;
case EXCP_OVERFLOW:
case EXCP_COND:
case EXCP_ASSIST:
case EXCP_DTLB_MISS:
case EXCP_NA_ITLB_MISS:
@ -167,7 +167,7 @@ void hppa_cpu_do_interrupt(CPUState *cs)
vaddr = hppa_form_gva_psw(old_psw, env->iasq_f, vaddr);
t = hppa_get_physical_address(env, vaddr, MMU_KERNEL_IDX,
0, &paddr, &prot, NULL);
0, &paddr, &prot);
if (t >= 0) {
/* We can't re-load the instruction. */
env->cr[CR_IIR] = 0;
@ -241,21 +241,22 @@ void hppa_cpu_do_interrupt(CPUState *cs)
[EXCP_SYSCALL_LWS] = "syscall-lws",
[EXCP_TOC] = "TOC (transfer of control)",
};
static int count;
const char *name = NULL;
char unknown[16];
if (i >= 0 && i < ARRAY_SIZE(names)) {
name = names[i];
FILE *logfile = qemu_log_trylock();
if (logfile) {
const char *name = NULL;
if (i >= 0 && i < ARRAY_SIZE(names)) {
name = names[i];
}
if (name) {
fprintf(logfile, "INT: cpu %d %s\n", cs->cpu_index, name);
} else {
fprintf(logfile, "INT: cpu %d unknown %d\n", cs->cpu_index, i);
}
hppa_cpu_dump_state(cs, logfile, 0);
qemu_log_unlock(logfile);
}
if (!name) {
snprintf(unknown, sizeof(unknown), "unknown %d", i);
name = unknown;
}
qemu_log("INT %6d: %s @ " TARGET_FMT_lx ":" TARGET_FMT_lx
" for " TARGET_FMT_lx ":" TARGET_FMT_lx "\n",
++count, name, env->cr[CR_IIASQ], env->cr[CR_IIAOQ],
env->cr[CR_ISR], env->cr[CR_IOR]);
}
cs->exception_index = -1;
}

View File

@ -197,18 +197,13 @@ static int match_prot_id64(CPUHPPAState *env, uint32_t access_id)
}
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
int type, hwaddr *pphys, int *pprot,
HPPATLBEntry **tlb_entry)
int type, hwaddr *pphys, int *pprot)
{
hwaddr phys;
int prot, r_prot, w_prot, x_prot, priv;
HPPATLBEntry *ent;
int ret = -1;
if (tlb_entry) {
*tlb_entry = NULL;
}
/* Virtual translation disabled. Map absolute to physical. */
if (MMU_IDX_MMU_DISABLED(mmu_idx)) {
switch (mmu_idx) {
@ -238,10 +233,6 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
goto egress;
}
if (tlb_entry) {
*tlb_entry = ent;
}
/* We now know the physical address. */
phys = ent->pa + (addr - ent->itree.start);
@ -296,30 +287,38 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
goto egress;
}
/* In reverse priority order, check for conditions which raise faults.
As we go, remove PROT bits that cover the condition we want to check.
In this way, the resulting PROT will force a re-check of the
architectural TLB entry for the next access. */
if (unlikely(!ent->d)) {
if (type & PAGE_WRITE) {
/* The D bit is not set -- TLB Dirty Bit Fault. */
ret = EXCP_TLB_DIRTY;
}
prot &= PAGE_READ | PAGE_EXEC;
}
if (unlikely(ent->b)) {
if (type & PAGE_WRITE) {
/* The B bit is set -- Data Memory Break Fault. */
ret = EXCP_DMB;
}
prot &= PAGE_READ | PAGE_EXEC;
}
/*
* In priority order, check for conditions which raise faults.
* Remove PROT bits that cover the condition we want to check,
* so that the resulting PROT will force a re-check of the
* architectural TLB entry for the next access.
*/
if (unlikely(ent->t)) {
prot &= PAGE_EXEC;
if (!(type & PAGE_EXEC)) {
/* The T bit is set -- Page Reference Fault. */
ret = EXCP_PAGE_REF;
}
prot &= PAGE_EXEC;
} else if (!ent->d) {
prot &= PAGE_READ | PAGE_EXEC;
if (type & PAGE_WRITE) {
/* The D bit is not set -- TLB Dirty Bit Fault. */
ret = EXCP_TLB_DIRTY;
}
} else if (unlikely(ent->b)) {
prot &= PAGE_READ | PAGE_EXEC;
if (type & PAGE_WRITE) {
/*
* The B bit is set -- Data Memory Break Fault.
* Except when PSW_X is set, allow this single access to succeed.
* The write bit will be invalidated for subsequent accesses.
*/
if (env->psw_xb & PSW_X) {
prot |= PAGE_WRITE_INV;
} else {
ret = EXCP_DMB;
}
}
}
egress:
@ -342,7 +341,7 @@ hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
cpu->env.psw & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX);
excp = hppa_get_physical_address(&cpu->env, addr, mmu_idx, 0,
&phys, &prot, NULL);
&phys, &prot);
/* Since we're translating for debugging, the only error that is a
hard error is no translation at all. Otherwise, while a real cpu
@ -424,7 +423,6 @@ bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
{
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = &cpu->env;
HPPATLBEntry *ent;
int prot, excp, a_prot;
hwaddr phys;
@ -440,8 +438,7 @@ bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
break;
}
excp = hppa_get_physical_address(env, addr, mmu_idx,
a_prot, &phys, &prot, &ent);
excp = hppa_get_physical_address(env, addr, mmu_idx, a_prot, &phys, &prot);
if (unlikely(excp >= 0)) {
if (probe) {
return false;
@ -682,7 +679,7 @@ target_ulong HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
int prot, excp;
excp = hppa_get_physical_address(env, addr, MMU_KERNEL_IDX, 0,
&phys, &prot, NULL);
&phys, &prot);
if (excp >= 0) {
if (excp == EXCP_DTLB_MISS) {
excp = EXCP_NA_DTLB_MISS;
@ -694,13 +691,6 @@ target_ulong HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
return phys;
}
/* Return the ar_type of the TLB at VADDR, or -1. */
int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr)
{
HPPATLBEntry *ent = hppa_find_tlb(env, vaddr);
return ent ? ent->ar_type : -1;
}
/*
* diag_btlb() emulates the PDC PDC_BLOCK_TLB firmware call to
* allow operating systems to modify the Block TLB (BTLB) entries.
@ -796,3 +786,30 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
break;
}
}
uint64_t HELPER(b_gate_priv)(CPUHPPAState *env, uint64_t iaoq_f)
{
uint64_t gva = hppa_form_gva(env, env->iasq_f, iaoq_f);
HPPATLBEntry *ent = hppa_find_tlb(env, gva);
if (ent == NULL) {
raise_exception_with_ior(env, EXCP_ITLB_MISS, GETPC(), gva, false);
}
/*
* There should be no need to check page permissions, as that will
* already have been done by tb_lookup via get_page_addr_code.
* All we need at this point is to check the ar_type.
*
* No change for non-gateway pages or for priv decrease.
*/
if (ent->ar_type & 4) {
int old_priv = iaoq_f & 3;
int new_priv = ent->ar_type & 3;
if (new_priv < old_priv) {
iaoq_f = (iaoq_f & -4) | new_priv;
}
}
return iaoq_f;
}

View File

@ -42,20 +42,6 @@ G_NORETURN void hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra)
cpu_loop_exit_restore(cs, ra);
}
void HELPER(tsv)(CPUHPPAState *env, target_ulong cond)
{
if (unlikely((target_long)cond < 0)) {
hppa_dynamic_excp(env, EXCP_OVERFLOW, GETPC());
}
}
void HELPER(tcond)(CPUHPPAState *env, target_ulong cond)
{
if (unlikely(cond)) {
hppa_dynamic_excp(env, EXCP_COND, GETPC());
}
}
static void atomic_store_mask32(CPUHPPAState *env, target_ulong addr,
uint32_t val, uint32_t mask, uintptr_t ra)
{
@ -348,8 +334,7 @@ target_ulong HELPER(probe)(CPUHPPAState *env, target_ulong addr,
}
mmu_idx = PRIV_P_TO_MMU_IDX(level, env->psw & PSW_P);
excp = hppa_get_physical_address(env, addr, mmu_idx, 0, &phys,
&prot, NULL);
excp = hppa_get_physical_address(env, addr, mmu_idx, 0, &phys, &prot);
if (excp >= 0) {
cpu_restore_state(env_cpu(env), GETPC());
hppa_set_ior_and_isr(env, addr, MMU_IDX_MMU_DISABLED(mmu_idx));

View File

@ -18,6 +18,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
@ -93,6 +94,17 @@ void HELPER(rfi)(CPUHPPAState *env)
env->iaoq_b = env->cr_back[1];
env->iasq_f = (env->cr[CR_IIASQ] << 32) & ~(env->iaoq_f & mask);
env->iasq_b = (env->cr_back[0] << 32) & ~(env->iaoq_b & mask);
if (qemu_loglevel_mask(CPU_LOG_INT)) {
FILE *logfile = qemu_log_trylock();
if (logfile) {
CPUState *cs = env_cpu(env);
fprintf(logfile, "RFI: cpu %d\n", cs->cpu_index);
hppa_cpu_dump_state(cs, logfile, 0);
qemu_log_unlock(logfile);
}
}
}
static void getshadowregs(CPUHPPAState *env)

File diff suppressed because it is too large Load Diff