Skip to content

Commit

Permalink
Merge pull request qemu#20 from yongbok/i6400-mips64r6-PRIP4
Browse files Browse the repository at this point in the history
Misaligned Memory Accesses for R6 and MSA
Fix to clear MSACSR for fexdo, fexupl and fexupr

Updates for qemu#17 

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
  • Loading branch information
yongbok committed Dec 17, 2014
2 parents 56df874 + dfa9fa8 commit 52e1faa
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 27 deletions.
8 changes: 5 additions & 3 deletions include/qom/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ typedef struct CPUClass {
void (*do_interrupt)(CPUState *cpu);
CPUUnassignedAccess do_unassigned_access;
void (*do_unaligned_access)(CPUState *cpu, vaddr addr,
int is_write, int is_user, uintptr_t retaddr);
int is_write, int is_user, uintptr_t retaddr,
unsigned size);
bool (*virtio_is_big_endian)(CPUState *cpu);
int (*memory_rw_debug)(CPUState *cpu, vaddr addr,
uint8_t *buf, int len, bool is_write);
Expand Down Expand Up @@ -576,11 +577,12 @@ static inline void cpu_unassigned_access(CPUState *cpu, hwaddr addr,

static inline void cpu_unaligned_access(CPUState *cpu, vaddr addr,
int is_write, int is_user,
uintptr_t retaddr)
uintptr_t retaddr, unsigned size)
{
CPUClass *cc = CPU_GET_CLASS(cpu);

return cc->do_unaligned_access(cpu, addr, is_write, is_user, retaddr);
return cc->do_unaligned_access(cpu, addr, is_write, is_user, retaddr,
size);
}
#endif

Expand Down
24 changes: 12 additions & 12 deletions softmmu_template.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
}
#endif
if (!VICTIM_TLB_HIT(ADDR_READ)) {
Expand Down Expand Up @@ -218,7 +218,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
do_unaligned_access:
#ifdef ALIGNED_ONLY
cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
#endif
addr1 = addr & ~(DATA_SIZE - 1);
addr2 = addr1 + DATA_SIZE;
Expand All @@ -237,7 +237,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
}
#endif

Expand Down Expand Up @@ -271,7 +271,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
}
#endif
if (!VICTIM_TLB_HIT(ADDR_READ)) {
Expand Down Expand Up @@ -306,7 +306,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
do_unaligned_access:
#ifdef ALIGNED_ONLY
cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
#endif
addr1 = addr & ~(DATA_SIZE - 1);
addr2 = addr1 + DATA_SIZE;
Expand All @@ -325,7 +325,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
}
#endif

