diff options
Diffstat (limited to 'target')
| -rw-r--r-- | target/arm/cpu.c | 7 | ||||
| -rw-r--r-- | target/arm/cpu.h | 62 | ||||
| -rw-r--r-- | target/arm/helper.c | 142 | ||||
| -rw-r--r-- | target/arm/translate-a64.c | 227 | ||||
| -rw-r--r-- | target/mips/Makefile.objs | 2 | ||||
| -rw-r--r-- | target/mips/cp0_timer.c | 165 | ||||
| -rw-r--r-- | target/mips/cpu-qom.h | 1 | ||||
| -rw-r--r-- | target/mips/cpu.c | 54 | ||||
| -rw-r--r-- | target/mips/cpu.h | 357 | ||||
| -rw-r--r-- | target/mips/dsp_helper.c | 56 | ||||
| -rw-r--r-- | target/mips/gdbstub.c | 1 | ||||
| -rw-r--r-- | target/mips/helper.c | 1 | ||||
| -rw-r--r-- | target/mips/internal.h | 422 | ||||
| -rw-r--r-- | target/mips/kvm.c | 1 | ||||
| -rw-r--r-- | target/mips/machine.c | 1 | ||||
| -rw-r--r-- | target/mips/msa_helper.c | 1 | ||||
| -rw-r--r-- | target/mips/op_helper.c | 1 | ||||
| -rw-r--r-- | target/mips/translate.c | 23 | ||||
| -rw-r--r-- | target/mips/translate_init.c | 58 | ||||
| -rw-r--r-- | target/s390x/kvm.c | 9 |
20 files changed, 996 insertions, 595 deletions
diff --git a/target/arm/cpu.c b/target/arm/cpu.c index f61ca660e6..4300de66e2 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -187,6 +187,13 @@ static void arm_cpu_reset(CPUState *s) if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { env->v7m.secure = true; + } else { + /* This bit resets to 0 if security is supported, but 1 if + * it is not. The bit is not present in v7M, but we set it + * here so we can avoid having to make checks on it conditional + * on ARM_FEATURE_V8 (we don't let the guest see the bit). + */ + env->v7m.aircr = R_V7M_AIRCR_BFHFNMINS_MASK; } /* In v7M the reset value of this bit is IMPDEF, but ARM recommends diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 6e50ae2b55..8afceca873 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -449,6 +449,7 @@ typedef struct CPUARMState { int exception; uint32_t primask[M_REG_NUM_BANKS]; uint32_t faultmask[M_REG_NUM_BANKS]; + uint32_t aircr; /* only holds r/w state if security extn implemented */ uint32_t secure; /* Is CPU in Secure state? (not guest visible) */ } v7m; @@ -1200,6 +1201,17 @@ FIELD(V7M_CCR, STKALIGN, 9, 1) FIELD(V7M_CCR, DC, 16, 1) FIELD(V7M_CCR, IC, 17, 1) +/* V7M AIRCR bits */ +FIELD(V7M_AIRCR, VECTRESET, 0, 1) +FIELD(V7M_AIRCR, VECTCLRACTIVE, 1, 1) +FIELD(V7M_AIRCR, SYSRESETREQ, 2, 1) +FIELD(V7M_AIRCR, SYSRESETREQS, 3, 1) +FIELD(V7M_AIRCR, PRIGROUP, 8, 3) +FIELD(V7M_AIRCR, BFHFNMINS, 13, 1) +FIELD(V7M_AIRCR, PRIS, 14, 1) +FIELD(V7M_AIRCR, ENDIANNESS, 15, 1) +FIELD(V7M_AIRCR, VECTKEY, 16, 16) + /* V7M CFSR bits for MMFSR */ FIELD(V7M_CFSR, IACCVIOL, 0, 1) FIELD(V7M_CFSR, DACCVIOL, 1, 1) @@ -1451,19 +1463,42 @@ static inline bool armv7m_nvic_can_take_pending_exception(void *opaque) return true; } #endif -void armv7m_nvic_set_pending(void *opaque, int irq); -void armv7m_nvic_acknowledge_irq(void *opaque); +/** + * armv7m_nvic_set_pending: mark the specified exception as pending + * @opaque: the NVIC + * @irq: the exception number to mark pending + * @secure: false for non-banked exceptions or for the nonsecure + * version of a banked exception, true for the secure version of a banked + * exception. + * + * Marks the specified exception as pending. Note that we will assert() + * if @secure is true and @irq does not specify one of the fixed set + * of architecturally banked exceptions. + */ +void armv7m_nvic_set_pending(void *opaque, int irq, bool secure); +/** + * armv7m_nvic_acknowledge_irq: make highest priority pending exception active + * @opaque: the NVIC + * + * Move the current highest priority pending exception from the pending + * state to the active state, and update v7m.exception to indicate that + * it is the exception currently being handled. + * + * Returns: true if exception should be taken to Secure state, false for NS + */ +bool armv7m_nvic_acknowledge_irq(void *opaque); /** * armv7m_nvic_complete_irq: complete specified interrupt or exception * @opaque: the NVIC * @irq: the exception number to complete + * @secure: true if this exception was secure * * Returns: -1 if the irq was not active * 1 if completing this irq brought us back to base (no active irqs) * 0 if there is still an irq active after this one was completed * (Ignoring -1, this is the same as the RETTOBASE value before completion.) */ -int armv7m_nvic_complete_irq(void *opaque, int irq); +int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure); /** * armv7m_nvic_raw_execution_priority: return the raw execution priority * @opaque: the NVIC @@ -1474,6 +1509,21 @@ int armv7m_nvic_complete_irq(void *opaque, int irq); * (v8M ARM ARM I_PKLD.) */ int armv7m_nvic_raw_execution_priority(void *opaque); +/** + * armv7m_nvic_neg_prio_requested: return true if the requested execution + * priority is negative for the specified security state. + * @opaque: the NVIC + * @secure: the security state to test + * This corresponds to the pseudocode IsReqExecPriNeg(). + */ +#ifndef CONFIG_USER_ONLY +bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure); +#else +static inline bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure) +{ + return false; +} +#endif /* Interface for defining coprocessor registers. * Registers are defined in tables of arm_cp_reginfo structs @@ -2259,11 +2309,7 @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch) if (arm_feature(env, ARM_FEATURE_M)) { ARMMMUIdx mmu_idx = el == 0 ? ARMMMUIdx_MUser : ARMMMUIdx_MPriv; - /* Execution priority is negative if FAULTMASK is set or - * we're in a HardFault or NMI handler. - */ - if ((env->v7m.exception > 0 && env->v7m.exception <= 3) - || env->v7m.faultmask[env->v7m.secure]) { + if (armv7m_nvic_neg_prio_requested(env->nvic, env->v7m.secure)) { mmu_idx = ARMMMUIdx_MNegPri; } diff --git a/target/arm/helper.c b/target/arm/helper.c index 4f41841ef6..8be78ea2f8 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6218,6 +6218,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) bool return_to_sp_process = false; bool return_to_handler = false; bool rettobase = false; + bool exc_secure = false; /* We can only get here from an EXCP_EXCEPTION_EXIT, and * gen_bx_excret() enforces the architectural rule @@ -6256,16 +6257,17 @@ static void do_v7m_exception_exit(ARMCPU *cpu) * which security state's faultmask to clear. (v8M ARM ARM R_KBNF.) */ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - int es = excret & R_V7M_EXCRET_ES_MASK; + exc_secure = excret & R_V7M_EXCRET_ES_MASK; if (armv7m_nvic_raw_execution_priority(env->nvic) >= 0) { - env->v7m.faultmask[es] = 0; + env->v7m.faultmask[exc_secure] = 0; } } else { env->v7m.faultmask[M_REG_NS] = 0; } } - switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception)) { + switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception, + exc_secure)) { case -1: /* attempt to exit an exception that isn't active */ ufault = true; @@ -6306,7 +6308,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) * stack, directly take a usage fault on the current stack. */ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK; - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure); v7m_exception_taken(cpu, excret); qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing " "stackframe: failed exception return integrity check\n"); @@ -6345,8 +6347,11 @@ static void do_v7m_exception_exit(ARMCPU *cpu) * exception return excret specified then this is a UsageFault. */ if (return_to_handler != arm_v7m_is_handler_mode(env)) { - /* Take an INVPC UsageFault by pushing the stack again. */ - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); + /* Take an INVPC UsageFault by pushing the stack again. + * TODO: the v8M version of this code should target the + * background state for this exception. + */ + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false); env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK; v7m_push_stack(cpu); v7m_exception_taken(cpu, excret); @@ -6406,20 +6411,20 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) handle it. */ switch (cs->exception_index) { case EXCP_UDEF: - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure); env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK; break; case EXCP_NOCP: - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure); env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK; break; case EXCP_INVSTATE: - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure); env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK; break; case EXCP_SWI: /* The PC already points to the next instruction. */ - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secure); break; case EXCP_PREFETCH_ABORT: case EXCP_DATA_ABORT: @@ -6443,7 +6448,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) env->v7m.bfar); break; } - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false); break; default: /* All other FSR values are either MPU faults or "can't happen @@ -6463,7 +6468,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) env->v7m.mmfar[env->v7m.secure]); break; } - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, + env->v7m.secure); break; } break; @@ -6480,7 +6486,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) return; } } - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false); break; case EXCP_IRQ: break; @@ -8892,12 +8898,68 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) break; case 20: /* CONTROL */ return env->v7m.control[env->v7m.secure]; + case 0x94: /* CONTROL_NS */ + /* We have to handle this here because unprivileged Secure code + * can read the NS CONTROL register. + */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.control[M_REG_NS]; } if (el == 0) { return 0; /* unprivileged reads others as zero */ } + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + switch (reg) { + case 0x88: /* MSP_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.other_ss_msp; + case 0x89: /* PSP_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.other_ss_psp; + case 0x90: /* PRIMASK_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.primask[M_REG_NS]; + case 0x91: /* BASEPRI_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.basepri[M_REG_NS]; + case 0x93: /* FAULTMASK_NS */ + if (!env->v7m.secure) { + return 0; + } + return env->v7m.faultmask[M_REG_NS]; + case 0x98: /* SP_NS */ + { + /* This gives the non-secure SP selected based on whether we're + * currently in handler mode or not, using the NS CONTROL.SPSEL. + */ + bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK; + + if (!env->v7m.secure) { + return 0; + } + if (!arm_v7m_is_handler_mode(env) && spsel) { + return env->v7m.other_ss_psp; + } else { + return env->v7m.other_ss_msp; + } + } + default: + break; + } + } + switch (reg) { case 8: /* MSP */ return (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) ? @@ -8936,6 +8998,60 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) return; } + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + switch (reg) { + case 0x88: /* MSP_NS */ + if (!env->v7m.secure) { + return; + } + env->v7m.other_ss_msp = val; + return; + case 0x89: /* PSP_NS */ + if (!env->v7m.secure) { + return; + } + env->v7m.other_ss_psp = val; + return; + case 0x90: /* PRIMASK_NS */ + if (!env->v7m.secure) { + return; + } + env->v7m.primask[M_REG_NS] = val & 1; + return; + case 0x91: /* BASEPRI_NS */ + if (!env->v7m.secure) { + return; + } + env->v7m.basepri[M_REG_NS] = val & 0xff; + return; + case 0x93: /* FAULTMASK_NS */ + if (!env->v7m.secure) { + return; + } + env->v7m.faultmask[M_REG_NS] = val & 1; + return; + case 0x98: /* SP_NS */ + { + /* This gives the non-secure SP selected based on whether we're + * currently in handler mode or not, using the NS CONTROL.SPSEL. + */ + bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK; + + if (!env->v7m.secure) { + return; + } + if (!arm_v7m_is_handler_mode(env) && spsel) { + env->v7m.other_ss_psp = val; + } else { + env->v7m.other_ss_msp = val; + } + return; + } + default: + break; + } + } + switch (reg) { case 0 ... 7: /* xPSR sub-fields */ /* only APSR is actually writable */ diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 083568c468..899ffb96fc 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1203,12 +1203,14 @@ static inline AArch64DecodeFn *lookup_disas_fn(const AArch64DecodeTable *table, } /* - * the instruction disassembly implemented here matches - * the instruction encoding classifications in chapter 3 (C3) - * of the ARM Architecture Reference Manual (DDI0487A_a) + * The instruction disassembly implemented here matches + * the instruction encoding classifications in chapter C4 + * of the ARM Architecture Reference Manual (DDI0487B_a); + * classification names and decode diagrams here should generally + * match up with those in the manual. */ -/* C3.2.7 Unconditional branch (immediate) +/* Unconditional branch (immediate) * 31 30 26 25 0 * +----+-----------+-------------------------------------+ * | op | 0 0 1 0 1 | imm26 | @@ -1219,15 +1221,15 @@ static void disas_uncond_b_imm(DisasContext *s, uint32_t insn) uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4; if (insn & (1U << 31)) { - /* C5.6.26 BL Branch with link */ + /* BL Branch with link */ tcg_gen_movi_i64(cpu_reg(s, 30), s->pc); } - /* C5.6.20 B Branch / C5.6.26 BL Branch with link */ + /* B Branch / BL Branch with link */ gen_goto_tb(s, 0, addr); } -/* C3.2.1 Compare & branch (immediate) +/* Compare and branch (immediate) * 31 30 25 24 23 5 4 0 * +----+-------------+----+---------------------+--------+ * | sf | 0 1 1 0 1 0 | op | imm19 | Rt | @@ -1256,7 +1258,7 @@ static void disas_comp_b_imm(DisasContext *s, uint32_t insn) gen_goto_tb(s, 1, addr); } -/* C3.2.5 Test & branch (immediate) +/* Test and branch (immediate) * 31 30 25 24 23 19 18 5 4 0 * +----+-------------+----+-------+-------------+------+ * | b5 | 0 1 1 0 1 1 | op | b40 | imm14 | Rt | @@ -1285,7 +1287,7 @@ static void disas_test_b_imm(DisasContext *s, uint32_t insn) gen_goto_tb(s, 1, addr); } -/* C3.2.2 / C5.6.19 Conditional branch (immediate) +/* Conditional branch (immediate) * 31 25 24 23 5 4 3 0 * +---------------+----+---------------------+----+------+ * | 0 1 0 1 0 1 0 | o1 | imm19 | o0 | cond | @@ -1316,7 +1318,7 @@ static void disas_cond_b_imm(DisasContext *s, uint32_t insn) } } -/* C5.6.68 HINT */ +/* HINT instruction group, including various allocated HINTs */ static void handle_hint(DisasContext *s, uint32_t insn, unsigned int op1, unsigned int op2, unsigned int crm) { @@ -1401,7 +1403,7 @@ static void handle_sync(DisasContext *s, uint32_t insn, } } -/* C5.6.130 MSR (immediate) - move immediate to processor state field */ +/* MSR (immediate) - move immediate to processor state field */ static void handle_msr_i(DisasContext *s, uint32_t insn, unsigned int op1, unsigned int op2, unsigned int crm) { @@ -1477,10 +1479,10 @@ static void gen_set_nzcv(TCGv_i64 tcg_rt) tcg_temp_free_i32(nzcv); } -/* C5.6.129 MRS - move from system register - * C5.6.131 MSR (register) - move to system register - * C5.6.204 SYS - * C5.6.205 SYSL +/* MRS - move from system register + * MSR (register) - move to system register + * SYS + * SYSL * These are all essentially the same insn in 'read' and 'write' * versions, with varying op0 fields. */ @@ -1603,7 +1605,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, } } -/* C3.2.4 System +/* System * 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0 * +---------------------+---+-----+-----+-------+-------+-----+------+ * | 1 1 0 1 0 1 0 1 0 0 | L | op0 | op1 | CRn | CRm | op2 | Rt | @@ -1626,13 +1628,13 @@ static void disas_system(DisasContext *s, uint32_t insn) return; } switch (crn) { - case 2: /* C5.6.68 HINT */ + case 2: /* HINT (including allocated hints like NOP, YIELD, etc) */ handle_hint(s, insn, op1, op2, crm); break; case 3: /* CLREX, DSB, DMB, ISB */ handle_sync(s, insn, op1, op2, crm); break; - case 4: /* C5.6.130 MSR (immediate) */ + case 4: /* MSR (immediate) */ handle_msr_i(s, insn, op1, op2, crm); break; default: @@ -1644,7 +1646,7 @@ static void disas_system(DisasContext *s, uint32_t insn) handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt); } -/* C3.2.3 Exception generation +/* Exception generation * * 31 24 23 21 20 5 4 2 1 0 * +-----------------+-----+------------------------+-----+----+ @@ -1751,7 +1753,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) } } -/* C3.2.7 Unconditional branch (register) +/* Unconditional branch (register) * 31 25 24 21 20 16 15 10 9 5 4 0 * +---------------+-------+-------+-------+------+-------+ * | 1 1 0 1 0 1 1 | opc | op2 | op3 | Rn | op4 | @@ -1806,7 +1808,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn) s->base.is_jmp = DISAS_JUMP; } -/* C3.2 Branches, exception generating and system instructions */ +/* Branches, exception generating and system instructions */ static void disas_b_exc_sys(DisasContext *s, uint32_t insn) { switch (extract32(insn, 25, 7)) { @@ -1966,7 +1968,7 @@ static bool disas_ldst_compute_iss_sf(int size, bool is_signed, int opc) return regsize == 64; } -/* C3.3.6 Load/store exclusive +/* Load/store exclusive * * 31 30 29 24 23 22 21 20 16 15 14 10 9 5 4 0 * +-----+-------------+----+---+----+------+----+-------+------+------+ @@ -2043,7 +2045,7 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) } /* - * C3.3.5 Load register (literal) + * Load register (literal) * * 31 30 29 27 26 25 24 23 5 4 0 * +-----+-------+---+-----+-------------------+-------+ @@ -2099,15 +2101,15 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn) } /* - * C5.6.80 LDNP (Load Pair - non-temporal hint) - * C5.6.81 LDP (Load Pair - non vector) - * C5.6.82 LDPSW (Load Pair Signed Word - non vector) - * C5.6.176 STNP (Store Pair - non-temporal hint) - * C5.6.177 STP (Store Pair - non vector) - * C6.3.165 LDNP (Load Pair of SIMD&FP - non-temporal hint) - * C6.3.165 LDP (Load Pair of SIMD&FP) - * C6.3.284 STNP (Store Pair of SIMD&FP - non-temporal hint) - * C6.3.284 STP (Store Pair of SIMD&FP) + * LDNP (Load Pair - non-temporal hint) + * LDP (Load Pair - non vector) + * LDPSW (Load Pair Signed Word - non vector) + * STNP (Store Pair - non-temporal hint) + * STP (Store Pair - non vector) + * LDNP (Load Pair of SIMD&FP - non-temporal hint) + * LDP (Load Pair of SIMD&FP) + * STNP (Store Pair of SIMD&FP - non-temporal hint) + * STP (Store Pair of SIMD&FP) * * 31 30 29 27 26 25 24 23 22 21 15 14 10 9 5 4 0 * +-----+-------+---+---+-------+---+-----------------------------+ @@ -2253,9 +2255,9 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) } /* - * C3.3.8 Load/store (immediate post-indexed) - * C3.3.9 Load/store (immediate pre-indexed) - * C3.3.12 Load/store (unscaled immediate) + * Load/store (immediate post-indexed) + * Load/store (immediate pre-indexed) + * Load/store (unscaled immediate) * * 31 30 29 27 26 25 24 23 22 21 20 12 11 10 9 5 4 0 * +----+-------+---+-----+-----+---+--------+-----+------+------+ @@ -2371,7 +2373,7 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, } /* - * C3.3.10 Load/store (register offset) + * Load/store (register offset) * * 31 30 29 27 26 25 24 23 22 21 20 16 15 13 12 11 10 9 5 4 0 * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+ @@ -2468,7 +2470,7 @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn, } /* - * C3.3.13 Load/store (unsigned immediate) + * Load/store (unsigned immediate) * * 31 30 29 27 26 25 24 23 22 21 10 9 5 * +----+-------+---+-----+-----+------------+-------+------+ @@ -2579,14 +2581,14 @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn) } } -/* C3.3.1 AdvSIMD load/store multiple structures +/* AdvSIMD load/store multiple structures * * 31 30 29 23 22 21 16 15 12 11 10 9 5 4 0 * +---+---+---------------+---+-------------+--------+------+------+------+ * | 0 | Q | 0 0 1 1 0 0 0 | L | 0 0 0 0 0 0 | opcode | size | Rn | Rt | * +---+---+---------------+---+-------------+--------+------+------+------+ * - * C3.3.2 AdvSIMD load/store multiple structures (post-indexed) + * AdvSIMD load/store multiple structures (post-indexed) * * 31 30 29 23 22 21 20 16 15 12 11 10 9 5 4 0 * +---+---+---------------+---+---+---------+--------+------+------+------+ @@ -2711,14 +2713,14 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_addr); } -/* C3.3.3 AdvSIMD load/store single structure +/* AdvSIMD load/store single structure * * 31 30 29 23 22 21 20 16 15 13 12 11 10 9 5 4 0 * +---+---+---------------+-----+-----------+-----+---+------+------+------+ * | 0 | Q | 0 0 1 1 0 1 0 | L R | 0 0 0 0 0 | opc | S | size | Rn | Rt | * +---+---+---------------+-----+-----------+-----+---+------+------+------+ * - * C3.3.4 AdvSIMD load/store single structure (post-indexed) + * AdvSIMD load/store single structure (post-indexed) * * 31 30 29 23 22 21 20 16 15 13 12 11 10 9 5 4 0 * +---+---+---------------+-----+-----------+-----+---+------+------+------+ @@ -2861,7 +2863,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_addr); } -/* C3.3 Loads and stores */ +/* Loads and stores */ static void disas_ldst(DisasContext *s, uint32_t insn) { switch (extract32(insn, 24, 6)) { @@ -2891,7 +2893,7 @@ static void disas_ldst(DisasContext *s, uint32_t insn) } } -/* C3.4.6 PC-rel. addressing +/* PC-rel. addressing * 31 30 29 28 24 23 5 4 0 * +----+-------+-----------+-------------------+------+ * | op | immlo | 1 0 0 0 0 | immhi | Rd | @@ -2920,7 +2922,7 @@ static void disas_pc_rel_adr(DisasContext *s, uint32_t insn) } /* - * C3.4.1 Add/subtract (immediate) + * Add/subtract (immediate) * * 31 30 29 28 24 23 22 21 10 9 5 4 0 * +--+--+--+-----------+-----+-------------+-----+-----+ @@ -3070,7 +3072,7 @@ static bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn, return true; } -/* C3.4.4 Logical (immediate) +/* Logical (immediate) * 31 30 29 28 23 22 21 16 15 10 9 5 4 0 * +----+-----+-------------+---+------+------+------+------+ * | sf | opc | 1 0 0 1 0 0 | N | immr | imms | Rn | Rd | @@ -3143,7 +3145,7 @@ static void disas_logic_imm(DisasContext *s, uint32_t insn) } /* - * C3.4.5 Move wide (immediate) + * Move wide (immediate) * * 31 30 29 28 23 22 21 20 5 4 0 * +--+-----+-------------+-----+----------------+------+ @@ -3195,7 +3197,7 @@ static void disas_movw_imm(DisasContext *s, uint32_t insn) } } -/* C3.4.2 Bitfield +/* Bitfield * 31 30 29 28 23 22 21 16 15 10 9 5 4 0 * +----+-----+-------------+---+------+------+------+------+ * | sf | opc | 1 0 0 1 1 0 | N | immr | imms | Rn | Rd | @@ -3273,7 +3275,7 @@ static void disas_bitfield(DisasContext *s, uint32_t insn) } } -/* C3.4.3 Extract +/* Extract * 31 30 29 28 23 22 21 20 16 15 10 9 5 4 0 * +----+------+-------------+---+----+------+--------+------+------+ * | sf | op21 | 1 0 0 1 1 1 | N | o0 | Rm | imms | Rn | Rd | @@ -3333,7 +3335,7 @@ static void disas_extract(DisasContext *s, uint32_t insn) } } -/* C3.4 Data processing - immediate */ +/* Data processing - immediate */ static void disas_data_proc_imm(DisasContext *s, uint32_t insn) { switch (extract32(insn, 23, 6)) { @@ -3427,7 +3429,7 @@ static void shift_reg_imm(TCGv_i64 dst, TCGv_i64 src, int sf, } } -/* C3.5.10 Logical (shifted register) +/* Logical (shifted register) * 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0 * +----+-----+-----------+-------+---+------+--------+------+------+ * | sf | opc | 0 1 0 1 0 | shift | N | Rm | imm6 | Rn | Rd | @@ -3518,7 +3520,7 @@ static void disas_logic_reg(DisasContext *s, uint32_t insn) } /* - * C3.5.1 Add/subtract (extended register) + * Add/subtract (extended register) * * 31|30|29|28 24|23 22|21|20 16|15 13|12 10|9 5|4 0| * +--+--+--+-----------+-----+--+-------+------+------+----+----+ @@ -3591,7 +3593,7 @@ static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn) } /* - * C3.5.2 Add/subtract (shifted register) + * Add/subtract (shifted register) * * 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0 * +--+--+--+-----------+-----+--+-------+---------+------+------+ @@ -3654,13 +3656,12 @@ static void disas_add_sub_reg(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_result); } -/* C3.5.9 Data-processing (3 source) - - 31 30 29 28 24 23 21 20 16 15 14 10 9 5 4 0 - +--+------+-----------+------+------+----+------+------+------+ - |sf| op54 | 1 1 0 1 1 | op31 | Rm | o0 | Ra | Rn | Rd | - +--+------+-----------+------+------+----+------+------+------+ - +/* Data-processing (3 source) + * + * 31 30 29 28 24 23 21 20 16 15 14 10 9 5 4 0 + * +--+------+-----------+------+------+----+------+------+------+ + * |sf| op54 | 1 1 0 1 1 | op31 | Rm | o0 | Ra | Rn | Rd | + * +--+------+-----------+------+------+----+------+------+------+ */ static void disas_data_proc_3src(DisasContext *s, uint32_t insn) { @@ -3753,7 +3754,7 @@ static void disas_data_proc_3src(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_tmp); } -/* C3.5.3 - Add/subtract (with carry) +/* Add/subtract (with carry) * 31 30 29 28 27 26 25 24 23 22 21 20 16 15 10 9 5 4 0 * +--+--+--+------------------------+------+---------+------+-----+ * |sf|op| S| 1 1 0 1 0 0 0 0 | rm | opcode2 | Rn | Rd | @@ -3795,7 +3796,7 @@ static void disas_adc_sbc(DisasContext *s, uint32_t insn) } } -/* C3.5.4 - C3.5.5 Conditional compare (immediate / register) +/* Conditional compare (immediate / register) * 31 30 29 28 27 26 25 24 23 22 21 20 16 15 12 11 10 9 5 4 3 0 * +--+--+--+------------------------+--------+------+----+--+------+--+-----+ * |sf|op| S| 1 1 0 1 0 0 1 0 |imm5/rm | cond |i/r |o2| Rn |o3|nzcv | @@ -3900,7 +3901,7 @@ static void disas_cc(DisasContext *s, uint32_t insn) tcg_temp_free_i32(tcg_t2); } -/* C3.5.6 Conditional select +/* Conditional select * 31 30 29 28 21 20 16 15 12 11 10 9 5 4 0 * +----+----+---+-----------------+------+------+-----+------+------+ * | sf | op | S | 1 1 0 1 0 1 0 0 | Rm | cond | op2 | Rn | Rd | @@ -4011,7 +4012,7 @@ static void handle_rbit(DisasContext *s, unsigned int sf, } } -/* C5.6.149 REV with sf==1, opcode==3 ("REV64") */ +/* REV with sf==1, opcode==3 ("REV64") */ static void handle_rev64(DisasContext *s, unsigned int sf, unsigned int rn, unsigned int rd) { @@ -4022,8 +4023,8 @@ static void handle_rev64(DisasContext *s, unsigned int sf, tcg_gen_bswap64_i64(cpu_reg(s, rd), cpu_reg(s, rn)); } -/* C5.6.149 REV with sf==0, opcode==2 - * C5.6.151 REV32 (sf==1, opcode==2) +/* REV with sf==0, opcode==2 + * REV32 (sf==1, opcode==2) */ static void handle_rev32(DisasContext *s, unsigned int sf, unsigned int rn, unsigned int rd) @@ -4048,7 +4049,7 @@ static void handle_rev32(DisasContext *s, unsigned int sf, } } -/* C5.6.150 REV16 (opcode==1) */ +/* REV16 (opcode==1) */ static void handle_rev16(DisasContext *s, unsigned int sf, unsigned int rn, unsigned int rd) { @@ -4067,7 +4068,7 @@ static void handle_rev16(DisasContext *s, unsigned int sf, tcg_temp_free_i64(tcg_tmp); } -/* C3.5.7 Data-processing (1 source) +/* Data-processing (1 source) * 31 30 29 28 21 20 16 15 10 9 5 4 0 * +----+---+---+-----------------+---------+--------+------+------+ * | sf | 1 | S | 1 1 0 1 0 1 1 0 | opcode2 | opcode | Rn | Rd | @@ -4136,7 +4137,7 @@ static void handle_div(DisasContext *s, bool is_signed, unsigned int sf, } } -/* C5.6.115 LSLV, C5.6.118 LSRV, C5.6.17 ASRV, C5.6.154 RORV */ +/* LSLV, LSRV, ASRV, RORV */ static void handle_shift_reg(DisasContext *s, enum a64_shift_type shift_type, unsigned int sf, unsigned int rm, unsigned int rn, unsigned int rd) @@ -4198,7 +4199,7 @@ static void handle_crc32(DisasContext *s, tcg_temp_free_i32(tcg_bytes); } -/* C3.5.8 Data-processing (2 source) +/* Data-processing (2 source) * 31 30 29 28 21 20 16 15 10 9 5 4 0 * +----+---+---+-----------------+------+--------+------+------+ * | sf | 0 | S | 1 1 0 1 0 1 1 0 | Rm | opcode | Rn | Rd | @@ -4257,7 +4258,7 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn) } } -/* C3.5 Data processing - register */ +/* Data processing - register */ static void disas_data_proc_reg(DisasContext *s, uint32_t insn) { switch (extract32(insn, 24, 5)) { @@ -4351,7 +4352,7 @@ static void handle_fp_compare(DisasContext *s, bool is_double, tcg_temp_free_i64(tcg_flags); } -/* C3.6.22 Floating point compare +/* Floating point compare * 31 30 29 28 24 23 22 21 20 16 15 14 13 10 9 5 4 0 * +---+---+---+-----------+------+---+------+-----+---------+------+-------+ * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | op | 1 0 0 0 | Rn | op2 | @@ -4381,7 +4382,7 @@ static void disas_fp_compare(DisasContext *s, uint32_t insn) handle_fp_compare(s, type, rn, rm, opc & 1, opc & 2); } -/* C3.6.23 Floating point conditional compare +/* Floating point conditional compare * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 3 0 * +---+---+---+-----------+------+---+------+------+-----+------+----+------+ * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | cond | 0 1 | Rn | op | nzcv | @@ -4429,7 +4430,7 @@ static void disas_fp_ccomp(DisasContext *s, uint32_t insn) } } -/* C3.6.24 Floating point conditional select +/* Floating point conditional select * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0 * +---+---+---+-----------+------+---+------+------+-----+------+------+ * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | cond | 1 1 | Rn | Rd | @@ -4476,7 +4477,7 @@ static void disas_fp_csel(DisasContext *s, uint32_t insn) tcg_temp_free_i64(t_true); } -/* C3.6.25 Floating-point data-processing (1 source) - single precision */ +/* Floating-point data-processing (1 source) - single precision */ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn) { TCGv_ptr fpst; @@ -4532,7 +4533,7 @@ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn) tcg_temp_free_i32(tcg_res); } -/* C3.6.25 Floating-point data-processing (1 source) - double precision */ +/* Floating-point data-processing (1 source) - double precision */ static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn) { TCGv_ptr fpst; @@ -4654,7 +4655,7 @@ static void handle_fp_fcvt(DisasContext *s, int opcode, } } -/* C3.6.25 Floating point data-processing (1 source) +/* Floating point data-processing (1 source) * 31 30 29 28 24 23 22 21 20 15 14 10 9 5 4 0 * +---+---+---+-----------+------+---+--------+-----------+------+------+ * | M | 0 | S | 1 1 1 1 0 | type | 1 | opcode | 1 0 0 0 0 | Rn | Rd | @@ -4712,7 +4713,7 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn) } } -/* C3.6.26 Floating-point data-processing (2 source) - single precision */ +/* Floating-point data-processing (2 source) - single precision */ static void handle_fp_2src_single(DisasContext *s, int opcode, int rd, int rn, int rm) { @@ -4765,7 +4766,7 @@ static void handle_fp_2src_single(DisasContext *s, int opcode, tcg_temp_free_i32(tcg_res); } -/* C3.6.26 Floating-point data-processing (2 source) - double precision */ +/* Floating-point data-processing (2 source) - double precision */ static void handle_fp_2src_double(DisasContext *s, int opcode, int rd, int rn, int rm) { @@ -4818,7 +4819,7 @@ static void handle_fp_2src_double(DisasContext *s, int opcode, tcg_temp_free_i64(tcg_res); } -/* C3.6.26 Floating point data-processing (2 source) +/* Floating point data-processing (2 source) * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0 * +---+---+---+-----------+------+---+------+--------+-----+------+------+ * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | opcode | 1 0 | Rn | Rd | @@ -4855,7 +4856,7 @@ static void disas_fp_2src(DisasContext *s, uint32_t insn) } } -/* C3.6.27 Floating-point data-processing (3 source) - single precision */ +/* Floating-point data-processing (3 source) - single precision */ static void handle_fp_3src_single(DisasContext *s, bool o0, bool o1, int rd, int rn, int rm, int ra) { @@ -4893,7 +4894,7 @@ static void handle_fp_3src_single(DisasContext *s, bool o0, bool o1, tcg_temp_free_i32(tcg_res); } -/* C3.6.27 Floating-point data-processing (3 source) - double precision */ +/* Floating-point data-processing (3 source) - double precision */ static void handle_fp_3src_double(DisasContext *s, bool o0, bool o1, int rd, int rn, int rm, int ra) { @@ -4931,7 +4932,7 @@ static void handle_fp_3src_double(DisasContext *s, bool o0, bool o1, tcg_temp_free_i64(tcg_res); } -/* C3.6.27 Floating point data-processing (3 source) +/* Floating point data-processing (3 source) * 31 30 29 28 24 23 22 21 20 16 15 14 10 9 5 4 0 * +---+---+---+-----------+------+----+------+----+------+------+------+ * | M | 0 | S | 1 1 1 1 1 | type | o1 | Rm | o0 | Ra | Rn | Rd | @@ -4965,7 +4966,7 @@ static void disas_fp_3src(DisasContext *s, uint32_t insn) } } -/* C3.6.28 Floating point immediate +/* Floating point immediate * 31 30 29 28 24 23 22 21 20 13 12 10 9 5 4 0 * +---+---+---+-----------+------+---+------------+-------+------+------+ * | M | 0 | S | 1 1 1 1 0 | type | 1 | imm8 | 1 0 0 | imm5 | Rd | @@ -5136,7 +5137,7 @@ static void handle_fpfpcvt(DisasContext *s, int rd, int rn, int opcode, tcg_temp_free_i32(tcg_shift); } -/* C3.6.29 Floating point <-> fixed point conversions +/* Floating point <-> fixed point conversions * 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0 * +----+---+---+-----------+------+---+-------+--------+-------+------+------+ * | sf | 0 | S | 1 1 1 1 0 | type | 0 | rmode | opcode | scale | Rn | Rd | @@ -5236,7 +5237,7 @@ static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof) } } -/* C3.6.30 Floating point <-> integer conversions +/* Floating point <-> integer conversions * 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0 * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+ * | sf | 0 | S | 1 1 1 1 0 | type | 1 | rmode | opc | 0 0 0 0 0 0 | Rn | Rd | @@ -5371,7 +5372,7 @@ static void do_ext64(DisasContext *s, TCGv_i64 tcg_left, TCGv_i64 tcg_right, tcg_temp_free_i64(tcg_tmp); } -/* C3.6.1 EXT +/* EXT * 31 30 29 24 23 22 21 20 16 15 14 11 10 9 5 4 0 * +---+---+-------------+-----+---+------+---+------+---+------+------+ * | 0 | Q | 1 0 1 1 1 0 | op2 | 0 | Rm | 0 | imm4 | 0 | Rn | Rd | @@ -5444,7 +5445,7 @@ static void disas_simd_ext(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_resh); } -/* C3.6.2 TBL/TBX +/* TBL/TBX * 31 30 29 24 23 22 21 20 16 15 14 13 12 11 10 9 5 4 0 * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+ * | 0 | Q | 0 0 1 1 1 0 | op2 | 0 | Rm | 0 | len | op | 0 0 | Rn | Rd | @@ -5512,7 +5513,7 @@ static void disas_simd_tb(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_resh); } -/* C3.6.3 ZIP/UZP/TRN +/* ZIP/UZP/TRN * 31 30 29 24 23 22 21 20 16 15 14 12 11 10 9 5 4 0 * +---+---+-------------+------+---+------+---+------------------+------+ * | 0 | Q | 0 0 1 1 1 0 | size | 0 | Rm | 0 | opc | 1 0 | Rn | Rd | @@ -5624,7 +5625,7 @@ static void do_minmaxop(DisasContext *s, TCGv_i32 tcg_elt1, TCGv_i32 tcg_elt2, } } -/* C3.6.4 AdvSIMD across lanes +/* AdvSIMD across lanes * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0 * +---+---+---+-----------+------+-----------+--------+-----+------+------+ * | 0 | Q | U | 0 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 | Rn | Rd | @@ -5791,7 +5792,7 @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_res); } -/* C6.3.31 DUP (Element, Vector) +/* DUP (Element, Vector) * * 31 30 29 21 20 16 15 10 9 5 4 0 * +---+---+-------------------+--------+-------------+------+------+ @@ -5834,7 +5835,7 @@ static void handle_simd_dupe(DisasContext *s, int is_q, int rd, int rn, tcg_temp_free_i64(tmp); } -/* C6.3.31 DUP (element, scalar) +/* DUP (element, scalar) * 31 21 20 16 15 10 9 5 4 0 * +-----------------------+--------+-------------+------+------+ * | 0 1 0 1 1 1 1 0 0 0 0 | imm5 | 0 0 0 0 0 1 | Rn | Rd | @@ -5867,7 +5868,7 @@ static void handle_simd_dupes(DisasContext *s, int rd, int rn, tcg_temp_free_i64(tmp); } -/* C6.3.32 DUP (General) +/* DUP (General) * * 31 30 29 21 20 16 15 10 9 5 4 0 * +---+---+-------------------+--------+-------------+------+------+ @@ -5901,7 +5902,7 @@ static void handle_simd_dupg(DisasContext *s, int is_q, int rd, int rn, } } -/* C6.3.150 INS (Element) +/* INS (Element) * * 31 21 20 16 15 14 11 10 9 5 4 0 * +-----------------------+--------+------------+---+------+------+ @@ -5939,7 +5940,7 @@ static void handle_simd_inse(DisasContext *s, int rd, int rn, } -/* C6.3.151 INS (General) +/* INS (General) * * 31 21 20 16 15 10 9 5 4 0 * +-----------------------+--------+-------------+------+------+ @@ -5968,8 +5969,8 @@ static void handle_simd_insg(DisasContext *s, int rd, int rn, int imm5) } /* - * C6.3.321 UMOV (General) - * C6.3.237 SMOV (General) + * UMOV (General) + * SMOV (General) * * 31 30 29 21 20 16 15 12 10 9 5 4 0 * +---+---+-------------------+--------+-------------+------+------+ @@ -6014,7 +6015,7 @@ static void handle_simd_umov_smov(DisasContext *s, int is_q, int is_signed, } } -/* C3.6.5 AdvSIMD copy +/* AdvSIMD copy * 31 30 29 28 21 20 16 15 14 11 10 9 5 4 0 * +---+---+----+-----------------+------+---+------+---+------+------+ * | 0 | Q | op | 0 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 | Rn | Rd | @@ -6066,7 +6067,7 @@ static void disas_simd_copy(DisasContext *s, uint32_t insn) } } -/* C3.6.6 AdvSIMD modified immediate +/* AdvSIMD modified immediate * 31 30 29 28 19 18 16 15 12 11 10 9 5 4 0 * +---+---+----+---------------------+-----+-------+----+---+-------+------+ * | 0 | Q | op | 0 1 1 1 1 0 0 0 0 0 | abc | cmode | o2 | 1 | defgh | Rd | @@ -6199,7 +6200,7 @@ static void disas_simd_mod_imm(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_imm); } -/* C3.6.7 AdvSIMD scalar copy +/* AdvSIMD scalar copy * 31 30 29 28 21 20 16 15 14 11 10 9 5 4 0 * +-----+----+-----------------+------+---+------+---+------+------+ * | 0 1 | op | 1 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 | Rn | Rd | @@ -6222,7 +6223,7 @@ static void disas_simd_scalar_copy(DisasContext *s, uint32_t insn) handle_simd_dupes(s, rd, rn, imm5); } -/* C3.6.8 AdvSIMD scalar pairwise +/* AdvSIMD scalar pairwise * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0 * +-----+---+-----------+------+-----------+--------+-----+------+------+ * | 0 1 | U | 1 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 | Rn | Rd | @@ -6948,7 +6949,7 @@ static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar, tcg_temp_free_i32(tcg_rmode); } -/* C3.6.9 AdvSIMD scalar shift by immediate +/* AdvSIMD scalar shift by immediate * 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0 * +-----+---+-------------+------+------+--------+---+------+------+ * | 0 1 | U | 1 1 1 1 1 0 | immh | immb | opcode | 1 | Rn | Rd | @@ -7023,7 +7024,7 @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn) } } -/* C3.6.10 AdvSIMD scalar three different +/* AdvSIMD scalar three different * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0 * +-----+---+-----------+------+---+------+--------+-----+------+------+ * | 0 1 | U | 1 1 1 1 0 | size | 1 | Rm | opcode | 0 0 | Rn | Rd | @@ -7410,7 +7411,7 @@ static void handle_3same_float(DisasContext *s, int size, int elements, } } -/* C3.6.11 AdvSIMD scalar three same +/* AdvSIMD scalar three same * 31 30 29 28 24 23 22 21 20 16 15 11 10 9 5 4 0 * +-----+---+-----------+------+---+------+--------+---+------+------+ * | 0 1 | U | 1 1 1 1 0 | size | 1 | Rm | opcode | 1 | Rn | Rd | @@ -8079,7 +8080,7 @@ static void handle_2misc_satacc(DisasContext *s, bool is_scalar, bool is_u, } } -/* C3.6.12 AdvSIMD scalar two reg misc +/* AdvSIMD scalar two reg misc * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0 * +-----+---+-----------+------+-----------+--------+-----+------+------+ * | 0 1 | U | 1 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 | Rn | Rd | @@ -8507,7 +8508,7 @@ static void handle_vec_simd_shrn(DisasContext *s, bool is_q, } -/* C3.6.14 AdvSIMD shift by immediate +/* AdvSIMD shift by immediate * 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0 * +---+---+---+-------------+------+------+--------+---+------+------+ * | 0 | Q | U | 0 1 1 1 1 0 | immh | immb | opcode | 1 | Rn | Rd | @@ -8926,7 +8927,7 @@ static void handle_pmull_64(DisasContext *s, int is_q, int rd, int rn, int rm) tcg_temp_free_i64(tcg_res); } -/* C3.6.15 AdvSIMD three different +/* AdvSIMD three different * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0 * +---+---+---+-----------+------+---+------+--------+-----+------+------+ * | 0 | Q | U | 0 1 1 1 0 | size | 1 | Rm | opcode | 0 0 | Rn | Rd | @@ -9663,7 +9664,7 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) } } -/* C3.6.16 AdvSIMD three same +/* AdvSIMD three same * 31 30 29 28 24 23 22 21 20 16 15 11 10 9 5 4 0 * +---+---+---+-----------+------+---+------+--------+---+------+------+ * | 0 | Q | U | 0 1 1 1 0 | size | 1 | Rm | opcode | 1 | Rn | Rd | @@ -9932,7 +9933,7 @@ static void handle_shll(DisasContext *s, bool is_q, int size, int rn, int rd) } } -/* C3.6.17 AdvSIMD two reg misc +/* AdvSIMD two reg misc * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0 * +---+---+---+-----------+------+-----------+--------+-----+------+------+ * | 0 | Q | U | 0 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 | Rn | Rd | @@ -10444,12 +10445,12 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) } } -/* C3.6.13 AdvSIMD scalar x indexed element +/* AdvSIMD scalar x indexed element * 31 30 29 28 24 23 22 21 20 19 16 15 12 11 10 9 5 4 0 * +-----+---+-----------+------+---+---+------+-----+---+---+------+------+ * | 0 1 | U | 1 1 1 1 1 | size | L | M | Rm | opc | H | 0 | Rn | Rd | * +-----+---+-----------+------+---+---+------+-----+---+---+------+------+ - * C3.6.18 AdvSIMD vector x indexed element + * AdvSIMD vector x indexed element * 31 30 29 28 24 23 22 21 20 19 16 15 12 11 10 9 5 4 0 * +---+---+---+-----------+------+---+---+------+-----+---+---+------+------+ * | 0 | Q | U | 0 1 1 1 1 | size | L | M | Rm | opc | H | 0 | Rn | Rd | @@ -10899,7 +10900,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) } } -/* C3.6.19 Crypto AES +/* Crypto AES * 31 24 23 22 21 17 16 12 11 10 9 5 4 0 * +-----------------+------+-----------+--------+-----+------+------+ * | 0 1 0 0 1 1 1 0 | size | 1 0 1 0 0 | opcode | 1 0 | Rn | Rd | @@ -10962,7 +10963,7 @@ static void disas_crypto_aes(DisasContext *s, uint32_t insn) tcg_temp_free_i32(tcg_decrypt); } -/* C3.6.20 Crypto three-reg SHA +/* Crypto three-reg SHA * 31 24 23 22 21 20 16 15 14 12 11 10 9 5 4 0 * +-----------------+------+---+------+---+--------+-----+------+------+ * | 0 1 0 1 1 1 1 0 | size | 0 | Rm | 0 | opcode | 0 0 | Rn | Rd | @@ -11034,7 +11035,7 @@ static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn) tcg_temp_free_i32(tcg_rm_regno); } -/* C3.6.21 Crypto two-reg SHA +/* Crypto two-reg SHA * 31 24 23 22 21 17 16 12 11 10 9 5 4 0 * +-----------------+------+-----------+--------+-----+------+------+ * | 0 1 0 1 1 1 1 0 | size | 1 0 1 0 0 | opcode | 1 0 | Rn | Rd | diff --git a/target/mips/Makefile.objs b/target/mips/Makefile.objs index bc5ed8511f..651f36f517 100644 --- a/target/mips/Makefile.objs +++ b/target/mips/Makefile.objs @@ -1,4 +1,4 @@ obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o obj-y += gdbstub.o msa_helper.o mips-semi.o -obj-$(CONFIG_SOFTMMU) += machine.o +obj-$(CONFIG_SOFTMMU) += machine.o cp0_timer.o obj-$(CONFIG_KVM) += kvm.o diff --git a/target/mips/cp0_timer.c b/target/mips/cp0_timer.c new file mode 100644 index 0000000000..f4716395df --- /dev/null +++ b/target/mips/cp0_timer.c @@ -0,0 +1,165 @@ +/* + * QEMU MIPS timer support + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/mips/cpudevs.h" +#include "qemu/timer.h" +#include "sysemu/kvm.h" +#include "internal.h" + +#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */ + +/* XXX: do not use a global */ +uint32_t cpu_mips_get_random (CPUMIPSState *env) +{ + static uint32_t seed = 1; + static uint32_t prev_idx = 0; + uint32_t idx; + uint32_t nb_rand_tlb = env->tlb->nb_tlb - env->CP0_Wired; + + if (nb_rand_tlb == 1) { + return env->tlb->nb_tlb - 1; + } + + /* Don't return same value twice, so get another value */ + do { + /* Use a simple algorithm of Linear Congruential Generator + * from ISO/IEC 9899 standard. */ + seed = 1103515245 * seed + 12345; + idx = (seed >> 16) % nb_rand_tlb + env->CP0_Wired; + } while (idx == prev_idx); + prev_idx = idx; + return idx; +} + +/* MIPS R4K timer */ +static void cpu_mips_timer_update(CPUMIPSState *env) +{ + uint64_t now, next; + uint32_t wait; + + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + wait = env->CP0_Compare - env->CP0_Count - (uint32_t)(now / TIMER_PERIOD); + next = now + (uint64_t)wait * TIMER_PERIOD; + timer_mod(env->timer, next); +} + +/* Expire the timer. */ +static void cpu_mips_timer_expire(CPUMIPSState *env) +{ + cpu_mips_timer_update(env); + if (env->insn_flags & ISA_MIPS32R2) { + env->CP0_Cause |= 1 << CP0Ca_TI; + } + qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); +} + +uint32_t cpu_mips_get_count (CPUMIPSState *env) +{ + if (env->CP0_Cause & (1 << CP0Ca_DC)) { + return env->CP0_Count; + } else { + uint64_t now; + + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + if (timer_pending(env->timer) + && timer_expired(env->timer, now)) { + /* The timer has already expired. */ + cpu_mips_timer_expire(env); + } + + return env->CP0_Count + (uint32_t)(now / TIMER_PERIOD); + } +} + +void cpu_mips_store_count (CPUMIPSState *env, uint32_t count) +{ + /* + * This gets called from cpu_state_reset(), potentially before timer init. + * So env->timer may be NULL, which is also the case with KVM enabled so + * treat timer as disabled in that case. + */ + if (env->CP0_Cause & (1 << CP0Ca_DC) || !env->timer) + env->CP0_Count = count; + else { + /* Store new count register */ + env->CP0_Count = count - + (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD); + /* Update timer timer */ + cpu_mips_timer_update(env); + } +} + +void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value) +{ + env->CP0_Compare = value; + if (!(env->CP0_Cause & (1 << CP0Ca_DC))) + cpu_mips_timer_update(env); + if (env->insn_flags & ISA_MIPS32R2) + env->CP0_Cause &= ~(1 << CP0Ca_TI); + qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); +} + +void cpu_mips_start_count(CPUMIPSState *env) +{ + cpu_mips_store_count(env, env->CP0_Count); +} + +void cpu_mips_stop_count(CPUMIPSState *env) +{ + /* Store the current value */ + env->CP0_Count += (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / + TIMER_PERIOD); +} + +static void mips_timer_cb (void *opaque) +{ + CPUMIPSState *env; + + env = opaque; +#if 0 + qemu_log("%s\n", __func__); +#endif + + if (env->CP0_Cause & (1 << CP0Ca_DC)) + return; + + /* ??? This callback should occur when the counter is exactly equal to + the comparator value. Offset the count by one to avoid immediately + retriggering the callback before any virtual time has passed. */ + env->CP0_Count++; + cpu_mips_timer_expire(env); + env->CP0_Count--; +} + +void cpu_mips_clock_init (MIPSCPU *cpu) +{ + CPUMIPSState *env = &cpu->env; + + /* + * If we're in KVM mode, don't create the periodic timer, that is handled in + * kernel. + */ + if (!kvm_enabled()) { + env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &mips_timer_cb, env); + } +} diff --git a/target/mips/cpu-qom.h b/target/mips/cpu-qom.h index 3f5bf23823..ee58606afe 100644 --- a/target/mips/cpu-qom.h +++ b/target/mips/cpu-qom.h @@ -49,6 +49,7 @@ typedef struct MIPSCPUClass { DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); + const struct mips_def_t *cpu_def; } MIPSCPUClass; typedef struct MIPSCPU MIPSCPU; diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 1bb66b7a5a..1a9a3ed94d 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "cpu.h" +#include "internal.h" #include "kvm_mips.h" #include "qemu-common.h" #include "sysemu/kvm.h" @@ -122,6 +123,7 @@ static void mips_cpu_disas_set_info(CPUState *s, disassemble_info *info) { static void mips_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); + MIPSCPU *cpu = MIPS_CPU(dev); MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev); Error *local_err = NULL; @@ -131,6 +133,8 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp) return; } + cpu_mips_realize_env(&cpu->env); + cpu_reset(cs); qemu_init_vcpu(cs); @@ -142,14 +146,36 @@ static void mips_cpu_initfn(Object *obj) CPUState *cs = CPU(obj); MIPSCPU *cpu = MIPS_CPU(obj); CPUMIPSState *env = &cpu->env; + MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(obj); cs->env_ptr = env; + env->cpu_model = mcc->cpu_def; if (tcg_enabled()) { mips_tcg_init(); } } +static char *mips_cpu_type_name(const char *cpu_model) +{ + return g_strdup_printf("%s-" TYPE_MIPS_CPU, cpu_model); +} + +static ObjectClass *mips_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + char *typename; + + if (cpu_model == NULL) { + return NULL; + } + + typename = mips_cpu_type_name(cpu_model); + oc = object_class_by_name(typename); + g_free(typename); + return oc; +} + static void mips_cpu_class_init(ObjectClass *c, void *data) { MIPSCPUClass *mcc = MIPS_CPU_CLASS(c); @@ -162,6 +188,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) mcc->parent_reset = cc->reset; cc->reset = mips_cpu_reset; + cc->class_by_name = mips_cpu_class_by_name; cc->has_work = mips_cpu_has_work; cc->do_interrupt = mips_cpu_do_interrupt; cc->cpu_exec_interrupt = mips_cpu_exec_interrupt; @@ -189,14 +216,39 @@ static const TypeInfo mips_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(MIPSCPU), .instance_init = mips_cpu_initfn, - .abstract = false, + .abstract = true, .class_size = sizeof(MIPSCPUClass), .class_init = mips_cpu_class_init, }; +static void mips_cpu_cpudef_class_init(ObjectClass *oc, void *data) +{ + MIPSCPUClass *mcc = MIPS_CPU_CLASS(oc); + mcc->cpu_def = data; +} + +static void mips_register_cpudef_type(const struct mips_def_t *def) +{ + char *typename = mips_cpu_type_name(def->name); + TypeInfo ti = { + .name = typename, + .parent = TYPE_MIPS_CPU, + .class_init = mips_cpu_cpudef_class_init, + .class_data = (void *)def, + }; + + type_register(&ti); + g_free(typename); +} + static void mips_cpu_register_types(void) { + int i; + type_register_static(&mips_cpu_type_info); + for (i = 0; i < mips_defs_number; i++) { + mips_register_cpudef_type(&mips_defs[i]); + } } type_init(mips_cpu_register_types) diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 74f6a5b098..66265e4eb6 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1,8 +1,6 @@ #ifndef MIPS_CPU_H #define MIPS_CPU_H -//#define DEBUG_OP - #define ALIGNED_ONLY #define CPUArchState struct CPUMIPSState @@ -15,56 +13,11 @@ struct CPUMIPSState; -typedef struct r4k_tlb_t r4k_tlb_t; -struct r4k_tlb_t { - target_ulong VPN; - uint32_t PageMask; - uint16_t ASID; - unsigned int G:1; - unsigned int C0:3; - unsigned int C1:3; - unsigned int V0:1; - unsigned int V1:1; - unsigned int D0:1; - unsigned int D1:1; - unsigned int XI0:1; - unsigned int XI1:1; - unsigned int RI0:1; - unsigned int RI1:1; - unsigned int EHINV:1; - uint64_t PFN[2]; -}; - -#if !defined(CONFIG_USER_ONLY) typedef struct CPUMIPSTLBContext CPUMIPSTLBContext; -struct CPUMIPSTLBContext { - uint32_t nb_tlb; - uint32_t tlb_in_use; - int (*map_address) (struct CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong address, int rw, int access_type); - void (*helper_tlbwi)(struct CPUMIPSState *env); - void (*helper_tlbwr)(struct CPUMIPSState *env); - void (*helper_tlbp)(struct CPUMIPSState *env); - void (*helper_tlbr)(struct CPUMIPSState *env); - void (*helper_tlbinv)(struct CPUMIPSState *env); - void (*helper_tlbinvf)(struct CPUMIPSState *env); - union { - struct { - r4k_tlb_t tlb[MIPS_TLB_MAX]; - } r4k; - } mmu; -}; -#endif /* MSA Context */ #define MSA_WRLEN (128) -enum CPUMIPSMSADataFormat { - DF_BYTE = 0, - DF_HALF, - DF_WORD, - DF_DOUBLE -}; - typedef union wr_t wr_t; union wr_t { int8_t b[MSA_WRLEN/8]; @@ -682,40 +635,6 @@ static inline MIPSCPU *mips_env_get_cpu(CPUMIPSState *env) #define ENV_OFFSET offsetof(MIPSCPU, env) -#ifndef CONFIG_USER_ONLY -extern const struct VMStateDescription vmstate_mips_cpu; -#endif - -void mips_cpu_do_interrupt(CPUState *cpu); -bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req); -void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, - int flags); -hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); -int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, - MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr); - -#if !defined(CONFIG_USER_ONLY) -int no_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, int rw, int access_type); -int fixed_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, int rw, int access_type); -int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, int rw, int access_type); -void r4k_helper_tlbwi(CPUMIPSState *env); -void r4k_helper_tlbwr(CPUMIPSState *env); -void r4k_helper_tlbp(CPUMIPSState *env); -void r4k_helper_tlbr(CPUMIPSState *env); -void r4k_helper_tlbinv(CPUMIPSState *env); -void r4k_helper_tlbinvf(CPUMIPSState *env); - -void mips_cpu_unassigned_access(CPUState *cpu, hwaddr addr, - bool is_write, bool is_exec, int unused, - unsigned size); -#endif - void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf); #define cpu_signal_handler cpu_mips_signal_handler @@ -746,42 +665,6 @@ static inline int cpu_mmu_index (CPUMIPSState *env, bool ifetch) return hflags_mmu_index(env->hflags); } -static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env) -{ - 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)); -} - -/* 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; - - if (env->CP0_Config3 & (1 << CP0C3_VEIC)) { - /* A MIPS configured with a vectorizing external interrupt controller - will feed a vector into the Cause pending lines. The core treats - the status lines as a vector level, not as indiviual masks. */ - r = pending > status; - } else { - /* 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) != 0; - } - return r; -} - #include "exec/cpu-all.h" /* Memory access type : @@ -847,100 +730,32 @@ enum { #define EXCP_SC 0x100 /* - * This is an interrnally generated WAKE request line. + * This is an internally generated WAKE request line. * It is driven by the CPU itself. Raised when the MT * block wants to wake a VPE from an inactive state and * cleared when VPE goes from active to inactive. */ #define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0 -void mips_tcg_init(void); -MIPSCPU *cpu_mips_init(const char *cpu_model); int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); -#define cpu_init(cpu_model) CPU(cpu_mips_init(cpu_model)) +#define cpu_init(cpu_model) cpu_generic_init(TYPE_MIPS_CPU, cpu_model) bool cpu_supports_cps_smp(const char *cpu_model); bool cpu_supports_isa(const char *cpu_model, unsigned int isa); void cpu_set_exception_base(int vp_index, target_ulong address); -/* TODO QOM'ify CPU reset and remove */ -void cpu_state_reset(CPUMIPSState *s); - -/* mips_timer.c */ -uint32_t cpu_mips_get_random (CPUMIPSState *env); -uint32_t cpu_mips_get_count (CPUMIPSState *env); -void cpu_mips_store_count (CPUMIPSState *env, uint32_t value); -void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value); -void cpu_mips_start_count(CPUMIPSState *env); -void cpu_mips_stop_count(CPUMIPSState *env); - /* mips_int.c */ void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level); /* helper.c */ -int mips_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, - int mmu_idx); - -/* op_helper.c */ -uint32_t float_class_s(uint32_t arg, float_status *fst); -uint64_t float_class_d(uint64_t arg, float_status *fst); - -#if !defined(CONFIG_USER_ONLY) -void r4k_invalidate_tlb (CPUMIPSState *env, int idx, int use_extra); -hwaddr cpu_mips_translate_address (CPUMIPSState *env, target_ulong address, - int rw); -#endif target_ulong exception_resume_pc (CPUMIPSState *env); -/* op_helper.c */ -extern unsigned int ieee_rm[]; -int ieee_ex_to_mips(int xcpt); - -static inline void restore_rounding_mode(CPUMIPSState *env) -{ - set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], - &env->active_fpu.fp_status); -} - -static inline void restore_flush_mode(CPUMIPSState *env) -{ - set_flush_to_zero((env->active_fpu.fcr31 & (1 << FCR31_FS)) != 0, - &env->active_fpu.fp_status); -} - static inline void restore_snan_bit_mode(CPUMIPSState *env) { set_snan_bit_is_one((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) == 0, &env->active_fpu.fp_status); } -static inline void restore_fp_status(CPUMIPSState *env) -{ - restore_rounding_mode(env); - restore_flush_mode(env); - restore_snan_bit_mode(env); -} - -static inline void restore_msa_fp_status(CPUMIPSState *env) -{ - float_status *status = &env->active_tc.msa_fp_status; - int rounding_mode = (env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM; - bool flush_to_zero = (env->active_tc.msacsr & MSACSR_FS_MASK) != 0; - - set_float_rounding_mode(ieee_rm[rounding_mode], status); - set_flush_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, target_ulong *cs_base, uint32_t *flags) { @@ -950,172 +765,4 @@ static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc, MIPS_HFLAG_HWRENA_ULR); } -static inline int mips_vpe_active(CPUMIPSState *env) -{ - int active = 1; - - /* Check that the VPE is enabled. */ - if (!(env->mvp->CP0_MVPControl & (1 << CP0MVPCo_EVP))) { - active = 0; - } - /* Check that the VPE is activated. */ - if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))) { - active = 0; - } - - /* Now verify that there are active thread contexts in the VPE. - - This assumes the CPU model will internally reschedule threads - if the active one goes to sleep. If there are no threads available - the active one will be in a sleeping state, and we can turn off - the entire VPE. */ - if (!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_A))) { - /* TC is not activated. */ - active = 0; - } - if (env->active_tc.CP0_TCHalt & 1) { - /* TC is in halt state. */ - active = 0; - } - - return active; -} - -static inline int mips_vp_active(CPUMIPSState *env) -{ - CPUState *other_cs = first_cpu; - - /* Check if the VP disabled other VPs (which means the VP is enabled) */ - if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) { - return 1; - } - - /* Check if the virtual processor is disabled due to a DVP */ - CPU_FOREACH(other_cs) { - MIPSCPU *other_cpu = MIPS_CPU(other_cs); - if ((&other_cpu->env != env) && - ((other_cpu->env.CP0_VPControl >> CP0VPCtl_DIS) & 1)) { - return 0; - } - } - return 1; -} - -static inline void compute_hflags(CPUMIPSState *env) -{ - env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | - 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_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)) { - env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; - } -#if defined(TARGET_MIPS64) - if ((env->insn_flags & ISA_MIPS3) && - (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || - (env->CP0_Status & (1 << CP0St_PX)) || - (env->CP0_Status & (1 << CP0St_UX)))) { - env->hflags |= MIPS_HFLAG_64; - } - - if (!(env->insn_flags & ISA_MIPS3)) { - env->hflags |= MIPS_HFLAG_AWRAP; - } else if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && - !(env->CP0_Status & (1 << CP0St_UX))) { - env->hflags |= MIPS_HFLAG_AWRAP; - } else if (env->insn_flags & ISA_MIPS64R6) { - /* Address wrapping for Supervisor and Kernel is specified in R6 */ - if ((((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_SM) && - !(env->CP0_Status & (1 << CP0St_SX))) || - (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_KM) && - !(env->CP0_Status & (1 << CP0St_KX)))) { - env->hflags |= MIPS_HFLAG_AWRAP; - } - } -#endif - if (((env->CP0_Status & (1 << CP0St_CU0)) && - !(env->insn_flags & ISA_MIPS32R6)) || - !(env->hflags & MIPS_HFLAG_KSU)) { - env->hflags |= MIPS_HFLAG_CP0; - } - if (env->CP0_Status & (1 << CP0St_CU1)) { - env->hflags |= MIPS_HFLAG_FPU; - } - if (env->CP0_Status & (1 << CP0St_FR)) { - env->hflags |= MIPS_HFLAG_F64; - } - if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_KM) && - (env->CP0_Config5 & (1 << CP0C5_SBRI))) { - env->hflags |= MIPS_HFLAG_SBRI; - } - if (env->insn_flags & ASE_DSPR2) { - /* Enables access MIPS DSP resources, now our cpu is DSP ASER2, - so enable to access DSPR2 resources. */ - if (env->CP0_Status & (1 << CP0St_MX)) { - env->hflags |= MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2; - } - - } else if (env->insn_flags & ASE_DSP) { - /* Enables access MIPS DSP resources, now our cpu is DSP ASE, - so enable to access DSP resources. */ - if (env->CP0_Status & (1 << CP0St_MX)) { - env->hflags |= MIPS_HFLAG_DSP; - } - - } - if (env->insn_flags & ISA_MIPS32R2) { - if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { - env->hflags |= MIPS_HFLAG_COP1X; - } - } else if (env->insn_flags & ISA_MIPS32) { - if (env->hflags & MIPS_HFLAG_64) { - env->hflags |= MIPS_HFLAG_COP1X; - } - } else if (env->insn_flags & ISA_MIPS4) { - /* All supported MIPS IV CPUs use the XX (CU3) to enable - and disable the MIPS IV extensions to the MIPS III ISA. - Some other MIPS IV CPUs ignore the bit, so the check here - would be too restrictive for them. */ - if (env->CP0_Status & (1U << CP0St_CU3)) { - env->hflags |= MIPS_HFLAG_COP1X; - } - } - if (env->insn_flags & ASE_MSA) { - if (env->CP0_Config5 & (1 << CP0C5_MSAEn)) { - env->hflags |= MIPS_HFLAG_MSA; - } - } - if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) { - if (env->CP0_Config5 & (1 << CP0C5_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; - } - } -} - -void cpu_mips_tlb_flush(CPUMIPSState *env); -void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc); -void cpu_mips_store_status(CPUMIPSState *env, target_ulong val); -void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val); - -void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, uint32_t exception, - int error_code, uintptr_t pc); - -static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env, - uint32_t exception, - uintptr_t pc) -{ - do_raise_exception_err(env, exception, 0, pc); -} - #endif /* MIPS_CPU_H */ diff --git a/target/mips/dsp_helper.c b/target/mips/dsp_helper.c index dc707934ea..f152fea34a 100644 --- a/target/mips/dsp_helper.c +++ b/target/mips/dsp_helper.c @@ -45,9 +45,9 @@ typedef union { } DSP64Value; /*** MIPS DSP internal functions begin ***/ -#define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x) -#define MIPSDSP_OVERFLOW_ADD(a, b, c, d) (~(a ^ b) & (a ^ c) & d) -#define MIPSDSP_OVERFLOW_SUB(a, b, c, d) ((a ^ b) & (a ^ c) & d) +#define MIPSDSP_ABS(x) (((x) >= 0) ? (x) : -(x)) +#define MIPSDSP_OVERFLOW_ADD(a, b, c, d) (~((a) ^ (b)) & ((a) ^ (c)) & (d)) +#define MIPSDSP_OVERFLOW_SUB(a, b, c, d) (((a) ^ (b)) & ((a) ^ (c)) & (d)) static inline void set_DSPControl_overflow_flag(uint32_t flag, int position, CPUMIPSState *env) @@ -1047,47 +1047,47 @@ static inline int32_t mipsdsp_cmpu_lt(uint32_t a, uint32_t b) #define MIPSDSP_SPLIT32_8(num, a, b, c, d) \ do { \ - a = (num >> 24) & MIPSDSP_Q0; \ - b = (num >> 16) & MIPSDSP_Q0; \ - c = (num >> 8) & MIPSDSP_Q0; \ - d = num & MIPSDSP_Q0; \ + a = ((num) >> 24) & MIPSDSP_Q0; \ + b = ((num) >> 16) & MIPSDSP_Q0; \ + c = ((num) >> 8) & MIPSDSP_Q0; \ + d = (num) & MIPSDSP_Q0; \ } while (0) #define MIPSDSP_SPLIT32_16(num, a, b) \ do { \ - a = (num >> 16) & MIPSDSP_LO; \ - b = num & MIPSDSP_LO; \ + a = ((num) >> 16) & MIPSDSP_LO; \ + b = (num) & MIPSDSP_LO; \ } while (0) -#define MIPSDSP_RETURN32_8(a, b, c, d) ((target_long)(int32_t) \ - (((uint32_t)a << 24) | \ - (((uint32_t)b << 16) | \ - (((uint32_t)c << 8) | \ - ((uint32_t)d & 0xFF))))) -#define MIPSDSP_RETURN32_16(a, b) ((target_long)(int32_t) \ - (((uint32_t)a << 16) | \ - ((uint32_t)b & 0xFFFF))) +#define MIPSDSP_RETURN32_8(a, b, c, d) ((target_long)(int32_t) \ + (((uint32_t)(a) << 24) | \ + ((uint32_t)(b) << 16) | \ + ((uint32_t)(c) << 8) | \ + ((uint32_t)(d) & 0xFF))) +#define MIPSDSP_RETURN32_16(a, b) ((target_long)(int32_t) \ + (((uint32_t)(a) << 16) | \ + ((uint32_t)(b) & 0xFFFF))) #ifdef TARGET_MIPS64 #define MIPSDSP_SPLIT64_16(num, a, b, c, d) \ do { \ - a = (num >> 48) & MIPSDSP_LO; \ - b = (num >> 32) & MIPSDSP_LO; \ - c = (num >> 16) & MIPSDSP_LO; \ - d = num & MIPSDSP_LO; \ + a = ((num) >> 48) & MIPSDSP_LO; \ + b = ((num) >> 32) & MIPSDSP_LO; \ + c = ((num) >> 16) & MIPSDSP_LO; \ + d = (num) & MIPSDSP_LO; \ } while (0) #define MIPSDSP_SPLIT64_32(num, a, b) \ do { \ - a = (num >> 32) & MIPSDSP_LLO; \ - b = num & MIPSDSP_LLO; \ + a = ((num) >> 32) & MIPSDSP_LLO; \ + b = (num) & MIPSDSP_LLO; \ } while (0) -#define MIPSDSP_RETURN64_16(a, b, c, d) (((uint64_t)a << 48) | \ - ((uint64_t)b << 32) | \ - ((uint64_t)c << 16) | \ - (uint64_t)d) -#define MIPSDSP_RETURN64_32(a, b) (((uint64_t)a << 32) | (uint64_t)b) +#define MIPSDSP_RETURN64_16(a, b, c, d) (((uint64_t)(a) << 48) | \ + ((uint64_t)(b) << 32) | \ + ((uint64_t)(c) << 16) | \ + (uint64_t)(d)) +#define MIPSDSP_RETURN64_32(a, b) (((uint64_t)(a) << 32) | (uint64_t)(b)) #endif /** DSP Arithmetic Sub-class insns **/ diff --git a/target/mips/gdbstub.c b/target/mips/gdbstub.c index 7c682289c2..6d1fb70f2c 100644 --- a/target/mips/gdbstub.c +++ b/target/mips/gdbstub.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "cpu.h" +#include "internal.h" #include "exec/gdbstub.h" int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) diff --git a/target/mips/helper.c b/target/mips/helper.c index ca39aca08a..ea076261af 100644 --- a/target/mips/helper.c +++ b/target/mips/helper.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "exec/log.h" diff --git a/target/mips/internal.h b/target/mips/internal.h new file mode 100644 index 0000000000..45ded3484c --- /dev/null +++ b/target/mips/internal.h @@ -0,0 +1,422 @@ +/* mips internal definitions and helpers + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef MIPS_INTERNAL_H +#define MIPS_INTERNAL_H + + +/* MMU types, the first four entries have the same layout as the + CP0C0_MT field. */ +enum mips_mmu_types { + MMU_TYPE_NONE, + MMU_TYPE_R4000, + MMU_TYPE_RESERVED, + MMU_TYPE_FMT, + MMU_TYPE_R3000, + MMU_TYPE_R6000, + MMU_TYPE_R8000 +}; + +struct mips_def_t { + const char *name; + int32_t CP0_PRid; + int32_t CP0_Config0; + int32_t CP0_Config1; + int32_t CP0_Config2; + int32_t CP0_Config3; + int32_t CP0_Config4; + int32_t CP0_Config4_rw_bitmask; + int32_t CP0_Config5; + int32_t CP0_Config5_rw_bitmask; + int32_t CP0_Config6; + int32_t CP0_Config7; + target_ulong CP0_LLAddr_rw_bitmask; + int CP0_LLAddr_shift; + int32_t SYNCI_Step; + int32_t CCRes; + int32_t CP0_Status_rw_bitmask; + int32_t CP0_TCStatus_rw_bitmask; + int32_t CP0_SRSCtl; + int32_t CP1_fcr0; + int32_t CP1_fcr31_rw_bitmask; + int32_t CP1_fcr31; + int32_t MSAIR; + int32_t SEGBITS; + int32_t PABITS; + int32_t CP0_SRSConf0_rw_bitmask; + int32_t CP0_SRSConf0; + int32_t CP0_SRSConf1_rw_bitmask; + int32_t CP0_SRSConf1; + int32_t CP0_SRSConf2_rw_bitmask; + int32_t CP0_SRSConf2; + int32_t CP0_SRSConf3_rw_bitmask; + int32_t CP0_SRSConf3; + int32_t CP0_SRSConf4_rw_bitmask; + 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; +}; + +extern const struct mips_def_t mips_defs[]; +extern const int mips_defs_number; + +enum CPUMIPSMSADataFormat { + DF_BYTE = 0, + DF_HALF, + DF_WORD, + DF_DOUBLE +}; + +void mips_cpu_do_interrupt(CPUState *cpu); +bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req); +void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, + int flags); +hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr); + +#if !defined(CONFIG_USER_ONLY) + +typedef struct r4k_tlb_t r4k_tlb_t; +struct r4k_tlb_t { + target_ulong VPN; + uint32_t PageMask; + uint16_t ASID; + unsigned int G:1; + unsigned int C0:3; + unsigned int C1:3; + unsigned int V0:1; + unsigned int V1:1; + unsigned int D0:1; + unsigned int D1:1; + unsigned int XI0:1; + unsigned int XI1:1; + unsigned int RI0:1; + unsigned int RI1:1; + unsigned int EHINV:1; + uint64_t PFN[2]; +}; + +struct CPUMIPSTLBContext { + uint32_t nb_tlb; + uint32_t tlb_in_use; + int (*map_address)(struct CPUMIPSState *env, hwaddr *physical, int *prot, + target_ulong address, int rw, int access_type); + void (*helper_tlbwi)(struct CPUMIPSState *env); + void (*helper_tlbwr)(struct CPUMIPSState *env); + void (*helper_tlbp)(struct CPUMIPSState *env); + void (*helper_tlbr)(struct CPUMIPSState *env); + void (*helper_tlbinv)(struct CPUMIPSState *env); + void (*helper_tlbinvf)(struct CPUMIPSState *env); + union { + struct { + r4k_tlb_t tlb[MIPS_TLB_MAX]; + } r4k; + } mmu; +}; + +int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, + target_ulong address, int rw, int access_type); +int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, + target_ulong address, int rw, int access_type); +int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, + target_ulong address, int rw, int access_type); +void r4k_helper_tlbwi(CPUMIPSState *env); +void r4k_helper_tlbwr(CPUMIPSState *env); +void r4k_helper_tlbp(CPUMIPSState *env); +void r4k_helper_tlbr(CPUMIPSState *env); +void r4k_helper_tlbinv(CPUMIPSState *env); +void r4k_helper_tlbinvf(CPUMIPSState *env); +void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra); + +void mips_cpu_unassigned_access(CPUState *cpu, hwaddr addr, + bool is_write, bool is_exec, int unused, + unsigned size); +hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, + int rw); +#endif + +#define cpu_signal_handler cpu_mips_signal_handler + +#ifndef CONFIG_USER_ONLY +extern const struct VMStateDescription vmstate_mips_cpu; +#endif + +static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env) +{ + 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)); +} + +/* 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; + + if (env->CP0_Config3 & (1 << CP0C3_VEIC)) { + /* A MIPS configured with a vectorizing external interrupt controller + will feed a vector into the Cause pending lines. The core treats + the status lines as a vector level, not as indiviual masks. */ + r = pending > status; + } else { + /* 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) != 0; + } + return r; +} + +void mips_tcg_init(void); + +/* TODO QOM'ify CPU reset and remove */ +void cpu_state_reset(CPUMIPSState *s); +void cpu_mips_realize_env(CPUMIPSState *env); + +/* cp0_timer.c */ +uint32_t cpu_mips_get_random(CPUMIPSState *env); +uint32_t cpu_mips_get_count(CPUMIPSState *env); +void cpu_mips_store_count(CPUMIPSState *env, uint32_t value); +void cpu_mips_store_compare(CPUMIPSState *env, uint32_t value); +void cpu_mips_start_count(CPUMIPSState *env); +void cpu_mips_stop_count(CPUMIPSState *env); + +/* helper.c */ +int mips_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, + int mmu_idx); + +/* op_helper.c */ +uint32_t float_class_s(uint32_t arg, float_status *fst); +uint64_t float_class_d(uint64_t arg, float_status *fst); + +extern unsigned int ieee_rm[]; +int ieee_ex_to_mips(int xcpt); + +static inline void restore_rounding_mode(CPUMIPSState *env) +{ + set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], + &env->active_fpu.fp_status); +} + +static inline void restore_flush_mode(CPUMIPSState *env) +{ + set_flush_to_zero((env->active_fpu.fcr31 & (1 << FCR31_FS)) != 0, + &env->active_fpu.fp_status); +} + +static inline void restore_fp_status(CPUMIPSState *env) +{ + restore_rounding_mode(env); + restore_flush_mode(env); + restore_snan_bit_mode(env); +} + +static inline void restore_msa_fp_status(CPUMIPSState *env) +{ + float_status *status = &env->active_tc.msa_fp_status; + int rounding_mode = (env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM; + bool flush_to_zero = (env->active_tc.msacsr & MSACSR_FS_MASK) != 0; + + set_float_rounding_mode(ieee_rm[rounding_mode], status); + set_flush_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 int mips_vpe_active(CPUMIPSState *env) +{ + int active = 1; + + /* Check that the VPE is enabled. */ + if (!(env->mvp->CP0_MVPControl & (1 << CP0MVPCo_EVP))) { + active = 0; + } + /* Check that the VPE is activated. */ + if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))) { + active = 0; + } + + /* Now verify that there are active thread contexts in the VPE. + + This assumes the CPU model will internally reschedule threads + if the active one goes to sleep. If there are no threads available + the active one will be in a sleeping state, and we can turn off + the entire VPE. */ + if (!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_A))) { + /* TC is not activated. */ + active = 0; + } + if (env->active_tc.CP0_TCHalt & 1) { + /* TC is in halt state. */ + active = 0; + } + + return active; +} + +static inline int mips_vp_active(CPUMIPSState *env) +{ + CPUState *other_cs = first_cpu; + + /* Check if the VP disabled other VPs (which means the VP is enabled) */ + if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) { + return 1; + } + + /* Check if the virtual processor is disabled due to a DVP */ + CPU_FOREACH(other_cs) { + MIPSCPU *other_cpu = MIPS_CPU(other_cs); + if ((&other_cpu->env != env) && + ((other_cpu->env.CP0_VPControl >> CP0VPCtl_DIS) & 1)) { + return 0; + } + } + return 1; +} + +static inline void compute_hflags(CPUMIPSState *env) +{ + env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | + 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_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)) { + env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; + } +#if defined(TARGET_MIPS64) + if ((env->insn_flags & ISA_MIPS3) && + (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || + (env->CP0_Status & (1 << CP0St_PX)) || + (env->CP0_Status & (1 << CP0St_UX)))) { + env->hflags |= MIPS_HFLAG_64; + } + + if (!(env->insn_flags & ISA_MIPS3)) { + env->hflags |= MIPS_HFLAG_AWRAP; + } else if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && + !(env->CP0_Status & (1 << CP0St_UX))) { + env->hflags |= MIPS_HFLAG_AWRAP; + } else if (env->insn_flags & ISA_MIPS64R6) { + /* Address wrapping for Supervisor and Kernel is specified in R6 */ + if ((((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_SM) && + !(env->CP0_Status & (1 << CP0St_SX))) || + (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_KM) && + !(env->CP0_Status & (1 << CP0St_KX)))) { + env->hflags |= MIPS_HFLAG_AWRAP; + } + } +#endif + if (((env->CP0_Status & (1 << CP0St_CU0)) && + !(env->insn_flags & ISA_MIPS32R6)) || + !(env->hflags & MIPS_HFLAG_KSU)) { + env->hflags |= MIPS_HFLAG_CP0; + } + if (env->CP0_Status & (1 << CP0St_CU1)) { + env->hflags |= MIPS_HFLAG_FPU; + } + if (env->CP0_Status & (1 << CP0St_FR)) { + env->hflags |= MIPS_HFLAG_F64; + } + if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_KM) && + (env->CP0_Config5 & (1 << CP0C5_SBRI))) { + env->hflags |= MIPS_HFLAG_SBRI; + } + if (env->insn_flags & ASE_DSPR2) { + /* Enables access MIPS DSP resources, now our cpu is DSP ASER2, + so enable to access DSPR2 resources. */ + if (env->CP0_Status & (1 << CP0St_MX)) { + env->hflags |= MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2; + } + + } else if (env->insn_flags & ASE_DSP) { + /* Enables access MIPS DSP resources, now our cpu is DSP ASE, + so enable to access DSP resources. */ + if (env->CP0_Status & (1 << CP0St_MX)) { + env->hflags |= MIPS_HFLAG_DSP; + } + + } + if (env->insn_flags & ISA_MIPS32R2) { + if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { + env->hflags |= MIPS_HFLAG_COP1X; + } + } else if (env->insn_flags & ISA_MIPS32) { + if (env->hflags & MIPS_HFLAG_64) { + env->hflags |= MIPS_HFLAG_COP1X; + } + } else if (env->insn_flags & ISA_MIPS4) { + /* All supported MIPS IV CPUs use the XX (CU3) to enable + and disable the MIPS IV extensions to the MIPS III ISA. + Some other MIPS IV CPUs ignore the bit, so the check here + would be too restrictive for them. */ + if (env->CP0_Status & (1U << CP0St_CU3)) { + env->hflags |= MIPS_HFLAG_COP1X; + } + } + if (env->insn_flags & ASE_MSA) { + if (env->CP0_Config5 & (1 << CP0C5_MSAEn)) { + env->hflags |= MIPS_HFLAG_MSA; + } + } + if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) { + if (env->CP0_Config5 & (1 << CP0C5_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; + } + } +} + +void cpu_mips_tlb_flush(CPUMIPSState *env); +void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc); +void cpu_mips_store_status(CPUMIPSState *env, target_ulong val); +void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val); + +void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, uint32_t exception, + int error_code, uintptr_t pc); + +static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env, + uint32_t exception, + uintptr_t pc) +{ + do_raise_exception_err(env, exception, 0, pc); +} + +#endif diff --git a/target/mips/kvm.c b/target/mips/kvm.c index 3b7b1d962a..8e72850962 100644 --- a/target/mips/kvm.c +++ b/target/mips/kvm.c @@ -16,6 +16,7 @@ #include "qemu-common.h" #include "cpu.h" +#include "internal.h" #include "qemu/error-report.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" diff --git a/target/mips/machine.c b/target/mips/machine.c index 898825de3b..20100d5adb 100644 --- a/target/mips/machine.c +++ b/target/mips/machine.c @@ -1,6 +1,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "cpu.h" +#include "internal.h" #include "hw/hw.h" #include "migration/cpu.h" diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 1fdb0d9792..f167a42655 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index 320f2b0dc4..e537a8bfd8 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "cpu.h" +#include "internal.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" diff --git a/target/mips/translate.c b/target/mips/translate.c index c78d27294c..d16d879df7 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -23,6 +23,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" #include "disas/disas.h" #include "exec/exec-all.h" #include "tcg-op.h" @@ -20511,29 +20512,15 @@ void mips_tcg_init(void) #include "translate_init.c" -MIPSCPU *cpu_mips_init(const char *cpu_model) +void cpu_mips_realize_env(CPUMIPSState *env) { - MIPSCPU *cpu; - CPUMIPSState *env; - const mips_def_t *def; - - def = cpu_mips_find_by_name(cpu_model); - if (!def) - return NULL; - cpu = MIPS_CPU(object_new(TYPE_MIPS_CPU)); - env = &cpu->env; - env->cpu_model = def; env->exception_base = (int32_t)0xBFC00000; #ifndef CONFIG_USER_ONLY - mmu_init(env, def); + mmu_init(env, env->cpu_model); #endif - fpu_init(env, def); - mvp_init(env, def); - - object_property_set_bool(OBJECT(cpu), true, "realized", NULL); - - return cpu; + fpu_init(env, env->cpu_model); + mvp_init(env, env->cpu_model); } bool cpu_supports_cps_smp(const char *cpu_model) diff --git a/target/mips/translate_init.c b/target/mips/translate_init.c index 255d25bacd..8bbded46c4 100644 --- a/target/mips/translate_init.c +++ b/target/mips/translate_init.c @@ -51,64 +51,9 @@ #define MIPS_CONFIG5 \ ((0 << CP0C5_M)) -/* MMU types, the first four entries have the same layout as the - CP0C0_MT field. */ -enum mips_mmu_types { - MMU_TYPE_NONE, - MMU_TYPE_R4000, - MMU_TYPE_RESERVED, - MMU_TYPE_FMT, - MMU_TYPE_R3000, - MMU_TYPE_R6000, - MMU_TYPE_R8000 -}; - -struct mips_def_t { - const char *name; - int32_t CP0_PRid; - int32_t CP0_Config0; - int32_t CP0_Config1; - int32_t CP0_Config2; - int32_t CP0_Config3; - int32_t CP0_Config4; - int32_t CP0_Config4_rw_bitmask; - int32_t CP0_Config5; - int32_t CP0_Config5_rw_bitmask; - int32_t CP0_Config6; - int32_t CP0_Config7; - target_ulong CP0_LLAddr_rw_bitmask; - int CP0_LLAddr_shift; - int32_t SYNCI_Step; - int32_t CCRes; - int32_t CP0_Status_rw_bitmask; - int32_t CP0_TCStatus_rw_bitmask; - int32_t CP0_SRSCtl; - int32_t CP1_fcr0; - int32_t CP1_fcr31_rw_bitmask; - int32_t CP1_fcr31; - int32_t MSAIR; - int32_t SEGBITS; - int32_t PABITS; - int32_t CP0_SRSConf0_rw_bitmask; - int32_t CP0_SRSConf0; - int32_t CP0_SRSConf1_rw_bitmask; - int32_t CP0_SRSConf1; - int32_t CP0_SRSConf2_rw_bitmask; - int32_t CP0_SRSConf2; - int32_t CP0_SRSConf3_rw_bitmask; - int32_t CP0_SRSConf3; - int32_t CP0_SRSConf4_rw_bitmask; - 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; -}; - /*****************************************************************************/ /* MIPS CPU definitions */ -static const mips_def_t mips_defs[] = +const mips_def_t mips_defs[] = { { .name = "4Kc", @@ -808,6 +753,7 @@ static const mips_def_t mips_defs[] = #endif }; +const int mips_defs_number = ARRAY_SIZE(mips_defs); static const mips_def_t *cpu_mips_find_by_name (const char *name) { diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 720cb1d833..ebb75cafaa 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -311,8 +311,13 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } - /* Try to enable AIS facility */ - kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0); + /* + * The migration interface for ais was introduced with kernel 4.13 + * but the capability itself had been active since 4.12. As migration + * support is considered necessary let's disable ais in the 2.10 + * machine. + */ + /* kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0); */ qemu_mutex_init(&qemu_sigp_mutex); |