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()) {
/* 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;
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. */

View File

@ -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);
}

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));
#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;

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_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)

View File

@ -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)

View File

@ -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

View File

@ -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,