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:
Peter Maydell 2015-10-30 16:30:25 +00:00
commit e79ea9e424
8 changed files with 112 additions and 59 deletions

View File

@ -901,7 +901,7 @@ static void main_cpu_reset(void *opaque)
if (kvm_enabled()) { if (kvm_enabled()) {
/* Start running from the bootloader we wrote to end of RAM */ /* 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;
} }
} }

View File

@ -53,12 +53,15 @@ static bool mips_cpu_has_work(CPUState *cs)
CPUMIPSState *env = &cpu->env; CPUMIPSState *env = &cpu->env;
bool has_work = false; bool has_work = false;
/* It is implementation dependent if non-enabled interrupts /* Prior to MIPS Release 6 it is implementation dependent if non-enabled
wake-up the CPU, however most of the implementations only interrupts wake-up the CPU, however most of the implementations only
check for interrupts that can be taken. */ check for interrupts that can be taken. */
if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && if ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
cpu_mips_hw_interrupts_pending(env)) { 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. */ /* MIPS-MT has the ability to halt the CPU. */

View File

@ -469,6 +469,7 @@ struct CPUMIPSState {
#define CP0C5_CV 29 #define CP0C5_CV 29
#define CP0C5_EVA 28 #define CP0C5_EVA 28
#define CP0C5_MSAEn 27 #define CP0C5_MSAEn 27
#define CP0C5_XNP 13
#define CP0C5_UFE 9 #define CP0C5_UFE 9
#define CP0C5_FRE 8 #define CP0C5_FRE 8
#define CP0C5_SBRI 6 #define CP0C5_SBRI 6
@ -637,23 +638,24 @@ static inline int cpu_mmu_index (CPUMIPSState *env, bool ifetch)
return env->hflags & MIPS_HFLAG_KSU; 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; return (env->CP0_Status & (1 << CP0St_IE)) &&
int32_t status; !(env->CP0_Status & (1 << CP0St_EXL)) &&
int r; !(env->CP0_Status & (1 << CP0St_ERL)) &&
!(env->hflags & MIPS_HFLAG_DM) &&
if (!(env->CP0_Status & (1 << CP0St_IE)) ||
(env->CP0_Status & (1 << CP0St_EXL)) ||
(env->CP0_Status & (1 << CP0St_ERL)) ||
/* Note that the TCStatus IXMT field is initialized to zero, /* Note that the TCStatus IXMT field is initialized to zero,
and only MT capable cores can set it to one. So we don't and only MT capable cores can set it to one. So we don't
need to check for MT capabilities here. */ need to check for MT capabilities here. */
(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_IXMT)) || !(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_IXMT));
(env->hflags & MIPS_HFLAG_DM)) { }
/* Interrupts are disabled */
return 0; /* 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; pending = env->CP0_Cause & CP0Ca_IP_mask;
status = env->CP0_Status & 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) /* A MIPS configured with compatibility or VInt (Vectored Interrupts)
treats the pending lines as individual interrupt lines, the status treats the pending lines as individual interrupt lines, the status
lines are individual masks. */ lines are individual masks. */
r = pending & status; r = (pending & status) != 0;
} }
return r; return r;
} }
@ -1000,7 +1002,12 @@ static inline void cpu_mips_store_status(CPUMIPSState *env, target_ulong val)
if (env->insn_flags & ISA_MIPS32R6) { if (env->insn_flags & ISA_MIPS32R6) {
bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3; 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) { if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) {
mask &= ~(3 << CP0St_KSU); mask &= ~(3 << CP0St_KSU);
} }

View File