Expand Down Expand Up @@ -397,7 +397,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
}
#endif
if (!VICTIM_TLB_HIT(addr_write)) {
Expand Down Expand Up @@ -429,7 +429,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
do_unaligned_access:
#ifdef ALIGNED_ONLY
cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
#endif
/* XXX: not efficient, but simple */
/* Note: relies on the fact that tlb_fill() does not remove the
Expand All @@ -449,7 +449,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
}
#endif

Expand Down Expand Up @@ -478,7 +478,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
}
#endif
if (!VICTIM_TLB_HIT(addr_write)) {
Expand Down Expand Up @@ -510,7 +510,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
do_unaligned_access:
#ifdef ALIGNED_ONLY
cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
#endif
/* XXX: not efficient, but simple */
/* Note: relies on the fact that tlb_fill() does not remove the
Expand All @@ -530,7 +530,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
mmu_idx, retaddr);
mmu_idx, retaddr, DATA_SIZE);
}
#endif

Expand Down
3 changes: 2 additions & 1 deletion target-alpha/cpu-qom.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int alpha_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
int is_write, int is_user, uintptr_t retaddr);
int is_write, int is_user, uintptr_t retaddr,
unsigned size);

#endif
3 changes: 2 additions & 1 deletion target-alpha/mem_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ uint64_t helper_stq_c_phys(CPUAlphaState *env, uint64_t p, uint64_t v)
}

void alpha_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
int is_write, int is_user, uintptr_t retaddr)
int is_write, int is_user, uintptr_t retaddr,
unsigned size)
{
AlphaCPU *cpu = ALPHA_CPU(cs);
CPUAlphaState *env = &cpu->env;
Expand Down
3 changes: 2 additions & 1 deletion target-mips/cpu-qom.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
int is_write, int is_user, uintptr_t retaddr);
int is_write, int is_user, uintptr_t retaddr,
unsigned size);

#endif
2 changes: 2 additions & 0 deletions target-mips/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,8 @@ int mips_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
void r4k_invalidate_tlb (CPUMIPSState *env, int idx, int use_extra);
hwaddr cpu_mips_translate_address (CPUMIPSState *env, target_ulong address,
int rw);
bool cpu_mips_validate_access(CPUMIPSState *env, target_ulong address,
target_ulong badvaddr, unsigned data_size, int rw);
#endif
target_ulong exception_resume_pc (CPUMIPSState *env);

Expand Down
33 changes: 33 additions & 0 deletions target-mips/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,39 @@ hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, int r
return physical;
}
}

bool cpu_mips_validate_access(CPUMIPSState *env, target_ulong address,
target_ulong badvaddr, unsigned data_size, int rw)
{
hwaddr physical;
int prot;
int access_type = ACCESS_INT;
int ret;
target_ulong addr;

addr = address & ~(data_size - 1);
ret = get_physical_address(env, &physical, &prot,
addr, rw, access_type);
if (ret != TLBRET_MATCH) {
raise_mmu_exception(env, badvaddr, rw, ret);
return false;
}
if (data_size > 1
&& unlikely((address & ~TARGET_PAGE_MASK) + data_size - 1
>= TARGET_PAGE_SIZE)) {
addr += data_size;
ret = get_physical_address(env, &physical, &prot,
addr, rw, access_type);
if (ret != TLBRET_MATCH) {
if (ret != TLBRET_BADADDR) {
badvaddr = addr;
}
raise_mmu_exception(env, badvaddr, rw, ret);
return false;
}
}
return true;
}
#endif

static const char * const excp_names[EXCP_LAST + 1] = {
Expand Down
6 changes: 6 additions & 0 deletions target-mips/msa_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -2650,6 +2650,8 @@ void helper_msa_fexdo_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
uint32_t i;

clear_msacsr_cause(env);

switch (df) {
case DF_WORD:
for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
Expand Down Expand Up @@ -3201,6 +3203,8 @@ void helper_msa_fexupl_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
uint32_t i;

clear_msacsr_cause(env);

switch (df) {
case DF_WORD:
for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
Expand Down Expand Up @@ -3233,6 +3237,8 @@ void helper_msa_fexupr_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
uint32_t i;

clear_msacsr_cause(env);

switch (df) {
case DF_WORD:
for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
Expand Down
55 changes: 51 additions & 4 deletions target-mips/op_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,16 +304,20 @@ static inline hwaddr do_translate_address(CPUMIPSState *env,
}
}

#define HELPER_LD_ATOMIC(name, insn) \
#define HELPER_LD_ATOMIC(name, insn, almask) \
target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \
{ \
if (arg & almask) { \
env->CP0_BadVAddr = arg; \
helper_raise_exception(env, EXCP_AdEL); \
} \
env->lladdr = do_translate_address(env, arg, 0); \
env->llval = do_##insn(env, arg, mem_idx); \
return env->llval; \
}
HELPER_LD_ATOMIC(ll, lw)
HELPER_LD_ATOMIC(ll, lw, 0x3)
#ifdef TARGET_MIPS64
HELPER_LD_ATOMIC(lld, ld)
HELPER_LD_ATOMIC(lld, ld, 0x7)
#endif
#undef HELPER_LD_ATOMIC

Expand Down Expand Up @@ -2451,13 +2455,26 @@ void helper_wait(CPUMIPSState *env)

void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
int access_type, int is_user,
uintptr_t retaddr)
uintptr_t retaddr, unsigned size)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
int error_code = 0;
int excp;

if (env->insn_flags & ISA_MIPS32R6) {
/* Release 6 provides support for misaligned memory access for
* all ordinary memory reference instructions
* */
if (!cpu_mips_validate_access(env, addr, addr, size, access_type)) {
CPUState *cs = CPU(mips_env_get_cpu(env));
do_raise_exception_err(env, cs->exception_index,
env->error_code, retaddr);
return;
}
return;
}

