target-mips: add CP0.PageGrain.ELPA support

CP0.PageGrain.ELPA enables support for large physical addresses. This field
is encoded as follows:
0: Large physical address support is disabled.
1: Large physical address support is enabled.

If this bit is a 1, the following changes occur to coprocessor 0 registers:
- The PFNX field of the EntryLo0 and EntryLo1 registers is writable and
concatenated with the PFN field to form the full page frame number.
- Access to optional COP0 registers with PA extension, LLAddr, TagLo is
defined.

P5600 can operate in 32-bit or 40-bit Physical Address Mode. Therefore if
XPA is disabled (CP0.PageGrain.ELPA = 0) then assume 32-bit Address Mode.
In MIPS64 assume 36 as default PABITS (when CP0.PageGrain.ELPA = 0).

env->PABITS value is constant and indicates maximum PABITS available on
a core, whereas env->PAMask is calculated from env->PABITS and is also
affected by CP0.PageGrain.ELPA.

Backports commit e117f52636d04502fab28bd3abe93347c29f39a5 from qemu
This commit is contained in:
Leon Alrae 2018-02-13 13:55:30 -05:00 committed by Lioncash
parent a13d401fe8
commit 59865351e0
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
4 changed files with 43 additions and 12 deletions

View file

@ -225,8 +225,14 @@ struct CPUMIPSState {
uint32_t SEGBITS; uint32_t SEGBITS;
uint32_t PABITS; uint32_t PABITS;
#if defined(TARGET_MIPS64)
# define PABITS_BASE 36
#else
# define PABITS_BASE 32
#endif
target_ulong SEGMask; target_ulong SEGMask;
uint64_t PAMask; uint64_t PAMask;
#define PAMASK_BASE ((1ULL << PABITS_BASE) - 1)
int32_t msair; int32_t msair;
#define MSAIR_ProcID 8 #define MSAIR_ProcID 8
@ -290,6 +296,7 @@ struct CPUMIPSState {
int32_t CP0_PageGrain; int32_t CP0_PageGrain;
#define CP0PG_RIE 31 #define CP0PG_RIE 31
#define CP0PG_XIE 30 #define CP0PG_XIE 30
#define CP0PG_ELPA 29
#define CP0PG_IEC 27 #define CP0PG_IEC 27
int32_t CP0_Wired; int32_t CP0_Wired;
int32_t CP0_SRSConf0_rw_bitmask; int32_t CP0_SRSConf0_rw_bitmask;
@ -519,7 +526,7 @@ struct CPUMIPSState {
#define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ #define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */
uint32_t hflags; /* CPU State */ uint32_t hflags; /* CPU State */
/* TMASK defines different execution modes */ /* TMASK defines different execution modes */
#define MIPS_HFLAG_TMASK 0x35807FF #define MIPS_HFLAG_TMASK 0x75807FF
#define MIPS_HFLAG_MODE 0x00007 /* execution modes */ #define MIPS_HFLAG_MODE 0x00007 /* execution modes */
/* The KSU flags must be the lowest bits in hflags. The flag order /* The KSU flags must be the lowest bits in hflags. The flag order
must be the same as defined for CP0 Status. This allows to use must be the same as defined for CP0 Status. This allows to use
@ -565,8 +572,9 @@ struct CPUMIPSState {
#define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */ #define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */
#define MIPS_HFLAG_SBRI 0x400000 /* R6 SDBBP causes RI excpt. in user mode */ #define MIPS_HFLAG_SBRI 0x400000 /* R6 SDBBP causes RI excpt. in user mode */
#define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */ #define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */
#define MIPS_HFLAG_MSA 0x1000000 /* FRE enabled */ #define MIPS_HFLAG_MSA 0x1000000
#define MIPS_HFLAG_FRE 0x2000000 /* FRE enabled */ #define MIPS_HFLAG_FRE 0x2000000 /* FRE enabled */
#define MIPS_HFLAG_ELPA 0x4000000
target_ulong btarget; /* Jump / branch target */ target_ulong btarget; /* Jump / branch target */
target_ulong bcond; /* Branch condition (if needed) */ target_ulong bcond; /* Branch condition (if needed) */
@ -805,6 +813,15 @@ static inline void restore_msa_fp_status(CPUMIPSState *env)
set_flush_inputs_to_zero(flush_to_zero, status); set_flush_inputs_to_zero(flush_to_zero, status);
} }
static inline void restore_pamask(CPUMIPSState *env)
{
if (env->hflags & MIPS_HFLAG_ELPA) {
env->PAMask = (1ULL << env->PABITS) - 1;
} else {
env->PAMask = PAMASK_BASE;
}
}
static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc, static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
target_ulong *cs_base, int *flags) target_ulong *cs_base, int *flags)
{ {
@ -852,7 +869,9 @@ static inline void compute_hflags(CPUMIPSState *env)
env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 | MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 |
MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE); MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE |
MIPS_HFLAG_ELPA);
if (!(env->CP0_Status & (1 << CP0St_EXL)) && if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
!(env->CP0_Status & (1 << CP0St_ERL)) && !(env->CP0_Status & (1 << CP0St_ERL)) &&
!(env->hflags & MIPS_HFLAG_DM)) { !(env->hflags & MIPS_HFLAG_DM)) {
@ -938,6 +957,11 @@ static inline void compute_hflags(CPUMIPSState *env)
env->hflags |= MIPS_HFLAG_FRE; env->hflags |= MIPS_HFLAG_FRE;
} }
} }
if (env->CP0_Config3 & (1 << CP0C3_LPA)) {
if (env->CP0_PageGrain & (1 << CP0PG_ELPA)) {
env->hflags |= MIPS_HFLAG_ELPA;
}
}
} }
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY

View file

@ -10,11 +10,11 @@
#if defined(TARGET_MIPS64) #if defined(TARGET_MIPS64)
#define TARGET_LONG_BITS 64 #define TARGET_LONG_BITS 64
#define TARGET_PHYS_ADDR_SPACE_BITS 36 #define TARGET_PHYS_ADDR_SPACE_BITS 48
#define TARGET_VIRT_ADDR_SPACE_BITS 42 #define TARGET_VIRT_ADDR_SPACE_BITS 42
#else #else
#define TARGET_LONG_BITS 32 #define TARGET_LONG_BITS 32
#define TARGET_PHYS_ADDR_SPACE_BITS 36 #define TARGET_PHYS_ADDR_SPACE_BITS 40
#define TARGET_VIRT_ADDR_SPACE_BITS 32 #define TARGET_VIRT_ADDR_SPACE_BITS 32
#endif #endif

View file

@ -1067,19 +1067,23 @@ void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
env->CP0_VPEOpt = arg1 & 0x0000ffff; env->CP0_VPEOpt = arg1 & 0x0000ffff;
} }
#define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF)
void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
{ {
/* Large physaddr (PABITS) not implemented */
/* 1k pages not implemented */ /* 1k pages not implemented */
target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30)); env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env))
| (rxi << (CP0EnLo_XI - 30));
} }
#if defined(TARGET_MIPS64) #if defined(TARGET_MIPS64)
#define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6)
void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1) void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
{ {
uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | rxi; env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
} }
#endif #endif
@ -1245,17 +1249,17 @@ void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
{ {
/* Large physaddr (PABITS) not implemented */
/* 1k pages not implemented */ /* 1k pages not implemented */
target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30)); env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env))
| (rxi << (CP0EnLo_XI - 30));
} }
#if defined(TARGET_MIPS64) #if defined(TARGET_MIPS64)
void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1) void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
{ {
uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | rxi; env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
} }
#endif #endif
@ -1282,6 +1286,8 @@ void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
/* 1k pages not implemented */ /* 1k pages not implemented */
env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) | env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
(env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask); (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
compute_hflags(env);
restore_pamask(env);
} }
void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)

View file

@ -5146,6 +5146,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
check_insn(ctx, ISA_MIPS32R2); check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(ctx, arg, offsetof(CPUMIPSState, CP0_PageGrain)); gen_mfc0_load32(ctx, arg, offsetof(CPUMIPSState, CP0_PageGrain));
rn = "PageGrain"; rn = "PageGrain";
ctx->bstate = BS_STOP;
break; break;
default: default:
goto cp0_unimplemented; goto cp0_unimplemented;
@ -19793,7 +19794,6 @@ void cpu_state_reset(CPUMIPSState *env)
} }
#endif #endif
env->PABITS = env->cpu_model->PABITS; env->PABITS = env->cpu_model->PABITS;
env->PAMask = (1ULL << env->cpu_model->PABITS) - 1;
env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask; env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask;
env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0; env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0;
env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask; env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask;
@ -19910,6 +19910,7 @@ void cpu_state_reset(CPUMIPSState *env)
compute_hflags(env); compute_hflags(env);
restore_rounding_mode(env); restore_rounding_mode(env);
restore_flush_mode(env); restore_flush_mode(env);
restore_pamask(env);
cs->exception_index = EXCP_NONE; cs->exception_index = EXCP_NONE;
} }