Skip to content

Commit

Permalink
Merge tag 'pull-hppa-20240515' of https://gitlab.com/rth7680/qemu int…
Browse files Browse the repository at this point in the history
…o 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>
  • Loading branch information
rth7680 committed May 15, 2024
2 parents 2b01688 + 9e035f0 commit 922582a
Show file tree
Hide file tree
Showing 15 changed files with 857 additions and 741 deletions.
4 changes: 2 additions & 2 deletions linux-user/elfload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
14 changes: 7 additions & 7 deletions linux-user/hppa/cpu_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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);
Expand All @@ -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:
Expand All @@ -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);
Expand Down
6 changes: 4 additions & 2 deletions linux-user/hppa/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions linux-user/hppa/target_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
86 changes: 62 additions & 24 deletions target/hppa/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,61 +32,96 @@ 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);
}

static void hppa_cpu_synchronize_from_tb(CPUState *cs,
const TranslationBlock *tb)
void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc,
uint64_t *pcsbase, uint32_t *pflags)
{
HPPACPU *cpu = HPPA_CPU(cs);
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;
}

tcg_debug_assert(!tcg_cflags_has(cs, CF_PCREL));
/* ??? 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
cpu->env.iaoq_f = tb->pc;
cpu->env.iaoq_b = tb->cs_base;
flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus;
#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;
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,
const TranslationBlock *tb)
{
HPPACPU *cpu = HPPA_CPU(cs);

/* 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)
Expand Down Expand Up @@ -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)
Expand Down
80 changes: 35 additions & 45 deletions target/hppa/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */

Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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);

Expand Down

0 comments on commit 922582a

Please sign in to comment.