MIPS patches 2015-10-30
Changes: * R6 CPU can be woken up by non-enabled interrupts * PC fix in KVM * Coprocessor 0 XContext calculation fix * various MIPS R6 updates -----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJWM4QMAAoJEFIRjjwLKdprOUIIAJPz+fbhszYBKQedoCeSZruG Fu6FcaaMd+EW4eawNrcLEo+ARyHc/5MhUf7bMjOBXgxa5M3Z4glu3DCyxYGdt+GN HGB/v09WqqGZiX5js7axudVJ3DXsZ36uRmevEGskYK2Wgtaue77oy/fXjUzOiJXm TGh/dgyNKIv6yltH/VfI7Bs0g7sHts767t+37m1/CLi5MmlxXD3DXwMyj1PIQHZY Bd87KbgRb2O4zhBnKGuQCjzrxBYI3mT8MlNwGBOaR5RidOYVv+Mn7RSN04NzZpc1 PtGH+he2TfcA6aHQ5ze09ipm6EY+DbJAJzlLTF+33opcw/uIHrz5j+dOWNWast4= =ytpO -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/lalrae/tags/mips-20151030' into staging MIPS patches 2015-10-30 Changes: * R6 CPU can be woken up by non-enabled interrupts * PC fix in KVM * Coprocessor 0 XContext calculation fix * various MIPS R6 updates # gpg: Signature made Fri 30 Oct 2015 14:51:56 GMT using RSA key ID 0B29DA6B # gpg: Good signature from "Leon Alrae <leon.alrae@imgtec.com>" * remotes/lalrae/tags/mips-20151030: target-mips: fix updating XContext on mmu exception target-mips: add SIGRIE instruction target-mips: Set Config5.XNP for R6 cores target-mips: add PC, XNP reg numbers to RDHWR hw/mips_malta: Fix KVM PC initialisation target-mips: Add enum for BREAK32 target-mips: update writing to CP0.Status.KX/SX/UX in MIPS Release R6 target-mips: implement the CPU wake-up on non-enabled interrupts in R6 target-mips: move the test for enabled interrupts to a separate function Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e79ea9e424
@ -901,7 +901,7 @@ static void main_cpu_reset(void *opaque)
|
||||
|
||||
if (kvm_enabled()) {
|
||||
/* Start running from the bootloader we wrote to end of RAM */
|
||||
env->active_tc.PC = 0x40000000 + loaderparams.ram_size;
|
||||
env->active_tc.PC = 0x40000000 + loaderparams.ram_low_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,12 +53,15 @@ static bool mips_cpu_has_work(CPUState *cs)
|
||||
CPUMIPSState *env = &cpu->env;
|
||||
bool has_work = false;
|
||||
|
||||
/* It is implementation dependent if non-enabled interrupts
|
||||
wake-up the CPU, however most of the implementations only
|
||||
/* Prior to MIPS Release 6 it is implementation dependent if non-enabled
|
||||
interrupts wake-up the CPU, however most of the implementations only
|
||||
check for interrupts that can be taken. */
|
||||
if ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
cpu_mips_hw_interrupts_pending(env)) {
|
||||
has_work = true;
|
||||
if (cpu_mips_hw_interrupts_enabled(env) ||
|
||||
(env->insn_flags & ISA_MIPS32R6)) {
|
||||
has_work = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* MIPS-MT has the ability to halt the CPU. */
|
||||
|
@ -469,6 +469,7 @@ struct CPUMIPSState {
|
||||
#define CP0C5_CV 29
|
||||
#define CP0C5_EVA 28
|
||||
#define CP0C5_MSAEn 27
|
||||
#define CP0C5_XNP 13
|
||||
#define CP0C5_UFE 9
|
||||
#define CP0C5_FRE 8
|
||||
#define CP0C5_SBRI 6
|
||||
@ -637,23 +638,24 @@ static inline int cpu_mmu_index (CPUMIPSState *env, bool ifetch)
|
||||
return env->hflags & MIPS_HFLAG_KSU;
|
||||
}
|
||||
|
||||
static inline int cpu_mips_hw_interrupts_pending(CPUMIPSState *env)
|
||||
static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env)
|
||||
{
|
||||
int32_t pending;
|
||||
int32_t status;
|
||||
int r;
|
||||
|
||||
if (!(env->CP0_Status & (1 << CP0St_IE)) ||
|
||||
(env->CP0_Status & (1 << CP0St_EXL)) ||
|
||||
(env->CP0_Status & (1 << CP0St_ERL)) ||
|
||||
return (env->CP0_Status & (1 << CP0St_IE)) &&
|
||||
!(env->CP0_Status & (1 << CP0St_EXL)) &&
|
||||
!(env->CP0_Status & (1 << CP0St_ERL)) &&
|
||||
!(env->hflags & MIPS_HFLAG_DM) &&
|
||||
/* Note that the TCStatus IXMT field is initialized to zero,
|
||||
and only MT capable cores can set it to one. So we don't
|
||||
need to check for MT capabilities here. */
|
||||
(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_IXMT)) ||
|
||||
(env->hflags & MIPS_HFLAG_DM)) {
|
||||
/* Interrupts are disabled */
|
||||
return 0;
|
||||
}
|
||||
!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_IXMT));
|
||||
}
|
||||
|
||||
/* Check if there is pending and not masked out interrupt */
|
||||
static inline bool cpu_mips_hw_interrupts_pending(CPUMIPSState *env)
|
||||
{
|
||||
int32_t pending;
|
||||
int32_t status;
|
||||
bool r;
|
||||
|
||||
pending = env->CP0_Cause & CP0Ca_IP_mask;
|
||||
status = env->CP0_Status & CP0Ca_IP_mask;
|
||||
@ -667,7 +669,7 @@ static inline int cpu_mips_hw_interrupts_pending(CPUMIPSState *env)
|
||||
/* A MIPS configured with compatibility or VInt (Vectored Interrupts)
|
||||
treats the pending lines as individual interrupt lines, the status
|
||||
lines are individual masks. */
|
||||
r = pending & status;
|
||||
r = (pending & status) != 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@ -1000,7 +1002,12 @@ static inline void cpu_mips_store_status(CPUMIPSState *env, target_ulong val)
|
||||
|
||||
if (env->insn_flags & ISA_MIPS32R6) {
|
||||
bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3;
|
||||
|
||||
#if defined(TARGET_MIPS64)
|
||||
uint32_t ksux = (1 << CP0St_KX) & val;
|
||||
ksux |= (ksux >> 1) & val; /* KX = 0 forces SX to be 0 */
|
||||
ksux |= (ksux >> 1) & val; /* SX = 0 forces UX to be 0 */
|
||||
val = (val & ~(7 << CP0St_UX)) | ksux;
|
||||
#endif
|
||||
if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) {
|
||||
mask &= ~(3 << CP0St_KSU);
|
||||
}
|
||||
|
@ -293,9 +293,10 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
|
||||
(env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
|
||||
#if defined(TARGET_MIPS64)
|
||||
env->CP0_EntryHi &= env->SEGMask;
|
||||
env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
|
||||
((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |
|
||||
((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
|
||||
env->CP0_XContext =
|
||||
/* PTEBase */ (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
|
||||
/* R */ (extract64(address, 62, 2) << (env->SEGBITS - 9)) |
|
||||
/* BadVPN2 */ (extract64(address, 13, env->SEGBITS - 13) << 4);
|
||||
#endif
|
||||
cs->exception_index = exception;
|
||||
env->error_code = error_code;
|
||||
@ -759,7 +760,8 @@ bool mips_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
MIPSCPU *cpu = MIPS_CPU(cs);
|
||||
CPUMIPSState *env = &cpu->env;
|
||||
|
||||
if (cpu_mips_hw_interrupts_pending(env)) {
|
||||
if (cpu_mips_hw_interrupts_enabled(env) &&
|
||||
cpu_mips_hw_interrupts_pending(env)) {
|
||||
/* Raise it */
|
||||
cs->exception_index = EXCP_EXT_INTERRUPT;
|
||||
env->error_code = 0;
|
||||
|
@ -358,6 +358,8 @@ DEF_HELPER_1(rdhwr_cpunum, tl, env)
|
||||
DEF_HELPER_1(rdhwr_synci_step, tl, env)
|
||||
DEF_HELPER_1(rdhwr_cc, tl, env)
|
||||
DEF_HELPER_1(rdhwr_ccres, tl, env)
|
||||
DEF_HELPER_1(rdhwr_performance, tl, env)
|
||||
DEF_HELPER_1(rdhwr_xnp, tl, env)
|
||||
DEF_HELPER_2(pmon, void, env, int)
|
||||
DEF_HELPER_1(wait, void, env)
|
||||
|
||||
|
@ -1357,6 +1357,13 @@ void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
uint32_t mask = 0x0000000F;
|
||||
|
||||
if ((env->CP0_Config1 & (1 << CP0C1_PC)) &&
|
||||
(env->insn_flags & ISA_MIPS32R6)) {
|
||||
mask |= (1 << 4);
|
||||
}
|
||||
if (env->insn_flags & ISA_MIPS32R6) {
|
||||
mask |= (1 << 5);
|
||||
}
|
||||
if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
|
||||
mask |= (1 << 29);
|
||||
|
||||
@ -2185,53 +2192,52 @@ void helper_deret(CPUMIPSState *env)
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
static inline void check_hwrena(CPUMIPSState *env, int reg)
|
||||
{
|
||||
if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) {
|
||||
return;
|
||||
}
|
||||
do_raise_exception(env, EXCP_RI, GETPC());
|
||||
}
|
||||
|
||||
target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
|
||||
{
|
||||
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
||||
(env->CP0_HWREna & (1 << 0)))
|
||||
return env->CP0_EBase & 0x3ff;
|
||||
else
|
||||
do_raise_exception(env, EXCP_RI, GETPC());
|
||||
|
||||
return 0;
|
||||
check_hwrena(env, 0);
|
||||
return env->CP0_EBase & 0x3ff;
|
||||
}
|
||||
|
||||
target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
|
||||
{
|
||||
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
||||
(env->CP0_HWREna & (1 << 1)))
|
||||
return env->SYNCI_Step;
|
||||
else
|
||||
do_raise_exception(env, EXCP_RI, GETPC());
|
||||
|
||||
return 0;
|
||||
check_hwrena(env, 1);
|
||||
return env->SYNCI_Step;
|
||||
}
|
||||
|
||||
target_ulong helper_rdhwr_cc(CPUMIPSState *env)
|
||||
{
|
||||
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
||||
(env->CP0_HWREna & (1 << 2))) {
|
||||
check_hwrena(env, 2);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
return env->CP0_Count;
|
||||
return env->CP0_Count;
|
||||
#else
|
||||
return (int32_t)cpu_mips_get_count(env);
|
||||
return (int32_t)cpu_mips_get_count(env);
|
||||
#endif
|
||||
} else {
|
||||
do_raise_exception(env, EXCP_RI, GETPC());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
|
||||
{
|
||||
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
||||
(env->CP0_HWREna & (1 << 3)))
|
||||
return env->CCRes;
|
||||
else
|
||||
do_raise_exception(env, EXCP_RI, GETPC());
|
||||
check_hwrena(env, 3);
|
||||
return env->CCRes;
|
||||
}
|
||||
|
||||
return 0;
|
||||
target_ulong helper_rdhwr_performance(CPUMIPSState *env)
|
||||
{
|
||||
check_hwrena(env, 4);
|
||||
return env->CP0_Performance0;
|
||||
}
|
||||
|
||||
target_ulong helper_rdhwr_xnp(CPUMIPSState *env)
|
||||
{
|
||||
check_hwrena(env, 5);
|
||||
return (env->CP0_Config5 >> CP0C5_XNP) & 1;
|
||||
}
|
||||
|
||||
void helper_pmon(CPUMIPSState *env, int function)
|
||||
|
@ -323,6 +323,7 @@ enum {
|
||||
OPC_TLTIU = (0x0B << 16) | OPC_REGIMM,
|
||||
OPC_TEQI = (0x0C << 16) | OPC_REGIMM,
|
||||
OPC_TNEI = (0x0E << 16) | OPC_REGIMM,
|
||||
OPC_SIGRIE = (0x17 << 16) | OPC_REGIMM,
|
||||
OPC_SYNCI = (0x1F << 16) | OPC_REGIMM,
|
||||
|
||||
OPC_DAHI = (0x06 << 16) | OPC_REGIMM,
|
||||
@ -10333,7 +10334,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_rdhwr(DisasContext *ctx, int rt, int rd)
|
||||
static void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel)
|
||||
{
|
||||
TCGv t0;
|
||||
|
||||
@ -10361,6 +10362,22 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd)
|
||||
gen_helper_rdhwr_ccres(t0, cpu_env);
|
||||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
case 4:
|
||||
check_insn(ctx, ISA_MIPS32R6);
|
||||
if (sel != 0) {
|
||||
/* Performance counter registers are not implemented other than
|
||||
* control register 0.
|
||||
*/
|
||||
generate_exception(ctx, EXCP_RI);
|
||||
}
|
||||
gen_helper_rdhwr_performance(t0, cpu_env);
|
||||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
case 5:
|
||||
check_insn(ctx, ISA_MIPS32R6);
|
||||
gen_helper_rdhwr_xnp(t0, cpu_env);
|
||||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
case 29:
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
tcg_gen_ld_tl(t0, cpu_env,
|
||||
@ -11979,6 +11996,7 @@ enum {
|
||||
ROTR = 0x3,
|
||||
SELEQZ = 0x5,
|
||||
SELNEZ = 0x6,
|
||||
R6_RDHWR = 0x7,
|
||||
|
||||
SLLV = 0x0,
|
||||
SRLV = 0x1,
|
||||
@ -12009,11 +12027,13 @@ enum {
|
||||
MODU = 0x7,
|
||||
|
||||
/* The following can be distinguished by their lower 6 bits. */
|
||||
BREAK32 = 0x07,
|
||||
INS = 0x0c,
|
||||
LSA = 0x0f,
|
||||
ALIGN = 0x1f,
|
||||
EXT = 0x2c,
|
||||
POOL32AXF = 0x3c
|
||||
POOL32AXF = 0x3c,
|
||||
SIGRIE = 0x3f
|
||||
};
|
||||
|
||||
/* POOL32AXF encoding of minor opcode field extension */
|
||||
@ -12931,7 +12951,8 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs)
|
||||
gen_cl(ctx, mips32_op, rt, rs);
|
||||
break;
|
||||
case RDHWR:
|
||||
gen_rdhwr(ctx, rt, rs);
|
||||
check_insn_opc_removed(ctx, ISA_MIPS32R6);
|
||||
gen_rdhwr(ctx, rt, rs, 0);
|
||||
break;
|
||||
case WSBH:
|
||||
gen_bshfl(ctx, OPC_WSBH, rs, rt);
|
||||
@ -13486,6 +13507,10 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
|
||||
check_insn(ctx, ISA_MIPS32R6);
|
||||
gen_cond_move(ctx, OPC_SELNEZ, rd, rs, rt);
|
||||
break;
|
||||
case R6_RDHWR:
|
||||
check_insn(ctx, ISA_MIPS32R6);
|
||||
gen_rdhwr(ctx, rt, rs, extract32(ctx->opcode, 11, 3));
|
||||
break;
|
||||
default:
|
||||
goto pool32a_invalid;
|
||||
}
|
||||
@ -13629,9 +13654,13 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
|
||||
case POOL32AXF:
|
||||
gen_pool32axf(env, ctx, rt, rs);
|
||||
break;
|
||||
case 0x07:
|
||||
case BREAK32:
|
||||
generate_exception_end(ctx, EXCP_BREAK);
|
||||
break;
|
||||
case SIGRIE:
|
||||
check_insn(ctx, ISA_MIPS32R6);
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
break;
|
||||
default:
|
||||
pool32a_invalid:
|
||||
MIPS_INVAL("pool32a");
|
||||
@ -17732,7 +17761,7 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
|
||||
break;
|
||||
#endif
|
||||
case OPC_RDHWR:
|
||||
gen_rdhwr(ctx, rt, rd);
|
||||
gen_rdhwr(ctx, rt, rd, extract32(ctx->opcode, 6, 3));
|
||||
break;
|
||||
case OPC_FORK:
|
||||
check_insn(ctx, ASE_MT);
|
||||
@ -18950,6 +18979,10 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
|
||||
check_insn_opc_removed(ctx, ISA_MIPS32R6);
|
||||
gen_trap(ctx, op1, rs, -1, imm);
|
||||
break;
|
||||
case OPC_SIGRIE:
|
||||
check_insn(ctx, ISA_MIPS32R6);
|
||||
generate_exception_end(ctx, EXCP_RI);
|
||||
break;
|
||||
case OPC_SYNCI:
|
||||
check_insn(ctx, ISA_MIPS32R2);
|
||||
/* Break the TB to be able to sync copied instructions
|
||||
|
@ -447,7 +447,7 @@ static const mips_def_t mips_defs[] =
|
||||
(1 << CP0C3_RXI) | (1U << CP0C3_M),
|
||||
.CP0_Config4 = MIPS_CONFIG4 | (0xfc << CP0C4_KScrExist) |
|
||||
(3 << CP0C4_IE) | (1U << CP0C4_M),
|
||||
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_LLB),
|
||||
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_XNP) | (1 << CP0C5_LLB),
|
||||
.CP0_Config5_rw_bitmask = (1 << CP0C5_SBRI) | (1 << CP0C5_FRE) |
|
||||
(1 << CP0C5_UFE),
|
||||
.CP0_LLAddr_rw_bitmask = 0,
|
||||
@ -665,7 +665,7 @@ static const mips_def_t mips_defs[] =
|
||||
(1 << CP0C3_RXI) | (1 << CP0C3_LPA),
|
||||
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (3 << CP0C4_IE) |
|
||||
(0xfc << CP0C4_KScrExist),
|
||||
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_LLB),
|
||||
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_XNP) | (1 << CP0C5_LLB),
|
||||
.CP0_Config5_rw_bitmask = (1 << CP0C5_MSAEn) | (1 << CP0C5_SBRI) |
|
||||
(1 << CP0C5_FRE) | (1 << CP0C5_UFE),
|
||||
.CP0_LLAddr_rw_bitmask = 0,
|
||||
|
Loading…
Reference in New Issue
Block a user