@ -293,9 +293,10 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
(env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1)); (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
#if defined(TARGET_MIPS64) #if defined(TARGET_MIPS64)
env->CP0_EntryHi &= env->SEGMask; env->CP0_EntryHi &= env->SEGMask;
env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) | env->CP0_XContext =
((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) | /* PTEBase */ (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9); /* R */ (extract64(address, 62, 2) << (env->SEGBITS - 9)) |
/* BadVPN2 */ (extract64(address, 13, env->SEGBITS - 13) << 4);
#endif #endif
cs->exception_index = exception; cs->exception_index = exception;
env->error_code = error_code; env->error_code = error_code;
@ -759,7 +760,8 @@ bool mips_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
MIPSCPU *cpu = MIPS_CPU(cs); MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env; 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 */ /* Raise it */
cs->exception_index = EXCP_EXT_INTERRUPT; cs->exception_index = EXCP_EXT_INTERRUPT;
env->error_code = 0; env->error_code = 0;

View File

@ -358,6 +358,8 @@ DEF_HELPER_1(rdhwr_cpunum, tl, env)
DEF_HELPER_1(rdhwr_synci_step, tl, env) DEF_HELPER_1(rdhwr_synci_step, tl, env)
DEF_HELPER_1(rdhwr_cc, tl, env) DEF_HELPER_1(rdhwr_cc, tl, env)
DEF_HELPER_1(rdhwr_ccres, 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_2(pmon, void, env, int)
DEF_HELPER_1(wait, void, env) DEF_HELPER_1(wait, void, env)

View File

@ -1357,6 +1357,13 @@ void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
{ {
uint32_t mask = 0x0000000F; 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)) { if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
mask |= (1 << 29); mask |= (1 << 29);
@ -2185,53 +2192,52 @@ void helper_deret(CPUMIPSState *env)
} }
#endif /* !CONFIG_USER_ONLY */ #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) target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
{ {
if ((env->hflags & MIPS_HFLAG_CP0) || check_hwrena(env, 0);
(env->CP0_HWREna & (1 << 0))) return env->CP0_EBase & 0x3ff;
return env->CP0_EBase & 0x3ff;
else
do_raise_exception(env, EXCP_RI, GETPC());
return 0;
} }
target_ulong helper_rdhwr_synci_step(CPUMIPSState *env) target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
{ {
if ((env->hflags & MIPS_HFLAG_CP0) || check_hwrena(env, 1);
(env->CP0_HWREna & (1 << 1))) return env->SYNCI_Step;
return env->SYNCI_Step;
else
do_raise_exception(env, EXCP_RI, GETPC());
return 0;
} }
target_ulong helper_rdhwr_cc(CPUMIPSState *env) target_ulong helper_rdhwr_cc(CPUMIPSState *env)
{ {
if ((env->hflags & MIPS_HFLAG_CP0) || check_hwrena(env, 2);
(env->CP0_HWREna & (1 << 2))) {
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
return env->CP0_Count; return env->CP0_Count;
#else #else
return (int32_t)cpu_mips_get_count(env); return (int32_t)cpu_mips_get_count(env);
#endif #endif
} else {
do_raise_exception(env, EXCP_RI, GETPC());
}
return 0;
} }
target_ulong helper_rdhwr_ccres(CPUMIPSState *env) target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
{ {
if ((env->hflags & MIPS_HFLAG_CP0) || check_hwrena(env, 3);
(env->CP0_HWREna & (1 << 3))) return env->CCRes;
return env->CCRes; }
else
do_raise_exception(env, EXCP_RI, GETPC());
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) void helper_pmon(CPUMIPSState *env, int function)

View File

@ -323,6 +323,7 @@ enum {
OPC_TLTIU = (0x0B << 16) | OPC_REGIMM, OPC_TLTIU = (0x0B << 16) | OPC_REGIMM,
OPC_TEQI = (0x0C << 16) | OPC_REGIMM, OPC_TEQI = (0x0C << 16) | OPC_REGIMM,
OPC_TNEI = (0x0E << 16) | OPC_REGIMM, OPC_TNEI = (0x0E << 16) | OPC_REGIMM,
OPC_SIGRIE = (0x17 << 16) | OPC_REGIMM,
OPC_SYNCI = (0x1F << 16) | OPC_REGIMM, OPC_SYNCI = (0x1F << 16) | OPC_REGIMM,
OPC_DAHI = (0x06 << 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; TCGv t0;
@ -10361,6 +10362,22 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd)
gen_helper_rdhwr_ccres(t0, cpu_env); gen_helper_rdhwr_ccres(t0, cpu_env);
gen_store_gpr(t0, rt); gen_store_gpr(t0, rt);
break; 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: case 29:
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
tcg_gen_ld_tl(t0, cpu_env, tcg_gen_ld_tl(t0, cpu_env,
@ -11979,6 +11996,7 @@ enum {
ROTR = 0x3, ROTR = 0x3,
SELEQZ = 0x5, SELEQZ = 0x5,
SELNEZ = 0x6, SELNEZ = 0x6,
R6_RDHWR = 0x7,
SLLV = 0x0, SLLV = 0x0,
SRLV = 0x1, SRLV = 0x1,
@ -12009,11 +12027,13 @@ enum {
MODU = 0x7, MODU = 0x7,
/* The following can be distinguished by their lower 6 bits. */ /* The following can be distinguished by their lower 6 bits. */
BREAK32 = 0x07,
INS = 0x0c, INS = 0x0c,
LSA = 0x0f, LSA = 0x0f,
ALIGN = 0x1f, ALIGN = 0x1f,
EXT = 0x2c, EXT = 0x2c,
POOL32AXF = 0x3c POOL32AXF = 0x3c,
SIGRIE = 0x3f
}; };
/* POOL32AXF encoding of minor opcode field extension */ /* 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); gen_cl(ctx, mips32_op, rt, rs);
break; break;
case RDHWR: case RDHWR:
gen_rdhwr(ctx, rt, rs); check_insn_opc_removed(ctx, ISA_MIPS32R6);
gen_rdhwr(ctx, rt, rs, 0);
break; break;
case WSBH: case WSBH:
gen_bshfl(ctx, OPC_WSBH, rs, rt); 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); check_insn(ctx, ISA_MIPS32R6);
gen_cond_move(ctx, OPC_SELNEZ, rd, rs, rt); gen_cond_move(ctx, OPC_SELNEZ, rd, rs, rt);
break; break;
case R6_RDHWR:
check_insn(ctx, ISA_MIPS32R6);
gen_rdhwr(ctx, rt, rs, extract32(ctx->opcode, 11, 3));
break;
default: default:
goto pool32a_invalid; goto pool32a_invalid;
} }
@ -13629,9 +13654,13 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
case POOL32AXF: case POOL32AXF:
gen_pool32axf(env, ctx, rt, rs); gen_pool32axf(env, ctx, rt, rs);
break; break;
case 0x07: case BREAK32:
generate_exception_end(ctx, EXCP_BREAK); generate_exception_end(ctx, EXCP_BREAK);
break; break;
case SIGRIE:
check_insn(ctx, ISA_MIPS32R6);
generate_exception_end(ctx, EXCP_RI);
break;
default: default:
pool32a_invalid: pool32a_invalid:
MIPS_INVAL("pool32a"); MIPS_INVAL("pool32a");
@ -17732,7 +17761,7 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
break; break;
#endif #endif
case OPC_RDHWR: case OPC_RDHWR:
gen_rdhwr(ctx, rt, rd); gen_rdhwr(ctx, rt, rd, extract32(ctx->opcode, 6, 3));
break; break;
case OPC_FORK: case OPC_FORK:
check_insn(ctx, ASE_MT); check_insn(ctx, ASE_MT);
@ -18950,6 +18979,10 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
check_insn_opc_removed(ctx, ISA_MIPS32R6); check_insn_opc_removed(ctx, ISA_MIPS32R6);
gen_trap(ctx, op1, rs, -1, imm); gen_trap(ctx, op1, rs, -1, imm);
break; break;
case OPC_SIGRIE:
check_insn(ctx, ISA_MIPS32R6);
generate_exception_end(ctx, EXCP_RI);
break;
case OPC_SYNCI: case OPC_SYNCI:
check_insn(ctx, ISA_MIPS32R2); check_insn(ctx, ISA_MIPS32R2);
/* Break the TB to be able to sync copied instructions /* Break the TB to be able to sync copied instructions

View File

@ -447,7 +447,7 @@ static const mips_def_t mips_defs[] =
(1 << CP0C3_RXI) | (1U << CP0C3_M), (1 << CP0C3_RXI) | (1U << CP0C3_M),
.CP0_Config4 = MIPS_CONFIG4 | (0xfc << CP0C4_KScrExist) | .CP0_Config4 = MIPS_CONFIG4 | (0xfc << CP0C4_KScrExist) |
(3 << CP0C4_IE) | (1U << CP0C4_M), (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) | .CP0_Config5_rw_bitmask = (1 << CP0C5_SBRI) | (1 << CP0C5_FRE) |
(1 << CP0C5_UFE), (1 << CP0C5_UFE),
.CP0_LLAddr_rw_bitmask = 0, .CP0_LLAddr_rw_bitmask = 0,
@ -665,7 +665,7 @@ static const mips_def_t mips_defs[] =
(1 << CP0C3_RXI) | (1 << CP0C3_LPA), (1 << CP0C3_RXI) | (1 << CP0C3_LPA),
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (3 << CP0C4_IE) | .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (3 << CP0C4_IE) |
(0xfc << CP0C4_KScrExist), (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) | .CP0_Config5_rw_bitmask = (1 << CP0C5_MSAEn) | (1 << CP0C5_SBRI) |
(1 << CP0C5_FRE) | (1 << CP0C5_UFE), (1 << CP0C5_FRE) | (1 << CP0C5_UFE),
.CP0_LLAddr_rw_bitmask = 0, .CP0_LLAddr_rw_bitmask = 0,