env->CP0_BadVAddr = addr;

if (access_type == MMU_DATA_STORE) {
Expand Down Expand Up @@ -3814,13 +3831,37 @@ FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
/* Element-by-element access macros */
#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))

#if !defined(CONFIG_USER_ONLY)
static bool cpu_mips_validate_msa_block_access(CPUMIPSState *env,
target_ulong address, int df, int rw)
{
int i;
for (i = 0; i < DF_ELEMENTS(df); i++) {
if (!cpu_mips_validate_access(env, address + (i << df),
address, (1 << df), rw)) {
CPUState *cs = CPU(mips_env_get_cpu(env));
do_raise_exception_err(env, cs->exception_index,
env->error_code, GETRA());
return false;
}
}
return true;
}
#endif

void helper_msa_ld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t rs,
int32_t s10)
{
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
target_ulong addr = env->active_tc.gpr[rs] + (s10 << df);
int i;

#if !defined(CONFIG_USER_ONLY)
if (!cpu_mips_validate_msa_block_access(env, addr, df, MMU_DATA_LOAD)) {
return;
}
#endif

switch (df) {
case DF_BYTE:
for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) {
Expand Down Expand Up @@ -3856,6 +3897,12 @@ void helper_msa_st_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t rs,
target_ulong addr = env->active_tc.gpr[rs] + (s10 << df);
int i;

#if !defined(CONFIG_USER_ONLY)
if (!cpu_mips_validate_msa_block_access(env, addr, df, MMU_DATA_STORE)) {
return;
}
#endif

switch (df) {
case DF_BYTE:
for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) {
Expand Down
2 changes: 1 addition & 1 deletion target-mips/translate_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ static const mips_def_t mips_defs[] =
},
{
/* A generic CPU supporting MIPS64 Release 6 ISA.
FIXME: Support IEEE 754-2008 FP and misaligned memory accesses.
FIXME: Support IEEE 754-2008 FP.
Eventually this should be replaced by a real CPU model. */
.name = "MIPS64R6-generic",
.CP0_PRid = 0x00010000,
Expand Down
3 changes: 2 additions & 1 deletion target-sparc/cpu-qom.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cpu,
vaddr addr, int is_write,
int is_user, uintptr_t retaddr);
int is_user, uintptr_t retaddr,
unsigned size);

#endif
3 changes: 2 additions & 1 deletion target-sparc/ldst_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -2420,7 +2420,8 @@ void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr,
#if !defined(CONFIG_USER_ONLY)
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cs,
vaddr addr, int is_write,
int is_user, uintptr_t retaddr)
int is_user, uintptr_t retaddr,
unsigned size)
{
SPARCCPU *cpu = SPARC_CPU(cs);
CPUSPARCState *env = &cpu->env;
Expand Down
3 changes: 2 additions & 1 deletion target-xtensa/cpu-qom.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
int is_write, int is_user, uintptr_t retaddr);
int is_write, int is_user,
uintptr_t retaddr, unsigned size);

#endif
2 changes: 1 addition & 1 deletion target-xtensa/op_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
#include "qemu/timer.h"

void xtensa_cpu_do_unaligned_access(CPUState *cs,
vaddr addr, int is_write, int is_user, uintptr_t retaddr)
vaddr addr, int is_write, int is_user, uintptr_t retaddr, unsigned size)
{
XtensaCPU *cpu = XTENSA_CPU(cs);
CPUXtensaState *env = &cpu->env;
Expand Down

0 comments on commit 52e1faa

Please sign in to comment.