mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/yongbok/tags/mips-20170721' into staging
MIPS patches 2017-07-21 Changes: * Add Enhanced Virtual Addressing (EVA) support # gpg: Signature made Fri 21 Jul 2017 03:25:15 BST # gpg: using RSA key 0x2238EB86D5F797C2 # gpg: Good signature from "Yongbok Kim <yongbok.kim@imgtec.com>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 8600 4CF5 3415 A5D9 4CFA 2B5C 2238 EB86 D5F7 97C2 * remotes/yongbok/tags/mips-20170721: target/mips: Enable CP0_EBase.WG on MIPS64 CPUs target/mips: Add EVA support to P5600 target/mips: Implement segmentation control target/mips: Add segmentation control registers target/mips: Add an MMU mode for ERL target/mips: Abstract mmu_idx from hflags target/mips: Check memory permissions with mem_idx target/mips: Decode microMIPS EVA load & store instructions target/mips: Decode MIPS32 EVA load & store instructions target/mips: Prepare loads/stores for EVA target/mips: Add CP0_Ebase.WG (write gate) support target/mips: Weaken TLB flush on UX,SX,KX,ASID changes target/mips: Fix TLBWI shadow flush for EHINV,XI,RI target/mips: Fix MIPS64 MFC0 UserLocal on BE host Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+53
-5
@@ -134,7 +134,7 @@ struct CPUMIPSFPUContext {
|
||||
#define FP_UNIMPLEMENTED 32
|
||||
};
|
||||
|
||||
#define NB_MMU_MODES 3
|
||||
#define NB_MMU_MODES 4
|
||||
#define TARGET_INSN_START_EXTRA_WORDS 2
|
||||
|
||||
typedef struct CPUMIPSMVPContext CPUMIPSMVPContext;
|
||||
@@ -306,6 +306,36 @@ struct CPUMIPSState {
|
||||
#define CP0PG_XIE 30
|
||||
#define CP0PG_ELPA 29
|
||||
#define CP0PG_IEC 27
|
||||
target_ulong CP0_SegCtl0;
|
||||
target_ulong CP0_SegCtl1;
|
||||
target_ulong CP0_SegCtl2;
|
||||
#define CP0SC_PA 9
|
||||
#define CP0SC_PA_MASK (0x7FULL << CP0SC_PA)
|
||||
#define CP0SC_PA_1GMASK (0x7EULL << CP0SC_PA)
|
||||
#define CP0SC_AM 4
|
||||
#define CP0SC_AM_MASK (0x7ULL << CP0SC_AM)
|
||||
#define CP0SC_AM_UK 0ULL
|
||||
#define CP0SC_AM_MK 1ULL
|
||||
#define CP0SC_AM_MSK 2ULL
|
||||
#define CP0SC_AM_MUSK 3ULL
|
||||
#define CP0SC_AM_MUSUK 4ULL
|
||||
#define CP0SC_AM_USK 5ULL
|
||||
#define CP0SC_AM_UUSK 7ULL
|
||||
#define CP0SC_EU 3
|
||||
#define CP0SC_EU_MASK (1ULL << CP0SC_EU)
|
||||
#define CP0SC_C 0
|
||||
#define CP0SC_C_MASK (0x7ULL << CP0SC_C)
|
||||
#define CP0SC_MASK (CP0SC_C_MASK | CP0SC_EU_MASK | CP0SC_AM_MASK | \
|
||||
CP0SC_PA_MASK)
|
||||
#define CP0SC_1GMASK (CP0SC_C_MASK | CP0SC_EU_MASK | CP0SC_AM_MASK | \
|
||||
CP0SC_PA_1GMASK)
|
||||
#define CP0SC0_MASK (CP0SC_MASK | (CP0SC_MASK << 16))
|
||||
#define CP0SC1_XAM 59
|
||||
#define CP0SC1_XAM_MASK (0x7ULL << CP0SC1_XAM)
|
||||
#define CP0SC1_MASK (CP0SC_MASK | (CP0SC_MASK << 16) | CP0SC1_XAM_MASK)
|
||||
#define CP0SC2_XR 56
|
||||
#define CP0SC2_XR_MASK (0xFFULL << CP0SC2_XR)
|
||||
#define CP0SC2_MASK (CP0SC_1GMASK | (CP0SC_1GMASK << 16) | CP0SC2_XR_MASK)
|
||||
int32_t CP0_Wired;
|
||||
int32_t CP0_SRSConf0_rw_bitmask;
|
||||
int32_t CP0_SRSConf0;
|
||||
@@ -399,7 +429,9 @@ struct CPUMIPSState {
|
||||
#define CP0Ca_EC 2
|
||||
target_ulong CP0_EPC;
|
||||
int32_t CP0_PRid;
|
||||
int32_t CP0_EBase;
|
||||
target_ulong CP0_EBase;
|
||||
target_ulong CP0_EBaseWG_rw_bitmask;
|
||||
#define CP0EBase_WG 11
|
||||
target_ulong CP0_CMGCRBase;
|
||||
int32_t CP0_Config0;
|
||||
#define CP0C0_M 31
|
||||
@@ -447,6 +479,7 @@ struct CPUMIPSState {
|
||||
#define CP0C3_MSAP 28
|
||||
#define CP0C3_BP 27
|
||||
#define CP0C3_BI 26
|
||||
#define CP0C3_SC 25
|
||||
#define CP0C3_IPLW 21
|
||||
#define CP0C3_MMAR 18
|
||||
#define CP0C3_MCU 17
|
||||
@@ -548,7 +581,7 @@ struct CPUMIPSState {
|
||||
#define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */
|
||||
uint32_t hflags; /* CPU State */
|
||||
/* TMASK defines different execution modes */
|
||||
#define MIPS_HFLAG_TMASK 0xF5807FF
|
||||
#define MIPS_HFLAG_TMASK 0x1F5807FF
|
||||
#define MIPS_HFLAG_MODE 0x00007 /* execution modes */
|
||||
/* 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
|
||||
@@ -598,6 +631,7 @@ struct CPUMIPSState {
|
||||
#define MIPS_HFLAG_FRE 0x2000000 /* FRE enabled */
|
||||
#define MIPS_HFLAG_ELPA 0x4000000
|
||||
#define MIPS_HFLAG_ITC_CACHE 0x8000000 /* CACHE instr. operates on ITC tag */
|
||||
#define MIPS_HFLAG_ERL 0x10000000 /* error level flag */
|
||||
target_ulong btarget; /* Jump / branch target */
|
||||
target_ulong bcond; /* Branch condition (if needed) */
|
||||
|
||||
@@ -695,10 +729,21 @@ extern uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env);
|
||||
#define MMU_MODE0_SUFFIX _kernel
|
||||
#define MMU_MODE1_SUFFIX _super
|
||||
#define MMU_MODE2_SUFFIX _user
|
||||
#define MMU_MODE3_SUFFIX _error
|
||||
#define MMU_USER_IDX 2
|
||||
|
||||
static inline int hflags_mmu_index(uint32_t hflags)
|
||||
{
|
||||
if (hflags & MIPS_HFLAG_ERL) {
|
||||
return 3; /* ERL */
|
||||
} else {
|
||||
return hflags & MIPS_HFLAG_KSU;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int cpu_mmu_index (CPUMIPSState *env, bool ifetch)
|
||||
{
|
||||
return env->hflags & MIPS_HFLAG_KSU;
|
||||
return hflags_mmu_index(env->hflags);
|
||||
}
|
||||
|
||||
static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env)
|
||||
@@ -962,7 +1007,10 @@ static inline void compute_hflags(CPUMIPSState *env)
|
||||
MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
|
||||
MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 |
|
||||
MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE |
|
||||
MIPS_HFLAG_ELPA);
|
||||
MIPS_HFLAG_ELPA | MIPS_HFLAG_ERL);
|
||||
if (env->CP0_Status & (1 << CP0St_ERL)) {
|
||||
env->hflags |= MIPS_HFLAG_ERL;
|
||||
}
|
||||
if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
|
||||
!(env->CP0_Status & (1 << CP0St_ERL)) &&
|
||||
!(env->hflags & MIPS_HFLAG_DM)) {
|
||||
|
||||
+170
-54
@@ -107,15 +107,107 @@ int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
|
||||
return TLBRET_NOMATCH;
|
||||
}
|
||||
|
||||
static int is_seg_am_mapped(unsigned int am, bool eu, int mmu_idx)
|
||||
{
|
||||
/*
|
||||
* Interpret access control mode and mmu_idx.
|
||||
* AdE? TLB?
|
||||
* AM K S U E K S U E
|
||||
* UK 0 0 1 1 0 0 - - 0
|
||||
* MK 1 0 1 1 0 1 - - !eu
|
||||
* MSK 2 0 0 1 0 1 1 - !eu
|
||||
* MUSK 3 0 0 0 0 1 1 1 !eu
|
||||
* MUSUK 4 0 0 0 0 0 1 1 0
|
||||
* USK 5 0 0 1 0 0 0 - 0
|
||||
* - 6 - - - - - - - -
|
||||
* UUSK 7 0 0 0 0 0 0 0 0
|
||||
*/
|
||||
int32_t adetlb_mask;
|
||||
|
||||
switch (mmu_idx) {
|
||||
case 3 /* ERL */:
|
||||
/* If EU is set, always unmapped */
|
||||
if (eu) {
|
||||
return 0;
|
||||
}
|
||||
/* fall through */
|
||||
case MIPS_HFLAG_KM:
|
||||
/* Never AdE, TLB mapped if AM={1,2,3} */
|
||||
adetlb_mask = 0x70000000;
|
||||
goto check_tlb;
|
||||
|
||||
case MIPS_HFLAG_SM:
|
||||
/* AdE if AM={0,1}, TLB mapped if AM={2,3,4} */
|
||||
adetlb_mask = 0xc0380000;
|
||||
goto check_ade;
|
||||
|
||||
case MIPS_HFLAG_UM:
|
||||
/* AdE if AM={0,1,2,5}, TLB mapped if AM={3,4} */
|
||||
adetlb_mask = 0xe4180000;
|
||||
/* fall through */
|
||||
check_ade:
|
||||
/* does this AM cause AdE in current execution mode */
|
||||
if ((adetlb_mask << am) < 0) {
|
||||
return TLBRET_BADADDR;
|
||||
}
|
||||
adetlb_mask <<= 8;
|
||||
/* fall through */
|
||||
check_tlb:
|
||||
/* is this AM mapped in current execution mode */
|
||||
return ((adetlb_mask << am) < 0);
|
||||
default:
|
||||
assert(0);
|
||||
return TLBRET_BADADDR;
|
||||
};
|
||||
}
|
||||
|
||||
static int get_seg_physical_address(CPUMIPSState *env, hwaddr *physical,
|
||||
int *prot, target_ulong real_address,
|
||||
int rw, int access_type, int mmu_idx,
|
||||
unsigned int am, bool eu,
|
||||
target_ulong segmask,
|
||||
hwaddr physical_base)
|
||||
{
|
||||
int mapped = is_seg_am_mapped(am, eu, mmu_idx);
|
||||
|
||||
if (mapped < 0) {
|
||||
/* is_seg_am_mapped can report TLBRET_BADADDR */
|
||||
return mapped;
|
||||
} else if (mapped) {
|
||||
/* The segment is TLB mapped */
|
||||
return env->tlb->map_address(env, physical, prot, real_address, rw,
|
||||
access_type);
|
||||
} else {
|
||||
/* The segment is unmapped */
|
||||
*physical = physical_base | (real_address & segmask);
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
return TLBRET_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_segctl_physical_address(CPUMIPSState *env, hwaddr *physical,
|
||||
int *prot, target_ulong real_address,
|
||||
int rw, int access_type, int mmu_idx,
|
||||
uint16_t segctl, target_ulong segmask)
|
||||
{
|
||||
unsigned int am = (segctl & CP0SC_AM_MASK) >> CP0SC_AM;
|
||||
bool eu = (segctl >> CP0SC_EU) & 1;
|
||||
hwaddr pa = ((hwaddr)segctl & CP0SC_PA_MASK) << 20;
|
||||
|
||||
return get_seg_physical_address(env, physical, prot, real_address, rw,
|
||||
access_type, mmu_idx, am, eu, segmask,
|
||||
pa & ~(hwaddr)segmask);
|
||||
}
|
||||
|
||||
static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
|
||||
int *prot, target_ulong real_address,
|
||||
int rw, int access_type)
|
||||
int rw, int access_type, int mmu_idx)
|
||||
{
|
||||
/* User mode can only access useg/xuseg */
|
||||
int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
|
||||
int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM;
|
||||
int kernel_mode = !user_mode && !supervisor_mode;
|
||||
#if defined(TARGET_MIPS64)
|
||||
int user_mode = mmu_idx == MIPS_HFLAG_UM;
|
||||
int supervisor_mode = mmu_idx == MIPS_HFLAG_SM;
|
||||
int kernel_mode = !user_mode && !supervisor_mode;
|
||||
int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
|
||||
int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
|
||||
int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
|
||||
@@ -148,12 +240,16 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
|
||||
|
||||
if (address <= USEG_LIMIT) {
|
||||
/* useg */
|
||||
if (env->CP0_Status & (1 << CP0St_ERL)) {
|
||||
*physical = address & 0xFFFFFFFF;
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
uint16_t segctl;
|
||||
|
||||
if (address >= 0x40000000UL) {
|
||||
segctl = env->CP0_SegCtl2;
|
||||
} else {
|
||||
ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
|
||||
segctl = env->CP0_SegCtl2 >> 16;
|
||||
}
|
||||
ret = get_segctl_physical_address(env, physical, prot, real_address, rw,
|
||||
access_type, mmu_idx, segctl,
|
||||
0x3FFFFFFF);
|
||||
#if defined(TARGET_MIPS64)
|
||||
} else if (address < 0x4000000000000000ULL) {
|
||||
/* xuseg */
|
||||
@@ -172,10 +268,33 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
|
||||
}
|
||||
} else if (address < 0xC000000000000000ULL) {
|
||||
/* xkphys */
|
||||
if (kernel_mode && KX &&
|
||||
(address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
|
||||
*physical = address & env->PAMask;
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
if ((address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
|
||||
/* KX/SX/UX bit to check for each xkphys EVA access mode */
|
||||
static const uint8_t am_ksux[8] = {
|
||||
[CP0SC_AM_UK] = (1u << CP0St_KX),
|
||||
[CP0SC_AM_MK] = (1u << CP0St_KX),
|
||||
[CP0SC_AM_MSK] = (1u << CP0St_SX),
|
||||
[CP0SC_AM_MUSK] = (1u << CP0St_UX),
|
||||
[CP0SC_AM_MUSUK] = (1u << CP0St_UX),
|
||||
[CP0SC_AM_USK] = (1u << CP0St_SX),
|
||||
[6] = (1u << CP0St_KX),
|
||||
[CP0SC_AM_UUSK] = (1u << CP0St_UX),
|
||||
};
|
||||
unsigned int am = CP0SC_AM_UK;
|
||||
unsigned int xr = (env->CP0_SegCtl2 & CP0SC2_XR_MASK) >> CP0SC2_XR;
|
||||
|
||||
if (xr & (1 << ((address >> 59) & 0x7))) {
|
||||
am = (env->CP0_SegCtl1 & CP0SC1_XAM_MASK) >> CP0SC1_XAM;
|
||||
}
|
||||
/* Does CP0_Status.KX/SX/UX permit the access mode (am) */
|
||||
if (env->CP0_Status & am_ksux[am]) {
|
||||
ret = get_seg_physical_address(env, physical, prot,
|
||||
real_address, rw, access_type,
|
||||
mmu_idx, am, false, env->PAMask,
|
||||
0);
|
||||
} else {
|
||||
ret = TLBRET_BADADDR;
|
||||
}
|
||||
} else {
|
||||
ret = TLBRET_BADADDR;
|
||||
}
|
||||
@@ -190,35 +309,25 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
|
||||
#endif
|
||||
} else if (address < (int32_t)KSEG1_BASE) {
|
||||
/* kseg0 */
|
||||
if (kernel_mode) {
|
||||
*physical = address - (int32_t)KSEG0_BASE;
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
} else {
|
||||
ret = TLBRET_BADADDR;
|
||||
}
|
||||
ret = get_segctl_physical_address(env, physical, prot, real_address, rw,
|
||||
access_type, mmu_idx,
|
||||
env->CP0_SegCtl1 >> 16, 0x1FFFFFFF);
|
||||
} else if (address < (int32_t)KSEG2_BASE) {
|
||||
/* kseg1 */
|
||||
if (kernel_mode) {
|
||||
*physical = address - (int32_t)KSEG1_BASE;
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
} else {
|
||||
ret = TLBRET_BADADDR;
|
||||
}
|
||||
ret = get_segctl_physical_address(env, physical, prot, real_address, rw,
|
||||
access_type, mmu_idx,
|
||||
env->CP0_SegCtl1, 0x1FFFFFFF);
|
||||
} else if (address < (int32_t)KSEG3_BASE) {
|
||||
/* sseg (kseg2) */
|
||||
if (supervisor_mode || kernel_mode) {
|
||||
ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
|
||||
} else {
|
||||
ret = TLBRET_BADADDR;
|
||||
}
|
||||
ret = get_segctl_physical_address(env, physical, prot, real_address, rw,
|
||||
access_type, mmu_idx,
|
||||
env->CP0_SegCtl0 >> 16, 0x1FFFFFFF);
|
||||
} else {
|
||||
/* kseg3 */
|
||||
/* XXX: debug segment is not emulated */
|
||||
if (kernel_mode) {
|
||||
ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
|
||||
} else {
|
||||
ret = TLBRET_BADADDR;
|
||||
}
|
||||
ret = get_segctl_physical_address(env, physical, prot, real_address, rw,
|
||||
access_type, mmu_idx,
|
||||
env->CP0_SegCtl0, 0x1FFFFFFF);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -290,7 +399,7 @@ void cpu_mips_store_status(CPUMIPSState *env, target_ulong val)
|
||||
#if defined(TARGET_MIPS64)
|
||||
if ((env->CP0_Status ^ old) & (old & (7 << CP0St_UX))) {
|
||||
/* Access to at least one of the 64-bit segments has been disabled */
|
||||
cpu_mips_tlb_flush(env);
|
||||
tlb_flush(CPU(mips_env_get_cpu(env)));
|
||||
}
|
||||
#endif
|
||||
if (env->CP0_Config3 & (1 << CP0C3_MT)) {
|
||||
@@ -413,11 +522,12 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
|
||||
hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
|
||||
{
|
||||
MIPSCPU *cpu = MIPS_CPU(cs);
|
||||
CPUMIPSState *env = &cpu->env;
|
||||
hwaddr phys_addr;
|
||||
int prot;
|
||||
|
||||
if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0,
|
||||
ACCESS_INT) != 0) {
|
||||
if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT,
|
||||
cpu_mmu_index(env, false)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return phys_addr;
|
||||
@@ -449,7 +559,7 @@ int mips_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
|
||||
correctly */
|
||||
access_type = ACCESS_INT;
|
||||
ret = get_physical_address(env, &physical, &prot,
|
||||
address, rw, access_type);
|
||||
address, rw, access_type, mmu_idx);
|
||||
switch (ret) {
|
||||
case TLBRET_MATCH:
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
@@ -487,8 +597,8 @@ hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, int r
|
||||
|
||||
/* data access */
|
||||
access_type = ACCESS_INT;
|
||||
ret = get_physical_address(env, &physical, &prot,
|
||||
address, rw, access_type);
|
||||
ret = get_physical_address(env, &physical, &prot, address, rw, access_type,
|
||||
cpu_mmu_index(env, false));
|
||||
if (ret != TLBRET_MATCH) {
|
||||
raise_mmu_exception(env, address, rw, ret);
|
||||
return -1LL;
|
||||
@@ -721,15 +831,17 @@ void mips_cpu_do_interrupt(CPUState *cs)
|
||||
#if defined(TARGET_MIPS64)
|
||||
int R = env->CP0_BadVAddr >> 62;
|
||||
int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
|
||||
int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
|
||||
int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
|
||||
|
||||
if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
|
||||
(!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
|
||||
if ((R != 0 || UX) && (R != 3 || KX) &&
|
||||
(!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)))) {
|
||||
offset = 0x080;
|
||||
else
|
||||
} else {
|
||||
#endif
|
||||
offset = 0x000;
|
||||
#if defined(TARGET_MIPS64)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
goto set_EPC;
|
||||
case EXCP_TLBS:
|
||||
@@ -740,15 +852,17 @@ void mips_cpu_do_interrupt(CPUState *cs)
|
||||
#if defined(TARGET_MIPS64)
|
||||
int R = env->CP0_BadVAddr >> 62;
|
||||
int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
|
||||
int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
|
||||
int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
|
||||
|
||||
if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
|
||||
(!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
|
||||
if ((R != 0 || UX) && (R != 3 || KX) &&
|
||||
(!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)))) {
|
||||
offset = 0x080;
|
||||
else
|
||||
} else {
|
||||
#endif
|
||||
offset = 0x000;
|
||||
#if defined(TARGET_MIPS64)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
goto set_EPC;
|
||||
case EXCP_AdEL:
|
||||
@@ -831,11 +945,7 @@ void mips_cpu_do_interrupt(CPUState *cs)
|
||||
goto set_EPC;
|
||||
case EXCP_CACHE:
|
||||
cause = 30;
|
||||
if (env->CP0_Status & (1 << CP0St_BEV)) {
|
||||
offset = 0x100;
|
||||
} else {
|
||||
offset = 0x20000100;
|
||||
}
|
||||
offset = 0x100;
|
||||
set_EPC:
|
||||
if (!(env->CP0_Status & (1 << CP0St_EXL))) {
|
||||
env->CP0_EPC = exception_resume_pc(env);
|
||||
@@ -861,9 +971,15 @@ void mips_cpu_do_interrupt(CPUState *cs)
|
||||
env->hflags &= ~MIPS_HFLAG_BMASK;
|
||||
if (env->CP0_Status & (1 << CP0St_BEV)) {
|
||||
env->active_tc.PC = env->exception_base + 0x200;
|
||||
} else if (cause == 30 && !(env->CP0_Config3 & (1 << CP0C3_SC) &&
|
||||
env->CP0_Config5 & (1 << CP0C5_CV))) {
|
||||
/* Force KSeg1 for cache errors */
|
||||
env->active_tc.PC = (int32_t)KSEG1_BASE |
|
||||
(env->CP0_EBase & 0x1FFFF000);
|
||||
} else {
|
||||
env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
|
||||
env->active_tc.PC = env->CP0_EBase & ~0xfff;
|
||||
}
|
||||
|
||||
env->active_tc.PC += offset;
|
||||
set_hflags_for_handler(env);
|
||||
env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
|
||||
|
||||
@@ -115,6 +115,9 @@ DEF_HELPER_2(mtc0_entrylo1, void, env, tl)
|
||||
DEF_HELPER_2(mtc0_context, void, env, tl)
|
||||
DEF_HELPER_2(mtc0_pagemask, void, env, tl)
|
||||
DEF_HELPER_2(mtc0_pagegrain, void, env, tl)
|
||||
DEF_HELPER_2(mtc0_segctl0, void, env, tl)
|
||||
DEF_HELPER_2(mtc0_segctl1, void, env, tl)
|
||||
DEF_HELPER_2(mtc0_segctl2, void, env, tl)
|
||||
DEF_HELPER_2(mtc0_wired, void, env, tl)
|
||||
DEF_HELPER_2(mtc0_srsconf0, void, env, tl)
|
||||
DEF_HELPER_2(mtc0_srsconf1, void, env, tl)
|
||||
|
||||
@@ -211,8 +211,8 @@ const VMStateDescription vmstate_tlb = {
|
||||
|
||||
const VMStateDescription vmstate_mips_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 8,
|
||||
.minimum_version_id = 8,
|
||||
.version_id = 10,
|
||||
.minimum_version_id = 10,
|
||||
.post_load = cpu_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
/* Active TC */
|
||||
@@ -252,6 +252,9 @@ const VMStateDescription vmstate_mips_cpu = {
|
||||
VMSTATE_UINTTL(env.CP0_Context, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_PageMask, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_PageGrain, MIPSCPU),
|
||||
VMSTATE_UINTTL(env.CP0_SegCtl0, MIPSCPU),
|
||||
VMSTATE_UINTTL(env.CP0_SegCtl1, MIPSCPU),
|
||||
VMSTATE_UINTTL(env.CP0_SegCtl2, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_Wired, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_SRSConf0, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_SRSConf1, MIPSCPU),
|
||||
@@ -272,7 +275,7 @@ const VMStateDescription vmstate_mips_cpu = {
|
||||
VMSTATE_INT32(env.CP0_Cause, MIPSCPU),
|
||||
VMSTATE_UINTTL(env.CP0_EPC, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_PRid, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_EBase, MIPSCPU),
|
||||
VMSTATE_UINTTL(env.CP0_EBase, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_Config0, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_Config1, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_Config2, MIPSCPU),
|
||||
|
||||
+57
-7
@@ -67,6 +67,7 @@ static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
|
||||
case 1: return (type) cpu_##insn##_super_ra(env, addr, retaddr); \
|
||||
default: \
|
||||
case 2: return (type) cpu_##insn##_user_ra(env, addr, retaddr); \
|
||||
case 3: return (type) cpu_##insn##_error_ra(env, addr, retaddr); \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
@@ -94,6 +95,9 @@ static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
|
||||
case 1: cpu_##insn##_super_ra(env, addr, val, retaddr); break; \
|
||||
default: \
|
||||
case 2: cpu_##insn##_user_ra(env, addr, val, retaddr); break; \
|
||||
case 3: \
|
||||
cpu_##insn##_error_ra(env, addr, val, retaddr); \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
@@ -1318,6 +1322,30 @@ void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
|
||||
restore_pamask(env);
|
||||
}
|
||||
|
||||
void helper_mtc0_segctl0(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
CPUState *cs = CPU(mips_env_get_cpu(env));
|
||||
|
||||
env->CP0_SegCtl0 = arg1 & CP0SC0_MASK;
|
||||
tlb_flush(cs);
|
||||
}
|
||||
|
||||
void helper_mtc0_segctl1(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
CPUState *cs = CPU(mips_env_get_cpu(env));
|
||||
|
||||
env->CP0_SegCtl1 = arg1 & CP0SC1_MASK;
|
||||
tlb_flush(cs);
|
||||
}
|
||||
|
||||
void helper_mtc0_segctl2(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
CPUState *cs = CPU(mips_env_get_cpu(env));
|
||||
|
||||
env->CP0_SegCtl2 = arg1 & CP0SC2_MASK;
|
||||
tlb_flush(cs);
|
||||
}
|
||||
|
||||
void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
if (env->insn_flags & ISA_MIPS32R6) {
|
||||
@@ -1416,7 +1444,7 @@ void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
|
||||
/* If the ASID changes, flush qemu's TLB. */
|
||||
if ((old & env->CP0_EntryHi_ASID_mask) !=
|
||||
(val & env->CP0_EntryHi_ASID_mask)) {
|
||||
cpu_mips_tlb_flush(env);
|
||||
tlb_flush(CPU(mips_env_get_cpu(env)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1450,7 +1478,10 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
|
||||
old, old & env->CP0_Cause & CP0Ca_IP_mask,
|
||||
val, val & env->CP0_Cause & CP0Ca_IP_mask,
|
||||
env->CP0_Cause);
|
||||
switch (env->hflags & MIPS_HFLAG_KSU) {
|
||||
switch (cpu_mmu_index(env, false)) {
|
||||
case 3:
|
||||
qemu_log(", ERL\n");
|
||||
break;
|
||||
case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
|
||||
case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
|
||||
case MIPS_HFLAG_KM: qemu_log("\n"); break;
|
||||
@@ -1515,14 +1546,22 @@ target_ulong helper_mftc0_ebase(CPUMIPSState *env)
|
||||
|
||||
void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
|
||||
target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
|
||||
if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
|
||||
mask |= ~0x3FFFFFFF;
|
||||
}
|
||||
env->CP0_EBase = (env->CP0_EBase & ~mask) | (arg1 & mask);
|
||||
}
|
||||
|
||||
void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
|
||||
CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
|
||||
other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
|
||||
target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
|
||||
if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
|
||||
mask |= ~0x3FFFFFFF;
|
||||
}
|
||||
other->CP0_EBase = (other->CP0_EBase & ~mask) | (arg1 & mask);
|
||||
}
|
||||
|
||||
target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
|
||||
@@ -2029,7 +2068,7 @@ void r4k_helper_tlbwi(CPUMIPSState *env)
|
||||
int idx;
|
||||
target_ulong VPN;
|
||||
uint16_t ASID;
|
||||
bool G, V0, D0, V1, D1;
|
||||
bool EHINV, G, V0, D0, V1, D1, XI0, XI1, RI0, RI1;
|
||||
|
||||
idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
|
||||
tlb = &env->tlb->mmu.r4k.tlb[idx];
|
||||
@@ -2038,17 +2077,25 @@ void r4k_helper_tlbwi(CPUMIPSState *env)
|
||||
VPN &= env->SEGMask;
|
||||
#endif
|
||||
ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
|
||||
EHINV = (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) != 0;
|
||||
G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
|
||||
V0 = (env->CP0_EntryLo0 & 2) != 0;
|
||||
D0 = (env->CP0_EntryLo0 & 4) != 0;
|
||||
XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) &1;
|
||||
RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) &1;
|
||||
V1 = (env->CP0_EntryLo1 & 2) != 0;
|
||||
D1 = (env->CP0_EntryLo1 & 4) != 0;
|
||||
XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) &1;
|
||||
RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) &1;
|
||||
|
||||
/* Discard cached TLB entries, unless tlbwi is just upgrading access
|
||||
permissions on the current entry. */
|
||||
if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
|
||||
(!tlb->EHINV && EHINV) ||
|
||||
(tlb->V0 && !V0) || (tlb->D0 && !D0) ||
|
||||
(tlb->V1 && !V1) || (tlb->D1 && !D1)) {
|
||||
(!tlb->XI0 && XI0) || (!tlb->RI0 && RI0) ||
|
||||
(tlb->V1 && !V1) || (tlb->D1 && !D1) ||
|
||||
(!tlb->XI1 && XI1) || (!tlb->RI1 && RI1)) {
|
||||
r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
|
||||
}
|
||||
|
||||
@@ -2228,7 +2275,10 @@ static void debug_post_eret(CPUMIPSState *env)
|
||||
qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
|
||||
if (env->hflags & MIPS_HFLAG_DM)
|
||||
qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
|
||||
switch (env->hflags & MIPS_HFLAG_KSU) {
|
||||
switch (cpu_mmu_index(env, false)) {
|
||||
case 3:
|
||||
qemu_log(", ERL\n");
|
||||
break;
|
||||
case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
|
||||
case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
|
||||
case MIPS_HFLAG_KM: qemu_log("\n"); break;
|
||||
|
||||
+360
-45
File diff suppressed because it is too large
Load Diff
@@ -101,6 +101,7 @@ struct mips_def_t {
|
||||
int32_t CP0_SRSConf4;
|
||||
int32_t CP0_PageGrain_rw_bitmask;
|
||||
int32_t CP0_PageGrain;
|
||||
target_ulong CP0_EBaseWG_rw_bitmask;
|
||||
int insn_flags;
|
||||
enum mips_mmu_types mmu_type;
|
||||
};
|
||||
@@ -420,9 +421,9 @@ static const mips_def_t mips_defs[] =
|
||||
},
|
||||
{
|
||||
/* FIXME:
|
||||
* Config3: CMGCR, SC, PW, VZ, CTXTC, CDMM, TL
|
||||
* Config3: CMGCR, PW, VZ, CTXTC, CDMM, TL
|
||||
* Config4: MMUExtDef
|
||||
* Config5: EVA, MRP
|
||||
* Config5: MRP
|
||||
* FIR(FCR0): Has2008
|
||||
* */
|
||||
.name = "P5600",
|
||||
@@ -435,13 +436,14 @@ static const mips_def_t mips_defs[] =
|
||||
(1 << CP0C1_PC) | (1 << CP0C1_FP),
|
||||
.CP0_Config2 = MIPS_CONFIG2,
|
||||
.CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP) |
|
||||
(1 << CP0C3_BP) | (1 << CP0C3_BI) | (1 << CP0C3_ULRI) |
|
||||
(1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt),
|
||||
(1 << CP0C3_BP) | (1 << CP0C3_BI) | (1 << CP0C3_SC) |
|
||||
(1 << CP0C3_ULRI) | (1 << CP0C3_RXI) | (1 << CP0C3_LPA) |
|
||||
(1 << CP0C3_VInt),
|
||||
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (2 << CP0C4_IE) |
|
||||
(0x1c << CP0C4_KScrExist),
|
||||
.CP0_Config4_rw_bitmask = 0,
|
||||
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_MVH) | (1 << CP0C5_LLB) |
|
||||
(1 << CP0C5_MRP),
|
||||
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_EVA) | (1 << CP0C5_MVH) |
|
||||
(1 << CP0C5_LLB) | (1 << CP0C5_MRP),
|
||||
.CP0_Config5_rw_bitmask = (1 << CP0C5_K) | (1 << CP0C5_CV) |
|
||||
(1 << CP0C5_MSAEn) | (1 << CP0C5_UFE) |
|
||||
(1 << CP0C5_FRE) | (1 << CP0C5_UFR),
|
||||
@@ -452,6 +454,7 @@ static const mips_def_t mips_defs[] =
|
||||
.CP0_Status_rw_bitmask = 0x3C68FF1F,
|
||||
.CP0_PageGrain_rw_bitmask = (1U << CP0PG_RIE) | (1 << CP0PG_XIE) |
|
||||
(1 << CP0PG_ELPA) | (1 << CP0PG_IEC),
|
||||
.CP0_EBaseWG_rw_bitmask = (1 << CP0EBase_WG),
|
||||
.CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_UFRP) | (1 << FCR0_HAS2008) |
|
||||
(1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
|
||||
(1 << FCR0_D) | (1 << FCR0_S) | (0x03 << FCR0_PRID),
|
||||
@@ -637,6 +640,7 @@ static const mips_def_t mips_defs[] =
|
||||
.SYNCI_Step = 32,
|
||||
.CCRes = 2,
|
||||
.CP0_Status_rw_bitmask = 0x36FBFFFF,
|
||||
.CP0_EBaseWG_rw_bitmask = (1 << CP0EBase_WG),
|
||||
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) |
|
||||
(1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
|
||||
(1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
|
||||
@@ -720,6 +724,7 @@ static const mips_def_t mips_defs[] =
|
||||
.CP0_PageGrain = (1 << CP0PG_IEC) | (1 << CP0PG_XIE) |
|
||||
(1U << CP0PG_RIE),
|
||||
.CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA),
|
||||
.CP0_EBaseWG_rw_bitmask = (1 << CP0EBase_WG),
|
||||
.CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_HAS2008) | (1 << FCR0_F64) |
|
||||
(1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
|
||||
(1 << FCR0_S) | (0x03 << FCR0_PRID) | (0x0 << FCR0_REV),
|
||||
|
||||
Reference in New Issue
Block a user