diff options
Diffstat (limited to 'target')
151 files changed, 7884 insertions, 4100 deletions
diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 1fd95d6c0f..ad3588a44a 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/qemu-print.h" #include "cpu.h" #include "qemu-common.h" #include "exec/exec-all.h" @@ -74,23 +75,17 @@ static void alpha_cpu_realizefn(DeviceState *dev, Error **errp) static void alpha_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - CPUListState *s = user_data; - (*s->cpu_fprintf)(s->file, " %s\n", - object_class_get_name(oc)); + qemu_printf(" %s\n", object_class_get_name(oc)); } -void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void alpha_cpu_list(void) { - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; GSList *list; list = object_class_get_list_sorted(TYPE_ALPHA_CPU, false); - (*cpu_fprintf)(f, "Available CPUs:\n"); - g_slist_foreach(list, alpha_cpu_list_entry, &s); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, alpha_cpu_list_entry, NULL); g_slist_free(list); } diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h index 7b50be785d..63bf3618ff 100644 --- a/target/alpha/cpu.h +++ b/target/alpha/cpu.h @@ -311,8 +311,7 @@ extern const struct VMStateDescription vmstate_alpha_cpu; void alpha_cpu_do_interrupt(CPUState *cpu); bool alpha_cpu_exec_interrupt(CPUState *cpu, int int_req); -void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags); +void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags); hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int alpha_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); @@ -470,7 +469,7 @@ void alpha_translate_init(void); #define ALPHA_CPU_TYPE_NAME(model) model ALPHA_CPU_TYPE_SUFFIX #define CPU_RESOLVING_TYPE TYPE_ALPHA_CPU -void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void alpha_cpu_list(void); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ diff --git a/target/alpha/helper.c b/target/alpha/helper.c index 57e2c212b3..7201576aae 100644 --- a/target/alpha/helper.c +++ b/target/alpha/helper.c @@ -23,6 +23,7 @@ #include "exec/exec-all.h" #include "fpu/softfloat.h" #include "exec/helper-proto.h" +#include "qemu/qemu-print.h" #define CONVERT_BIT(X, SRC, DST) \ @@ -426,8 +427,7 @@ bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request) return false; } -void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags) { static const char *linux_reg_names[] = { "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ", @@ -439,24 +439,24 @@ void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, CPUAlphaState *env = &cpu->env; int i; - cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n", - env->pc, extract32(env->flags, ENV_FLAG_PS_SHIFT, 8)); + qemu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n", + env->pc, extract32(env->flags, ENV_FLAG_PS_SHIFT, 8)); for (i = 0; i < 31; i++) { - cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx "%c", i, - linux_reg_names[i], cpu_alpha_load_gr(env, i), - (i % 3) == 2 ? '\n' : ' '); + qemu_fprintf(f, "IR%02d %s " TARGET_FMT_lx "%c", i, + linux_reg_names[i], cpu_alpha_load_gr(env, i), + (i % 3) == 2 ? '\n' : ' '); } - cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n", - env->lock_addr, env->lock_value); + qemu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n", + env->lock_addr, env->lock_value); if (flags & CPU_DUMP_FPU) { for (i = 0; i < 31; i++) { - cpu_fprintf(f, "FIR%02d %016" PRIx64 "%c", i, env->fir[i], - (i % 3) == 2 ? '\n' : ' '); + qemu_fprintf(f, "FIR%02d %016" PRIx64 "%c", i, env->fir[i], + (i % 3) == 2 ? '\n' : ' '); } } - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } /* This should only be called from translate, via gen_excp. diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 9d8f9b3eea..2c9cccf6c1 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -3049,10 +3049,10 @@ static const TranslatorOps alpha_tr_ops = { .disas_log = alpha_tr_disas_log, }; -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb) +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) { DisasContext dc; - translator_loop(&alpha_tr_ops, &dc.base, cpu, tb); + translator_loop(&alpha_tr_ops, &dc.base, cpu, tb, max_insns); } void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c index b2b22d231e..8b5fd7bc6e 100644 --- a/target/arm/arm-semi.c +++ b/target/arm/arm-semi.c @@ -650,7 +650,7 @@ target_ulong do_arm_semihosting(CPUARMState *env) /* fall through -- invalid for A32/T32 */ default: fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr); - cpu_dump_state(cs, stderr, fprintf, 0); + cpu_dump_state(cs, stderr, 0); abort(); } } diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 96f0ff0ec7..a181fa8dc1 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "target/arm/idau.h" -#include "qemu/error-report.h" #include "qapi/error.h" #include "qapi/visitor.h" #include "cpu.h" @@ -282,6 +281,11 @@ static void arm_cpu_reset(CPUState *s) env->v7m.ccr[M_REG_S] |= R_V7M_CCR_UNALIGN_TRP_MASK; } + if (arm_feature(env, ARM_FEATURE_VFP)) { + env->v7m.fpccr[M_REG_NS] = R_V7M_FPCCR_ASPEN_MASK; + env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK | + R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK; + } /* Unlike A/R profile, M profile defines the reset LR value */ env->regs[14] = 0xffffffff; @@ -1030,6 +1034,13 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) set_feature(env, ARM_FEATURE_THUMB_DSP); } + /* + * We rely on no XScale CPU having VFP so we can use the same bits in the + * TB flags field for VECSTRIDE and XSCALE_CPAR. + */ + assert(!(arm_feature(env, ARM_FEATURE_VFP) && + arm_feature(env, ARM_FEATURE_XSCALE))); + if (arm_feature(env, ARM_FEATURE_V7) && !arm_feature(env, ARM_FEATURE_M) && !arm_feature(env, ARM_FEATURE_PMSA)) { @@ -1109,6 +1120,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) #endif } else { cpu->id_aa64dfr0 &= ~0xf00; + cpu->id_dfr0 &= ~(0xf << 24); cpu->pmceid0 = 0; cpu->pmceid1 = 0; } @@ -1481,8 +1493,12 @@ static void cortex_m4_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_M); set_feature(&cpu->env, ARM_FEATURE_M_MAIN); set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); + set_feature(&cpu->env, ARM_FEATURE_VFP4); cpu->midr = 0x410fc240; /* r0p0 */ cpu->pmsav7_dregion = 8; + cpu->isar.mvfr0 = 0x10110021; + cpu->isar.mvfr1 = 0x11000011; + cpu->isar.mvfr2 = 0x00000000; cpu->id_pfr0 = 0x00000030; cpu->id_pfr1 = 0x00000200; cpu->id_dfr0 = 0x00100000; @@ -1509,9 +1525,13 @@ static void cortex_m33_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_M_MAIN); set_feature(&cpu->env, ARM_FEATURE_M_SECURITY); set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); + set_feature(&cpu->env, ARM_FEATURE_VFP4); cpu->midr = 0x410fd213; /* r0p3 */ cpu->pmsav7_dregion = 16; cpu->sau_sregion = 8; + cpu->isar.mvfr0 = 0x10110021; + cpu->isar.mvfr1 = 0x11000011; + cpu->isar.mvfr2 = 0x00000040; cpu->id_pfr0 = 0x00000030; cpu->id_pfr1 = 0x00000210; cpu->id_dfr0 = 0x00200000; @@ -1744,6 +1764,7 @@ static void cortex_a7_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); set_feature(&cpu->env, ARM_FEATURE_EL2); set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7; cpu->midr = 0x410fc075; cpu->reset_fpsid = 0x41023075; @@ -1789,6 +1810,7 @@ static void cortex_a15_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); set_feature(&cpu->env, ARM_FEATURE_EL2); set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15; cpu->midr = 0x412fc0f1; cpu->reset_fpsid = 0x410430f0; @@ -2025,6 +2047,11 @@ static void arm_max_initfn(Object *obj) t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); cpu->isar.id_isar6 = t; + t = cpu->isar.mvfr2; + t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ + cpu->isar.mvfr2 = t; + t = cpu->id_mmfr4; t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ cpu->id_mmfr4 = t; diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 5f23c62132..22bc6e00ab 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -57,6 +57,9 @@ #define EXCP_NOCP 17 /* v7M NOCP UsageFault */ #define EXCP_INVSTATE 18 /* v7M INVSTATE UsageFault */ #define EXCP_STKOF 19 /* v8M STKOF UsageFault */ +#define EXCP_LAZYFP 20 /* v7M fault during lazy FP stacking */ +#define EXCP_LSERR 21 /* v8M LSERR SecureFault */ +#define EXCP_UNALIGNED 22 /* v7M UNALIGNED UsageFault */ /* NB: add new EXCP_ defines to the array in arm_log_exception() too */ #define ARMV7M_EXCP_RESET 1 @@ -533,6 +536,11 @@ typedef struct CPUARMState { uint32_t scr[M_REG_NUM_BANKS]; uint32_t msplim[M_REG_NUM_BANKS]; uint32_t psplim[M_REG_NUM_BANKS]; + uint32_t fpcar[M_REG_NUM_BANKS]; + uint32_t fpccr[M_REG_NUM_BANKS]; + uint32_t fpdscr[M_REG_NUM_BANKS]; + uint32_t cpacr[M_REG_NUM_BANKS]; + uint32_t nsacr; } v7m; /* Information associated with an exception about to be taken: @@ -935,8 +943,7 @@ void arm_cpu_do_interrupt(CPUState *cpu); void arm_v7m_cpu_do_interrupt(CPUState *cpu); bool arm_cpu_exec_interrupt(CPUState *cpu, int int_req); -void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags); +void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags); hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr, MemTxAttrs *attrs); @@ -993,17 +1000,6 @@ int cpu_arm_signal_handler(int host_signum, void *pinfo, void *puc); /** - * pmccntr_op_start/finish - * @env: CPUARMState - * - * Convert the counter in the PMCCNTR between its delta form (the typical mode - * when it's enabled) and the guest-visible value. These two calls must always - * surround any action which might affect the counter. - */ -void pmccntr_op_start(CPUARMState *env); -void pmccntr_op_finish(CPUARMState *env); - -/** * pmu_op_start/finish * @env: CPUARMState * @@ -1588,6 +1584,35 @@ FIELD(V7M_CSSELR, LEVEL, 1, 3) */ FIELD(V7M_CSSELR, INDEX, 0, 4) +/* v7M FPCCR bits */ +FIELD(V7M_FPCCR, LSPACT, 0, 1) +FIELD(V7M_FPCCR, USER, 1, 1) +FIELD(V7M_FPCCR, S, 2, 1) +FIELD(V7M_FPCCR, THREAD, 3, 1) +FIELD(V7M_FPCCR, HFRDY, 4, 1) +FIELD(V7M_FPCCR, MMRDY, 5, 1) +FIELD(V7M_FPCCR, BFRDY, 6, 1) +FIELD(V7M_FPCCR, SFRDY, 7, 1) +FIELD(V7M_FPCCR, MONRDY, 8, 1) +FIELD(V7M_FPCCR, SPLIMVIOL, 9, 1) +FIELD(V7M_FPCCR, UFRDY, 10, 1) +FIELD(V7M_FPCCR, RES0, 11, 15) +FIELD(V7M_FPCCR, TS, 26, 1) +FIELD(V7M_FPCCR, CLRONRETS, 27, 1) +FIELD(V7M_FPCCR, CLRONRET, 28, 1) +FIELD(V7M_FPCCR, LSPENS, 29, 1) +FIELD(V7M_FPCCR, LSPEN, 30, 1) +FIELD(V7M_FPCCR, ASPEN, 31, 1) +/* These bits are banked. Others are non-banked and live in the M_REG_S bank */ +#define R_V7M_FPCCR_BANKED_MASK \ + (R_V7M_FPCCR_LSPACT_MASK | \ + R_V7M_FPCCR_USER_MASK | \ + R_V7M_FPCCR_THREAD_MASK | \ + R_V7M_FPCCR_MMRDY_MASK | \ + R_V7M_FPCCR_SPLIMVIOL_MASK | \ + R_V7M_FPCCR_UFRDY_MASK | \ + R_V7M_FPCCR_ASPEN_MASK) + /* * System register ID fields. */ @@ -1947,7 +1972,7 @@ static inline bool access_secure_reg(CPUARMState *env) (arm_is_secure(_env) && !arm_el_is_aa64((_env), 3)), \ (_val)) -void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void arm_cpu_list(void); uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, uint32_t cur_el, bool secure); @@ -1987,6 +2012,18 @@ void armv7m_nvic_set_pending(void *opaque, int irq, bool secure); */ void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure); /** + * armv7m_nvic_set_pending_lazyfp: mark this lazy FP 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. + * + * Similar to armv7m_nvic_set_pending(), but specifically for exceptions + * generated in the course of lazy stacking of FP registers. + */ +void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure); +/** * armv7m_nvic_get_pending_irq_info: return highest priority pending * exception, and whether it targets Secure state * @opaque: the NVIC @@ -2023,6 +2060,20 @@ void armv7m_nvic_acknowledge_irq(void *opaque); */ int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure); /** + * armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure) + * @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. + * + * Return whether an exception is "ready", i.e. whether the exception is + * enabled and is configured at a priority which would allow it to + * interrupt the current execution priority. This controls whether the + * RDY bit for it in the FPCCR is set. + */ +bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure); +/** * armv7m_nvic_raw_execution_priority: return the raw execution priority * @opaque: the NVIC * @@ -2875,6 +2926,13 @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx) } } +/* + * Return the MMU index for a v7M CPU with all relevant information + * manually specified. + */ +ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env, + bool secstate, bool priv, bool negpri); + /* Return the MMU index for a v7M CPU in the specified security and * privilege state. */ @@ -3102,18 +3160,27 @@ FIELD(TBFLAG_ANY, BE_DATA, 23, 1) FIELD(TBFLAG_A32, THUMB, 0, 1) FIELD(TBFLAG_A32, VECLEN, 1, 3) FIELD(TBFLAG_A32, VECSTRIDE, 4, 2) -FIELD(TBFLAG_A32, VFPEN, 7, 1) -FIELD(TBFLAG_A32, CONDEXEC, 8, 8) -FIELD(TBFLAG_A32, SCTLR_B, 16, 1) -/* We store the bottom two bits of the CPAR as TB flags and handle - * checks on the other bits at runtime +/* + * We store the bottom two bits of the CPAR as TB flags and handle + * checks on the other bits at runtime. This shares the same bits as + * VECSTRIDE, which is OK as no XScale CPU has VFP. */ -FIELD(TBFLAG_A32, XSCALE_CPAR, 17, 2) -/* Indicates whether cp register reads and writes by guest code should access +FIELD(TBFLAG_A32, XSCALE_CPAR, 4, 2) +/* + * Indicates whether cp register reads and writes by guest code should access * the secure or nonsecure bank of banked registers; note that this is not * the same thing as the current security state of the processor! */ -FIELD(TBFLAG_A32, NS, 19, 1) +FIELD(TBFLAG_A32, NS, 6, 1) +FIELD(TBFLAG_A32, VFPEN, 7, 1) +FIELD(TBFLAG_A32, CONDEXEC, 8, 8) +FIELD(TBFLAG_A32, SCTLR_B, 16, 1) +/* For M profile only, set if FPCCR.LSPACT is set */ +FIELD(TBFLAG_A32, LSPACT, 18, 1) +/* For M profile only, set if we must create a new FP context */ +FIELD(TBFLAG_A32, NEW_FP_CTXT_NEEDED, 19, 1) +/* For M profile only, set if FPCCR.S does not match current security state */ +FIELD(TBFLAG_A32, FPCCR_S_WRONG, 20, 1) /* For M profile only, Handler (ie not Thread) mode */ FIELD(TBFLAG_A32, HANDLER, 21, 1) /* For M profile only, whether we should generate stack-limit checks */ diff --git a/target/arm/helper.c b/target/arm/helper.c index 2607d39ad1..81a92ab491 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10,6 +10,7 @@ #include "sysemu/sysemu.h" #include "qemu/bitops.h" #include "qemu/crc32c.h" +#include "qemu/qemu-print.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "arm_ldst.h" @@ -1259,6 +1260,10 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter) int el = arm_current_el(env); uint8_t hpmn = env->cp15.mdcr_el2 & MDCR_HPMN; + if (!arm_feature(env, ARM_FEATURE_PMU)) { + return false; + } + if (!arm_feature(env, ARM_FEATURE_EL2) || (counter < hpmn || counter == 31)) { e = env->cp15.c9_pmcr & PMCRE; @@ -1333,7 +1338,7 @@ static void pmu_update_irq(CPUARMState *env) * etc. can be done logically. This is essentially a no-op if the counter is * not enabled at the time of the call. */ -void pmccntr_op_start(CPUARMState *env) +static void pmccntr_op_start(CPUARMState *env) { uint64_t cycles = cycles_get_count(env); @@ -1363,7 +1368,7 @@ void pmccntr_op_start(CPUARMState *env) * guest-visible count. A call to pmccntr_op_finish should follow every call to * pmccntr_op_start. */ -void pmccntr_op_finish(CPUARMState *env) +static void pmccntr_op_finish(CPUARMState *env) { if (pmu_counter_enabled(env, 31)) { #ifndef CONFIG_USER_ONLY @@ -2665,7 +2670,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { /* per-timer control */ { .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1, .secure = ARM_CP_SECSTATE_NS, - .type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R, + .type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL0_RW, .accessfn = gt_ptimer_access, .fieldoffset = offsetoflow32(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl), @@ -2674,7 +2679,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { { .name = "CNTP_CTL_S", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1, .secure = ARM_CP_SECSTATE_S, - .type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R, + .type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL0_RW, .accessfn = gt_ptimer_access, .fieldoffset = offsetoflow32(CPUARMState, cp15.c14_timer[GTIMER_SEC].ctl), @@ -2682,14 +2687,14 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { }, { .name = "CNTP_CTL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 1, - .type = ARM_CP_IO, .access = PL1_RW | PL0_R, + .type = ARM_CP_IO, .access = PL0_RW, .accessfn = gt_ptimer_access, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl), .resetvalue = 0, .writefn = gt_phys_ctl_write, .raw_writefn = raw_write, }, { .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1, - .type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R, + .type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL0_RW, .accessfn = gt_vtimer_access, .fieldoffset = offsetoflow32(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl), @@ -2697,7 +2702,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { }, { .name = "CNTV_CTL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 1, - .type = ARM_CP_IO, .access = PL1_RW | PL0_R, + .type = ARM_CP_IO, .access = PL0_RW, .accessfn = gt_vtimer_access, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl), .resetvalue = 0, @@ -2706,31 +2711,31 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { /* TimerValue views: a 32 bit downcounting view of the underlying state */ { .name = "CNTP_TVAL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0, .secure = ARM_CP_SECSTATE_NS, - .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, + .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL0_RW, .accessfn = gt_ptimer_access, .readfn = gt_phys_tval_read, .writefn = gt_phys_tval_write, }, { .name = "CNTP_TVAL_S", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0, .secure = ARM_CP_SECSTATE_S, - .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, + .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL0_RW, .accessfn = gt_ptimer_access, .readfn = gt_sec_tval_read, .writefn = gt_sec_tval_write, }, { .name = "CNTP_TVAL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 0, - .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, + .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL0_RW, .accessfn = gt_ptimer_access, .resetfn = gt_phys_timer_reset, .readfn = gt_phys_tval_read, .writefn = gt_phys_tval_write, }, { .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0, - .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, + .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL0_RW, .accessfn = gt_vtimer_access, .readfn = gt_virt_tval_read, .writefn = gt_virt_tval_write, }, { .name = "CNTV_TVAL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 0, - .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, + .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL0_RW, .accessfn = gt_vtimer_access, .resetfn = gt_virt_timer_reset, .readfn = gt_virt_tval_read, .writefn = gt_virt_tval_write, }, @@ -2758,7 +2763,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { /* Comparison value, indicating when the timer goes off */ { .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2, .secure = ARM_CP_SECSTATE_NS, - .access = PL1_RW | PL0_R, + .access = PL0_RW, .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), .accessfn = gt_ptimer_access, @@ -2766,7 +2771,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { }, { .name = "CNTP_CVAL_S", .cp = 15, .crm = 14, .opc1 = 2, .secure = ARM_CP_SECSTATE_S, - .access = PL1_RW | PL0_R, + .access = PL0_RW, .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].cval), .accessfn = gt_ptimer_access, @@ -2774,14 +2779,14 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { }, { .name = "CNTP_CVAL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 2, - .access = PL1_RW | PL0_R, + .access = PL0_RW, .type = ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), .resetvalue = 0, .accessfn = gt_ptimer_access, .writefn = gt_phys_cval_write, .raw_writefn = raw_write, }, { .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3, - .access = PL1_RW | PL0_R, + .access = PL0_RW, .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval), .accessfn = gt_vtimer_access, @@ -2789,7 +2794,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { }, { .name = "CNTV_CVAL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 2, - .access = PL1_RW | PL0_R, + .access = PL0_RW, .type = ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval), .resetvalue = 0, .accessfn = gt_vtimer_access, @@ -6720,29 +6725,23 @@ static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b) static void arm_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - CPUListState *s = user_data; const char *typename; char *name; typename = object_class_get_name(oc); name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_ARM_CPU)); - (*s->cpu_fprintf)(s->file, " %s\n", - name); + qemu_printf(" %s\n", name); g_free(name); } -void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void arm_cpu_list(void) { - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; GSList *list; list = object_class_get_list(TYPE_ARM_CPU, false); list = g_slist_sort(list, arm_cpu_list_compare); - (*cpu_fprintf)(f, "Available CPUs:\n"); - g_slist_foreach(list, arm_cpu_list_entry, &s); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, arm_cpu_list_entry, NULL); g_slist_free(list); } @@ -7379,6 +7378,24 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) g_assert_not_reached(); } +void HELPER(v7m_preserve_fp_state)(CPUARMState *env) +{ + /* translate.c should never generate calls here in user-only mode */ + g_assert_not_reached(); +} + +void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr) +{ + /* translate.c should never generate calls here in user-only mode */ + g_assert_not_reached(); +} + +void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr) +{ + /* translate.c should never generate calls here in user-only mode */ + g_assert_not_reached(); +} + uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) { /* The TT instructions can be used by unprivileged code, but in @@ -7557,8 +7574,37 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, return target_el; } +/* + * Return true if the v7M CPACR permits access to the FPU for the specified + * security state and privilege level. + */ +static bool v7m_cpacr_pass(CPUARMState *env, bool is_secure, bool is_priv) +{ + switch (extract32(env->v7m.cpacr[is_secure], 20, 2)) { + case 0: + case 2: /* UNPREDICTABLE: we treat like 0 */ + return false; + case 1: + return is_priv; + case 3: + return true; + default: + g_assert_not_reached(); + } +} + +/* + * What kind of stack write are we doing? This affects how exceptions + * generated during the stacking are treated. + */ +typedef enum StackingMode { + STACK_NORMAL, + STACK_IGNFAULTS, + STACK_LAZYFP, +} StackingMode; + static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value, - ARMMMUIdx mmu_idx, bool ignfault) + ARMMMUIdx mmu_idx, StackingMode mode) { CPUState *cs = CPU(cpu); CPUARMState *env = &cpu->env; @@ -7576,15 +7622,31 @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value, &attrs, &prot, &page_size, &fi, NULL)) { /* MPU/SAU lookup failed */ if (fi.type == ARMFault_QEMU_SFault) { - qemu_log_mask(CPU_LOG_INT, - "...SecureFault with SFSR.AUVIOL during stacking\n"); - env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVALID_MASK; + if (mode == STACK_LAZYFP) { + qemu_log_mask(CPU_LOG_INT, + "...SecureFault with SFSR.LSPERR " + "during lazy stacking\n"); + env->v7m.sfsr |= R_V7M_SFSR_LSPERR_MASK; + } else { + qemu_log_mask(CPU_LOG_INT, + "...SecureFault with SFSR.AUVIOL " + "during stacking\n"); + env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK; + } + env->v7m.sfsr |= R_V7M_SFSR_SFARVALID_MASK; env->v7m.sfar = addr; exc = ARMV7M_EXCP_SECURE; exc_secure = false; } else { - qemu_log_mask(CPU_LOG_INT, "...MemManageFault with CFSR.MSTKERR\n"); - env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK; + if (mode == STACK_LAZYFP) { + qemu_log_mask(CPU_LOG_INT, + "...MemManageFault with CFSR.MLSPERR\n"); + env->v7m.cfsr[secure] |= R_V7M_CFSR_MLSPERR_MASK; + } else { + qemu_log_mask(CPU_LOG_INT, + "...MemManageFault with CFSR.MSTKERR\n"); + env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK; + } exc = ARMV7M_EXCP_MEM; exc_secure = secure; } @@ -7594,8 +7656,13 @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value, attrs, &txres); if (txres != MEMTX_OK) { /* BusFault trying to write the data */ - qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n"); - env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK; + if (mode == STACK_LAZYFP) { + qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n"); + env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_LSPERR_MASK; + } else { + qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n"); + env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK; + } exc = ARMV7M_EXCP_BUS; exc_secure = false; goto pend_fault; @@ -7610,11 +7677,19 @@ pend_fault: * later if we have two derived exceptions. * The only case when we must not pend the exception but instead * throw it away is if we are doing the push of the callee registers - * and we've already generated a derived exception. Even in this - * case we will still update the fault status registers. + * and we've already generated a derived exception (this is indicated + * by the caller passing STACK_IGNFAULTS). Even in this case we will + * still update the fault status registers. */ - if (!ignfault) { + switch (mode) { + case STACK_NORMAL: armv7m_nvic_set_pending_derived(env->nvic, exc, exc_secure); + break; + case STACK_LAZYFP: + armv7m_nvic_set_pending_lazyfp(env->nvic, exc, exc_secure); + break; + case STACK_IGNFAULTS: + break; } return false; } @@ -7680,6 +7755,97 @@ pend_fault: return false; } +void HELPER(v7m_preserve_fp_state)(CPUARMState *env) +{ + /* + * Preserve FP state (because LSPACT was set and we are about + * to execute an FP instruction). This corresponds to the + * PreserveFPState() pseudocode. + * We may throw an exception if the stacking fails. + */ + ARMCPU *cpu = arm_env_get_cpu(env); + bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; + bool negpri = !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK); + bool is_priv = !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK); + bool splimviol = env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_MASK; + uint32_t fpcar = env->v7m.fpcar[is_secure]; + bool stacked_ok = true; + bool ts = is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK); + bool take_exception; + + /* Take the iothread lock as we are going to touch the NVIC */ + qemu_mutex_lock_iothread(); + + /* Check the background context had access to the FPU */ + if (!v7m_cpacr_pass(env, is_secure, is_priv)) { + armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, is_secure); + env->v7m.cfsr[is_secure] |= R_V7M_CFSR_NOCP_MASK; + stacked_ok = false; + } else if (!is_secure && !extract32(env->v7m.nsacr, 10, 1)) { + armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S); + env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK; + stacked_ok = false; + } + + if (!splimviol && stacked_ok) { + /* We only stack if the stack limit wasn't violated */ + int i; + ARMMMUIdx mmu_idx; + + mmu_idx = arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri); + for (i = 0; i < (ts ? 32 : 16); i += 2) { + uint64_t dn = *aa32_vfp_dreg(env, i / 2); + uint32_t faddr = fpcar + 4 * i; + uint32_t slo = extract64(dn, 0, 32); + uint32_t shi = extract64(dn, 32, 32); + + if (i >= 16) { + faddr += 8; /* skip the slot for the FPSCR */ + } + stacked_ok = stacked_ok && + v7m_stack_write(cpu, faddr, slo, mmu_idx, STACK_LAZYFP) && + v7m_stack_write(cpu, faddr + 4, shi, mmu_idx, STACK_LAZYFP); + } + + stacked_ok = stacked_ok && + v7m_stack_write(cpu, fpcar + 0x40, + vfp_get_fpscr(env), mmu_idx, STACK_LAZYFP); + } + + /* + * We definitely pended an exception, but it's possible that it + * might not be able to be taken now. If its priority permits us + * to take it now, then we must not update the LSPACT or FP regs, + * but instead jump out to take the exception immediately. + * If it's just pending and won't be taken until the current + * handler exits, then we do update LSPACT and the FP regs. + */ + take_exception = !stacked_ok && + armv7m_nvic_can_take_pending_exception(env->nvic); + + qemu_mutex_unlock_iothread(); + + if (take_exception) { + raise_exception_ra(env, EXCP_LAZYFP, 0, 1, GETPC()); + } + + env->v7m.fpccr[is_secure] &= ~R_V7M_FPCCR_LSPACT_MASK; + + if (ts) { + /* Clear s0 to s31 and the FPSCR */ + int i; + + for (i = 0; i < 32; i += 2) { + *aa32_vfp_dreg(env, i / 2) = 0; + } + vfp_set_fpscr(env, 0); + } + /* + * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them + * unchanged. + */ +} + /* Write to v7M CONTROL.SPSEL bit for the specified security bank. * This may change the current stack pointer between Main and Process * stack pointers if it is done for the CONTROL register for the current @@ -7801,6 +7967,9 @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest) /* translate.c should have made BXNS UNDEF unless we're secure */ assert(env->v7m.secure); + if (!(dest & 1)) { + env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK; + } switch_v7m_security_state(env, dest & 1); env->thumb = 1; env->regs[15] = dest & ~1; @@ -7858,6 +8027,7 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) */ write_v7m_exception(env, 1); } + env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK; switch_v7m_security_state(env, 0); env->thumb = 1; env->regs[15] = dest; @@ -7957,6 +8127,21 @@ load_fail: return false; } +static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr) +{ + /* + * Return the integrity signature value for the callee-saves + * stack frame section. @lr is the exception return payload/LR value + * whose FType bit forms bit 0 of the signature if FP is present. + */ + uint32_t sig = 0xfefa125a; + + if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) { + sig |= 1; + } + return sig; +} + static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain, bool ignore_faults) { @@ -7971,6 +8156,8 @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain, bool stacked_ok; uint32_t limit; bool want_psp; + uint32_t sig; + StackingMode smode = ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL; if (dotailchain) { bool mode = lr & R_V7M_EXCRET_MODE_MASK; @@ -8012,24 +8199,17 @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain, /* Write as much of the stack frame as we can. A write failure may * cause us to pend a derived exception. */ + sig = v7m_integrity_sig(env, lr); stacked_ok = - v7m_stack_write(cpu, frameptr, 0xfefa125b, mmu_idx, ignore_faults) && - v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx, - ignore_faults) && - v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx, - ignore_faults) && - v7m_stack_write(cpu, frameptr + 0x10, env->regs[6], mmu_idx, - ignore_faults) && - v7m_stack_write(cpu, frameptr + 0x14, env->regs[7], mmu_idx, - ignore_faults) && - v7m_stack_write(cpu, frameptr + 0x18, env->regs[8], mmu_idx, - ignore_faults) && - v7m_stack_write(cpu, frameptr + 0x1c, env->regs[9], mmu_idx, - ignore_faults) && - v7m_stack_write(cpu, frameptr + 0x20, env->regs[10], mmu_idx, - ignore_faults) && - v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, - ignore_faults); + v7m_stack_write(cpu, frameptr, sig, mmu_idx, smode) && + v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx, smode) && + v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx, smode) && + v7m_stack_write(cpu, frameptr + 0x10, env->regs[6], mmu_idx, smode) && + v7m_stack_write(cpu, frameptr + 0x14, env->regs[7], mmu_idx, smode) && + v7m_stack_write(cpu, frameptr + 0x18, env->regs[8], mmu_idx, smode) && + v7m_stack_write(cpu, frameptr + 0x1c, env->regs[9], mmu_idx, smode) && + v7m_stack_write(cpu, frameptr + 0x20, env->regs[10], mmu_idx, smode) && + v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smode); /* Update SP regardless of whether any of the stack accesses failed. */ *frame_sp_p = frameptr; @@ -8054,6 +8234,14 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain, qemu_log_mask(CPU_LOG_INT, "...taking pending %s exception %d\n", targets_secure ? "secure" : "nonsecure", exc); + if (dotailchain) { + /* Sanitize LR FType and PREFIX bits */ + if (!arm_feature(env, ARM_FEATURE_VFP)) { + lr |= R_V7M_EXCRET_FTYPE_MASK; + } + lr = deposit32(lr, 24, 8, 0xff); + } + if (arm_feature(env, ARM_FEATURE_V8)) { if (arm_feature(env, ARM_FEATURE_M_SECURITY) && (lr & R_V7M_EXCRET_S_MASK)) { @@ -8149,6 +8337,9 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain, switch_v7m_security_state(env, targets_secure); write_v7m_control_spsel(env, 0); arm_clear_exclusive(env); + /* Clear SFPA and FPCA (has no effect if no FPU) */ + env->v7m.control[M_REG_S] &= + ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK); /* Clear IT bits */ env->condexec_bits = 0; env->regs[14] = lr; @@ -8156,6 +8347,187 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain, env->thumb = addr & 1; } +static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr, + bool apply_splim) +{ + /* + * Like the pseudocode UpdateFPCCR: save state in FPCAR and FPCCR + * that we will need later in order to do lazy FP reg stacking. + */ + bool is_secure = env->v7m.secure; + void *nvic = env->nvic; + /* + * Some bits are unbanked and live always in fpccr[M_REG_S]; some bits + * are banked and we want to update the bit in the bank for the + * current security state; and in one case we want to specifically + * update the NS banked version of a bit even if we are secure. + */ + uint32_t *fpccr_s = &env->v7m.fpccr[M_REG_S]; + uint32_t *fpccr_ns = &env->v7m.fpccr[M_REG_NS]; + uint32_t *fpccr = &env->v7m.fpccr[is_secure]; + bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy; + + env->v7m.fpcar[is_secure] = frameptr & ~0x7; + + if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) { + bool splimviol; + uint32_t splim = v7m_sp_limit(env); + bool ign = armv7m_nvic_neg_prio_requested(nvic, is_secure) && + (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK); + + splimviol = !ign && frameptr < splim; + *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol); + } + + *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1); + + *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure); + + *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) == 0); + + *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, THREAD, + !arm_v7m_is_handler_mode(env)); + + hfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false); + *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy); + + bfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false); + *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy); + + mmrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secure); + *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy); + + ns_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, false); + *fpccr_ns = FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy); + + monrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false); + *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy); + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + s_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, true); + *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy); + + sfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, false); + *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, SFRDY, sfrdy); + } +} + +void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr) +{ + /* fptr is the value of Rn, the frame pointer we store the FP regs to */ + bool s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; + bool lspact = env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK; + + assert(env->v7m.secure); + + if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) { + return; + } + + /* Check access to the coprocessor is permitted */ + if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) { + raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC()); + } + + if (lspact) { + /* LSPACT should not be active when there is active FP state */ + raise_exception_ra(env, EXCP_LSERR, 0, 1, GETPC()); + } + + if (fptr & 7) { + raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC()); + } + + /* + * Note that we do not use v7m_stack_write() here, because the + * accesses should not set the FSR bits for stacking errors if they + * fail. (In pseudocode terms, they are AccType_NORMAL, not AccType_STACK + * or AccType_LAZYFP). Faults in cpu_stl_data() will throw exceptions + * and longjmp out. + */ + if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) { + bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK; + int i; + + for (i = 0; i < (ts ? 32 : 16); i += 2) { + uint64_t dn = *aa32_vfp_dreg(env, i / 2); + uint32_t faddr = fptr + 4 * i; + uint32_t slo = extract64(dn, 0, 32); + uint32_t shi = extract64(dn, 32, 32); + + if (i >= 16) { + faddr += 8; /* skip the slot for the FPSCR */ + } + cpu_stl_data(env, faddr, slo); + cpu_stl_data(env, faddr + 4, shi); + } + cpu_stl_data(env, fptr + 0x40, vfp_get_fpscr(env)); + + /* + * If TS is 0 then s0 to s15 and FPSCR are UNKNOWN; we choose to + * leave them unchanged, matching our choice in v7m_preserve_fp_state. + */ + if (ts) { + for (i = 0; i < 32; i += 2) { + *aa32_vfp_dreg(env, i / 2) = 0; + } + vfp_set_fpscr(env, 0); + } + } else { + v7m_update_fpccr(env, fptr, false); + } + + env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK; +} + +void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr) +{ + /* fptr is the value of Rn, the frame pointer we load the FP regs from */ + assert(env->v7m.secure); + + if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) { + return; + } + + /* Check access to the coprocessor is permitted */ + if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) { + raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC()); + } + + if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) { + /* State in FP is still valid */ + env->v7m.fpccr[M_REG_S] &= ~R_V7M_FPCCR_LSPACT_MASK; + } else { + bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK; + int i; + uint32_t fpscr; + + if (fptr & 7) { + raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC()); + } + + for (i = 0; i < (ts ? 32 : 16); i += 2) { + uint32_t slo, shi; + uint64_t dn; + uint32_t faddr = fptr + 4 * i; + + if (i >= 16) { + faddr += 8; /* skip the slot for the FPSCR */ + } + + slo = cpu_ldl_data(env, faddr); + shi = cpu_ldl_data(env, faddr + 4); + + dn = (uint64_t) shi << 32 | slo; + *aa32_vfp_dreg(env, i / 2) = dn; + } + fpscr = cpu_ldl_data(env, fptr + 0x40); + vfp_set_fpscr(env, fpscr); + } + + env->v7m.control[M_REG_S] |= R_V7M_CONTROL_FPCA_MASK; +} + static bool v7m_push_stack(ARMCPU *cpu) { /* Do the "set up stack frame" part of exception entry, @@ -8164,11 +8536,25 @@ static bool v7m_push_stack(ARMCPU *cpu) * should ignore further stack faults trying to process * that derived exception.) */ - bool stacked_ok; + bool stacked_ok = true, limitviol = false; CPUARMState *env = &cpu->env; uint32_t xpsr = xpsr_read(env); uint32_t frameptr = env->regs[13]; ARMMMUIdx mmu_idx = arm_mmu_idx(env); + uint32_t framesize; + bool nsacr_cp10 = extract32(env->v7m.nsacr, 10, 1); + + if ((env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) && + (env->v7m.secure || nsacr_cp10)) { + if (env->v7m.secure && + env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK) { + framesize = 0xa8; + } else { + framesize = 0x68; + } + } else { + framesize = 0x20; + } /* Align stack pointer if the guest wants that */ if ((frameptr & 4) && @@ -8177,7 +8563,13 @@ static bool v7m_push_stack(ARMCPU *cpu) xpsr |= XPSR_SPREALIGN; } - frameptr -= 0x20; + xpsr &= ~XPSR_SFPA; + if (env->v7m.secure && + (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) { + xpsr |= XPSR_SFPA; + } + + frameptr -= framesize; if (arm_feature(env, ARM_FEATURE_V8)) { uint32_t limit = v7m_sp_limit(env); @@ -8195,7 +8587,14 @@ static bool v7m_push_stack(ARMCPU *cpu) armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure); env->regs[13] = limit; - return true; + /* + * We won't try to perform any further memory accesses but + * we must continue through the following code to check for + * permission faults during FPU state preservation, and we + * must update FPCCR if lazy stacking is enabled. + */ + limitviol = true; + stacked_ok = false; } } @@ -8204,18 +8603,99 @@ static bool v7m_push_stack(ARMCPU *cpu) * (which may be taken in preference to the one we started with * if it has higher priority). */ - stacked_ok = - v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, false) && - v7m_stack_write(cpu, frameptr + 4, env->regs[1], mmu_idx, false) && - v7m_stack_write(cpu, frameptr + 8, env->regs[2], mmu_idx, false) && - v7m_stack_write(cpu, frameptr + 12, env->regs[3], mmu_idx, false) && - v7m_stack_write(cpu, frameptr + 16, env->regs[12], mmu_idx, false) && - v7m_stack_write(cpu, frameptr + 20, env->regs[14], mmu_idx, false) && - v7m_stack_write(cpu, frameptr + 24, env->regs[15], mmu_idx, false) && - v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, false); + stacked_ok = stacked_ok && + v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 4, env->regs[1], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 8, env->regs[2], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 12, env->regs[3], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 16, env->regs[12], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 20, env->regs[14], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 24, env->regs[15], + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, STACK_NORMAL); + + if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) { + /* FPU is active, try to save its registers */ + bool fpccr_s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; + bool lspact = env->v7m.fpccr[fpccr_s] & R_V7M_FPCCR_LSPACT_MASK; + + if (lspact && arm_feature(env, ARM_FEATURE_M_SECURITY)) { + qemu_log_mask(CPU_LOG_INT, + "...SecureFault because LSPACT and FPCA both set\n"); + env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + } else if (!env->v7m.secure && !nsacr_cp10) { + qemu_log_mask(CPU_LOG_INT, + "...Secure UsageFault with CFSR.NOCP because " + "NSACR.CP10 prevents stacking FP regs\n"); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S); + env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK; + } else { + if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) { + /* Lazy stacking disabled, save registers now */ + int i; + bool cpacr_pass = v7m_cpacr_pass(env, env->v7m.secure, + arm_current_el(env) != 0); - /* Update SP regardless of whether any of the stack accesses failed. */ - env->regs[13] = frameptr; + if (stacked_ok && !cpacr_pass) { + /* + * Take UsageFault if CPACR forbids access. The pseudocode + * here does a full CheckCPEnabled() but we know the NSACR + * check can never fail as we have already handled that. + */ + qemu_log_mask(CPU_LOG_INT, + "...UsageFault with CFSR.NOCP because " + "CPACR.CP10 prevents stacking FP regs\n"); + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, + env->v7m.secure); + env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK; + stacked_ok = false; + } + + for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) { + uint64_t dn = *aa32_vfp_dreg(env, i / 2); + uint32_t faddr = frameptr + 0x20 + 4 * i; + uint32_t slo = extract64(dn, 0, 32); + uint32_t shi = extract64(dn, 32, 32); + + if (i >= 16) { + faddr += 8; /* skip the slot for the FPSCR */ + } + stacked_ok = stacked_ok && + v7m_stack_write(cpu, faddr, slo, + mmu_idx, STACK_NORMAL) && + v7m_stack_write(cpu, faddr + 4, shi, + mmu_idx, STACK_NORMAL); + } + stacked_ok = stacked_ok && + v7m_stack_write(cpu, frameptr + 0x60, + vfp_get_fpscr(env), mmu_idx, STACK_NORMAL); + if (cpacr_pass) { + for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) { + *aa32_vfp_dreg(env, i / 2) = 0; + } + vfp_set_fpscr(env, 0); + } + } else { + /* Lazy stacking enabled, save necessary info to stack later */ + v7m_update_fpccr(env, frameptr + 0x20, true); + } + } + } + + /* + * If we broke a stack limit then SP was already updated earlier; + * otherwise we update SP regardless of whether any of the stack + * accesses failed or we took some other kind of fault. + */ + if (!limitviol) { + env->regs[13] = frameptr; + } return !stacked_ok; } @@ -8232,6 +8712,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu) bool rettobase = false; bool exc_secure = false; bool return_to_secure; + bool ftype; + bool restore_s16_s31; /* If we're not in Handler mode then jumps to magic exception-exit * addresses don't have magic behaviour. However for the v8M @@ -8269,6 +8751,16 @@ static void do_v7m_exception_exit(ARMCPU *cpu) excret); } + ftype = excret & R_V7M_EXCRET_FTYPE_MASK; + + if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) { + qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception " + "exit PC value 0x%" PRIx32 " is UNPREDICTABLE " + "if FPU not present\n", + excret); + ftype = true; + } + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { /* EXC_RETURN.ES validation check (R_SMFL). We must do this before * we pick which FAULTMASK to clear. @@ -8369,6 +8861,30 @@ static void do_v7m_exception_exit(ARMCPU *cpu) */ write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_secure); + /* + * Clear scratch FP values left in caller saved registers; this + * must happen before any kind of tail chaining. + */ + if ((env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_CLRONRET_MASK) && + (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) { + if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) { + env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing " + "stackframe: error during lazy state deactivation\n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } else { + /* Clear s0..s15 and FPSCR */ + int i; + + for (i = 0; i < 16; i += 2) { + *aa32_vfp_dreg(env, i / 2) = 0; + } + vfp_set_fpscr(env, 0); + } + } + if (sfault) { env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK; armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); @@ -8442,12 +8958,11 @@ static void do_v7m_exception_exit(ARMCPU *cpu) if (return_to_secure && ((excret & R_V7M_EXCRET_ES_MASK) == 0 || (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) { - uint32_t expected_sig = 0xfefa125b; uint32_t actual_sig; pop_ok = v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx); - if (pop_ok && expected_sig != actual_sig) { + if (pop_ok && v7m_integrity_sig(env, excret) != actual_sig) { /* Take a SecureFault on the current stack */ env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK; armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); @@ -8531,8 +9046,105 @@ static void do_v7m_exception_exit(ARMCPU *cpu) } } + if (!ftype) { + /* FP present and we need to handle it */ + if (!return_to_secure && + (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK)) { + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK; + qemu_log_mask(CPU_LOG_INT, + "...taking SecureFault on existing stackframe: " + "Secure LSPACT set but exception return is " + "not to secure state\n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } + + restore_s16_s31 = return_to_secure && + (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK); + + if (env->v7m.fpccr[return_to_secure] & R_V7M_FPCCR_LSPACT_MASK) { + /* State in FPU is still valid, just clear LSPACT */ + env->v7m.fpccr[return_to_secure] &= ~R_V7M_FPCCR_LSPACT_MASK; + } else { + int i; + uint32_t fpscr; + bool cpacr_pass, nsacr_pass; + + cpacr_pass = v7m_cpacr_pass(env, return_to_secure, + return_to_priv); + nsacr_pass = return_to_secure || + extract32(env->v7m.nsacr, 10, 1); + + if (!cpacr_pass) { + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, + return_to_secure); + env->v7m.cfsr[return_to_secure] |= R_V7M_CFSR_NOCP_MASK; + qemu_log_mask(CPU_LOG_INT, + "...taking UsageFault on existing " + "stackframe: CPACR.CP10 prevents unstacking " + "FP regs\n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } else if (!nsacr_pass) { + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, true); + env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_INVPC_MASK; + qemu_log_mask(CPU_LOG_INT, + "...taking Secure UsageFault on existing " + "stackframe: NSACR.CP10 prevents unstacking " + "FP regs\n"); + v7m_exception_taken(cpu, excret, true, false); + return; + } + + for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) { + uint32_t slo, shi; + uint64_t dn; + uint32_t faddr = frameptr + 0x20 + 4 * i; + + if (i >= 16) { + faddr += 8; /* Skip the slot for the FPSCR */ + } + + pop_ok = pop_ok && + v7m_stack_read(cpu, &slo, faddr, mmu_idx) && + v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx); + + if (!pop_ok) { + break; + } + + dn = (uint64_t)shi << 32 | slo; + *aa32_vfp_dreg(env, i / 2) = dn; + } + pop_ok = pop_ok && + v7m_stack_read(cpu, &fpscr, frameptr + 0x60, mmu_idx); + if (pop_ok) { + vfp_set_fpscr(env, fpscr); + } + if (!pop_ok) { + /* + * These regs are 0 if security extension present; + * otherwise merely UNKNOWN. We zero always. + */ + for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) { + *aa32_vfp_dreg(env, i / 2) = 0; + } + vfp_set_fpscr(env, 0); + } + } + } + env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S], + V7M_CONTROL, FPCA, !ftype); + /* Commit to consuming the stack frame */ frameptr += 0x20; + if (!ftype) { + frameptr += 0x48; + if (restore_s16_s31) { + frameptr += 0x40; + } + } /* Undo stack alignment (the SPREALIGN bit indicates that the original * pre-exception SP was not 8-aligned and we added a padding word to * align it, so we undo this by ORing in the bit that increases it @@ -8545,7 +9157,14 @@ static void do_v7m_exception_exit(ARMCPU *cpu) *frame_sp_p = frameptr; } /* This xpsr_write() will invalidate frame_sp_p as it may switch stack */ - xpsr_write(env, xpsr, ~XPSR_SPREALIGN); + xpsr_write(env, xpsr, ~(XPSR_SPREALIGN | XPSR_SFPA)); + + if (env->v7m.secure) { + bool sfpa = xpsr & XPSR_SFPA; + + env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S], + V7M_CONTROL, SFPA, sfpa); + } /* The restored xPSR exception field will be zero if we're * resuming in Thread mode. If that doesn't match what the @@ -8668,6 +9287,9 @@ static void arm_log_exception(int idx) [EXCP_NOCP] = "v7M NOCP UsageFault", [EXCP_INVSTATE] = "v7M INVSTATE UsageFault", [EXCP_STKOF] = "v8M STKOF UsageFault", + [EXCP_LAZYFP] = "v7M exception during lazy FP stacking", + [EXCP_LSERR] = "v8M LSERR UsageFault", + [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault", }; if (idx >= 0 && idx < ARRAY_SIZE(excnames)) { @@ -8786,6 +9408,7 @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu) qemu_log_mask(CPU_LOG_INT, "...really an SG instruction at 0x%08" PRIx32 ", executing it\n", env->regs[15]); env->regs[14] &= ~1; + env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK; switch_v7m_security_state(env, true); xpsr_write(env, 0, XPSR_IT); env->regs[15] += 4; @@ -8816,9 +9439,23 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK; break; case EXCP_NOCP: - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure); - env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK; + { + /* + * NOCP might be directed to something other than the current + * security state if this fault is because of NSACR; we indicate + * the target security state using exception.target_el. + */ + int target_secstate; + + if (env->exception.target_el == 3) { + target_secstate = M_REG_S; + } else { + target_secstate = env->v7m.secure; + } + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secstate); + env->v7m.cfsr[target_secstate] |= R_V7M_CFSR_NOCP_MASK; break; + } case EXCP_INVSTATE: armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure); env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK; @@ -8827,6 +9464,14 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure); env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK; break; + case EXCP_LSERR: + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK; + break; + case EXCP_UNALIGNED: + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure); + env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNALIGNED_MASK; + break; case EXCP_SWI: /* The PC already points to the next instruction. */ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secure); @@ -8946,6 +9591,12 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) return; } break; + case EXCP_LAZYFP: + /* + * We already pended the specific exception in the NVIC in the + * v7m_preserve_fp_state() helper function. + */ + break; default: cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); return; /* Never happens. Keep compiler happy. */ @@ -8953,8 +9604,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) if (arm_feature(env, ARM_FEATURE_V8)) { lr = R_V7M_EXCRET_RES1_MASK | - R_V7M_EXCRET_DCRS_MASK | - R_V7M_EXCRET_FTYPE_MASK; + R_V7M_EXCRET_DCRS_MASK; /* The S bit indicates whether we should return to Secure * or NonSecure (ie our current state). * The ES bit indicates whether we're taking this exception @@ -8969,6 +9619,9 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) if (env->v7m.secure) { lr |= R_V7M_EXCRET_S_MASK; } + if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) { + lr |= R_V7M_EXCRET_FTYPE_MASK; + } } else { lr = R_V7M_EXCRET_RES1_MASK | R_V7M_EXCRET_S_MASK | @@ -11994,7 +12647,14 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) return xpsr_read(env) & mask; break; case 20: /* CONTROL */ - return env->v7m.control[env->v7m.secure]; + { + uint32_t value = env->v7m.control[env->v7m.secure]; + if (!env->v7m.secure) { + /* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank */ + value |= env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK; + } + return value; + } case 0x94: /* CONTROL_NS */ /* We have to handle this here because unprivileged Secure code * can read the NS CONTROL register. @@ -12002,7 +12662,8 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) if (!env->v7m.secure) { return 0; } - return env->v7m.control[M_REG_NS]; + return env->v7m.control[M_REG_NS] | + (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK); } if (el == 0) { @@ -12108,9 +12769,13 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) */ uint32_t mask = extract32(maskreg, 8, 4); uint32_t reg = extract32(maskreg, 0, 8); + int cur_el = arm_current_el(env); - if (arm_current_el(env) == 0 && reg > 7) { - /* only xPSR sub-fields may be written by unprivileged */ + if (cur_el == 0 && reg > 7 && reg != 20) { + /* + * only xPSR sub-fields and CONTROL.SFPA may be written by + * unprivileged code + */ return; } @@ -12169,6 +12834,15 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) env->v7m.control[M_REG_NS] &= ~R_V7M_CONTROL_NPRIV_MASK; env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK; } + /* + * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0, + * RES0 if the FPU is not present, and is stored in the S bank + */ + if (arm_feature(env, ARM_FEATURE_VFP) && + extract32(env->v7m.nsacr, 10, 1)) { + env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK; + env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK; + } return; case 0x98: /* SP_NS */ { @@ -12271,21 +12945,41 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) env->v7m.faultmask[env->v7m.secure] = val & 1; break; case 20: /* CONTROL */ - /* Writing to the SPSEL bit only has an effect if we are in + /* + * Writing to the SPSEL bit only has an effect if we are in * thread mode; other bits can be updated by any privileged code. * write_v7m_control_spsel() deals with updating the SPSEL bit in * env->v7m.control, so we only need update the others. * For v7M, we must just ignore explicit writes to SPSEL in handler * mode; for v8M the write is permitted but will have no effect. + * All these bits are writes-ignored from non-privileged code, + * except for SFPA. */ - if (arm_feature(env, ARM_FEATURE_V8) || - !arm_v7m_is_handler_mode(env)) { + if (cur_el > 0 && (arm_feature(env, ARM_FEATURE_V8) || + !arm_v7m_is_handler_mode(env))) { write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0); } - if (arm_feature(env, ARM_FEATURE_M_MAIN)) { + if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) { env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK; env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK; } + if (arm_feature(env, ARM_FEATURE_VFP)) { + /* + * SFPA is RAZ/WI from NS or if no FPU. + * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present. + * Both are stored in the S bank. + */ + if (env->v7m.secure) { + env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK; + env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK; + } + if (cur_el > 0 && + (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) || + extract32(env->v7m.nsacr, 10, 1))) { + env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK; + env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK; + } + } break; default: bad_reg: @@ -12752,6 +13446,22 @@ int fp_exception_el(CPUARMState *env, int cur_el) return 0; } + if (arm_feature(env, ARM_FEATURE_M)) { + /* CPACR can cause a NOCP UsageFault taken to current security state */ + if (!v7m_cpacr_pass(env, env->v7m.secure, cur_el != 0)) { + return 1; + } + + if (arm_feature(env, ARM_FEATURE_M_SECURITY) && !env->v7m.secure) { + if (!extract32(env->v7m.nsacr, 10, 1)) { + /* FP insns cause a NOCP UsageFault taken to Secure */ + return 3; + } + } + + return 0; + } + /* The CPACR controls traps to EL1, or PL1 if we're 32 bit: * 0, 2 : trap EL0 and EL1/PL1 accesses * 1 : trap only EL0 accesses @@ -12802,8 +13512,8 @@ int fp_exception_el(CPUARMState *env, int cur_el) return 0; } -ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, - bool secstate, bool priv) +ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env, + bool secstate, bool priv, bool negpri) { ARMMMUIdx mmu_idx = ARM_MMU_IDX_M; @@ -12811,7 +13521,7 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, mmu_idx |= ARM_MMU_IDX_M_PRIV; } - if (armv7m_nvic_neg_prio_requested(env->nvic, secstate)) { + if (negpri) { mmu_idx |= ARM_MMU_IDX_M_NEGPRI; } @@ -12822,6 +13532,14 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, return mmu_idx; } +ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, + bool secstate, bool priv) +{ + bool negpri = armv7m_nvic_neg_prio_requested(env->nvic, secstate); + + return arm_v7m_mmu_idx_all(env, secstate, priv, negpri); +} + /* Return the MMU index for a v7M CPU in the specified security state */ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) { @@ -12939,10 +13657,14 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR_B, arm_sctlr_b(env)); flags = FIELD_DP32(flags, TBFLAG_A32, NS, !access_secure_reg(env)); if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30) - || arm_el_is_aa64(env, 1)) { + || arm_el_is_aa64(env, 1) || arm_feature(env, ARM_FEATURE_M)) { flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1); } - flags = FIELD_DP32(flags, TBFLAG_A32, XSCALE_CPAR, env->cp15.c15_cpar); + /* Note that XSCALE_CPAR shares bits with VECSTRIDE */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + flags = FIELD_DP32(flags, TBFLAG_A32, + XSCALE_CPAR, env->cp15.c15_cpar); + } } flags = FIELD_DP32(flags, TBFLAG_ANY, MMUIDX, arm_to_core_mmu_idx(mmu_idx)); @@ -12985,6 +13707,32 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, flags = FIELD_DP32(flags, TBFLAG_A32, STACKCHECK, 1); } + if (arm_feature(env, ARM_FEATURE_M_SECURITY) && + FIELD_EX32(env->v7m.fpccr[M_REG_S], V7M_FPCCR, S) != env->v7m.secure) { + flags = FIELD_DP32(flags, TBFLAG_A32, FPCCR_S_WRONG, 1); + } + + if (arm_feature(env, ARM_FEATURE_M) && + (env->v7m.fpccr[env->v7m.secure] & R_V7M_FPCCR_ASPEN_MASK) && + (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) || + (env->v7m.secure && + !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)))) { + /* + * ASPEN is set, but FPCA/SFPA indicate that there is no active + * FP context; we must create a new FP context before executing + * any FP insn. + */ + flags = FIELD_DP32(flags, TBFLAG_A32, NEW_FP_CTXT_NEEDED, 1); + } + + if (arm_feature(env, ARM_FEATURE_M)) { + bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; + + if (env->v7m.fpccr[is_secure] & R_V7M_FPCCR_LSPACT_MASK) { + flags = FIELD_DP32(flags, TBFLAG_A32, LSPACT, 1); + } + } + *pflags = flags; *cs_base = 0; } diff --git a/target/arm/helper.h b/target/arm/helper.h index a09566f795..50cb036378 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -69,6 +69,11 @@ DEF_HELPER_2(v7m_blxns, void, env, i32) DEF_HELPER_3(v7m_tt, i32, env, i32, i32) +DEF_HELPER_1(v7m_preserve_fp_state, void, env) + +DEF_HELPER_2(v7m_vlstm, void, env, i32) +DEF_HELPER_2(v7m_vlldm, void, env, i32) + DEF_HELPER_2(v8m_stackcheck, void, env, i32) DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32) diff --git a/target/arm/machine.c b/target/arm/machine.c index b292549614..09567d4fc6 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -305,6 +305,21 @@ static const VMStateDescription vmstate_m_v8m = { } }; +static const VMStateDescription vmstate_m_fp = { + .name = "cpu/m/fp", + .version_id = 1, + .minimum_version_id = 1, + .needed = vfp_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(env.v7m.fpcar, ARMCPU, M_REG_NUM_BANKS), + VMSTATE_UINT32_ARRAY(env.v7m.fpccr, ARMCPU, M_REG_NUM_BANKS), + VMSTATE_UINT32_ARRAY(env.v7m.fpdscr, ARMCPU, M_REG_NUM_BANKS), + VMSTATE_UINT32_ARRAY(env.v7m.cpacr, ARMCPU, M_REG_NUM_BANKS), + VMSTATE_UINT32(env.v7m.nsacr, ARMCPU), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_m = { .name = "cpu/m", .version_id = 4, @@ -330,6 +345,7 @@ static const VMStateDescription vmstate_m = { &vmstate_m_scr, &vmstate_m_other_sp, &vmstate_m_v8m, + &vmstate_m_fp, NULL } }; diff --git a/target/arm/trace-events b/target/arm/trace-events index 6b759f9d4f..41c63d7570 100644 --- a/target/arm/trace-events +++ b/target/arm/trace-events @@ -1,6 +1,6 @@ # See docs/devel/tracing.txt for syntax documentation. -# target/arm/helper.c +# helper.c arm_gt_recalc(int timer, int irqstate, uint64_t nexttick) "gt recalc: timer %d irqstate %d next tick 0x%" PRIx64 arm_gt_recalc_disabled(int timer) "gt recalc: timer %d irqstate 0 timer disabled" arm_gt_cval_write(int timer, uint64_t value) "gt_cval_write: timer %d value 0x%" PRIx64 @@ -9,5 +9,5 @@ arm_gt_ctl_write(int timer, uint64_t value) "gt_ctl_write: timer %d value 0x%" P arm_gt_imask_toggle(int timer, int irqstate) "gt_ctl_write: timer %d IMASK toggle, new irqstate %d" arm_gt_cntvoff_write(uint64_t value) "gt_cntvoff_write: value 0x%" PRIx64 -# target/arm/kvm.c +# kvm.c kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64 diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 1959046343..9dcc5ff3a3 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -27,6 +27,7 @@ #include "translate.h" #include "internals.h" #include "qemu/host-utils.h" +#include "qemu/qemu-print.h" #include "exec/semihost.h" #include "exec/gen-icount.h" @@ -151,8 +152,7 @@ static void set_btype(DisasContext *s, int val) s->btype = -1; } -void aarch64_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags) +void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -161,13 +161,13 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int el = arm_current_el(env); const char *ns_status; - cpu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); + qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); for (i = 0; i < 32; i++) { if (i == 31) { - cpu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]); + qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]); } else { - cpu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i], - (i + 2) % 3 ? " " : "\n"); + qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i], + (i + 2) % 3 ? " " : "\n"); } } @@ -176,29 +176,29 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f, } else { ns_status = ""; } - cpu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c", - psr, - psr & PSTATE_N ? 'N' : '-', - psr & PSTATE_Z ? 'Z' : '-', - psr & PSTATE_C ? 'C' : '-', - psr & PSTATE_V ? 'V' : '-', - ns_status, - el, - psr & PSTATE_SP ? 'h' : 't'); + qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c", + psr, + psr & PSTATE_N ? 'N' : '-', + psr & PSTATE_Z ? 'Z' : '-', + psr & PSTATE_C ? 'C' : '-', + psr & PSTATE_V ? 'V' : '-', + ns_status, + el, + psr & PSTATE_SP ? 'h' : 't'); if (cpu_isar_feature(aa64_bti, cpu)) { - cpu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10); + qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10); } if (!(flags & CPU_DUMP_FPU)) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); return; } if (fp_exception_el(env, el) != 0) { - cpu_fprintf(f, " FPU disabled\n"); + qemu_fprintf(f, " FPU disabled\n"); return; } - cpu_fprintf(f, " FPCR=%08x FPSR=%08x\n", - vfp_get_fpcr(env), vfp_get_fpsr(env)); + qemu_fprintf(f, " FPCR=%08x FPSR=%08x\n", + vfp_get_fpcr(env), vfp_get_fpsr(env)); if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) { int j, zcr_len = sve_zcr_len_for_el(env, el); @@ -206,11 +206,11 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f, for (i = 0; i <= FFR_PRED_NUM; i++) { bool eol; if (i == FFR_PRED_NUM) { - cpu_fprintf(f, "FFR="); + qemu_fprintf(f, "FFR="); /* It's last, so end the line. */ eol = true; } else { - cpu_fprintf(f, "P%02d=", i); + qemu_fprintf(f, "P%02d=", i); switch (zcr_len) { case 0: eol = i % 8 == 7; @@ -235,46 +235,46 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f, } else { digits = (zcr_len % 4 + 1) * 4; } - cpu_fprintf(f, "%0*" PRIx64 "%s", digits, - env->vfp.pregs[i].p[j], - j ? ":" : eol ? "\n" : " "); + qemu_fprintf(f, "%0*" PRIx64 "%s", digits, + env->vfp.pregs[i].p[j], + j ? ":" : eol ? "\n" : " "); } } for (i = 0; i < 32; i++) { if (zcr_len == 0) { - cpu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s", - i, env->vfp.zregs[i].d[1], - env->vfp.zregs[i].d[0], i & 1 ? "\n" : " "); + qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s", + i, env->vfp.zregs[i].d[1], + env->vfp.zregs[i].d[0], i & 1 ? "\n" : " "); } else if (zcr_len == 1) { - cpu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 - ":%016" PRIx64 ":%016" PRIx64 "\n", - i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2], - env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]); + qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 + ":%016" PRIx64 ":%016" PRIx64 "\n", + i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2], + env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]); } else { for (j = zcr_len; j >= 0; j--) { bool odd = (zcr_len - j) % 2 != 0; if (j == zcr_len) { - cpu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1); + qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1); } else if (!odd) { if (j > 0) { - cpu_fprintf(f, " [%x-%x]=", j, j - 1); + qemu_fprintf(f, " [%x-%x]=", j, j - 1); } else { - cpu_fprintf(f, " [%x]=", j); + qemu_fprintf(f, " [%x]=", j); } } - cpu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s", - env->vfp.zregs[i].d[j * 2 + 1], - env->vfp.zregs[i].d[j * 2], - odd || j == 0 ? "\n" : ":"); + qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s", + env->vfp.zregs[i].d[j * 2 + 1], + env->vfp.zregs[i].d[j * 2], + odd || j == 0 ? "\n" : ":"); } } } } else { for (i = 0; i < 32; i++) { uint64_t *q = aa64_vfp_qreg(env, i); - cpu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s", - i, q[1], q[0], (i & 1 ? "\n" : " ")); + qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s", + i, q[1], q[0], (i & 1 ? "\n" : " ")); } } } @@ -2510,7 +2510,7 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt, tcg_gen_qemu_ld_i64(d1, clean_addr, memidx, MO_64 | MO_ALIGN_16 | s->be_data); tcg_gen_addi_i64(a2, clean_addr, 8); - tcg_gen_qemu_ld_i64(d2, clean_addr, memidx, MO_64 | s->be_data); + tcg_gen_qemu_ld_i64(d2, a2, memidx, MO_64 | s->be_data); /* Compare the two words, also in memory order. */ tcg_gen_setcond_i64(TCG_COND_EQ, c1, d1, s1); diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 3a2eb51566..245cd82621 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -943,24 +943,30 @@ static bool trans_INDEX_rr(DisasContext *s, arg_INDEX_rr *a) static bool trans_ADDVL(DisasContext *s, arg_ADDVL *a) { - TCGv_i64 rd = cpu_reg_sp(s, a->rd); - TCGv_i64 rn = cpu_reg_sp(s, a->rn); - tcg_gen_addi_i64(rd, rn, a->imm * vec_full_reg_size(s)); + if (sve_access_check(s)) { + TCGv_i64 rd = cpu_reg_sp(s, a->rd); + TCGv_i64 rn = cpu_reg_sp(s, a->rn); + tcg_gen_addi_i64(rd, rn, a->imm * vec_full_reg_size(s)); + } return true; } static bool trans_ADDPL(DisasContext *s, arg_ADDPL *a) { - TCGv_i64 rd = cpu_reg_sp(s, a->rd); - TCGv_i64 rn = cpu_reg_sp(s, a->rn); - tcg_gen_addi_i64(rd, rn, a->imm * pred_full_reg_size(s)); + if (sve_access_check(s)) { + TCGv_i64 rd = cpu_reg_sp(s, a->rd); + TCGv_i64 rn = cpu_reg_sp(s, a->rn); + tcg_gen_addi_i64(rd, rn, a->imm * pred_full_reg_size(s)); + } return true; } static bool trans_RDVL(DisasContext *s, arg_RDVL *a) { - TCGv_i64 reg = cpu_reg(s, a->rd); - tcg_gen_movi_i64(reg, a->imm * vec_full_reg_size(s)); + if (sve_access_check(s)) { + TCGv_i64 reg = cpu_reg(s, a->rd); + tcg_gen_movi_i64(reg, a->imm * vec_full_reg_size(s)); + } return true; } diff --git a/target/arm/translate.c b/target/arm/translate.c index d408e4d7ef..10bc53f91c 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -28,6 +28,7 @@ #include "tcg-op-gvec.h" #include "qemu/log.h" #include "qemu/bitops.h" +#include "qemu/qemu-print.h" #include "arm_ldst.h" #include "exec/semihost.h" @@ -3398,8 +3399,14 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) * for attempts to execute invalid vfp/neon encodings with FP disabled. */ if (s->fp_excp_el) { - gen_exception_insn(s, 4, EXCP_UDEF, - syn_fp_access_trap(1, 0xe, false), s->fp_excp_el); + if (arm_dc_feature(s, ARM_FEATURE_M)) { + gen_exception_insn(s, 4, EXCP_NOCP, syn_uncategorized(), + s->fp_excp_el); + } else { + gen_exception_insn(s, 4, EXCP_UDEF, + syn_fp_access_trap(1, 0xe, false), + s->fp_excp_el); + } return 0; } @@ -3414,6 +3421,73 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) } } + if (arm_dc_feature(s, ARM_FEATURE_M)) { + /* Handle M-profile lazy FP state mechanics */ + + /* Trigger lazy-state preservation if necessary */ + if (s->v7m_lspact) { + /* + * Lazy state saving affects external memory and also the NVIC, + * so we must mark it as an IO operation for icount. + */ + if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } + gen_helper_v7m_preserve_fp_state(cpu_env); + if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + gen_io_end(); + } + /* + * If the preserve_fp_state helper doesn't throw an exception + * then it will clear LSPACT; we don't need to repeat this for + * any further FP insns in this TB. + */ + s->v7m_lspact = false; + } + + /* Update ownership of FP context: set FPCCR.S to match current state */ + if (s->v8m_fpccr_s_wrong) { + TCGv_i32 tmp; + + tmp = load_cpu_field(v7m.fpccr[M_REG_S]); + if (s->v8m_secure) { + tcg_gen_ori_i32(tmp, tmp, R_V7M_FPCCR_S_MASK); + } else { + tcg_gen_andi_i32(tmp, tmp, ~R_V7M_FPCCR_S_MASK); + } + store_cpu_field(tmp, v7m.fpccr[M_REG_S]); + /* Don't need to do this for any further FP insns in this TB */ + s->v8m_fpccr_s_wrong = false; + } + + if (s->v7m_new_fp_ctxt_needed) { + /* + * Create new FP context by updating CONTROL.FPCA, CONTROL.SFPA + * and the FPSCR. + */ + TCGv_i32 control, fpscr; + uint32_t bits = R_V7M_CONTROL_FPCA_MASK; + + fpscr = load_cpu_field(v7m.fpdscr[s->v8m_secure]); + gen_helper_vfp_set_fpscr(cpu_env, fpscr); + tcg_temp_free_i32(fpscr); + /* + * We don't need to arrange to end the TB, because the only + * parts of FPSCR which we cache in the TB flags are the VECLEN + * and VECSTRIDE, and those don't exist for M-profile. + */ + + if (s->v8m_secure) { + bits |= R_V7M_CONTROL_SFPA_MASK; + } + control = load_cpu_field(v7m.control[M_REG_S]); + tcg_gen_ori_i32(control, control, bits); + store_cpu_field(control, v7m.control[M_REG_S]); + /* Don't need to do this for any further FP insns in this TB */ + s->v7m_new_fp_ctxt_needed = false; + } + } + if (extract32(insn, 28, 4) == 0xf) { /* * Encodings with T=1 (Thumb) or unconditional (ARM): @@ -3512,12 +3586,27 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) } } } else { /* !dp */ + bool is_sysreg; + if ((insn & 0x6f) != 0x00) return 1; rn = VFP_SREG_N(insn); + + is_sysreg = extract32(insn, 21, 1); + + if (arm_dc_feature(s, ARM_FEATURE_M)) { + /* + * The only M-profile VFP vmrs/vmsr sysreg is FPSCR. + * Writes to R15 are UNPREDICTABLE; we choose to undef. + */ + if (is_sysreg && (rd == 15 || (rn >> 1) != ARM_VFP_FPSCR)) { + return 1; + } + } + if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ - if (insn & (1 << 21)) { + if (is_sysreg) { /* system register */ rn >>= 1; @@ -3584,7 +3673,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) } } else { /* arm->vfp */ - if (insn & (1 << 21)) { + if (is_sysreg) { rn >>= 1; /* system register */ switch (rn) { @@ -11706,10 +11795,19 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) case 6: case 7: case 14: case 15: /* Coprocessor. */ if (arm_dc_feature(s, ARM_FEATURE_M)) { - /* We don't currently implement M profile FP support, - * so this entire space should give a NOCP fault, with - * the exception of the v8M VLLDM and VLSTM insns, which - * must be NOPs in Secure state and UNDEF in Nonsecure state. + /* 0b111x_11xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx */ + if (extract32(insn, 24, 2) == 3) { + goto illegal_op; /* op0 = 0b11 : unallocated */ + } + + /* + * Decode VLLDM and VLSTM first: these are nonstandard because: + * * if there is no FPU then these insns must NOP in + * Secure state and UNDEF in Nonsecure state + * * if there is an FPU then these insns do not have + * the usual behaviour that disas_vfp_insn() provides of + * being controlled by CPACR/NSACR enable bits or the + * lazy-stacking logic. */ if (arm_dc_feature(s, ARM_FEATURE_V8) && (insn & 0xffa00f00) == 0xec200a00) { @@ -11720,9 +11818,31 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) if (!s->v8m_secure || (insn & 0x0040f0ff)) { goto illegal_op; } - /* Just NOP since FP support is not implemented */ + + if (arm_dc_feature(s, ARM_FEATURE_VFP)) { + TCGv_i32 fptr = load_reg(s, rn); + + if (extract32(insn, 20, 1)) { + gen_helper_v7m_vlldm(cpu_env, fptr); + } else { + gen_helper_v7m_vlstm(cpu_env, fptr); + } + tcg_temp_free_i32(fptr); + + /* End the TB, because we have updated FP control bits */ + s->base.is_jmp = DISAS_UPDATE; + } break; } + if (arm_dc_feature(s, ARM_FEATURE_VFP) && + ((insn >> 8) & 0xe) == 10) { + /* FP, and the CPU supports it */ + if (disas_vfp_insn(s, insn)) { + goto illegal_op; + } + break; + } + /* All other insns: NOCP */ gen_exception_insn(s, 4, EXCP_NOCP, syn_uncategorized(), default_exception_el(s)); @@ -13290,12 +13410,21 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->fp_excp_el = FIELD_EX32(tb_flags, TBFLAG_ANY, FPEXC_EL); dc->vfp_enabled = FIELD_EX32(tb_flags, TBFLAG_A32, VFPEN); dc->vec_len = FIELD_EX32(tb_flags, TBFLAG_A32, VECLEN); - dc->vec_stride = FIELD_EX32(tb_flags, TBFLAG_A32, VECSTRIDE); - dc->c15_cpar = FIELD_EX32(tb_flags, TBFLAG_A32, XSCALE_CPAR); + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + dc->c15_cpar = FIELD_EX32(tb_flags, TBFLAG_A32, XSCALE_CPAR); + dc->vec_stride = 0; + } else { + dc->vec_stride = FIELD_EX32(tb_flags, TBFLAG_A32, VECSTRIDE); + dc->c15_cpar = 0; + } dc->v7m_handler_mode = FIELD_EX32(tb_flags, TBFLAG_A32, HANDLER); dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) && regime_is_secure(env, dc->mmu_idx); dc->v8m_stackcheck = FIELD_EX32(tb_flags, TBFLAG_A32, STACKCHECK); + dc->v8m_fpccr_s_wrong = FIELD_EX32(tb_flags, TBFLAG_A32, FPCCR_S_WRONG); + dc->v7m_new_fp_ctxt_needed = + FIELD_EX32(tb_flags, TBFLAG_A32, NEW_FP_CTXT_NEEDED); + dc->v7m_lspact = FIELD_EX32(tb_flags, TBFLAG_A32, LSPACT); dc->cp_regs = cpu->cp_regs; dc->features = env->features; @@ -13755,7 +13884,7 @@ static const TranslatorOps thumb_translator_ops = { }; /* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb) +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) { DisasContext dc; const TranslatorOps *ops = &arm_translator_ops; @@ -13769,27 +13898,26 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb) } #endif - translator_loop(ops, &dc.base, cpu, tb); + translator_loop(ops, &dc.base, cpu, tb, max_insns); } -void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; int i; if (is_a64(env)) { - aarch64_cpu_dump_state(cs, f, cpu_fprintf, flags); + aarch64_cpu_dump_state(cs, f, flags); return; } for(i=0;i<16;i++) { - cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); + qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]); if ((i % 4) == 3) - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); else - cpu_fprintf(f, " "); + qemu_fprintf(f, " "); } if (arm_feature(env, ARM_FEATURE_M)) { @@ -13811,15 +13939,15 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, } } - cpu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n", - xpsr, - xpsr & XPSR_N ? 'N' : '-', - xpsr & XPSR_Z ? 'Z' : '-', - xpsr & XPSR_C ? 'C' : '-', - xpsr & XPSR_V ? 'V' : '-', - xpsr & XPSR_T ? 'T' : 'A', - ns_status, - mode); + qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n", + xpsr, + xpsr & XPSR_N ? 'N' : '-', + xpsr & XPSR_Z ? 'Z' : '-', + xpsr & XPSR_C ? 'C' : '-', + xpsr & XPSR_V ? 'V' : '-', + xpsr & XPSR_T ? 'T' : 'A', + ns_status, + mode); } else { uint32_t psr = cpsr_read(env); const char *ns_status = ""; @@ -13829,15 +13957,15 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S "; } - cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n", - psr, - psr & CPSR_N ? 'N' : '-', - psr & CPSR_Z ? 'Z' : '-', - psr & CPSR_C ? 'C' : '-', - psr & CPSR_V ? 'V' : '-', - psr & CPSR_T ? 'T' : 'A', - ns_status, - aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26); + qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n", + psr, + psr & CPSR_N ? 'N' : '-', + psr & CPSR_Z ? 'Z' : '-', + psr & CPSR_C ? 'C' : '-', + psr & CPSR_V ? 'V' : '-', + psr & CPSR_T ? 'T' : 'A', + ns_status, + aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26); } if (flags & CPU_DUMP_FPU) { @@ -13850,12 +13978,12 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, } for (i = 0; i < numvfpregs; i++) { uint64_t v = *aa32_vfp_dreg(env, i); - cpu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n", - i * 2, (uint32_t)v, - i * 2 + 1, (uint32_t)(v >> 32), - i, v); + qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n", + i * 2, (uint32_t)v, + i * 2 + 1, (uint32_t)(v >> 32), + i, v); } - cpu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env)); + qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env)); } } diff --git a/target/arm/translate.h b/target/arm/translate.h index 912cc2a4a5..c2348def0d 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -40,6 +40,9 @@ typedef struct DisasContext { bool v7m_handler_mode; bool v8m_secure; /* true if v8M and we're in Secure mode */ bool v8m_stackcheck; /* true if we need to perform v8M stack limit checks */ + bool v8m_fpccr_s_wrong; /* true if v8M FPCCR.S != v8m_secure */ + bool v7m_new_fp_ctxt_needed; /* ASPEN set but no active FP context */ + bool v7m_lspact; /* FPCCR.LSPACT set */ /* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI * so that top level loop can generate correct syndrome information. */ @@ -166,8 +169,7 @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) #ifdef TARGET_AARCH64 void a64_translate_init(void); void gen_a64_set_pc_im(uint64_t val); -void aarch64_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags); +void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags); extern const TranslatorOps aarch64_translator_ops; #else static inline void a64_translate_init(void) @@ -178,9 +180,7 @@ static inline void gen_a64_set_pc_im(uint64_t val) { } -static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, - int flags) +static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) { } #endif diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index 2468fc1629..7a46d99148 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -105,6 +105,14 @@ void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val) val &= ~FPCR_FZ16; } + if (arm_feature(env, ARM_FEATURE_M)) { + /* + * M profile FPSCR is RES0 for the QC, STRIDE, FZ16, LEN bits + * and also for the trapped-exception-handling bits IxE. + */ + val &= 0xf7c0009f; + } + /* * We don't implement trapped exception handling, so the * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!) diff --git a/target/cris/cpu.c b/target/cris/cpu.c index a23aba2688..75729bfdd5 100644 --- a/target/cris/cpu.c +++ b/target/cris/cpu.c @@ -23,6 +23,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/qemu-print.h" #include "cpu.h" #include "qemu-common.h" #include "mmu.h" @@ -103,27 +104,22 @@ static gint cris_cpu_list_compare(gconstpointer a, gconstpointer b) static void cris_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - CPUListState *s = user_data; const char *typename = object_class_get_name(oc); char *name; name = g_strndup(typename, strlen(typename) - strlen(CRIS_CPU_TYPE_SUFFIX)); - (*s->cpu_fprintf)(s->file, " %s\n", name); + qemu_printf(" %s\n", name); g_free(name); } -void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void cris_cpu_list(void) { - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; GSList *list; list = object_class_get_list(TYPE_CRIS_CPU, false); list = g_slist_sort(list, cris_cpu_list_compare); - (*cpu_fprintf)(f, "Available CPUs:\n"); - g_slist_foreach(list, cris_cpu_list_entry, &s); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, cris_cpu_list_entry, NULL); g_slist_free(list); } diff --git a/target/cris/cpu.h b/target/cris/cpu.h index 8bb1dbc989..0fbe771639 100644 --- a/target/cris/cpu.h +++ b/target/cris/cpu.h @@ -207,8 +207,7 @@ void cris_cpu_do_interrupt(CPUState *cpu); void crisv10_cpu_do_interrupt(CPUState *cpu); bool cris_cpu_exec_interrupt(CPUState *cpu, int int_req); -void cris_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags); +void cris_cpu_dump_state(CPUState *cs, FILE *f, int flags); hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); @@ -308,6 +307,6 @@ static inline void cpu_get_tb_cpu_state(CPUCRISState *env, target_ulong *pc, } #define cpu_list cris_cpu_list -void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void cris_cpu_list(void); #endif diff --git a/target/cris/helper.c b/target/cris/helper.c index b2dbb2075c..3939603c73 100644 --- a/target/cris/helper.c +++ b/target/cris/helper.c @@ -60,7 +60,7 @@ int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, cs->exception_index = 0xaa; cpu->env.pregs[PR_EDA] = address; - cpu_dump_state(cs, stderr, fprintf, 0); + cpu_dump_state(cs, stderr, 0); return 1; } diff --git a/target/cris/translate.c b/target/cris/translate.c index 11b2c11174..b005a5c20e 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -33,6 +33,7 @@ #include "exec/cpu_ldst.h" #include "exec/translator.h" #include "crisv32-decode.h" +#include "qemu/qemu-print.h" #include "exec/helper-gen.h" @@ -3080,7 +3081,7 @@ static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc) */ /* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { CPUCRISState *env = cs->env_ptr; uint32_t pc_start; @@ -3090,7 +3091,6 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) uint32_t page_start; target_ulong npc; int num_insns; - int max_insns; if (env->pregs[PR_VR] == 32) { dc->decoder = crisv32_decoder; @@ -3136,13 +3136,6 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) page_start = pc_start & TARGET_PAGE_MASK; num_insns = 0; - max_insns = tb_cflags(tb) & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } gen_tb_start(tb); do { @@ -3299,8 +3292,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) #endif } -void cris_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void cris_cpu_dump_state(CPUState *cs, FILE *f, int flags) { CRISCPU *cpu = CRIS_CPU(cs); CPUCRISState *env = &cpu->env; @@ -3308,7 +3300,7 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, const char **pregnames; int i; - if (!env || !f) { + if (!env) { return; } if (env->pregs[PR_VR] < 32) { @@ -3319,40 +3311,40 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, regnames = regnames_v32; } - cpu_fprintf(f, "PC=%x CCS=%x btaken=%d btarget=%x\n" - "cc_op=%d cc_src=%d cc_dest=%d cc_result=%x cc_mask=%x\n", - env->pc, env->pregs[PR_CCS], env->btaken, env->btarget, - env->cc_op, - env->cc_src, env->cc_dest, env->cc_result, env->cc_mask); + qemu_fprintf(f, "PC=%x CCS=%x btaken=%d btarget=%x\n" + "cc_op=%d cc_src=%d cc_dest=%d cc_result=%x cc_mask=%x\n", + env->pc, env->pregs[PR_CCS], env->btaken, env->btarget, + env->cc_op, + env->cc_src, env->cc_dest, env->cc_result, env->cc_mask); for (i = 0; i < 16; i++) { - cpu_fprintf(f, "%s=%8.8x ", regnames[i], env->regs[i]); + qemu_fprintf(f, "%s=%8.8x ", regnames[i], env->regs[i]); if ((i + 1) % 4 == 0) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } - cpu_fprintf(f, "\nspecial regs:\n"); + qemu_fprintf(f, "\nspecial regs:\n"); for (i = 0; i < 16; i++) { - cpu_fprintf(f, "%s=%8.8x ", pregnames[i], env->pregs[i]); + qemu_fprintf(f, "%s=%8.8x ", pregnames[i], env->pregs[i]); if ((i + 1) % 4 == 0) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } if (env->pregs[PR_VR] >= 32) { uint32_t srs = env->pregs[PR_SRS]; - cpu_fprintf(f, "\nsupport function regs bank %x:\n", srs); + qemu_fprintf(f, "\nsupport function regs bank %x:\n", srs); if (srs < ARRAY_SIZE(env->sregs)) { for (i = 0; i < 16; i++) { - cpu_fprintf(f, "s%2.2d=%8.8x ", - i, env->sregs[srs][i]); + qemu_fprintf(f, "s%2.2d=%8.8x ", + i, env->sregs[srs][i]); if ((i + 1) % 4 == 0) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } } } - cpu_fprintf(f, "\n\n"); + qemu_fprintf(f, "\n\n"); } diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 00bf444620..e64f48581e 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/qemu-print.h" #include "cpu.h" #include "qemu-common.h" #include "exec/exec-all.h" @@ -113,22 +114,17 @@ static void hppa_cpu_realizefn(DeviceState *dev, Error **errp) static void hppa_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - CPUListState *s = user_data; - (*s->cpu_fprintf)(s->file, " %s\n", object_class_get_name(oc)); + qemu_printf(" %s\n", object_class_get_name(oc)); } -void hppa_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void hppa_cpu_list(void) { - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; GSList *list; list = object_class_get_list_sorted(TYPE_HPPA_CPU, false); - (*cpu_fprintf)(f, "Available CPUs:\n"); - g_slist_foreach(list, hppa_cpu_list_entry, &s); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, hppa_cpu_list_entry, NULL); g_slist_free(list); } diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 861bbb1f16..923346adb6 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -143,6 +143,10 @@ #endif #define CR_RC 0 +#define CR_PID1 8 +#define CR_PID2 9 +#define CR_PID3 12 +#define CR_PID4 13 #define CR_SCRCCR 10 #define CR_SAR 11 #define CR_IVA 14 @@ -268,7 +272,7 @@ void hppa_translate_init(void); #define CPU_RESOLVING_TYPE TYPE_HPPA_CPU -void hppa_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void hppa_cpu_list(void); static inline target_ulong hppa_form_gva_psw(target_ureg psw, uint64_t spc, target_ureg off) @@ -341,6 +345,12 @@ target_ureg cpu_hppa_get_psw(CPUHPPAState *env); void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg); void cpu_hppa_loaded_fr0(CPUHPPAState *env); +#ifdef CONFIG_USER_ONLY +static inline void cpu_hppa_change_prot_id(CPUHPPAState *env) { } +#else +void cpu_hppa_change_prot_id(CPUHPPAState *env); +#endif + #define cpu_signal_handler cpu_hppa_signal_handler int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc); @@ -349,7 +359,7 @@ int hppa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); void hppa_cpu_do_interrupt(CPUState *cpu); bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req); -void hppa_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function, int); +void hppa_cpu_dump_state(CPUState *cs, FILE *f, int); #ifdef CONFIG_USER_ONLY int hppa_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, int rw, int midx); diff --git a/target/hppa/gdbstub.c b/target/hppa/gdbstub.c index 3157a690f2..983bf92aaf 100644 --- a/target/hppa/gdbstub.c +++ b/target/hppa/gdbstub.c @@ -93,19 +93,19 @@ int hppa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) val = env->cr[CR_RC]; break; case 52: - val = env->cr[8]; + val = env->cr[CR_PID1]; break; case 53: - val = env->cr[9]; + val = env->cr[CR_PID2]; break; case 54: val = env->cr[CR_SCRCCR]; break; case 55: - val = env->cr[12]; + val = env->cr[CR_PID3]; break; case 56: - val = env->cr[13]; + val = env->cr[CR_PID4]; break; case 57: val = env->cr[24]; @@ -224,19 +224,23 @@ int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->cr[CR_RC] = val; break; case 52: - env->cr[8] = val; + env->cr[CR_PID1] = val; + cpu_hppa_change_prot_id(env); break; case 53: - env->cr[9] = val; + env->cr[CR_PID2] = val; + cpu_hppa_change_prot_id(env); break; case 54: env->cr[CR_SCRCCR] = val; break; case 55: - env->cr[12] = val; + env->cr[CR_PID3] = val; + cpu_hppa_change_prot_id(env); break; case 56: - env->cr[13] = val; + env->cr[CR_PID4] = val; + cpu_hppa_change_prot_id(env); break; case 57: env->cr[24] = val; diff --git a/target/hppa/helper.c b/target/hppa/helper.c index 6539061e52..11c61b3ca2 100644 --- a/target/hppa/helper.c +++ b/target/hppa/helper.c @@ -21,7 +21,9 @@ #include "cpu.h" #include "fpu/softfloat.h" +#include "exec/exec-all.h" #include "exec/helper-proto.h" +#include "qemu/qemu-print.h" target_ureg cpu_hppa_get_psw(CPUHPPAState *env) { @@ -49,6 +51,7 @@ target_ureg cpu_hppa_get_psw(CPUHPPAState *env) void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw) { + target_ureg old_psw = env->psw; target_ureg cb = 0; env->psw = psw & ~(PSW_N | PSW_V | PSW_CB); @@ -64,10 +67,17 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw) cb |= ((psw >> 9) & 1) << 8; cb |= ((psw >> 8) & 1) << 4; env->psw_cb = cb; + + /* If PSW_P changes, it affects how we translate addresses. */ + if ((psw ^ old_psw) & PSW_P) { +#ifndef CONFIG_USER_ONLY + CPUState *src = CPU(hppa_env_get_cpu(env)); + tlb_flush_by_mmuidx(src, 0xf); +#endif + } } -void hppa_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags) +void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags) { HPPACPU *cpu = HPPA_CPU(cs); CPUHPPAState *env = &cpu->env; @@ -76,9 +86,9 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, char psw_c[20]; int i; - cpu_fprintf(f, "IA_F " TARGET_FMT_lx " IA_B " TARGET_FMT_lx "\n", - hppa_form_gva_psw(psw, env->iasq_f, env->iaoq_f), - hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b)); + qemu_fprintf(f, "IA_F " TARGET_FMT_lx " IA_B " TARGET_FMT_lx "\n", + hppa_form_gva_psw(psw, env->iasq_f, env->iaoq_f), + hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b)); psw_c[0] = (psw & PSW_W ? 'W' : '-'); psw_c[1] = (psw & PSW_E ? 'E' : '-'); @@ -101,20 +111,20 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, psw_c[18] = '\0'; psw_cb = ((env->psw_cb >> 4) & 0x01111111) | (env->psw_cb_msb << 28); - cpu_fprintf(f, "PSW " TREG_FMT_lx " CB " TREG_FMT_lx " %s\n", - psw, psw_cb, psw_c); + qemu_fprintf(f, "PSW " TREG_FMT_lx " CB " TREG_FMT_lx " %s\n", + psw, psw_cb, psw_c); for (i = 0; i < 32; i++) { - cpu_fprintf(f, "GR%02d " TREG_FMT_lx "%c", i, env->gr[i], - (i & 3) == 3 ? '\n' : ' '); + qemu_fprintf(f, "GR%02d " TREG_FMT_lx "%c", i, env->gr[i], + (i & 3) == 3 ? '\n' : ' '); } #ifndef CONFIG_USER_ONLY for (i = 0; i < 8; i++) { - cpu_fprintf(f, "SR%02d %08x%c", i, (uint32_t)(env->sr[i] >> 32), - (i & 3) == 3 ? '\n' : ' '); + qemu_fprintf(f, "SR%02d %08x%c", i, (uint32_t)(env->sr[i] >> 32), + (i & 3) == 3 ? '\n' : ' '); } #endif - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); /* ??? FR */ } diff --git a/target/hppa/helper.h b/target/hppa/helper.h index bfe0dd1db1..38d834ef6b 100644 --- a/target/hppa/helper.h +++ b/target/hppa/helper.h @@ -92,4 +92,5 @@ DEF_HELPER_FLAGS_3(itlbp, TCG_CALL_NO_RWG, void, env, tl, tr) DEF_HELPER_FLAGS_2(ptlb, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_1(ptlbe, TCG_CALL_NO_RWG, void, env) DEF_HELPER_FLAGS_2(lpa, TCG_CALL_NO_WG, tr, env, tl) +DEF_HELPER_FLAGS_1(change_prot_id, TCG_CALL_NO_RWG, void, env) #endif diff --git a/target/hppa/insns.decode b/target/hppa/insns.decode index 55ff39dd05..f0dd71dd08 100644 --- a/target/hppa/insns.decode +++ b/target/hppa/insns.decode @@ -133,6 +133,9 @@ ixtlbx 000001 b:5 r:5 sp:2 0100000 addr:1 0 00000 data=1 ixtlbx 000001 b:5 r:5 ... 000000 addr:1 0 00000 \ sp=%assemble_sr3x data=0 +# pcxl and pcxl2 Fast TLB Insert instructions +ixtlbxf 000001 00000 r:5 00 0 data:1 01000 addr:1 0 00000 + pxtlbx 000001 b:5 x:5 sp:2 0100100 local:1 m:1 ----- data=1 pxtlbx 000001 b:5 x:5 ... 000100 local:1 m:1 ----- \ sp=%assemble_sr3x data=0 @@ -525,3 +528,6 @@ fmpy_d 001110 ..... ..... 010 ..... ... ..... @f0e_d_3 fdiv_d 001110 ..... ..... 011 ..... ... ..... @f0e_d_3 xmpyu 001110 ..... ..... 010 .0111 .00 t:5 r1=%ra64 r2=%rb64 + +# diag +diag 000101 ----- ----- ---- ---- ---- ---- diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c index aecf3075f6..77fb544838 100644 --- a/target/hppa/mem_helper.c +++ b/target/hppa/mem_helper.c @@ -22,6 +22,7 @@ #include "exec/exec-all.h" #include "exec/helper-proto.h" #include "qom/cpu.h" +#include "trace.h" #ifdef CONFIG_USER_ONLY int hppa_cpu_handle_mmu_fault(CPUState *cs, vaddr address, @@ -43,9 +44,12 @@ static hppa_tlb_entry *hppa_find_tlb(CPUHPPAState *env, vaddr addr) for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) { hppa_tlb_entry *ent = &env->tlb[i]; if (ent->va_b <= addr && addr <= ent->va_e) { + trace_hppa_tlb_find_entry(env, ent + i, ent->entry_valid, + ent->va_b, ent->va_e, ent->pa); return ent; } } + trace_hppa_tlb_find_entry_not_found(env, addr); return NULL; } @@ -55,6 +59,8 @@ static void hppa_flush_tlb_ent(CPUHPPAState *env, hppa_tlb_entry *ent) unsigned i, n = 1 << (2 * ent->page_size); uint64_t addr = ent->va_b; + trace_hppa_tlb_flush_ent(env, ent, ent->va_b, ent->va_e, ent->pa); + for (i = 0; i < n; ++i, addr += TARGET_PAGE_SIZE) { /* Do not flush MMU_PHYS_IDX. */ tlb_flush_page_by_mmuidx(cs, addr, 0xf); @@ -96,9 +102,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, if (ent == NULL || !ent->entry_valid) { phys = 0; prot = 0; - /* ??? Unconditionally report data tlb miss, - even if this is an instruction fetch. */ - ret = EXCP_DTLB_MISS; + ret = (type == PAGE_EXEC) ? EXCP_ITLB_MISS : EXCP_DTLB_MISS; goto egress; } @@ -127,7 +131,20 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, break; } - /* ??? Check PSW_P and ent->access_prot. This can remove PAGE_WRITE. */ + /* access_id == 0 means public page and no check is performed */ + if ((env->psw & PSW_P) && ent->access_id) { + /* If bits [31:1] match, and bit 0 is set, suppress write. */ + int match = ent->access_id * 2 + 1; + + if (match == env->cr[CR_PID1] || match == env->cr[CR_PID2] || + match == env->cr[CR_PID3] || match == env->cr[CR_PID4]) { + prot &= PAGE_READ | PAGE_EXEC; + if (type == PAGE_WRITE) { + ret = EXCP_DMPI; + goto egress; + } + } + } /* No guest access type indicates a non-architectural access from within QEMU. Bypass checks for access, D, B and T bits. */ @@ -137,8 +154,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, if (unlikely(!(prot & type))) { /* The access isn't allowed -- Inst/Data Memory Protection Fault. */ - ret = (type & PAGE_EXEC ? EXCP_IMP : - prot & PAGE_READ ? EXCP_DMP : EXCP_DMAR); + ret = (type & PAGE_EXEC) ? EXCP_IMP : EXCP_DMAR; goto egress; } @@ -171,6 +187,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, egress: *pphys = phys; *pprot = prot; + trace_hppa_tlb_get_physical_address(env, ret, prot, addr, phys); return ret; } @@ -200,6 +217,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size, MMUAccessType type, int mmu_idx, uintptr_t retaddr) { HPPACPU *cpu = HPPA_CPU(cs); + CPUHPPAState *env = &cpu->env; int prot, excp, a_prot; hwaddr phys; @@ -215,9 +233,10 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size, break; } - excp = hppa_get_physical_address(&cpu->env, addr, mmu_idx, + excp = hppa_get_physical_address(env, addr, mmu_idx, a_prot, &phys, &prot); if (unlikely(excp >= 0)) { + trace_hppa_tlb_fill_excp(env, addr, size, type, mmu_idx); /* Failure. Raise the indicated exception. */ cs->exception_index = excp; if (cpu->env.psw & PSW_Q) { @@ -228,6 +247,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size, cpu_loop_exit_restore(cs, retaddr); } + trace_hppa_tlb_fill_success(env, addr & TARGET_PAGE_MASK, + phys & TARGET_PAGE_MASK, size, type, mmu_idx); /* Success! Store the translation into the QEMU TLB. */ tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK, prot, mmu_idx, TARGET_PAGE_SIZE); @@ -242,11 +263,13 @@ void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg) /* Zap any old entries covering ADDR; notice empty entries on the way. */ for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) { hppa_tlb_entry *ent = &env->tlb[i]; - if (!ent->entry_valid) { - empty = ent; - } else if (ent->va_b <= addr && addr <= ent->va_e) { - hppa_flush_tlb_ent(env, ent); - empty = ent; + if (ent->va_b <= addr && addr <= ent->va_e) { + if (ent->entry_valid) { + hppa_flush_tlb_ent(env, ent); + } + if (!empty) { + empty = ent; + } } } @@ -259,6 +282,7 @@ void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg) empty->va_b = addr & TARGET_PAGE_MASK; empty->va_e = empty->va_b + TARGET_PAGE_SIZE - 1; empty->pa = extract32(reg, 5, 20) << TARGET_PAGE_BITS; + trace_hppa_tlb_itlba(env, empty, empty->va_b, empty->va_e, empty->pa); } /* Insert (Insn/Data) TLB Protection. Note this is PA 1.1 only. */ @@ -266,7 +290,7 @@ void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg) { hppa_tlb_entry *ent = hppa_find_tlb(env, addr); - if (unlikely(ent == NULL || ent->entry_valid)) { + if (unlikely(ent == NULL)) { qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n"); return; } @@ -280,6 +304,8 @@ void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg) ent->d = extract32(reg, 28, 1); ent->t = extract32(reg, 29, 1); ent->entry_valid = 1; + trace_hppa_tlb_itlbp(env, ent, ent->access_id, ent->u, ent->ar_pl2, + ent->ar_pl1, ent->ar_type, ent->b, ent->d, ent->t); } /* Purge (Insn/Data) TLB. This is explicitly page-based, and is @@ -299,6 +325,7 @@ void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr) { CPUState *src = CPU(hppa_env_get_cpu(env)); CPUState *cpu; + trace_hppa_tlb_ptlb(env); run_on_cpu_data data = RUN_ON_CPU_TARGET_PTR(addr); CPU_FOREACH(cpu) { @@ -314,11 +341,24 @@ void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr) void HELPER(ptlbe)(CPUHPPAState *env) { CPUState *src = CPU(hppa_env_get_cpu(env)); - + trace_hppa_tlb_ptlbe(env); memset(env->tlb, 0, sizeof(env->tlb)); tlb_flush_by_mmuidx(src, 0xf); } +void cpu_hppa_change_prot_id(CPUHPPAState *env) +{ + if (env->psw & PSW_P) { + CPUState *src = CPU(hppa_env_get_cpu(env)); + tlb_flush_by_mmuidx(src, 0xf); + } +} + +void HELPER(change_prot_id)(CPUHPPAState *env) +{ + cpu_hppa_change_prot_id(env); +} + target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr) { hwaddr phys; @@ -335,8 +375,10 @@ target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr) if (excp == EXCP_DTLB_MISS) { excp = EXCP_NA_DTLB_MISS; } + trace_hppa_tlb_lpa_failed(env, addr); hppa_dynamic_excp(env, excp, GETPC()); } + trace_hppa_tlb_lpa_success(env, addr, phys); return phys; } diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index 268caaaa20..a55a5dfc02 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -25,6 +25,7 @@ #include "sysemu/sysemu.h" #include "qemu/timer.h" #include "fpu/softfloat.h" +#include "trace.h" void QEMU_NORETURN HELPER(excp)(CPUHPPAState *env, int excp) { @@ -165,6 +166,7 @@ target_ureg HELPER(probe)(CPUHPPAState *env, target_ulong addr, int prot, excp; hwaddr phys; + trace_hppa_tlb_probe(addr, level, want); /* Fail if the requested privilege level is higher than current. */ if (level < (env->iaoq_f & 3)) { return 0; @@ -676,11 +678,6 @@ target_ureg HELPER(swap_system_mask)(CPUHPPAState *env, target_ureg nsm) void HELPER(rfi)(CPUHPPAState *env) { - /* ??? On second reading this condition simply seems - to be undefined rather than a diagnosed trap. */ - if (env->psw & (PSW_I | PSW_R | PSW_Q)) { - helper_excp(env, EXCP_ILL); - } env->iasq_f = (uint64_t)env->cr[CR_IIASQ] << 32; env->iasq_b = (uint64_t)env->cr_back[0] << 32; env->iaoq_f = env->cr[CR_IIAOQ]; diff --git a/target/hppa/trace-events b/target/hppa/trace-events new file mode 100644 index 0000000000..0731ce7ce1 --- /dev/null +++ b/target/hppa/trace-events @@ -0,0 +1,18 @@ +# See docs/devel/tracing.txt for syntax documentation. + +# mem_helper.c +disable hppa_tlb_flush_ent(void *env, void *ent, uint64_t va_b, uint64_t va_e, uint64_t pa) "env=%p ent=%p va_b=0x%lx va_e=0x%lx pa=0x%lx" +disable hppa_tlb_find_entry(void *env, void *ent, int valid, uint64_t va_b, uint64_t va_e, uint64_t pa) "env=%p ent=%p valid=%d va_b=0x%lx va_e=0x%lx pa=0x%lx" +disable hppa_tlb_find_entry_not_found(void *env, uint64_t addr) "env=%p addr=%08lx" +disable hppa_tlb_get_physical_address(void *env, int ret, int prot, uint64_t addr, uint64_t phys) "env=%p ret=%d prot=%d addr=0x%lx phys=0x%lx" +disable hppa_tlb_fill_excp(void *env, uint64_t addr, int size, int type, int mmu_idx) "env=%p addr=0x%lx size=%d type=%d mmu_idx=%d" +disable hppa_tlb_fill_success(void *env, uint64_t addr, uint64_t phys, int size, int type, int mmu_idx) "env=%p addr=0x%lx phys=0x%lx size=%d type=%d mmu_idx=%d" +disable hppa_tlb_itlba(void *env, void *ent, uint64_t va_b, uint64_t va_e, uint64_t pa) "env=%p ent=%p va_b=0x%lx va_e=0x%lx pa=0x%lx" +disable hppa_tlb_itlbp(void *env, void *ent, int access_id, int u, int pl2, int pl1, int type, int b, int d, int t) "env=%p ent=%p access_id=%x u=%d pl2=%d pl1=%d type=%d b=%d d=%d t=%d" +disable hppa_tlb_ptlb(void *env) "env=%p" +disable hppa_tlb_ptlbe(void *env) "env=%p" +disable hppa_tlb_lpa_success(void *env, uint64_t addr, uint64_t phys) "env=%p addr=0x%lx phys=0x%lx" +disable hppa_tlb_lpa_failed(void *env, uint64_t addr) "env=%p addr=0x%lx" + +# op_helper.c +disable hppa_tlb_probe(uint64_t addr, int level, int want) "addr=0x%lx level=%d want=%d" diff --git a/target/hppa/translate.c b/target/hppa/translate.c index dc5636fe94..e1febdfea1 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -347,6 +347,7 @@ static int expand_shl11(int val) /* Similarly, but we want to return to the main loop immediately to recognize unmasked interrupts. */ #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2 +#define DISAS_EXIT DISAS_TARGET_3 /* global register indexes */ static TCGv_reg cpu_gr[32]; @@ -816,12 +817,10 @@ static bool gen_illegal(DisasContext *ctx) static bool use_goto_tb(DisasContext *ctx, target_ureg dest) { - /* Suppress goto_tb in the case of single-steping and IO. */ - if ((tb_cflags(ctx->base.tb) & CF_LAST_IO) - || ctx->base.singlestep_enabled) { - return false; - } - return true; + /* Suppress goto_tb for page crossing, IO, or single-steping. */ + return !(((ctx->base.pc_first ^ dest) & TARGET_PAGE_MASK) + || (tb_cflags(ctx->base.tb) & CF_LAST_IO) + || ctx->base.singlestep_enabled); } /* If the next insn is to be nullified, and it's on the same page, @@ -2258,6 +2257,16 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); break; + case CR_PID1: + case CR_PID2: + case CR_PID3: + case CR_PID4: + tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl])); +#ifndef CONFIG_USER_ONLY + gen_helper_change_prot_id(cpu_env); +#endif + break; + default: tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl])); break; @@ -2474,9 +2483,8 @@ static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) gen_helper_itlbp(cpu_env, addr, reg); } - /* Exit TB for ITLB change if mmu is enabled. This *should* not be - the case, since the OS TLB fill handler runs with mmu disabled. */ - if (!a->data && (ctx->tb_flags & PSW_C)) { + /* Exit TB for TLB change if mmu is enabled. */ + if (ctx->tb_flags & PSW_C) { ctx->base.is_jmp = DISAS_IAQ_N_STALE; } return nullify_end(ctx); @@ -2503,7 +2511,61 @@ static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a) } /* Exit TB for TLB change if mmu is enabled. */ - if (!a->data && (ctx->tb_flags & PSW_C)) { + if (ctx->tb_flags & PSW_C) { + ctx->base.is_jmp = DISAS_IAQ_N_STALE; + } + return nullify_end(ctx); +#endif +} + +/* + * Implement the pcxl and pcxl2 Fast TLB Insert instructions. + * See + * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf + * page 13-9 (195/206) + */ +static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) +{ + CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); +#ifndef CONFIG_USER_ONLY + TCGv_tl addr, atl, stl; + TCGv_reg reg; + + nullify_over(ctx); + + /* + * FIXME: + * if (not (pcxl or pcxl2)) + * return gen_illegal(ctx); + * + * Note for future: these are 32-bit systems; no hppa64. + */ + + atl = tcg_temp_new_tl(); + stl = tcg_temp_new_tl(); + addr = tcg_temp_new_tl(); + + tcg_gen_ld32u_i64(stl, cpu_env, + a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) + : offsetof(CPUHPPAState, cr[CR_IIASQ])); + tcg_gen_ld32u_i64(atl, cpu_env, + a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) + : offsetof(CPUHPPAState, cr[CR_IIAOQ])); + tcg_gen_shli_i64(stl, stl, 32); + tcg_gen_or_tl(addr, atl, stl); + tcg_temp_free_tl(atl); + tcg_temp_free_tl(stl); + + reg = load_gpr(ctx, a->r); + if (a->addr) { + gen_helper_itlba(cpu_env, addr, reg); + } else { + gen_helper_itlbp(cpu_env, addr, reg); + } + tcg_temp_free_tl(addr); + + /* Exit TB for TLB change if mmu is enabled. */ + if (ctx->tb_flags & PSW_C) { ctx->base.is_jmp = DISAS_IAQ_N_STALE; } return nullify_end(ctx); @@ -3033,7 +3095,7 @@ static bool do_addb(DisasContext *ctx, unsigned r, TCGv_reg in1, DisasCond cond; in2 = load_gpr(ctx, r); - dest = dest_gpr(ctx, r); + dest = tcg_temp_new(); sv = NULL; cb_msb = NULL; @@ -3049,6 +3111,8 @@ static bool do_addb(DisasContext *ctx, unsigned r, TCGv_reg in1, } cond = do_cond(c * 2 + f, dest, cb_msb, sv); + save_gpr(ctx, r, dest); + tcg_temp_free(dest); return do_cbranch(ctx, disp, n, &cond); } @@ -3446,6 +3510,8 @@ static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) { target_ureg dest = iaoq_dest(ctx, a->disp); + nullify_over(ctx); + /* Make sure the caller hasn't done something weird with the queue. * ??? This is not quite the same as the PSW[B] bit, which would be * expensive to track. Real hardware will trap for @@ -3483,7 +3549,16 @@ static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) } #endif - return do_dbranch(ctx, dest, a->l, a->n); + if (a->l) { + TCGv_reg tmp = dest_gpr(ctx, a->l); + if (ctx->privilege < 3) { + tcg_gen_andi_reg(tmp, tmp, -4); + } + tcg_gen_ori_reg(tmp, tmp, ctx->privilege); + save_gpr(ctx, a->l, tmp); + } + + return do_dbranch(ctx, dest, 0, a->n); } static bool trans_blr(DisasContext *ctx, arg_blr *a) @@ -4048,6 +4123,13 @@ static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) return nullify_end(ctx); } +static bool trans_diag(DisasContext *ctx, arg_diag *a) +{ + qemu_log_mask(LOG_UNIMP, "DIAG opcode ignored\n"); + cond_free(&ctx->null_cond); + return true; +} + static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); @@ -4191,19 +4273,31 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) ctx->iaoq_b = ctx->iaoq_n; ctx->base.pc_next += 4; - if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) { - return; - } - if (ctx->iaoq_f == -1) { - tcg_gen_mov_reg(cpu_iaoq_f, cpu_iaoq_b); - copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); + switch (ret) { + case DISAS_NORETURN: + case DISAS_IAQ_N_UPDATED: + break; + + case DISAS_NEXT: + case DISAS_IAQ_N_STALE: + case DISAS_IAQ_N_STALE_EXIT: + if (ctx->iaoq_f == -1) { + tcg_gen_mov_reg(cpu_iaoq_f, cpu_iaoq_b); + copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); #ifndef CONFIG_USER_ONLY - tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); + tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); #endif - nullify_save(ctx); - ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; - } else if (ctx->iaoq_b == -1) { - tcg_gen_mov_reg(cpu_iaoq_b, ctx->iaoq_n_var); + nullify_save(ctx); + ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT + ? DISAS_EXIT + : DISAS_IAQ_N_UPDATED); + } else if (ctx->iaoq_b == -1) { + tcg_gen_mov_reg(cpu_iaoq_b, ctx->iaoq_n_var); + } + break; + + default: + g_assert_not_reached(); } } @@ -4225,11 +4319,12 @@ static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) case DISAS_IAQ_N_UPDATED: if (ctx->base.singlestep_enabled) { gen_excp_1(EXCP_DEBUG); - } else if (is_jmp == DISAS_IAQ_N_STALE_EXIT) { - tcg_gen_exit_tb(NULL, 0); - } else { + } else if (is_jmp != DISAS_IAQ_N_STALE_EXIT) { tcg_gen_lookup_and_goto_ptr(); } + /* FALLTHRU */ + case DISAS_EXIT: + tcg_gen_exit_tb(NULL, 0); break; default: g_assert_not_reached(); @@ -4271,11 +4366,10 @@ static const TranslatorOps hppa_tr_ops = { .disas_log = hppa_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) - +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { DisasContext ctx; - translator_loop(&hppa_tr_ops, &ctx.base, cs, tb); + translator_loop(&hppa_tr_ops, &ctx.base, cs, tb, max_insns); } void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb, diff --git a/target/i386/cpu.c b/target/i386/cpu.c index d90c01a059..722c5514d4 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -21,6 +21,7 @@ #include "qemu/units.h" #include "qemu/cutils.h" #include "qemu/bitops.h" +#include "qemu/qemu-print.h" #include "cpu.h" #include "exec/exec-all.h" @@ -1089,7 +1090,6 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .reg = R_EDX, }, .tcg_features = TCG_7_0_EDX_FEATURES, - .unmigratable_flags = CPUID_7_0_EDX_ARCH_CAPABILITIES, }, [FEAT_8000_0007_EDX] = { .type = CPUID_FEATURE_WORD, @@ -2533,7 +2533,7 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_AVX512VL | CPUID_7_0_EBX_CLFLUSHOPT, .features[FEAT_7_0_ECX] = - CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_OSPKE | + CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_AVX512VNNI, .features[FEAT_7_0_EDX] = CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_SPEC_CTRL_SSBD, @@ -2586,7 +2586,7 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_7_0_EBX_SMAP, .features[FEAT_7_0_ECX] = CPUID_7_0_ECX_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | - CPUID_7_0_ECX_OSPKE | CPUID_7_0_ECX_VBMI2 | CPUID_7_0_ECX_GFNI | + CPUID_7_0_ECX_VBMI2 | CPUID_7_0_ECX_GFNI | CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | CPUID_7_0_ECX_AVX512_VPOPCNTDQ, @@ -2644,7 +2644,7 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_7_0_EBX_AVX512VL | CPUID_7_0_EBX_CLFLUSHOPT, .features[FEAT_7_0_ECX] = CPUID_7_0_ECX_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | - CPUID_7_0_ECX_OSPKE | CPUID_7_0_ECX_VBMI2 | CPUID_7_0_ECX_GFNI | + CPUID_7_0_ECX_VBMI2 | CPUID_7_0_ECX_GFNI | CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57, @@ -2935,6 +2935,56 @@ static X86CPUDefinition builtin_x86_defs[] = { .model_id = "AMD EPYC Processor (with IBPB)", .cache_info = &epyc_cache_info, }, + { + .name = "Dhyana", + .level = 0xd, + .vendor = CPUID_VENDOR_HYGON, + .family = 24, + .model = 0, + .stepping = 1, + .features[FEAT_1_EDX] = + CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | + CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | + CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | + CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | + CPUID_VME | CPUID_FP87, + .features[FEAT_1_ECX] = + CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | + CPUID_EXT_XSAVE | CPUID_EXT_POPCNT | + CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | + CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | + CPUID_EXT_MONITOR | CPUID_EXT_SSE3, + .features[FEAT_8000_0001_EDX] = + CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | + CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | + CPUID_EXT2_SYSCALL, + .features[FEAT_8000_0001_ECX] = + CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | + CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | + CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM | + CPUID_EXT3_TOPOEXT, + .features[FEAT_8000_0008_EBX] = + CPUID_8000_0008_EBX_IBPB, + .features[FEAT_7_0_EBX] = + CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | + CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED | + CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT, + /* + * Missing: XSAVES (not supported by some Linux versions, + * including v4.1 to v4.12). + * KVM doesn't yet expose any XSAVES state save component. + */ + .features[FEAT_XSAVE] = + CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | + CPUID_XSAVE_XGETBV1, + .features[FEAT_6_EAX] = + CPUID_6_EAX_ARAT, + .features[FEAT_SVM] = + CPUID_SVM_NPT | CPUID_SVM_NRIPSAVE, + .xlevel = 0x8000001E, + .model_id = "Hygon Dhyana Processor", + .cache_info = &epyc_cache_info, + }, }; typedef struct PropValue { @@ -3672,7 +3722,7 @@ static void x86_cpu_class_check_missing_features(X86CPUClass *xcc, /* Print all cpuid feature names in featureset */ -static void listflags(FILE *f, fprintf_function print, GList *features) +static void listflags(GList *features) { size_t len = 0; GList *tmp; @@ -3680,13 +3730,13 @@ static void listflags(FILE *f, fprintf_function print, GList *features) for (tmp = features; tmp; tmp = tmp->next) { const char *name = tmp->data; if ((len + strlen(name) + 1) >= 75) { - print(f, "\n"); + qemu_printf("\n"); len = 0; } - print(f, "%s%s", len == 0 ? " " : " ", name); + qemu_printf("%s%s", len == 0 ? " " : " ", name); len += strlen(name) + 1; } - print(f, "\n"); + qemu_printf("\n"); } /* Sort alphabetically by type name, respecting X86CPUClass::ordering. */ @@ -3722,32 +3772,26 @@ static void x86_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; X86CPUClass *cc = X86_CPU_CLASS(oc); - CPUListState *s = user_data; char *name = x86_cpu_class_get_model_name(cc); const char *desc = cc->model_description; if (!desc && cc->cpu_def) { desc = cc->cpu_def->model_id; } - (*s->cpu_fprintf)(s->file, "x86 %-20s %-48s\n", - name, desc); + qemu_printf("x86 %-20s %-48s\n", name, desc); g_free(name); } /* list available CPU models and flags */ -void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void x86_cpu_list(void) { int i, j; - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; GSList *list; GList *names = NULL; - (*cpu_fprintf)(f, "Available CPUs:\n"); + qemu_printf("Available CPUs:\n"); list = get_sorted_cpu_model_list(); - g_slist_foreach(list, x86_cpu_list_entry, &s); + g_slist_foreach(list, x86_cpu_list_entry, NULL); g_slist_free(list); names = NULL; @@ -3762,9 +3806,9 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf) names = g_list_sort(names, (GCompareFunc)strcmp); - (*cpu_fprintf)(f, "\nRecognized CPUID flags:\n"); - listflags(f, cpu_fprintf, names); - (*cpu_fprintf)(f, "\n"); + qemu_printf("\nRecognized CPUID flags:\n"); + listflags(names); + qemu_printf("\n"); g_list_free(names); } @@ -4547,6 +4591,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 0x8000001D: *eax = 0; + if (cpu->cache_info_passthrough) { + host_cpuid(index, count, eax, ebx, ecx, edx); + break; + } switch (count) { case 0: /* L1 dcache info */ encode_cache_cpuid8000001d(env->cache_info_amd.l1d_cache, cs, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 83fb522554..0128910661 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -726,6 +726,8 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_VENDOR_VIA "CentaurHauls" +#define CPUID_VENDOR_HYGON "HygonGenuine" + #define CPUID_MWAIT_IBE (1U << 1) /* Interrupts can exit capability */ #define CPUID_MWAIT_EMX (1U << 0) /* enumeration supported */ @@ -1521,8 +1523,7 @@ int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, void x86_cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, Error **errp); -void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags); +void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags); hwaddr x86_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); @@ -1532,7 +1533,7 @@ int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); void x86_cpu_exec_enter(CPUState *cpu); void x86_cpu_exec_exit(CPUState *cpu); -void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void x86_cpu_list(void); int cpu_x86_support_mca_broadcast(CPUX86State *env); int cpu_get_pic_interrupt(CPUX86State *s); @@ -1924,8 +1925,7 @@ void enable_compat_apic_id_mode(void); #define APIC_DEFAULT_ADDRESS 0xfee00000 #define APIC_SPACE_SIZE 0x100000 -void x86_cpu_dump_local_apic_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags); +void x86_cpu_dump_local_apic_state(CPUState *cs, int flags); /* cpu.c */ bool cpu_is_bsp(X86CPU *cpu); diff --git a/target/i386/hax-all.c b/target/i386/hax-all.c index b978a9b821..44b89c1d74 100644 --- a/target/i386/hax-all.c +++ b/target/i386/hax-all.c @@ -540,7 +540,7 @@ static int hax_vcpu_hax_exec(CPUArchState *env) ht->_exit_reason); qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); hax_vcpu_sync_state(env, 0); - cpu_dump_state(cpu, stderr, fprintf, 0); + cpu_dump_state(cpu, stderr, 0); ret = -1; break; case HAX_EXIT_HLT: @@ -571,7 +571,7 @@ static int hax_vcpu_hax_exec(CPUArchState *env) fprintf(stderr, "Unknown exit %x from HAX\n", ht->_exit_status); qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); hax_vcpu_sync_state(env, 0); - cpu_dump_state(cpu, stderr, fprintf, 0); + cpu_dump_state(cpu, stderr, 0); ret = 1; break; } diff --git a/target/i386/helper.c b/target/i386/helper.c index e695f8ba7a..96336055f3 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/exec-all.h" +#include "qemu/qemu-print.h" #include "sysemu/kvm.h" #include "kvm_i386.h" #ifndef CONFIG_USER_ONLY @@ -155,38 +156,41 @@ static const char *cc_op_str[CC_OP_NB] = { }; static void -cpu_x86_dump_seg_cache(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf, +cpu_x86_dump_seg_cache(CPUX86State *env, FILE *f, const char *name, struct SegmentCache *sc) { #ifdef TARGET_X86_64 if (env->hflags & HF_CS64_MASK) { - cpu_fprintf(f, "%-3s=%04x %016" PRIx64 " %08x %08x", name, - sc->selector, sc->base, sc->limit, sc->flags & 0x00ffff00); + qemu_fprintf(f, "%-3s=%04x %016" PRIx64 " %08x %08x", name, + sc->selector, sc->base, sc->limit, + sc->flags & 0x00ffff00); } else #endif { - cpu_fprintf(f, "%-3s=%04x %08x %08x %08x", name, sc->selector, - (uint32_t)sc->base, sc->limit, sc->flags & 0x00ffff00); + qemu_fprintf(f, "%-3s=%04x %08x %08x %08x", name, sc->selector, + (uint32_t)sc->base, sc->limit, + sc->flags & 0x00ffff00); } if (!(env->hflags & HF_PE_MASK) || !(sc->flags & DESC_P_MASK)) goto done; - cpu_fprintf(f, " DPL=%d ", (sc->flags & DESC_DPL_MASK) >> DESC_DPL_SHIFT); + qemu_fprintf(f, " DPL=%d ", + (sc->flags & DESC_DPL_MASK) >> DESC_DPL_SHIFT); if (sc->flags & DESC_S_MASK) { if (sc->flags & DESC_CS_MASK) { - cpu_fprintf(f, (sc->flags & DESC_L_MASK) ? "CS64" : - ((sc->flags & DESC_B_MASK) ? "CS32" : "CS16")); - cpu_fprintf(f, " [%c%c", (sc->flags & DESC_C_MASK) ? 'C' : '-', - (sc->flags & DESC_R_MASK) ? 'R' : '-'); + qemu_fprintf(f, (sc->flags & DESC_L_MASK) ? "CS64" : + ((sc->flags & DESC_B_MASK) ? "CS32" : "CS16")); + qemu_fprintf(f, " [%c%c", (sc->flags & DESC_C_MASK) ? 'C' : '-', + (sc->flags & DESC_R_MASK) ? 'R' : '-'); } else { - cpu_fprintf(f, - (sc->flags & DESC_B_MASK || env->hflags & HF_LMA_MASK) - ? "DS " : "DS16"); - cpu_fprintf(f, " [%c%c", (sc->flags & DESC_E_MASK) ? 'E' : '-', - (sc->flags & DESC_W_MASK) ? 'W' : '-'); + qemu_fprintf(f, (sc->flags & DESC_B_MASK + || env->hflags & HF_LMA_MASK) + ? "DS " : "DS16"); + qemu_fprintf(f, " [%c%c", (sc->flags & DESC_E_MASK) ? 'E' : '-', + (sc->flags & DESC_W_MASK) ? 'W' : '-'); } - cpu_fprintf(f, "%c]", (sc->flags & DESC_A_MASK) ? 'A' : '-'); + qemu_fprintf(f, "%c]", (sc->flags & DESC_A_MASK) ? 'A' : '-'); } else { static const char *sys_type_name[2][16] = { { /* 32 bit mode */ @@ -202,13 +206,12 @@ cpu_x86_dump_seg_cache(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf, "Reserved", "IntGate64", "TrapGate64" } }; - cpu_fprintf(f, "%s", - sys_type_name[(env->hflags & HF_LMA_MASK) ? 1 : 0] - [(sc->flags & DESC_TYPE_MASK) - >> DESC_TYPE_SHIFT]); + qemu_fprintf(f, "%s", + sys_type_name[(env->hflags & HF_LMA_MASK) ? 1 : 0] + [(sc->flags & DESC_TYPE_MASK) >> DESC_TYPE_SHIFT]); } done: - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } #ifndef CONFIG_USER_ONLY @@ -231,12 +234,10 @@ static inline const char *dm2str(uint32_t dm) return str[dm]; } -static void dump_apic_lvt(FILE *f, fprintf_function cpu_fprintf, - const char *name, uint32_t lvt, bool is_timer) +static void dump_apic_lvt(const char *name, uint32_t lvt, bool is_timer) { uint32_t dm = (lvt & APIC_LVT_DELIV_MOD) >> APIC_LVT_DELIV_MOD_SHIFT; - cpu_fprintf(f, - "%s\t 0x%08x %s %-5s %-6s %-7s %-12s %-6s", + qemu_printf("%s\t 0x%08x %s %-5s %-6s %-7s %-12s %-6s", name, lvt, lvt & APIC_LVT_INT_POLARITY ? "active-lo" : "active-hi", lvt & APIC_LVT_LEVEL_TRIGGER ? "level" : "edge", @@ -248,9 +249,9 @@ static void dump_apic_lvt(FILE *f, fprintf_function cpu_fprintf, "tsc-deadline" : "one-shot", dm2str(dm)); if (dm != APIC_DM_NMI) { - cpu_fprintf(f, " (vec %u)\n", lvt & APIC_VECTOR_MASK); + qemu_printf(" (vec %u)\n", lvt & APIC_VECTOR_MASK); } else { - cpu_fprintf(f, "\n"); + qemu_printf("\n"); } } @@ -282,8 +283,7 @@ static inline void mask2str(char *str, uint32_t val, uint8_t size) #define MAX_LOGICAL_APIC_ID_MASK_SIZE 16 -static void dump_apic_icr(FILE *f, fprintf_function cpu_fprintf, - APICCommonState *s, CPUX86State *env) +static void dump_apic_icr(APICCommonState *s, CPUX86State *env) { uint32_t icr = s->icr[0], icr2 = s->icr[1]; uint8_t dest_shorthand = \ @@ -293,16 +293,16 @@ static void dump_apic_icr(FILE *f, fprintf_function cpu_fprintf, uint32_t dest_field; bool x2apic; - cpu_fprintf(f, "ICR\t 0x%08x %s %s %s %s\n", + qemu_printf("ICR\t 0x%08x %s %s %s %s\n", icr, logical_mod ? "logical" : "physical", icr & APIC_ICR_TRIGGER_MOD ? "level" : "edge", icr & APIC_ICR_LEVEL ? "assert" : "de-assert", shorthand2str(dest_shorthand)); - cpu_fprintf(f, "ICR2\t 0x%08x", icr2); + qemu_printf("ICR2\t 0x%08x", icr2); if (dest_shorthand != 0) { - cpu_fprintf(f, "\n"); + qemu_printf("\n"); return; } x2apic = env->features[FEAT_1_ECX] & CPUID_EXT_X2APIC; @@ -310,9 +310,9 @@ static void dump_apic_icr(FILE *f, fprintf_function cpu_fprintf, if (!logical_mod) { if (x2apic) { - cpu_fprintf(f, " cpu %u (X2APIC ID)\n", dest_field); + qemu_printf(" cpu %u (X2APIC ID)\n", dest_field); } else { - cpu_fprintf(f, " cpu %u (APIC ID)\n", + qemu_printf(" cpu %u (APIC ID)\n", dest_field & APIC_LOGDEST_XAPIC_ID); } return; @@ -320,87 +320,84 @@ static void dump_apic_icr(FILE *f, fprintf_function cpu_fprintf, if (s->dest_mode == 0xf) { /* flat mode */ mask2str(apic_id_str, icr2 >> APIC_ICR_DEST_SHIFT, 8); - cpu_fprintf(f, " mask %s (APIC ID)\n", apic_id_str); + qemu_printf(" mask %s (APIC ID)\n", apic_id_str); } else if (s->dest_mode == 0) { /* cluster mode */ if (x2apic) { mask2str(apic_id_str, dest_field & APIC_LOGDEST_X2APIC_ID, 16); - cpu_fprintf(f, " cluster %u mask %s (X2APIC ID)\n", + qemu_printf(" cluster %u mask %s (X2APIC ID)\n", dest_field >> APIC_LOGDEST_X2APIC_SHIFT, apic_id_str); } else { mask2str(apic_id_str, dest_field & APIC_LOGDEST_XAPIC_ID, 4); - cpu_fprintf(f, " cluster %u mask %s (APIC ID)\n", + qemu_printf(" cluster %u mask %s (APIC ID)\n", dest_field >> APIC_LOGDEST_XAPIC_SHIFT, apic_id_str); } } } -static void dump_apic_interrupt(FILE *f, fprintf_function cpu_fprintf, - const char *name, uint32_t *ireg_tab, +static void dump_apic_interrupt(const char *name, uint32_t *ireg_tab, uint32_t *tmr_tab) { int i, empty = true; - cpu_fprintf(f, "%s\t ", name); + qemu_printf("%s\t ", name); for (i = 0; i < 256; i++) { if (apic_get_bit(ireg_tab, i)) { - cpu_fprintf(f, "%u%s ", i, + qemu_printf("%u%s ", i, apic_get_bit(tmr_tab, i) ? "(level)" : ""); empty = false; } } - cpu_fprintf(f, "%s\n", empty ? "(none)" : ""); + qemu_printf("%s\n", empty ? "(none)" : ""); } -void x86_cpu_dump_local_apic_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags) +void x86_cpu_dump_local_apic_state(CPUState *cs, int flags) { X86CPU *cpu = X86_CPU(cs); APICCommonState *s = APIC_COMMON(cpu->apic_state); if (!s) { - cpu_fprintf(f, "local apic state not available\n"); + qemu_printf("local apic state not available\n"); return; } uint32_t *lvt = s->lvt; - cpu_fprintf(f, "dumping local APIC state for CPU %-2u\n\n", + qemu_printf("dumping local APIC state for CPU %-2u\n\n", CPU(cpu)->cpu_index); - dump_apic_lvt(f, cpu_fprintf, "LVT0", lvt[APIC_LVT_LINT0], false); - dump_apic_lvt(f, cpu_fprintf, "LVT1", lvt[APIC_LVT_LINT1], false); - dump_apic_lvt(f, cpu_fprintf, "LVTPC", lvt[APIC_LVT_PERFORM], false); - dump_apic_lvt(f, cpu_fprintf, "LVTERR", lvt[APIC_LVT_ERROR], false); - dump_apic_lvt(f, cpu_fprintf, "LVTTHMR", lvt[APIC_LVT_THERMAL], false); - dump_apic_lvt(f, cpu_fprintf, "LVTT", lvt[APIC_LVT_TIMER], true); - - cpu_fprintf(f, "Timer\t DCR=0x%x (divide by %u) initial_count = %u\n", + dump_apic_lvt("LVT0", lvt[APIC_LVT_LINT0], false); + dump_apic_lvt("LVT1", lvt[APIC_LVT_LINT1], false); + dump_apic_lvt("LVTPC", lvt[APIC_LVT_PERFORM], false); + dump_apic_lvt("LVTERR", lvt[APIC_LVT_ERROR], false); + dump_apic_lvt("LVTTHMR", lvt[APIC_LVT_THERMAL], false); + dump_apic_lvt("LVTT", lvt[APIC_LVT_TIMER], true); + + qemu_printf("Timer\t DCR=0x%x (divide by %u) initial_count = %u\n", s->divide_conf & APIC_DCR_MASK, divider_conf(s->divide_conf), s->initial_count); - cpu_fprintf(f, "SPIV\t 0x%08x APIC %s, focus=%s, spurious vec %u\n", + qemu_printf("SPIV\t 0x%08x APIC %s, focus=%s, spurious vec %u\n", s->spurious_vec, s->spurious_vec & APIC_SPURIO_ENABLED ? "enabled" : "disabled", s->spurious_vec & APIC_SPURIO_FOCUS ? "on" : "off", s->spurious_vec & APIC_VECTOR_MASK); - dump_apic_icr(f, cpu_fprintf, s, &cpu->env); + dump_apic_icr(s, &cpu->env); - cpu_fprintf(f, "ESR\t 0x%08x\n", s->esr); + qemu_printf("ESR\t 0x%08x\n", s->esr); - dump_apic_interrupt(f, cpu_fprintf, "ISR", s->isr, s->tmr); - dump_apic_interrupt(f, cpu_fprintf, "IRR", s->irr, s->tmr); + dump_apic_interrupt("ISR", s->isr, s->tmr); + dump_apic_interrupt("IRR", s->irr, s->tmr); - cpu_fprintf(f, "\nAPR 0x%02x TPR 0x%02x DFR 0x%02x LDR 0x%02x", + qemu_printf("\nAPR 0x%02x TPR 0x%02x DFR 0x%02x LDR 0x%02x", s->arb_id, s->tpr, s->dest_mode, s->log_dest); if (s->dest_mode == 0) { - cpu_fprintf(f, "(cluster %u: id %u)", + qemu_printf("(cluster %u: id %u)", s->log_dest >> APIC_LOGDEST_XAPIC_SHIFT, s->log_dest & APIC_LOGDEST_XAPIC_ID); } - cpu_fprintf(f, " PPR 0x%02x\n", apic_get_ppr(s)); + qemu_printf(" PPR 0x%02x\n", apic_get_ppr(s)); } #else -void x86_cpu_dump_local_apic_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags) +void x86_cpu_dump_local_apic_state(CPUState *cs, int flags) { } #endif /* !CONFIG_USER_ONLY */ @@ -408,8 +405,7 @@ void x86_cpu_dump_local_apic_state(CPUState *cs, FILE *f, #define DUMP_CODE_BYTES_TOTAL 50 #define DUMP_CODE_BYTES_BACKWARD 20 -void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; @@ -420,109 +416,107 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, eflags = cpu_compute_eflags(env); #ifdef TARGET_X86_64 if (env->hflags & HF_CS64_MASK) { - cpu_fprintf(f, - "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n" - "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n" - "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n" - "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n" - "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", - env->regs[R_EAX], - env->regs[R_EBX], - env->regs[R_ECX], - env->regs[R_EDX], - env->regs[R_ESI], - env->regs[R_EDI], - env->regs[R_EBP], - env->regs[R_ESP], - env->regs[8], - env->regs[9], - env->regs[10], - env->regs[11], - env->regs[12], - env->regs[13], - env->regs[14], - env->regs[15], - env->eip, eflags, - eflags & DF_MASK ? 'D' : '-', - eflags & CC_O ? 'O' : '-', - eflags & CC_S ? 'S' : '-', - eflags & CC_Z ? 'Z' : '-', - eflags & CC_A ? 'A' : '-', - eflags & CC_P ? 'P' : '-', - eflags & CC_C ? 'C' : '-', - env->hflags & HF_CPL_MASK, - (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, - (env->a20_mask >> 20) & 1, - (env->hflags >> HF_SMM_SHIFT) & 1, - cs->halted); + qemu_fprintf(f, "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n" + "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n" + "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n" + "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n" + "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", + env->regs[R_EAX], + env->regs[R_EBX], + env->regs[R_ECX], + env->regs[R_EDX], + env->regs[R_ESI], + env->regs[R_EDI], + env->regs[R_EBP], + env->regs[R_ESP], + env->regs[8], + env->regs[9], + env->regs[10], + env->regs[11], + env->regs[12], + env->regs[13], + env->regs[14], + env->regs[15], + env->eip, eflags, + eflags & DF_MASK ? 'D' : '-', + eflags & CC_O ? 'O' : '-', + eflags & CC_S ? 'S' : '-', + eflags & CC_Z ? 'Z' : '-', + eflags & CC_A ? 'A' : '-', + eflags & CC_P ? 'P' : '-', + eflags & CC_C ? 'C' : '-', + env->hflags & HF_CPL_MASK, + (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, + (env->a20_mask >> 20) & 1, + (env->hflags >> HF_SMM_SHIFT) & 1, + cs->halted); } else #endif { - cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" - "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", - (uint32_t)env->regs[R_EAX], - (uint32_t)env->regs[R_EBX], - (uint32_t)env->regs[R_ECX], - (uint32_t)env->regs[R_EDX], - (uint32_t)env->regs[R_ESI], - (uint32_t)env->regs[R_EDI], - (uint32_t)env->regs[R_EBP], - (uint32_t)env->regs[R_ESP], - (uint32_t)env->eip, eflags, - eflags & DF_MASK ? 'D' : '-', - eflags & CC_O ? 'O' : '-', - eflags & CC_S ? 'S' : '-', - eflags & CC_Z ? 'Z' : '-', - eflags & CC_A ? 'A' : '-', - eflags & CC_P ? 'P' : '-', - eflags & CC_C ? 'C' : '-', - env->hflags & HF_CPL_MASK, - (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, - (env->a20_mask >> 20) & 1, - (env->hflags >> HF_SMM_SHIFT) & 1, - cs->halted); + qemu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" + "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", + (uint32_t)env->regs[R_EAX], + (uint32_t)env->regs[R_EBX], + (uint32_t)env->regs[R_ECX], + (uint32_t)env->regs[R_EDX], + (uint32_t)env->regs[R_ESI], + (uint32_t)env->regs[R_EDI], + (uint32_t)env->regs[R_EBP], + (uint32_t)env->regs[R_ESP], + (uint32_t)env->eip, eflags, + eflags & DF_MASK ? 'D' : '-', + eflags & CC_O ? 'O' : '-', + eflags & CC_S ? 'S' : '-', + eflags & CC_Z ? 'Z' : '-', + eflags & CC_A ? 'A' : '-', + eflags & CC_P ? 'P' : '-', + eflags & CC_C ? 'C' : '-', + env->hflags & HF_CPL_MASK, + (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, + (env->a20_mask >> 20) & 1, + (env->hflags >> HF_SMM_SHIFT) & 1, + cs->halted); } for(i = 0; i < 6; i++) { - cpu_x86_dump_seg_cache(env, f, cpu_fprintf, seg_name[i], - &env->segs[i]); + cpu_x86_dump_seg_cache(env, f, seg_name[i], &env->segs[i]); } - cpu_x86_dump_seg_cache(env, f, cpu_fprintf, "LDT", &env->ldt); - cpu_x86_dump_seg_cache(env, f, cpu_fprintf, "TR", &env->tr); + cpu_x86_dump_seg_cache(env, f, "LDT", &env->ldt); + cpu_x86_dump_seg_cache(env, f, "TR", &env->tr); #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { - cpu_fprintf(f, "GDT= %016" PRIx64 " %08x\n", - env->gdt.base, env->gdt.limit); - cpu_fprintf(f, "IDT= %016" PRIx64 " %08x\n", - env->idt.base, env->idt.limit); - cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n", - (uint32_t)env->cr[0], - env->cr[2], - env->cr[3], - (uint32_t)env->cr[4]); + qemu_fprintf(f, "GDT= %016" PRIx64 " %08x\n", + env->gdt.base, env->gdt.limit); + qemu_fprintf(f, "IDT= %016" PRIx64 " %08x\n", + env->idt.base, env->idt.limit); + qemu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n", + (uint32_t)env->cr[0], + env->cr[2], + env->cr[3], + (uint32_t)env->cr[4]); for(i = 0; i < 4; i++) - cpu_fprintf(f, "DR%d=%016" PRIx64 " ", i, env->dr[i]); - cpu_fprintf(f, "\nDR6=%016" PRIx64 " DR7=%016" PRIx64 "\n", - env->dr[6], env->dr[7]); + qemu_fprintf(f, "DR%d=%016" PRIx64 " ", i, env->dr[i]); + qemu_fprintf(f, "\nDR6=%016" PRIx64 " DR7=%016" PRIx64 "\n", + env->dr[6], env->dr[7]); } else #endif { - cpu_fprintf(f, "GDT= %08x %08x\n", - (uint32_t)env->gdt.base, env->gdt.limit); - cpu_fprintf(f, "IDT= %08x %08x\n", - (uint32_t)env->idt.base, env->idt.limit); - cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n", - (uint32_t)env->cr[0], - (uint32_t)env->cr[2], - (uint32_t)env->cr[3], - (uint32_t)env->cr[4]); + qemu_fprintf(f, "GDT= %08x %08x\n", + (uint32_t)env->gdt.base, env->gdt.limit); + qemu_fprintf(f, "IDT= %08x %08x\n", + (uint32_t)env->idt.base, env->idt.limit); + qemu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n", + (uint32_t)env->cr[0], + (uint32_t)env->cr[2], + (uint32_t)env->cr[3], + (uint32_t)env->cr[4]); for(i = 0; i < 4; i++) { - cpu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]); + qemu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]); } - cpu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n", - env->dr[6], env->dr[7]); + qemu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n", + env->dr[6], env->dr[7]); } if (flags & CPU_DUMP_CCOP) { if ((unsigned)env->cc_op < CC_OP_NB) @@ -531,55 +525,55 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); #ifdef TARGET_X86_64 if (env->hflags & HF_CS64_MASK) { - cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n", - env->cc_src, env->cc_dst, - cc_op_name); + qemu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n", + env->cc_src, env->cc_dst, + cc_op_name); } else #endif { - cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", - (uint32_t)env->cc_src, (uint32_t)env->cc_dst, - cc_op_name); + qemu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", + (uint32_t)env->cc_src, (uint32_t)env->cc_dst, + cc_op_name); } } - cpu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer); + qemu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer); if (flags & CPU_DUMP_FPU) { int fptag; fptag = 0; for(i = 0; i < 8; i++) { fptag |= ((!env->fptags[i]) << i); } - cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n", - env->fpuc, - (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11, - env->fpstt, - fptag, - env->mxcsr); + qemu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n", + env->fpuc, + (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11, + env->fpstt, + fptag, + env->mxcsr); for(i=0;i<8;i++) { CPU_LDoubleU u; u.d = env->fpregs[i].d; - cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x", - i, u.l.lower, u.l.upper); + qemu_fprintf(f, "FPR%d=%016" PRIx64 " %04x", + i, u.l.lower, u.l.upper); if ((i & 1) == 1) - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); else - cpu_fprintf(f, " "); + qemu_fprintf(f, " "); } if (env->hflags & HF_CS64_MASK) nb = 16; else nb = 8; for(i=0;i<nb;i++) { - cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x", - i, - env->xmm_regs[i].ZMM_L(3), - env->xmm_regs[i].ZMM_L(2), - env->xmm_regs[i].ZMM_L(1), - env->xmm_regs[i].ZMM_L(0)); + qemu_fprintf(f, "XMM%02d=%08x%08x%08x%08x", + i, + env->xmm_regs[i].ZMM_L(3), + env->xmm_regs[i].ZMM_L(2), + env->xmm_regs[i].ZMM_L(1), + env->xmm_regs[i].ZMM_L(0)); if ((i & 1) == 1) - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); else - cpu_fprintf(f, " "); + qemu_fprintf(f, " "); } } if (flags & CPU_DUMP_CODE) { @@ -588,17 +582,17 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, uint8_t code; char codestr[3]; - cpu_fprintf(f, "Code="); + qemu_fprintf(f, "Code="); for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) { if (cpu_memory_rw_debug(cs, base - offs + i, &code, 1, 0) == 0) { snprintf(codestr, sizeof(codestr), "%02x", code); } else { snprintf(codestr, sizeof(codestr), "??"); } - cpu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "", - i == offs ? "<" : "", codestr, i == offs ? ">" : ""); + qemu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "", + i == offs ? "<" : "", codestr, i == offs ? ">" : ""); } - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } diff --git a/target/i386/kvm.c b/target/i386/kvm.c index beae1b99da..3b29ce5c0d 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -389,6 +389,15 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, if (host_tsx_blacklisted()) { ret &= ~(CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_HLE); } + } else if (function == 7 && index == 0 && reg == R_EDX) { + /* + * Linux v4.17-v4.20 incorrectly return ARCH_CAPABILITIES on SVM hosts. + * We can detect the bug by checking if MSR_IA32_ARCH_CAPABILITIES is + * returned by KVM_GET_MSR_INDEX_LIST. + */ + if (!has_msr_arch_capabs) { + ret &= ~CPUID_7_0_EDX_ARCH_CAPABILITIES; + } } else if (function == 0x80000001 && reg == R_ECX) { /* * It's safe to enable TOPOEXT even if it's not returned by diff --git a/target/i386/monitor.c b/target/i386/monitor.c index 74a13c571b..56e2dbece7 100644 --- a/target/i386/monitor.c +++ b/target/i386/monitor.c @@ -664,8 +664,7 @@ void hmp_info_local_apic(Monitor *mon, const QDict *qdict) monitor_printf(mon, "No CPU available\n"); return; } - x86_cpu_dump_local_apic_state(cs, (FILE *)mon, monitor_fprintf, - CPU_DUMP_FPU); + x86_cpu_dump_local_apic_state(cs, CPU_DUMP_FPU); } void hmp_info_io_apic(Monitor *mon, const QDict *qdict) diff --git a/target/i386/sev.c b/target/i386/sev.c index 20b2d325d8..cd77f6b5d4 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -131,6 +131,17 @@ sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size) { int r; struct kvm_enc_region range; + ram_addr_t offset; + MemoryRegion *mr; + + /* + * The RAM device presents a memory region that should be treated + * as IO region and should not be pinned. + */ + mr = memory_region_from_host(host, &offset); + if (mr && memory_region_is_ram_device(mr)) { + return; + } range.addr = (__u64)(unsigned long)host; range.size = size; diff --git a/target/i386/trace-events b/target/i386/trace-events index 6a19a69af5..789c700d4a 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -1,12 +1,12 @@ # See docs/devel/tracing.txt for syntax documentation. -# target/i386/kvm.c +# kvm.c kvm_x86_fixup_msi_error(uint32_t gsi) "VT-d failed to remap interrupt for GSI %" PRIu32 kvm_x86_add_msi_route(int virq) "Adding route entry for virq %d" kvm_x86_remove_msi_route(int virq) "Removing route entry for virq %d" kvm_x86_update_msi_routes(int num) "Updated %d MSI routes" -# target/i386/sev.c +# sev.c kvm_sev_init(void) "" kvm_memcrypt_register_region(void *addr, size_t len) "addr %p len 0x%zu" kvm_memcrypt_unregister_region(void *addr, size_t len) "addr %p len 0x%zu" diff --git a/target/i386/translate.c b/target/i386/translate.c index 49cd298374..77d6b73e42 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -1398,6 +1398,11 @@ static void gen_op(DisasContext *s1, int op, TCGMemOp ot, int d) static void gen_inc(DisasContext *s1, TCGMemOp ot, int d, int c) { if (s1->prefix & PREFIX_LOCK) { + if (d != OR_TMP0) { + /* Lock prefix when destination is not memory */ + gen_illegal_opcode(s1); + return; + } tcg_gen_movi_tl(s1->T0, c > 0 ? 1 : -1); tcg_gen_atomic_add_fetch_tl(s1->T0, s1->A0, s1->T0, s1->mem_index, ot | MO_LE); @@ -8585,11 +8590,11 @@ static const TranslatorOps i386_tr_ops = { }; /* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb) +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) { DisasContext dc; - translator_loop(&i386_tr_ops, &dc.base, cpu, tb); + translator_loop(&i386_tr_ops, &dc.base, cpu, tb, max_insns); } void restore_state_to_opc(CPUX86State *env, TranslationBlock *tb, diff --git a/target/lm32/cpu.c b/target/lm32/cpu.c index b7499cb627..282da19994 100644 --- a/target/lm32/cpu.c +++ b/target/lm32/cpu.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/qemu-print.h" #include "cpu.h" #include "qemu-common.h" @@ -34,27 +35,22 @@ static void lm32_cpu_set_pc(CPUState *cs, vaddr value) static void lm32_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - CPUListState *s = user_data; const char *typename = object_class_get_name(oc); char *name; name = g_strndup(typename, strlen(typename) - strlen(LM32_CPU_TYPE_SUFFIX)); - (*s->cpu_fprintf)(s->file, " %s\n", name); + qemu_printf(" %s\n", name); g_free(name); } -void lm32_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void lm32_cpu_list(void) { - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; GSList *list; list = object_class_get_list_sorted(TYPE_LM32_CPU, false); - (*cpu_fprintf)(f, "Available CPUs:\n"); - g_slist_foreach(list, lm32_cpu_list_entry, &s); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, lm32_cpu_list_entry, NULL); g_slist_free(list); } diff --git a/target/lm32/cpu.h b/target/lm32/cpu.h index 66157eefe9..9b1e6c2d58 100644 --- a/target/lm32/cpu.h +++ b/target/lm32/cpu.h @@ -219,8 +219,7 @@ extern const struct VMStateDescription vmstate_lm32_cpu; void lm32_cpu_do_interrupt(CPUState *cpu); bool lm32_cpu_exec_interrupt(CPUState *cs, int int_req); -void lm32_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, - int flags); +void lm32_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int lm32_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); @@ -243,7 +242,7 @@ static inline lm32_wp_t lm32_wp_type(uint32_t dc, int idx) is returned if the signal was handled by the virtual CPU. */ int cpu_lm32_signal_handler(int host_signum, void *pinfo, void *puc); -void lm32_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void lm32_cpu_list(void); void lm32_translate_init(void); void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value); void QEMU_NORETURN raise_exception(CPULM32State *env, int index); diff --git a/target/lm32/translate.c b/target/lm32/translate.c index b32feb7564..f0e0e7058e 100644 --- a/target/lm32/translate.c +++ b/target/lm32/translate.c @@ -24,6 +24,7 @@ #include "exec/exec-all.h" #include "exec/translator.h" #include "tcg-op.h" +#include "qemu/qemu-print.h" #include "exec/cpu_ldst.h" #include "hw/lm32/lm32_pic.h" @@ -1049,7 +1050,7 @@ static inline void decode(DisasContext *dc, uint32_t ir) } /* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { CPULM32State *env = cs->env_ptr; LM32CPU *cpu = lm32_env_get_cpu(env); @@ -1057,7 +1058,6 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) uint32_t pc_start; uint32_t page_start; int num_insns; - int max_insns; pc_start = tb->pc; dc->features = cpu->features; @@ -1077,13 +1077,6 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) page_start = pc_start & TARGET_PAGE_MASK; num_insns = 0; - max_insns = tb_cflags(tb) & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } gen_tb_start(tb); do { @@ -1161,38 +1154,37 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) #endif } -void lm32_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void lm32_cpu_dump_state(CPUState *cs, FILE *f, int flags) { LM32CPU *cpu = LM32_CPU(cs); CPULM32State *env = &cpu->env; int i; - if (!env || !f) { + if (!env) { return; } - cpu_fprintf(f, "IN: PC=%x %s\n", - env->pc, lookup_symbol(env->pc)); + qemu_fprintf(f, "IN: PC=%x %s\n", + env->pc, lookup_symbol(env->pc)); - cpu_fprintf(f, "ie=%8.8x (IE=%x EIE=%x BIE=%x) im=%8.8x ip=%8.8x\n", - env->ie, - (env->ie & IE_IE) ? 1 : 0, - (env->ie & IE_EIE) ? 1 : 0, - (env->ie & IE_BIE) ? 1 : 0, - lm32_pic_get_im(env->pic_state), - lm32_pic_get_ip(env->pic_state)); - cpu_fprintf(f, "eba=%8.8x deba=%8.8x\n", - env->eba, - env->deba); + qemu_fprintf(f, "ie=%8.8x (IE=%x EIE=%x BIE=%x) im=%8.8x ip=%8.8x\n", + env->ie, + (env->ie & IE_IE) ? 1 : 0, + (env->ie & IE_EIE) ? 1 : 0, + (env->ie & IE_BIE) ? 1 : 0, + lm32_pic_get_im(env->pic_state), + lm32_pic_get_ip(env->pic_state)); + qemu_fprintf(f, "eba=%8.8x deba=%8.8x\n", + env->eba, + env->deba); for (i = 0; i < 32; i++) { - cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); + qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); if ((i + 1) % 4 == 0) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } - cpu_fprintf(f, "\n\n"); + qemu_fprintf(f, "\n\n"); } void restore_state_to_opc(CPULM32State *env, TranslationBlock *tb, diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index f154565117..ad41608341 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -179,8 +179,7 @@ static inline M68kCPU *m68k_env_get_cpu(CPUM68KState *env) void m68k_cpu_do_interrupt(CPUState *cpu); bool m68k_cpu_exec_interrupt(CPUState *cpu, int int_req); -void m68k_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, - int flags); +void m68k_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int m68k_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); @@ -499,7 +498,7 @@ static inline int m68k_feature(CPUM68KState *env, int feature) return (env->features & (1u << feature)) != 0; } -void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void m68k_cpu_list(void); void register_m68k_insns (CPUM68KState *env); @@ -573,5 +572,6 @@ static inline void cpu_get_tb_cpu_state(CPUM68KState *env, target_ulong *pc, } } -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUM68KState *env); +void dump_mmu(CPUM68KState *env); + #endif diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 3e26d337bf..d958a34959 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -22,9 +22,9 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/gdbstub.h" - #include "exec/helper-proto.h" #include "fpu/softfloat.h" +#include "qemu/qemu-print.h" #define SIGNBIT (1u << 31) @@ -49,28 +49,22 @@ static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b) static void m68k_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *c = data; - CPUListState *s = user_data; const char *typename; char *name; typename = object_class_get_name(c); name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU)); - (*s->cpu_fprintf)(s->file, "%s\n", - name); + qemu_printf("%s\n", name); g_free(name); } -void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void m68k_cpu_list(void) { - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; GSList *list; list = object_class_get_list(TYPE_M68K_CPU, false); list = g_slist_sort(list, m68k_cpu_list_compare); - g_slist_foreach(list, m68k_cpu_list_entry, &s); + g_slist_foreach(list, m68k_cpu_list_entry, NULL); g_slist_free(list); } @@ -375,30 +369,28 @@ int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, /* MMU: 68040 only */ -static void print_address_zone(FILE *f, fprintf_function cpu_fprintf, - uint32_t logical, uint32_t physical, +static void print_address_zone(uint32_t logical, uint32_t physical, uint32_t size, int attr) { - cpu_fprintf(f, "%08x - %08x -> %08x - %08x %c ", + qemu_printf("%08x - %08x -> %08x - %08x %c ", logical, logical + size - 1, physical, physical + size - 1, attr & 4 ? 'W' : '-'); size >>= 10; if (size < 1024) { - cpu_fprintf(f, "(%d KiB)\n", size); + qemu_printf("(%d KiB)\n", size); } else { size >>= 10; if (size < 1024) { - cpu_fprintf(f, "(%d MiB)\n", size); + qemu_printf("(%d MiB)\n", size); } else { size >>= 10; - cpu_fprintf(f, "(%d GiB)\n", size); + qemu_printf("(%d GiB)\n", size); } } } -static void dump_address_map(FILE *f, fprintf_function cpu_fprintf, - CPUM68KState *env, uint32_t root_pointer) +static void dump_address_map(CPUM68KState *env, uint32_t root_pointer) { int i, j, k; int tic_size, tic_shift; @@ -460,7 +452,7 @@ static void dump_address_map(FILE *f, fprintf_function cpu_fprintf, if (first_logical != 0xffffffff) { size = last_logical + (1 << tic_shift) - first_logical; - print_address_zone(f, cpu_fprintf, first_logical, + print_address_zone(first_logical, first_physical, size, last_attr); } first_logical = logical; @@ -471,126 +463,125 @@ static void dump_address_map(FILE *f, fprintf_function cpu_fprintf, } if (first_logical != logical || (attr & 4) != (last_attr & 4)) { size = logical + (1 << tic_shift) - first_logical; - print_address_zone(f, cpu_fprintf, first_logical, first_physical, size, - last_attr); + print_address_zone(first_logical, first_physical, size, last_attr); } } #define DUMP_CACHEFLAGS(a) \ switch (a & M68K_DESC_CACHEMODE) { \ case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \ - cpu_fprintf(f, "T"); \ + qemu_printf("T"); \ break; \ case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \ - cpu_fprintf(f, "C"); \ + qemu_printf("C"); \ break; \ case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \ - cpu_fprintf(f, "S"); \ + qemu_printf("S"); \ break; \ case M68K_DESC_CM_NCACHE: /* noncachable */ \ - cpu_fprintf(f, "N"); \ + qemu_printf("N"); \ break; \ } -static void dump_ttr(FILE *f, fprintf_function cpu_fprintf, uint32_t ttr) +static void dump_ttr(uint32_t ttr) { if ((ttr & M68K_TTR_ENABLED) == 0) { - cpu_fprintf(f, "disabled\n"); + qemu_printf("disabled\n"); return; } - cpu_fprintf(f, "Base: 0x%08x Mask: 0x%08x Control: ", + qemu_printf("Base: 0x%08x Mask: 0x%08x Control: ", ttr & M68K_TTR_ADDR_BASE, (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT); switch (ttr & M68K_TTR_SFIELD) { case M68K_TTR_SFIELD_USER: - cpu_fprintf(f, "U"); + qemu_printf("U"); break; case M68K_TTR_SFIELD_SUPER: - cpu_fprintf(f, "S"); + qemu_printf("S"); break; default: - cpu_fprintf(f, "*"); + qemu_printf("*"); break; } DUMP_CACHEFLAGS(ttr); if (ttr & M68K_DESC_WRITEPROT) { - cpu_fprintf(f, "R"); + qemu_printf("R"); } else { - cpu_fprintf(f, "W"); + qemu_printf("W"); } - cpu_fprintf(f, " U: %d\n", (ttr & M68K_DESC_USERATTR) >> + qemu_printf(" U: %d\n", (ttr & M68K_DESC_USERATTR) >> M68K_DESC_USERATTR_SHIFT); } -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUM68KState *env) +void dump_mmu(CPUM68KState *env) { if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { - cpu_fprintf(f, "Translation disabled\n"); + qemu_printf("Translation disabled\n"); return; } - cpu_fprintf(f, "Page Size: "); + qemu_printf("Page Size: "); if (env->mmu.tcr & M68K_TCR_PAGE_8K) { - cpu_fprintf(f, "8kB\n"); + qemu_printf("8kB\n"); } else { - cpu_fprintf(f, "4kB\n"); + qemu_printf("4kB\n"); } - cpu_fprintf(f, "MMUSR: "); + qemu_printf("MMUSR: "); if (env->mmu.mmusr & M68K_MMU_B_040) { - cpu_fprintf(f, "BUS ERROR\n"); + qemu_printf("BUS ERROR\n"); } else { - cpu_fprintf(f, "Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000); + qemu_printf("Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000); /* flags found on the page descriptor */ if (env->mmu.mmusr & M68K_MMU_G_040) { - cpu_fprintf(f, "G"); /* Global */ + qemu_printf("G"); /* Global */ } else { - cpu_fprintf(f, "."); + qemu_printf("."); } if (env->mmu.mmusr & M68K_MMU_S_040) { - cpu_fprintf(f, "S"); /* Supervisor */ + qemu_printf("S"); /* Supervisor */ } else { - cpu_fprintf(f, "."); + qemu_printf("."); } if (env->mmu.mmusr & M68K_MMU_M_040) { - cpu_fprintf(f, "M"); /* Modified */ + qemu_printf("M"); /* Modified */ } else { - cpu_fprintf(f, "."); + qemu_printf("."); } if (env->mmu.mmusr & M68K_MMU_WP_040) { - cpu_fprintf(f, "W"); /* Write protect */ + qemu_printf("W"); /* Write protect */ } else { - cpu_fprintf(f, "."); + qemu_printf("."); } if (env->mmu.mmusr & M68K_MMU_T_040) { - cpu_fprintf(f, "T"); /* Transparent */ + qemu_printf("T"); /* Transparent */ } else { - cpu_fprintf(f, "."); + qemu_printf("."); } if (env->mmu.mmusr & M68K_MMU_R_040) { - cpu_fprintf(f, "R"); /* Resident */ + qemu_printf("R"); /* Resident */ } else { - cpu_fprintf(f, "."); + qemu_printf("."); } - cpu_fprintf(f, " Cache: "); + qemu_printf(" Cache: "); DUMP_CACHEFLAGS(env->mmu.mmusr); - cpu_fprintf(f, " U: %d\n", (env->mmu.mmusr >> 8) & 3); - cpu_fprintf(f, "\n"); + qemu_printf(" U: %d\n", (env->mmu.mmusr >> 8) & 3); + qemu_printf("\n"); } - cpu_fprintf(f, "ITTR0: "); - dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR0]); - cpu_fprintf(f, "ITTR1: "); - dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR1]); - cpu_fprintf(f, "DTTR0: "); - dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR0]); - cpu_fprintf(f, "DTTR1: "); - dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR1]); + qemu_printf("ITTR0: "); + dump_ttr(env->mmu.ttr[M68K_ITTR0]); + qemu_printf("ITTR1: "); + dump_ttr(env->mmu.ttr[M68K_ITTR1]); + qemu_printf("DTTR0: "); + dump_ttr(env->mmu.ttr[M68K_DTTR0]); + qemu_printf("DTTR1: "); + dump_ttr(env->mmu.ttr[M68K_DTTR1]); - cpu_fprintf(f, "SRP: 0x%08x\n", env->mmu.srp); - dump_address_map(f, cpu_fprintf, env, env->mmu.srp); + qemu_printf("SRP: 0x%08x\n", env->mmu.srp); + dump_address_map(env, env->mmu.srp); - cpu_fprintf(f, "URP: 0x%08x\n", env->mmu.urp); - dump_address_map(f, cpu_fprintf, env, env->mmu.urp); + qemu_printf("URP: 0x%08x\n", env->mmu.urp); + dump_address_map(env, env->mmu.urp); } static int check_TTR(uint32_t ttr, int *prot, target_ulong addr, diff --git a/target/m68k/monitor.c b/target/m68k/monitor.c index db582a34ac..2055fe8a00 100644 --- a/target/m68k/monitor.c +++ b/target/m68k/monitor.c @@ -19,7 +19,7 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) return; } - dump_mmu((FILE *)mon, (fprintf_function)monitor_printf, env1); + dump_mmu(env1); } static const MonitorDef monitor_defs[] = { diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 6217a683f1..58596278c2 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -24,6 +24,7 @@ #include "exec/exec-all.h" #include "tcg-op.h" #include "qemu/log.h" +#include "qemu/qemu-print.h" #include "exec/cpu_ldst.h" #include "exec/translator.h" @@ -6169,10 +6170,10 @@ static const TranslatorOps m68k_tr_ops = { .disas_log = m68k_tr_disas_log, }; -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb) +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) { DisasContext dc; - translator_loop(&m68k_tr_ops, &dc.base, cpu, tb); + translator_loop(&m68k_tr_ops, &dc.base, cpu, tb, max_insns); } static double floatx80_to_double(CPUM68KState *env, uint16_t high, uint64_t low) @@ -6187,76 +6188,75 @@ static double floatx80_to_double(CPUM68KState *env, uint16_t high, uint64_t low) return u.d; } -void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void m68k_cpu_dump_state(CPUState *cs, FILE *f, int flags) { M68kCPU *cpu = M68K_CPU(cs); CPUM68KState *env = &cpu->env; int i; uint16_t sr; for (i = 0; i < 8; i++) { - cpu_fprintf(f, "D%d = %08x A%d = %08x " - "F%d = %04x %016"PRIx64" (%12g)\n", - i, env->dregs[i], i, env->aregs[i], - i, env->fregs[i].l.upper, env->fregs[i].l.lower, - floatx80_to_double(env, env->fregs[i].l.upper, - env->fregs[i].l.lower)); - } - cpu_fprintf (f, "PC = %08x ", env->pc); + qemu_fprintf(f, "D%d = %08x A%d = %08x " + "F%d = %04x %016"PRIx64" (%12g)\n", + i, env->dregs[i], i, env->aregs[i], + i, env->fregs[i].l.upper, env->fregs[i].l.lower, + floatx80_to_double(env, env->fregs[i].l.upper, + env->fregs[i].l.lower)); + } + qemu_fprintf(f, "PC = %08x ", env->pc); sr = env->sr | cpu_m68k_get_ccr(env); - cpu_fprintf(f, "SR = %04x T:%x I:%x %c%c %c%c%c%c%c\n", - sr, (sr & SR_T) >> SR_T_SHIFT, (sr & SR_I) >> SR_I_SHIFT, - (sr & SR_S) ? 'S' : 'U', (sr & SR_M) ? '%' : 'I', - (sr & CCF_X) ? 'X' : '-', (sr & CCF_N) ? 'N' : '-', - (sr & CCF_Z) ? 'Z' : '-', (sr & CCF_V) ? 'V' : '-', - (sr & CCF_C) ? 'C' : '-'); - cpu_fprintf(f, "FPSR = %08x %c%c%c%c ", env->fpsr, - (env->fpsr & FPSR_CC_A) ? 'A' : '-', - (env->fpsr & FPSR_CC_I) ? 'I' : '-', - (env->fpsr & FPSR_CC_Z) ? 'Z' : '-', - (env->fpsr & FPSR_CC_N) ? 'N' : '-'); - cpu_fprintf(f, "\n " - "FPCR = %04x ", env->fpcr); + qemu_fprintf(f, "SR = %04x T:%x I:%x %c%c %c%c%c%c%c\n", + sr, (sr & SR_T) >> SR_T_SHIFT, (sr & SR_I) >> SR_I_SHIFT, + (sr & SR_S) ? 'S' : 'U', (sr & SR_M) ? '%' : 'I', + (sr & CCF_X) ? 'X' : '-', (sr & CCF_N) ? 'N' : '-', + (sr & CCF_Z) ? 'Z' : '-', (sr & CCF_V) ? 'V' : '-', + (sr & CCF_C) ? 'C' : '-'); + qemu_fprintf(f, "FPSR = %08x %c%c%c%c ", env->fpsr, + (env->fpsr & FPSR_CC_A) ? 'A' : '-', + (env->fpsr & FPSR_CC_I) ? 'I' : '-', + (env->fpsr & FPSR_CC_Z) ? 'Z' : '-', + (env->fpsr & FPSR_CC_N) ? 'N' : '-'); + qemu_fprintf(f, "\n " + "FPCR = %04x ", env->fpcr); switch (env->fpcr & FPCR_PREC_MASK) { case FPCR_PREC_X: - cpu_fprintf(f, "X "); + qemu_fprintf(f, "X "); break; case FPCR_PREC_S: - cpu_fprintf(f, "S "); + qemu_fprintf(f, "S "); break; case FPCR_PREC_D: - cpu_fprintf(f, "D "); + qemu_fprintf(f, "D "); break; } switch (env->fpcr & FPCR_RND_MASK) { case FPCR_RND_N: - cpu_fprintf(f, "RN "); + qemu_fprintf(f, "RN "); break; case FPCR_RND_Z: - cpu_fprintf(f, "RZ "); + qemu_fprintf(f, "RZ "); break; case FPCR_RND_M: - cpu_fprintf(f, "RM "); + qemu_fprintf(f, "RM "); break; case FPCR_RND_P: - cpu_fprintf(f, "RP "); + qemu_fprintf(f, "RP "); break; } - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); #ifdef CONFIG_SOFTMMU - cpu_fprintf(f, "%sA7(MSP) = %08x %sA7(USP) = %08x %sA7(ISP) = %08x\n", - env->current_sp == M68K_SSP ? "->" : " ", env->sp[M68K_SSP], - env->current_sp == M68K_USP ? "->" : " ", env->sp[M68K_USP], - env->current_sp == M68K_ISP ? "->" : " ", env->sp[M68K_ISP]); - cpu_fprintf(f, "VBR = 0x%08x\n", env->vbr); - cpu_fprintf(f, "SFC = %x DFC %x\n", env->sfc, env->dfc); - cpu_fprintf(f, "SSW %08x TCR %08x URP %08x SRP %08x\n", - env->mmu.ssw, env->mmu.tcr, env->mmu.urp, env->mmu.srp); - cpu_fprintf(f, "DTTR0/1: %08x/%08x ITTR0/1: %08x/%08x\n", - env->mmu.ttr[M68K_DTTR0], env->mmu.ttr[M68K_DTTR1], - env->mmu.ttr[M68K_ITTR0], env->mmu.ttr[M68K_ITTR1]); - cpu_fprintf(f, "MMUSR %08x, fault at %08x\n", - env->mmu.mmusr, env->mmu.ar); + qemu_fprintf(f, "%sA7(MSP) = %08x %sA7(USP) = %08x %sA7(ISP) = %08x\n", + env->current_sp == M68K_SSP ? "->" : " ", env->sp[M68K_SSP], + env->current_sp == M68K_USP ? "->" : " ", env->sp[M68K_USP], + env->current_sp == M68K_ISP ? "->" : " ", env->sp[M68K_ISP]); + qemu_fprintf(f, "VBR = 0x%08x\n", env->vbr); + qemu_fprintf(f, "SFC = %x DFC %x\n", env->sfc, env->dfc); + qemu_fprintf(f, "SSW %08x TCR %08x URP %08x SRP %08x\n", + env->mmu.ssw, env->mmu.tcr, env->mmu.urp, env->mmu.srp); + qemu_fprintf(f, "DTTR0/1: %08x/%08x ITTR0/1: %08x/%08x\n", + env->mmu.ttr[M68K_DTTR0], env->mmu.ttr[M68K_DTTR1], + env->mmu.ttr[M68K_ITTR0], env->mmu.ttr[M68K_ITTR1]); + qemu_fprintf(f, "MMUSR %08x, fault at %08x\n", + env->mmu.mmusr, env->mmu.ar); #endif } diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 792bbc97c7..f20e796865 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -328,8 +328,7 @@ static inline MicroBlazeCPU *mb_env_get_cpu(CPUMBState *env) void mb_cpu_do_interrupt(CPUState *cs); bool mb_cpu_exec_interrupt(CPUState *cs, int int_req); -void mb_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, - int flags); +void mb_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int mb_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index bc753793ec..9848e31d7f 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -42,7 +42,7 @@ int mb_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, int mmu_idx) { cs->exception_index = 0xaa; - cpu_dump_state(cs, stderr, fprintf, 0); + cpu_dump_state(cs, stderr, 0); return 1; } diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 78ca265b04..885fc44b51 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -28,6 +28,7 @@ #include "exec/cpu_ldst.h" #include "exec/helper-gen.h" #include "exec/translator.h" +#include "qemu/qemu-print.h" #include "trace-tcg.h" #include "exec/log.h" @@ -1600,7 +1601,7 @@ static inline void decode(DisasContext *dc, uint32_t ir) } /* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { CPUMBState *env = cs->env_ptr; MicroBlazeCPU *cpu = mb_env_get_cpu(env); @@ -1610,7 +1611,6 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) uint32_t page_start, org_flags; uint32_t npc; int num_insns; - int max_insns; pc_start = tb->pc; dc->cpu = cpu; @@ -1634,13 +1634,6 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) page_start = pc_start & TARGET_PAGE_MASK; num_insns = 0; - max_insns = tb_cflags(tb) & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } gen_tb_start(tb); do @@ -1785,36 +1778,36 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) assert(!dc->abort_at_next_insn); } -void mb_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; int i; - if (!env || !f) + if (!env) { return; + } - cpu_fprintf(f, "IN: PC=%" PRIx64 " %s\n", - env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC])); - cpu_fprintf(f, "rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " - "debug=%x imm=%x iflags=%x fsr=%" PRIx64 "\n", - env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR], - env->debug, env->imm, env->iflags, env->sregs[SR_FSR]); - cpu_fprintf(f, "btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) " - "eip=%d ie=%d\n", - env->btaken, env->btarget, - (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel", - (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel", - (bool)(env->sregs[SR_MSR] & MSR_EIP), - (bool)(env->sregs[SR_MSR] & MSR_IE)); + qemu_fprintf(f, "IN: PC=%" PRIx64 " %s\n", + env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC])); + qemu_fprintf(f, "rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " + "debug=%x imm=%x iflags=%x fsr=%" PRIx64 "\n", + env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR], + env->debug, env->imm, env->iflags, env->sregs[SR_FSR]); + qemu_fprintf(f, "btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) " + "eip=%d ie=%d\n", + env->btaken, env->btarget, + (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel", + (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel", + (bool)(env->sregs[SR_MSR] & MSR_EIP), + (bool)(env->sregs[SR_MSR] & MSR_IE)); for (i = 0; i < 32; i++) { - cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); + qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); if ((i + 1) % 4 == 0) - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } - cpu_fprintf(f, "\n\n"); + qemu_fprintf(f, "\n\n"); } void mb_tcg_init(void) diff --git a/target/mips/cpu.h b/target/mips/cpu.h index a10eeb0de3..1f41cf66d5 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1065,7 +1065,7 @@ static inline MIPSCPU *mips_env_get_cpu(CPUMIPSState *env) #define ENV_OFFSET offsetof(MIPSCPU, env) -void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf); +void mips_cpu_list(void); #define cpu_signal_handler cpu_mips_signal_handler #define cpu_list mips_cpu_list diff --git a/target/mips/internal.h b/target/mips/internal.h index 8f6fc919d5..286e3888ab 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -76,8 +76,7 @@ enum CPUMIPSMSADataFormat { 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); +void mips_cpu_dump_state(CPUState *cpu, FILE *f, 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); diff --git a/target/mips/trace-events b/target/mips/trace-events index 05eafd7870..ba87fe6062 100644 --- a/target/mips/trace-events +++ b/target/mips/trace-events @@ -1,5 +1,5 @@ # See docs/devel/tracing.txt for syntax documentation. -# target/mips/translate.c +# translate.c mips_translate_c0(const char *instr, const char *rn, int reg, int sel) "%s %s (reg %d sel %d)" mips_translate_tr(const char *instr, int rt, int u, int sel, int h) "%s (reg %d u %d sel %d h %d)" diff --git a/target/mips/translate.c b/target/mips/translate.c index 364bd6dc4f..f96c0d01ef 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -38,6 +38,7 @@ #include "trace-tcg.h" #include "exec/translator.h" #include "exec/log.h" +#include "qemu/qemu-print.h" #define MIPS_DEBUG_DISAS 0 @@ -29720,15 +29721,14 @@ static const TranslatorOps mips_tr_ops = { .disas_log = mips_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { DisasContext ctx; - translator_loop(&mips_tr_ops, &ctx.base, cs, tb); + translator_loop(&mips_tr_ops, &ctx.base, cs, tb, max_insns); } -static void fpu_dump_state(CPUMIPSState *env, FILE *f, fprintf_function fpu_fprintf, - int flags) +static void fpu_dump_state(CPUMIPSState *env, FILE *f, int flags) { int i; int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64); @@ -29736,68 +29736,69 @@ static void fpu_dump_state(CPUMIPSState *env, FILE *f, fprintf_function fpu_fpri #define printfpr(fp) \ do { \ if (is_fpu64) \ - fpu_fprintf(f, "w:%08x d:%016" PRIx64 \ - " fd:%13g fs:%13g psu: %13g\n", \ - (fp)->w[FP_ENDIAN_IDX], (fp)->d, \ - (double)(fp)->fd, \ - (double)(fp)->fs[FP_ENDIAN_IDX], \ - (double)(fp)->fs[!FP_ENDIAN_IDX]); \ + qemu_fprintf(f, "w:%08x d:%016" PRIx64 \ + " fd:%13g fs:%13g psu: %13g\n", \ + (fp)->w[FP_ENDIAN_IDX], (fp)->d, \ + (double)(fp)->fd, \ + (double)(fp)->fs[FP_ENDIAN_IDX], \ + (double)(fp)->fs[!FP_ENDIAN_IDX]); \ else { \ fpr_t tmp; \ tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ - fpu_fprintf(f, "w:%08x d:%016" PRIx64 \ - " fd:%13g fs:%13g psu:%13g\n", \ - tmp.w[FP_ENDIAN_IDX], tmp.d, \ - (double)tmp.fd, \ - (double)tmp.fs[FP_ENDIAN_IDX], \ - (double)tmp.fs[!FP_ENDIAN_IDX]); \ + qemu_fprintf(f, "w:%08x d:%016" PRIx64 \ + " fd:%13g fs:%13g psu:%13g\n", \ + tmp.w[FP_ENDIAN_IDX], tmp.d, \ + (double)tmp.fd, \ + (double)tmp.fs[FP_ENDIAN_IDX], \ + (double)tmp.fs[!FP_ENDIAN_IDX]); \ } \ } while(0) - fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%02x\n", - env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64, - get_float_exception_flags(&env->active_fpu.fp_status)); + qemu_fprintf(f, + "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%02x\n", + env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64, + get_float_exception_flags(&env->active_fpu.fp_status)); for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { - fpu_fprintf(f, "%3s: ", fregnames[i]); + qemu_fprintf(f, "%3s: ", fregnames[i]); printfpr(&env->active_fpu.fpr[i]); } #undef printfpr } -void mips_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void mips_cpu_dump_state(CPUState *cs, FILE *f, int flags) { MIPSCPU *cpu = MIPS_CPU(cs); CPUMIPSState *env = &cpu->env; int i; - cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx - " LO=0x" TARGET_FMT_lx " ds %04x " - TARGET_FMT_lx " " TARGET_FMT_ld "\n", - env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0], - env->hflags, env->btarget, env->bcond); + qemu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx + " LO=0x" TARGET_FMT_lx " ds %04x " + TARGET_FMT_lx " " TARGET_FMT_ld "\n", + env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0], + env->hflags, env->btarget, env->bcond); for (i = 0; i < 32; i++) { if ((i & 3) == 0) - cpu_fprintf(f, "GPR%02d:", i); - cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->active_tc.gpr[i]); + qemu_fprintf(f, "GPR%02d:", i); + qemu_fprintf(f, " %s " TARGET_FMT_lx, + regnames[i], env->active_tc.gpr[i]); if ((i & 3) == 3) - cpu_fprintf(f, "\n"); - } - - cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n", - env->CP0_Status, env->CP0_Cause, env->CP0_EPC); - cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%016" - PRIx64 "\n", - env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); - cpu_fprintf(f, " Config2 0x%08x Config3 0x%08x\n", - env->CP0_Config2, env->CP0_Config3); - cpu_fprintf(f, " Config4 0x%08x Config5 0x%08x\n", - env->CP0_Config4, env->CP0_Config5); + qemu_fprintf(f, "\n"); + } + + qemu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n", + env->CP0_Status, env->CP0_Cause, env->CP0_EPC); + qemu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%016" + PRIx64 "\n", + env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); + qemu_fprintf(f, " Config2 0x%08x Config3 0x%08x\n", + env->CP0_Config2, env->CP0_Config3); + qemu_fprintf(f, " Config4 0x%08x Config5 0x%08x\n", + env->CP0_Config4, env->CP0_Config5); if ((flags & CPU_DUMP_FPU) && (env->hflags & MIPS_HFLAG_FPU)) { - fpu_dump_state(env, f, cpu_fprintf, flags); + fpu_dump_state(env, f, flags); } } diff --git a/target/mips/translate_init.inc.c b/target/mips/translate_init.inc.c index bf559aff08..1c2d017d36 100644 --- a/target/mips/translate_init.inc.c +++ b/target/mips/translate_init.inc.c @@ -835,13 +835,12 @@ const mips_def_t mips_defs[] = }; const int mips_defs_number = ARRAY_SIZE(mips_defs); -void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf) +void mips_cpu_list(void) { int i; for (i = 0; i < ARRAY_SIZE(mips_defs); i++) { - (*cpu_fprintf)(f, "MIPS '%s'\n", - mips_defs[i].name); + qemu_printf("MIPS '%s'\n", mips_defs[i].name); } } diff --git a/target/moxie/cpu.h b/target/moxie/cpu.h index 080df4ee6f..f3b6d83ae7 100644 --- a/target/moxie/cpu.h +++ b/target/moxie/cpu.h @@ -112,8 +112,7 @@ static inline MoxieCPU *moxie_env_get_cpu(CPUMoxieState *env) #define ENV_OFFSET offsetof(MoxieCPU, env) void moxie_cpu_do_interrupt(CPUState *cs); -void moxie_cpu_dump_state(CPUState *cpu, FILE *f, - fprintf_function cpu_fprintf, int flags); +void moxie_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr moxie_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); void moxie_translate_init(void); int cpu_moxie_signal_handler(int host_signum, void *pinfo, diff --git a/target/moxie/helper.c b/target/moxie/helper.c index f3d8ee7d6b..287a45232c 100644 --- a/target/moxie/helper.c +++ b/target/moxie/helper.c @@ -101,7 +101,7 @@ int moxie_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, cs->exception_index = 0xaa; cpu->env.debug1 = address; - cpu_dump_state(cs, stderr, fprintf, 0); + cpu_dump_state(cs, stderr, 0); return 1; } diff --git a/target/moxie/translate.c b/target/moxie/translate.c index 68ca223e22..c668178f2c 100644 --- a/target/moxie/translate.c +++ b/target/moxie/translate.c @@ -28,6 +28,7 @@ #include "disas/disas.h" #include "tcg-op.h" #include "exec/cpu_ldst.h" +#include "qemu/qemu-print.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" @@ -69,24 +70,23 @@ static int extract_branch_offset(int opcode) return (((signed short)((opcode & ((1 << 10) - 1)) << 6)) >> 6) << 1; } -void moxie_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void moxie_cpu_dump_state(CPUState *cs, FILE *f, int flags) { MoxieCPU *cpu = MOXIE_CPU(cs); CPUMoxieState *env = &cpu->env; int i; - cpu_fprintf(f, "pc=0x%08x\n", env->pc); - cpu_fprintf(f, "$fp=0x%08x $sp=0x%08x $r0=0x%08x $r1=0x%08x\n", - env->gregs[0], env->gregs[1], env->gregs[2], env->gregs[3]); + qemu_fprintf(f, "pc=0x%08x\n", env->pc); + qemu_fprintf(f, "$fp=0x%08x $sp=0x%08x $r0=0x%08x $r1=0x%08x\n", + env->gregs[0], env->gregs[1], env->gregs[2], env->gregs[3]); for (i = 4; i < 16; i += 4) { - cpu_fprintf(f, "$r%d=0x%08x $r%d=0x%08x $r%d=0x%08x $r%d=0x%08x\n", - i-2, env->gregs[i], i-1, env->gregs[i + 1], - i, env->gregs[i + 2], i+1, env->gregs[i + 3]); + qemu_fprintf(f, "$r%d=0x%08x $r%d=0x%08x $r%d=0x%08x $r%d=0x%08x\n", + i - 2, env->gregs[i], i - 1, env->gregs[i + 1], + i, env->gregs[i + 2], i + 1, env->gregs[i + 3]); } for (i = 4; i < 16; i += 4) { - cpu_fprintf(f, "sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x\n", - i-2, env->sregs[i], i-1, env->sregs[i + 1], - i, env->sregs[i + 2], i+1, env->sregs[i + 3]); + qemu_fprintf(f, "sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x\n", + i - 2, env->sregs[i], i - 1, env->sregs[i + 1], + i, env->sregs[i + 2], i + 1, env->sregs[i + 3]); } } @@ -813,13 +813,13 @@ static int decode_opc(MoxieCPU *cpu, DisasContext *ctx) } /* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { CPUMoxieState *env = cs->env_ptr; MoxieCPU *cpu = moxie_env_get_cpu(env); DisasContext ctx; target_ulong pc_start; - int num_insns, max_insns; + int num_insns; pc_start = tb->pc; ctx.pc = pc_start; @@ -829,13 +829,6 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) ctx.singlestep_enabled = 0; ctx.bstate = BS_NONE; num_insns = 0; - max_insns = tb_cflags(tb) & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } gen_tb_start(tb); do { diff --git a/target/nios2/Makefile.objs b/target/nios2/Makefile.objs index 2a11c5ce08..010de0e7a6 100644 --- a/target/nios2/Makefile.objs +++ b/target/nios2/Makefile.objs @@ -1,4 +1,4 @@ -obj-y += translate.o op_helper.o helper.o cpu.o mmu.o +obj-y += translate.o op_helper.o helper.o cpu.o mmu.o nios2-semi.o obj-$(CONFIG_SOFTMMU) += monitor.o $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h index 047f3764b7..881e7d58c9 100644 --- a/target/nios2/cpu.h +++ b/target/nios2/cpu.h @@ -141,7 +141,7 @@ typedef struct Nios2CPUClass { #define R_PC 64 /* Exceptions */ -#define EXCP_BREAK -1 +#define EXCP_BREAK 0x1000 #define EXCP_RESET 0 #define EXCP_PRESET 1 #define EXCP_IRQ 2 @@ -212,9 +212,8 @@ static inline Nios2CPU *nios2_env_get_cpu(CPUNios2State *env) void nios2_tcg_init(void); void nios2_cpu_do_interrupt(CPUState *cs); int cpu_nios2_signal_handler(int host_signum, void *pinfo, void *puc); -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUNios2State *env); -void nios2_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, - int flags); +void dump_mmu(CPUNios2State *env); +void nios2_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr nios2_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); void nios2_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, MMUAccessType access_type, @@ -223,6 +222,8 @@ void nios2_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, qemu_irq *nios2_cpu_pic_init(Nios2CPU *cpu); void nios2_check_interrupts(CPUNios2State *env); +void do_nios2_semihosting(CPUNios2State *env); + #define TARGET_PHYS_ADDR_SPACE_BITS 32 #ifdef CONFIG_USER_ONLY # define TARGET_VIRT_ADDR_SPACE_BITS 31 diff --git a/target/nios2/helper.c b/target/nios2/helper.c index a8b8ec662a..e01fc1ff3e 100644 --- a/target/nios2/helper.c +++ b/target/nios2/helper.c @@ -23,8 +23,10 @@ #include "cpu.h" #include "qemu/host-utils.h" #include "exec/exec-all.h" +#include "exec/cpu_ldst.h" #include "exec/log.h" #include "exec/helper-proto.h" +#include "exec/semihost.h" #if defined(CONFIG_USER_ONLY) @@ -42,7 +44,7 @@ int nios2_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, cs->exception_index = 0xaa; /* Page 0x1000 is kuser helper */ if (address < 0x1000 || address >= 0x2000) { - cpu_dump_state(cs, stderr, fprintf, 0); + cpu_dump_state(cs, stderr, 0); } return 1; } @@ -169,6 +171,17 @@ void nios2_cpu_do_interrupt(CPUState *cs) break; case EXCP_BREAK: + qemu_log_mask(CPU_LOG_INT, "BREAK exception at pc=%x\n", + env->regs[R_PC]); + /* The semihosting instruction is "break 1". */ + if (semihosting_enabled() && + cpu_ldl_code(env, env->regs[R_PC]) == 0x003da07a) { + qemu_log_mask(CPU_LOG_INT, "Entering semihosting\n"); + env->regs[R_PC] += 4; + do_nios2_semihosting(env); + break; + } + if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) { env->regs[CR_BSTATUS] = env->regs[CR_STATUS]; env->regs[R_BA] = env->regs[R_PC] + 4; diff --git a/target/nios2/mmu.c b/target/nios2/mmu.c index 69b71cba4a..5acf442d8b 100644 --- a/target/nios2/mmu.c +++ b/target/nios2/mmu.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" +#include "qemu/qemu-print.h" #include "cpu.h" #include "exec/exec-all.h" #include "mmu.h" @@ -264,18 +265,18 @@ void mmu_init(CPUNios2State *env) mmu->tlb = g_new0(Nios2TLBEntry, cpu->tlb_num_entries); } -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUNios2State *env) +void dump_mmu(CPUNios2State *env) { Nios2CPU *cpu = nios2_env_get_cpu(env); int i; - cpu_fprintf(f, "MMU: ways %d, entries %d, pid bits %d\n", + qemu_printf("MMU: ways %d, entries %d, pid bits %d\n", cpu->tlb_num_ways, cpu->tlb_num_entries, cpu->pid_num_bits); for (i = 0; i < cpu->tlb_num_entries; i++) { Nios2TLBEntry *entry = &env->mmu.tlb[i]; - cpu_fprintf(f, "TLB[%d] = %08X %08X %c VPN %05X " + qemu_printf("TLB[%d] = %08X %08X %c VPN %05X " "PID %02X %c PFN %05X %c%c%c%c\n", i, entry->tag, entry->data, (entry->tag & (1 << 10)) ? 'V' : '-', diff --git a/target/nios2/monitor.c b/target/nios2/monitor.c index 422c81656a..d5e3393716 100644 --- a/target/nios2/monitor.c +++ b/target/nios2/monitor.c @@ -31,5 +31,5 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) { CPUArchState *env1 = mon_get_cpu_env(); - dump_mmu((FILE *)mon, (fprintf_function)monitor_printf, env1); + dump_mmu(env1); } diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c new file mode 100644 index 0000000000..cc2777d2f8 --- /dev/null +++ b/target/nios2/nios2-semi.c @@ -0,0 +1,455 @@ +/* + * Nios II Semihosting syscall interface. + * This code is derived from m68k-semi.c. + * The semihosting protocol implemented here is described in the + * libgloss sources: + * https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=libgloss/nios2/nios2-semi.txt;hb=HEAD + * + * Copyright (c) 2017-2019 Mentor Graphics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" + +#include "cpu.h" +#if defined(CONFIG_USER_ONLY) +#include "qemu.h" +#else +#include "qemu-common.h" +#include "exec/gdbstub.h" +#include "exec/softmmu-semi.h" +#endif +#include "qemu/log.h" +#include "sysemu/sysemu.h" + +#define HOSTED_EXIT 0 +#define HOSTED_INIT_SIM 1 +#define HOSTED_OPEN 2 +#define HOSTED_CLOSE 3 +#define HOSTED_READ 4 +#define HOSTED_WRITE 5 +#define HOSTED_LSEEK 6 +#define HOSTED_RENAME 7 +#define HOSTED_UNLINK 8 +#define HOSTED_STAT 9 +#define HOSTED_FSTAT 10 +#define HOSTED_GETTIMEOFDAY 11 +#define HOSTED_ISATTY 12 +#define HOSTED_SYSTEM 13 + +typedef uint32_t gdb_mode_t; +typedef uint32_t gdb_time_t; + +struct nios2_gdb_stat { + uint32_t gdb_st_dev; /* device */ + uint32_t gdb_st_ino; /* inode */ + gdb_mode_t gdb_st_mode; /* protection */ + uint32_t gdb_st_nlink; /* number of hard links */ + uint32_t gdb_st_uid; /* user ID of owner */ + uint32_t gdb_st_gid; /* group ID of owner */ + uint32_t gdb_st_rdev; /* device type (if inode device) */ + uint64_t gdb_st_size; /* total size, in bytes */ + uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */ + uint64_t gdb_st_blocks; /* number of blocks allocated */ + gdb_time_t gdb_st_atime; /* time of last access */ + gdb_time_t gdb_st_mtime; /* time of last modification */ + gdb_time_t gdb_st_ctime; /* time of last change */ +} QEMU_PACKED; + +struct gdb_timeval { + gdb_time_t tv_sec; /* second */ + uint64_t tv_usec; /* microsecond */ +} QEMU_PACKED; + +#define GDB_O_RDONLY 0x0 +#define GDB_O_WRONLY 0x1 +#define GDB_O_RDWR 0x2 +#define GDB_O_APPEND 0x8 +#define GDB_O_CREAT 0x200 +#define GDB_O_TRUNC 0x400 +#define GDB_O_EXCL 0x800 + +static int translate_openflags(int flags) +{ + int hf; + + if (flags & GDB_O_WRONLY) { + hf = O_WRONLY; + } else if (flags & GDB_O_RDWR) { + hf = O_RDWR; + } else { + hf = O_RDONLY; + } + + if (flags & GDB_O_APPEND) { + hf |= O_APPEND; + } + if (flags & GDB_O_CREAT) { + hf |= O_CREAT; + } + if (flags & GDB_O_TRUNC) { + hf |= O_TRUNC; + } + if (flags & GDB_O_EXCL) { + hf |= O_EXCL; + } + + return hf; +} + +static bool translate_stat(CPUNios2State *env, target_ulong addr, + struct stat *s) +{ + struct nios2_gdb_stat *p; + + p = lock_user(VERIFY_WRITE, addr, sizeof(struct nios2_gdb_stat), 0); + + if (!p) { + return false; + } + p->gdb_st_dev = cpu_to_be32(s->st_dev); + p->gdb_st_ino = cpu_to_be32(s->st_ino); + p->gdb_st_mode = cpu_to_be32(s->st_mode); + p->gdb_st_nlink = cpu_to_be32(s->st_nlink); + p->gdb_st_uid = cpu_to_be32(s->st_uid); + p->gdb_st_gid = cpu_to_be32(s->st_gid); + p->gdb_st_rdev = cpu_to_be32(s->st_rdev); + p->gdb_st_size = cpu_to_be64(s->st_size); +#ifdef _WIN32 + /* Windows stat is missing some fields. */ + p->gdb_st_blksize = 0; + p->gdb_st_blocks = 0; +#else + p->gdb_st_blksize = cpu_to_be64(s->st_blksize); + p->gdb_st_blocks = cpu_to_be64(s->st_blocks); +#endif + p->gdb_st_atime = cpu_to_be32(s->st_atime); + p->gdb_st_mtime = cpu_to_be32(s->st_mtime); + p->gdb_st_ctime = cpu_to_be32(s->st_ctime); + unlock_user(p, addr, sizeof(struct nios2_gdb_stat)); + return true; +} + +static void nios2_semi_return_u32(CPUNios2State *env, uint32_t ret, + uint32_t err) +{ + target_ulong args = env->regs[R_ARG1]; + if (put_user_u32(ret, args) || + put_user_u32(err, args + 4)) { + /* + * The nios2 semihosting ABI does not provide any way to report this + * error to the guest, so the best we can do is log it in qemu. + * It is always a guest error not to pass us a valid argument block. + */ + qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: return value " + "discarded because argument block not writable\n"); + } +} + +static void nios2_semi_return_u64(CPUNios2State *env, uint64_t ret, + uint32_t err) +{ + target_ulong args = env->regs[R_ARG1]; + if (put_user_u32(ret >> 32, args) || + put_user_u32(ret, args + 4) || + put_user_u32(err, args + 8)) { + /* No way to report this via nios2 semihosting ABI; just log it */ + qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: return value " + "discarded because argument block not writable\n"); + } +} + +static int nios2_semi_is_lseek; + +static void nios2_semi_cb(CPUState *cs, target_ulong ret, target_ulong err) +{ + Nios2CPU *cpu = NIOS2_CPU(cs); + CPUNios2State *env = &cpu->env; + + if (nios2_semi_is_lseek) { + /* + * FIXME: We've already lost the high bits of the lseek + * return value. + */ + nios2_semi_return_u64(env, ret, err); + nios2_semi_is_lseek = 0; + } else { + nios2_semi_return_u32(env, ret, err); + } +} + +/* + * Read the input value from the argument block; fail the semihosting + * call if the memory read fails. + */ +#define GET_ARG(n) do { \ + if (get_user_ual(arg ## n, args + (n) * 4)) { \ + result = -1; \ + errno = EFAULT; \ + goto failed; \ + } \ +} while (0) + +void do_nios2_semihosting(CPUNios2State *env) +{ + int nr; + uint32_t args; + target_ulong arg0, arg1, arg2, arg3; + void *p; + void *q; + uint32_t len; + uint32_t result; + + nr = env->regs[R_ARG0]; + args = env->regs[R_ARG1]; + switch (nr) { + case HOSTED_EXIT: + gdb_exit(env, env->regs[R_ARG0]); + exit(env->regs[R_ARG0]); + case HOSTED_OPEN: + GET_ARG(0); + GET_ARG(1); + GET_ARG(2); + GET_ARG(3); + if (use_gdb_syscalls()) { + gdb_do_syscall(nios2_semi_cb, "open,%s,%x,%x", arg0, (int)arg1, + arg2, arg3); + return; + } else { + p = lock_user_string(arg0); + if (!p) { + result = -1; + errno = EFAULT; + } else { + result = open(p, translate_openflags(arg2), arg3); + unlock_user(p, arg0, 0); + } + } + break; + case HOSTED_CLOSE: + { + /* Ignore attempts to close stdin/out/err. */ + GET_ARG(0); + int fd = arg0; + if (fd > 2) { + if (use_gdb_syscalls()) { + gdb_do_syscall(nios2_semi_cb, "close,%x", arg0); + return; + } else { + result = close(fd); + } + } else { + result = 0; + } + break; + } + case HOSTED_READ: + GET_ARG(0); + GET_ARG(1); + GET_ARG(2); + len = arg2; + if (use_gdb_syscalls()) { + gdb_do_syscall(nios2_semi_cb, "read,%x,%x,%x", + arg0, arg1, len); + return; + } else { + p = lock_user(VERIFY_WRITE, arg1, len, 0); + if (!p) { + result = -1; + errno = EFAULT; + } else { + result = read(arg0, p, len); + unlock_user(p, arg1, len); + } + } + break; + case HOSTED_WRITE: + GET_ARG(0); + GET_ARG(1); + GET_ARG(2); + len = arg2; + if (use_gdb_syscalls()) { + gdb_do_syscall(nios2_semi_cb, "write,%x,%x,%x", + arg0, arg1, len); + return; + } else { + p = lock_user(VERIFY_READ, arg1, len, 1); + if (!p) { + result = -1; + errno = EFAULT; + } else { + result = write(arg0, p, len); + unlock_user(p, arg0, 0); + } + } + break; + case HOSTED_LSEEK: + { + uint64_t off; + GET_ARG(0); + GET_ARG(1); + GET_ARG(2); + GET_ARG(3); + off = (uint32_t)arg2 | ((uint64_t)arg1 << 32); + if (use_gdb_syscalls()) { + nios2_semi_is_lseek = 1; + gdb_do_syscall(nios2_semi_cb, "lseek,%x,%lx,%x", + arg0, off, arg3); + } else { + off = lseek(arg0, off, arg3); + nios2_semi_return_u64(env, off, errno); + } + return; + } + case HOSTED_RENAME: + GET_ARG(0); + GET_ARG(1); + GET_ARG(2); + GET_ARG(3); + if (use_gdb_syscalls()) { + gdb_do_syscall(nios2_semi_cb, "rename,%s,%s", + arg0, (int)arg1, arg2, (int)arg3); + return; + } else { + p = lock_user_string(arg0); + q = lock_user_string(arg2); + if (!p || !q) { + result = -1; + errno = EFAULT; + } else { + result = rename(p, q); + } + unlock_user(p, arg0, 0); + unlock_user(q, arg2, 0); + } + break; + case HOSTED_UNLINK: + GET_ARG(0); + GET_ARG(1); + if (use_gdb_syscalls()) { + gdb_do_syscall(nios2_semi_cb, "unlink,%s", + arg0, (int)arg1); + return; + } else { + p = lock_user_string(arg0); + if (!p) { + result = -1; + errno = EFAULT; + } else { + result = unlink(p); + unlock_user(p, arg0, 0); + } + } + break; + case HOSTED_STAT: + GET_ARG(0); + GET_ARG(1); + GET_ARG(2); + if (use_gdb_syscalls()) { + gdb_do_syscall(nios2_semi_cb, "stat,%s,%x", + arg0, (int)arg1, arg2); + return; + } else { + struct stat s; + p = lock_user_string(arg0); + if (!p) { + result = -1; + errno = EFAULT; + } else { + result = stat(p, &s); + unlock_user(p, arg0, 0); + } + if (result == 0 && !translate_stat(env, arg2, &s)) { + result = -1; + errno = EFAULT; + } + } + break; + case HOSTED_FSTAT: + GET_ARG(0); + GET_ARG(1); + if (use_gdb_syscalls()) { + gdb_do_syscall(nios2_semi_cb, "fstat,%x,%x", + arg0, arg1); + return; + } else { + struct stat s; + result = fstat(arg0, &s); + if (result == 0 && !translate_stat(env, arg1, &s)) { + result = -1; + errno = EFAULT; + } + } + break; + case HOSTED_GETTIMEOFDAY: + /* Only the tv parameter is used. tz is assumed NULL. */ + GET_ARG(0); + if (use_gdb_syscalls()) { + gdb_do_syscall(nios2_semi_cb, "gettimeofday,%x,%x", + arg0, 0); + return; + } else { + qemu_timeval tv; + struct gdb_timeval *p; + result = qemu_gettimeofday(&tv); + if (result != 0) { + p = lock_user(VERIFY_WRITE, arg0, sizeof(struct gdb_timeval), + 0); + if (!p) { + result = -1; + errno = EFAULT; + } else { + p->tv_sec = cpu_to_be32(tv.tv_sec); + p->tv_usec = cpu_to_be64(tv.tv_usec); + unlock_user(p, arg0, sizeof(struct gdb_timeval)); + } + } + } + break; + case HOSTED_ISATTY: + GET_ARG(0); + if (use_gdb_syscalls()) { + gdb_do_syscall(nios2_semi_cb, "isatty,%x", arg0); + return; + } else { + result = isatty(arg0); + } + break; + case HOSTED_SYSTEM: + GET_ARG(0); + GET_ARG(1); + if (use_gdb_syscalls()) { + gdb_do_syscall(nios2_semi_cb, "system,%s", + arg0, (int)arg1); + return; + } else { + p = lock_user_string(arg0); + if (!p) { + result = -1; + errno = EFAULT; + } else { + result = system(p); + unlock_user(p, arg0, 0); + } + } + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: unsupported " + "semihosting syscall %d\n", nr); + result = 0; + } +failed: + nios2_semi_return_u32(env, result, errno); +} diff --git a/target/nios2/translate.c b/target/nios2/translate.c index 7fa03ed05a..17d8f1877c 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -31,6 +31,7 @@ #include "exec/log.h" #include "exec/cpu_ldst.h" #include "exec/translator.h" +#include "qemu/qemu-print.h" /* is_jmp field values */ #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ @@ -805,12 +806,11 @@ static void gen_exception(DisasContext *dc, uint32_t excp) } /* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { CPUNios2State *env = cs->env_ptr; DisasContext dc1, *dc = &dc1; int num_insns; - int max_insns; /* Initialize DC */ dc->cpu_env = cpu_env; @@ -823,20 +823,11 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) /* Set up instruction counts */ num_insns = 0; - if (cs->singlestep_enabled || singlestep) { - max_insns = 1; - } else { + if (max_insns > 1) { int page_insns = (TARGET_PAGE_SIZE - (tb->pc & TARGET_PAGE_MASK)) / 4; - max_insns = tb_cflags(tb) & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } if (max_insns > page_insns) { max_insns = page_insns; } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } } gen_tb_start(tb); @@ -914,33 +905,32 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) #endif } -void nios2_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags) { Nios2CPU *cpu = NIOS2_CPU(cs); CPUNios2State *env = &cpu->env; int i; - if (!env || !f) { + if (!env) { return; } - cpu_fprintf(f, "IN: PC=%x %s\n", - env->regs[R_PC], lookup_symbol(env->regs[R_PC])); + qemu_fprintf(f, "IN: PC=%x %s\n", + env->regs[R_PC], lookup_symbol(env->regs[R_PC])); for (i = 0; i < NUM_CORE_REGS; i++) { - cpu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]); + qemu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]); if ((i + 1) % 4 == 0) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } #if !defined(CONFIG_USER_ONLY) - cpu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n", - env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK, - (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4, - env->mmu.tlbacc_wr); + qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n", + env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK, + (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4, + env->mmu.tlbacc_wr); #endif - cpu_fprintf(f, "\n\n"); + qemu_fprintf(f, "\n\n"); } void nios2_tcg_init(void) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 541b2a66c7..d125236977 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/qemu-print.h" #include "cpu.h" #include "qemu-common.h" @@ -180,30 +181,24 @@ static gint openrisc_cpu_list_compare(gconstpointer a, gconstpointer b) static void openrisc_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - CPUListState *s = user_data; const char *typename; char *name; typename = object_class_get_name(oc); name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_OPENRISC_CPU)); - (*s->cpu_fprintf)(s->file, " %s\n", - name); + qemu_printf(" %s\n", name); g_free(name); } -void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf) +void cpu_openrisc_list(void) { - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; GSList *list; list = object_class_get_list(TYPE_OPENRISC_CPU, false); list = g_slist_sort(list, openrisc_cpu_list_compare); - (*cpu_fprintf)(f, "Available CPUs:\n"); - g_slist_foreach(list, openrisc_cpu_list_entry, &s); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, openrisc_cpu_list_entry, NULL); g_slist_free(list); } diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index f1b31bc24a..a50861955a 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -336,11 +336,10 @@ static inline OpenRISCCPU *openrisc_env_get_cpu(CPUOpenRISCState *env) #define ENV_OFFSET offsetof(OpenRISCCPU, env) -void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf); +void cpu_openrisc_list(void); void openrisc_cpu_do_interrupt(CPUState *cpu); bool openrisc_cpu_exec_interrupt(CPUState *cpu, int int_req); -void openrisc_cpu_dump_state(CPUState *cpu, FILE *f, - fprintf_function cpu_fprintf, int flags); +void openrisc_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); diff --git a/target/openrisc/disas.c b/target/openrisc/disas.c index bc63093ee9..5923b2429e 100644 --- a/target/openrisc/disas.c +++ b/target/openrisc/disas.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "disas/bfd.h" +#include "disas/dis-asm.h" #include "qemu/bitops.h" #include "cpu.h" diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 89680f882d..36821948c0 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -26,6 +26,7 @@ #include "qemu-common.h" #include "qemu/log.h" #include "qemu/bitops.h" +#include "qemu/qemu-print.h" #include "exec/cpu_ldst.h" #include "exec/translator.h" @@ -1408,25 +1409,23 @@ static const TranslatorOps openrisc_tr_ops = { .disas_log = openrisc_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { DisasContext ctx; - translator_loop(&openrisc_tr_ops, &ctx.base, cs, tb); + translator_loop(&openrisc_tr_ops, &ctx.base, cs, tb, max_insns); } -void openrisc_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, - int flags) +void openrisc_cpu_dump_state(CPUState *cs, FILE *f, int flags) { OpenRISCCPU *cpu = OPENRISC_CPU(cs); CPUOpenRISCState *env = &cpu->env; int i; - cpu_fprintf(f, "PC=%08x\n", env->pc); + qemu_fprintf(f, "PC=%08x\n", env->pc); for (i = 0; i < 32; ++i) { - cpu_fprintf(f, "R%02d=%08x%c", i, cpu_get_gpr(env, i), - (i % 4) == 3 ? '\n' : ' '); + qemu_fprintf(f, "R%02d=%08x%c", i, cpu_get_gpr(env, i), + (i % 4) == 3 ? '\n' : ' '); } } diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c index 7c75963e3c..9d7050b5fa 100644 --- a/target/ppc/cpu-models.c +++ b/target/ppc/cpu-models.c @@ -740,7 +740,7 @@ POWERPC_DEF("7457a_v1.2", CPU_POWERPC_74x7A_v12, 7455, "PowerPC 7457A v1.2 (G4)") /* 64 bits PowerPC */ -#if defined (TARGET_PPC64) +#if defined(TARGET_PPC64) POWERPC_DEF("970_v2.2", CPU_POWERPC_970_v22, 970, "PowerPC 970 v2.2") POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970, diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h index efdb2fa53c..4fdb73034d 100644 --- a/target/ppc/cpu-models.h +++ b/target/ppc/cpu-models.h @@ -393,7 +393,8 @@ enum { CPU_POWERPC_RS64IV = 0x00370000, #endif /* defined(TARGET_PPC64) */ /* Original POWER */ - /* XXX: should be POWER (RIOS), RSC3308, RSC4608, + /* + * XXX: should be POWER (RIOS), RSC3308, RSC4608, * POWER2 (RIOS2) & RSC2 (P2SC) here */ /* PA Semi core */ diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index fc12b4688e..5e7cf54b2f 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -23,23 +23,28 @@ #include "qemu-common.h" #include "qemu/int128.h" -//#define PPC_EMULATE_32BITS_HYPV +/* #define PPC_EMULATE_32BITS_HYPV */ -#if defined (TARGET_PPC64) +#if defined(TARGET_PPC64) /* PowerPC 64 definitions */ #define TARGET_LONG_BITS 64 #define TARGET_PAGE_BITS 12 #define TCG_GUEST_DEFAULT_MO 0 -/* Note that the official physical address space bits is 62-M where M - is implementation dependent. I've not looked up M for the set of - cpus we emulate at the system level. */ +/* + * Note that the official physical address space bits is 62-M where M + * is implementation dependent. I've not looked up M for the set of + * cpus we emulate at the system level. + */ #define TARGET_PHYS_ADDR_SPACE_BITS 62 -/* Note that the PPC environment architecture talks about 80 bit virtual - addresses, with segmentation. Obviously that's not all visible to a - single process, which is all we're concerned with here. */ +/* + * Note that the PPC environment architecture talks about 80 bit + * virtual addresses, with segmentation. Obviously that's not all + * visible to a single process, which is all we're concerned with + * here. + */ #ifdef TARGET_ABI32 # define TARGET_VIRT_ADDR_SPACE_BITS 32 #else @@ -49,7 +54,7 @@ #define TARGET_PAGE_BITS_64K 16 #define TARGET_PAGE_BITS_16M 24 -#else /* defined (TARGET_PPC64) */ +#else /* defined(TARGET_PPC64) */ /* PowerPC 32 definitions */ #define TARGET_LONG_BITS 32 #define TARGET_PAGE_BITS 12 @@ -57,14 +62,14 @@ #define TARGET_PHYS_ADDR_SPACE_BITS 36 #define TARGET_VIRT_ADDR_SPACE_BITS 32 -#endif /* defined (TARGET_PPC64) */ +#endif /* defined(TARGET_PPC64) */ #define CPUArchState struct CPUPPCState #include "exec/cpu-defs.h" #include "cpu-qom.h" -#if defined (TARGET_PPC64) +#if defined(TARGET_PPC64) #define PPC_ELF_MACHINE EM_PPC64 #else #define PPC_ELF_MACHINE EM_PPC @@ -237,9 +242,11 @@ struct ppc_spr_t { const char *name; target_ulong default_value; #ifdef CONFIG_KVM - /* We (ab)use the fact that all the SPRs will have ids for the + /* + * We (ab)use the fact that all the SPRs will have ids for the * ONE_REG interface will have KVM_REG_PPC to use 0 as meaning, - * don't sync this */ + * don't sync this + */ uint64_t one_reg_id; #endif }; @@ -656,39 +663,39 @@ enum { #define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) & \ 0x1F) -#define FP_FX (1ull << FPSCR_FX) -#define FP_FEX (1ull << FPSCR_FEX) -#define FP_VX (1ull << FPSCR_VX) -#define FP_OX (1ull << FPSCR_OX) -#define FP_UX (1ull << FPSCR_UX) -#define FP_ZX (1ull << FPSCR_ZX) -#define FP_XX (1ull << FPSCR_XX) -#define FP_VXSNAN (1ull << FPSCR_VXSNAN) -#define FP_VXISI (1ull << FPSCR_VXISI) -#define FP_VXIDI (1ull << FPSCR_VXIDI) -#define FP_VXZDZ (1ull << FPSCR_VXZDZ) -#define FP_VXIMZ (1ull << FPSCR_VXIMZ) -#define FP_VXVC (1ull << FPSCR_VXVC) -#define FP_FR (1ull << FSPCR_FR) -#define FP_FI (1ull << FPSCR_FI) -#define FP_C (1ull << FPSCR_C) -#define FP_FL (1ull << FPSCR_FL) -#define FP_FG (1ull << FPSCR_FG) -#define FP_FE (1ull << FPSCR_FE) -#define FP_FU (1ull << FPSCR_FU) -#define FP_FPCC (FP_FL | FP_FG | FP_FE | FP_FU) -#define FP_FPRF (FP_C | FP_FL | FP_FG | FP_FE | FP_FU) -#define FP_VXSOFT (1ull << FPSCR_VXSOFT) -#define FP_VXSQRT (1ull << FPSCR_VXSQRT) -#define FP_VXCVI (1ull << FPSCR_VXCVI) -#define FP_VE (1ull << FPSCR_VE) -#define FP_OE (1ull << FPSCR_OE) -#define FP_UE (1ull << FPSCR_UE) -#define FP_ZE (1ull << FPSCR_ZE) -#define FP_XE (1ull << FPSCR_XE) -#define FP_NI (1ull << FPSCR_NI) -#define FP_RN1 (1ull << FPSCR_RN1) -#define FP_RN (1ull << FPSCR_RN) +#define FP_FX (1ull << FPSCR_FX) +#define FP_FEX (1ull << FPSCR_FEX) +#define FP_VX (1ull << FPSCR_VX) +#define FP_OX (1ull << FPSCR_OX) +#define FP_UX (1ull << FPSCR_UX) +#define FP_ZX (1ull << FPSCR_ZX) +#define FP_XX (1ull << FPSCR_XX) +#define FP_VXSNAN (1ull << FPSCR_VXSNAN) +#define FP_VXISI (1ull << FPSCR_VXISI) +#define FP_VXIDI (1ull << FPSCR_VXIDI) +#define FP_VXZDZ (1ull << FPSCR_VXZDZ) +#define FP_VXIMZ (1ull << FPSCR_VXIMZ) +#define FP_VXVC (1ull << FPSCR_VXVC) +#define FP_FR (1ull << FSPCR_FR) +#define FP_FI (1ull << FPSCR_FI) +#define FP_C (1ull << FPSCR_C) +#define FP_FL (1ull << FPSCR_FL) +#define FP_FG (1ull << FPSCR_FG) +#define FP_FE (1ull << FPSCR_FE) +#define FP_FU (1ull << FPSCR_FU) +#define FP_FPCC (FP_FL | FP_FG | FP_FE | FP_FU) +#define FP_FPRF (FP_C | FP_FL | FP_FG | FP_FE | FP_FU) +#define FP_VXSOFT (1ull << FPSCR_VXSOFT) +#define FP_VXSQRT (1ull << FPSCR_VXSQRT) +#define FP_VXCVI (1ull << FPSCR_VXCVI) +#define FP_VE (1ull << FPSCR_VE) +#define FP_OE (1ull << FPSCR_OE) +#define FP_UE (1ull << FPSCR_UE) +#define FP_ZE (1ull << FPSCR_ZE) +#define FP_XE (1ull << FPSCR_XE) +#define FP_NI (1ull << FPSCR_NI) +#define FP_RN1 (1ull << FPSCR_RN1) +#define FP_RN (1ull << FPSCR_RN) /* the exception bits which can be cleared by mcrfs - includes FX */ #define FP_EX_CLEAR_BITS (FP_FX | FP_OX | FP_UX | FP_ZX | \ @@ -698,8 +705,8 @@ enum { /*****************************************************************************/ /* Vector status and control register */ -#define VSCR_NJ 16 /* Vector non-java */ -#define VSCR_SAT 0 /* Vector saturation */ +#define VSCR_NJ 16 /* Vector non-java */ +#define VSCR_SAT 0 /* Vector saturation */ /*****************************************************************************/ /* BookE e500 MMU registers */ @@ -962,9 +969,10 @@ struct ppc_radix_page_info { /*****************************************************************************/ /* The whole PowerPC CPU context */ -/* PowerPC needs eight modes for different hypervisor/supervisor/guest + - * real/paged mode combinations. The other two modes are for external PID - * load/store. +/* + * PowerPC needs eight modes for different hypervisor/supervisor/guest + * + real/paged mode combinations. The other two modes are for + * external PID load/store. */ #define NB_MMU_MODES 10 #define MMU_MODE8_SUFFIX _epl @@ -976,8 +984,9 @@ struct ppc_radix_page_info { #define PPC_CPU_INDIRECT_OPCODES_LEN 0x20 struct CPUPPCState { - /* First are the most commonly used resources - * during translated code execution + /* + * First are the most commonly used resources during translated + * code execution */ /* general purpose registers */ target_ulong gpr[32]; @@ -1023,8 +1032,8 @@ struct CPUPPCState { /* High part of 128-bit helper return. */ uint64_t retxh; - int access_type; /* when a memory exception occurs, the access - type is stored here */ + /* when a memory exception occurs, the access type is stored here */ + int access_type; CPU_COMMON @@ -1072,8 +1081,10 @@ struct CPUPPCState { /* SPE registers */ uint64_t spe_acc; uint32_t spe_fscr; - /* SPE and Altivec can share a status since they will never be used - * simultaneously */ + /* + * SPE and Altivec can share a status since they will never be + * used simultaneously + */ float_status vec_status; /* Internal devices resources */ @@ -1103,7 +1114,8 @@ struct CPUPPCState { int error_code; uint32_t pending_interrupts; #if !defined(CONFIG_USER_ONLY) - /* This is the IRQ controller, which is implementation dependent + /* + * This is the IRQ controller, which is implementation dependent * and only relevant when emulating a complete machine. */ uint32_t irq_input_state; @@ -1117,7 +1129,8 @@ struct CPUPPCState { hwaddr mpic_iack; /* true when the external proxy facility mode is enabled */ bool mpic_proxy; - /* set when the processor has an HV mode, thus HV priv + /* + * set when the processor has an HV mode, thus HV priv * instructions and SPRs are diallowed if MSR:HV is 0 */ bool has_hv_mode; @@ -1149,8 +1162,10 @@ struct CPUPPCState { /* booke timers */ - /* Specifies bit locations of the Time Base used to signal a fixed timer - * exception on a transition from 0 to 1. (watchdog or fixed-interval timer) + /* + * Specifies bit locations of the Time Base used to signal a fixed + * timer exception on a transition from 0 to 1. (watchdog or + * fixed-interval timer) * * 0 selects the least significant bit. * 63 selects the most significant bit. @@ -1250,8 +1265,8 @@ struct PPCVirtualHypervisorClass { void (*unmap_hptes)(PPCVirtualHypervisor *vhyp, const ppc_hash_pte64_t *hptes, hwaddr ptex, int n); - void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex, - uint64_t pte0, uint64_t pte1); + void (*hpte_set_c)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte1); + void (*hpte_set_r)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte1); void (*get_pate)(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry); target_ulong (*encode_hpt_for_kvm_pr)(PPCVirtualHypervisor *vhyp); }; @@ -1268,10 +1283,8 @@ struct PPCVirtualHypervisorClass { void ppc_cpu_do_interrupt(CPUState *cpu); bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req); -void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, - int flags); -void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f, - fprintf_function cpu_fprintf, int flags); +void ppc_cpu_dump_state(CPUState *cpu, FILE *f, int flags); +void ppc_cpu_dump_statistics(CPUState *cpu, int flags); hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int ppc_cpu_gdb_read_register_apple(CPUState *cpu, uint8_t *buf, int reg); @@ -1292,53 +1305,54 @@ extern const struct VMStateDescription vmstate_ppc_cpu; /*****************************************************************************/ void ppc_translate_init(void); -/* you can call this signal handler from your SIGBUS and SIGSEGV - signal handlers to inform the virtual CPU of exceptions. non zero - is returned if the signal was handled by the virtual CPU. */ -int cpu_ppc_signal_handler (int host_signum, void *pinfo, - void *puc); +/* + * you can call this signal handler from your SIGBUS and SIGSEGV + * signal handlers to inform the virtual CPU of exceptions. non zero + * is returned if the signal was handled by the virtual CPU. + */ +int cpu_ppc_signal_handler(int host_signum, void *pinfo, void *puc); #if defined(CONFIG_USER_ONLY) int ppc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, int rw, int mmu_idx); #endif #if !defined(CONFIG_USER_ONLY) -void ppc_store_sdr1 (CPUPPCState *env, target_ulong value); +void ppc_store_sdr1(CPUPPCState *env, target_ulong value); void ppc_store_ptcr(CPUPPCState *env, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ -void ppc_store_msr (CPUPPCState *env, target_ulong value); +void ppc_store_msr(CPUPPCState *env, target_ulong value); -void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); +void ppc_cpu_list(void); /* Time-base and decrementer management */ #ifndef NO_CPU_IO_DEFS -uint64_t cpu_ppc_load_tbl (CPUPPCState *env); -uint32_t cpu_ppc_load_tbu (CPUPPCState *env); -void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value); -void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value); -uint64_t cpu_ppc_load_atbl (CPUPPCState *env); -uint32_t cpu_ppc_load_atbu (CPUPPCState *env); -void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value); -void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value); +uint64_t cpu_ppc_load_tbl(CPUPPCState *env); +uint32_t cpu_ppc_load_tbu(CPUPPCState *env); +void cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value); +void cpu_ppc_store_tbl(CPUPPCState *env, uint32_t value); +uint64_t cpu_ppc_load_atbl(CPUPPCState *env); +uint32_t cpu_ppc_load_atbu(CPUPPCState *env); +void cpu_ppc_store_atbl(CPUPPCState *env, uint32_t value); +void cpu_ppc_store_atbu(CPUPPCState *env, uint32_t value); bool ppc_decr_clear_on_delivery(CPUPPCState *env); target_ulong cpu_ppc_load_decr(CPUPPCState *env); void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value); target_ulong cpu_ppc_load_hdecr(CPUPPCState *env); void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value); -uint64_t cpu_ppc_load_purr (CPUPPCState *env); -uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env); -uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env); +uint64_t cpu_ppc_load_purr(CPUPPCState *env); +uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env); +uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env); #if !defined(CONFIG_USER_ONLY) -void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value); -void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value); -target_ulong load_40x_pit (CPUPPCState *env); -void store_40x_pit (CPUPPCState *env, target_ulong val); -void store_40x_dbcr0 (CPUPPCState *env, uint32_t val); -void store_40x_sler (CPUPPCState *env, uint32_t val); -void store_booke_tcr (CPUPPCState *env, target_ulong val); -void store_booke_tsr (CPUPPCState *env, target_ulong val); -void ppc_tlb_invalidate_all (CPUPPCState *env); -void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr); +void cpu_ppc601_store_rtcl(CPUPPCState *env, uint32_t value); +void cpu_ppc601_store_rtcu(CPUPPCState *env, uint32_t value); +target_ulong load_40x_pit(CPUPPCState *env); +void store_40x_pit(CPUPPCState *env, target_ulong val); +void store_40x_dbcr0(CPUPPCState *env, uint32_t val); +void store_40x_sler(CPUPPCState *env, uint32_t val); +void store_booke_tcr(CPUPPCState *env, target_ulong val); +void store_booke_tsr(CPUPPCState *env, target_ulong val); +void ppc_tlb_invalidate_all(CPUPPCState *env); +void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr); void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp); #endif #endif @@ -1351,7 +1365,8 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn) gprv = env->gpr[gprn]; if (env->flags & POWERPC_FLAG_SPE) { - /* If the CPU implements the SPE extension, we have to get the + /* + * If the CPU implements the SPE extension, we have to get the * high bits of the GPR from the gprh storage area */ gprv &= 0xFFFFFFFFULL; @@ -1362,8 +1377,8 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn) } /* Device control registers */ -int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp); -int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val); +int ppc_dcr_read(ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp); +int ppc_dcr_write(ppc_dcr_t *dcr_env, int dcrn, uint32_t val); #define POWERPC_CPU_TYPE_SUFFIX "-" TYPE_POWERPC_CPU #define POWERPC_CPU_TYPE_NAME(model) model POWERPC_CPU_TYPE_SUFFIX @@ -1374,7 +1389,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val); /* MMU modes definitions */ #define MMU_USER_IDX 0 -static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch) +static inline int cpu_mmu_index(CPUPPCState *env, bool ifetch) { return ifetch ? env->immu_idx : env->dmmu_idx; } @@ -1992,17 +2007,17 @@ void ppc_compat_add_property(Object *obj, const char *name, /* External Input Interrupt Directed to Guest State */ #define EPCR_EXTGS (1 << 31) -#define L1CSR0_CPE 0x00010000 /* Data Cache Parity Enable */ -#define L1CSR0_CUL 0x00000400 /* (D-)Cache Unable to Lock */ -#define L1CSR0_DCLFR 0x00000100 /* D-Cache Lock Flash Reset */ -#define L1CSR0_DCFI 0x00000002 /* Data Cache Flash Invalidate */ -#define L1CSR0_DCE 0x00000001 /* Data Cache Enable */ +#define L1CSR0_CPE 0x00010000 /* Data Cache Parity Enable */ +#define L1CSR0_CUL 0x00000400 /* (D-)Cache Unable to Lock */ +#define L1CSR0_DCLFR 0x00000100 /* D-Cache Lock Flash Reset */ +#define L1CSR0_DCFI 0x00000002 /* Data Cache Flash Invalidate */ +#define L1CSR0_DCE 0x00000001 /* Data Cache Enable */ -#define L1CSR1_CPE 0x00010000 /* Instruction Cache Parity Enable */ -#define L1CSR1_ICUL 0x00000400 /* I-Cache Unable to Lock */ -#define L1CSR1_ICLFR 0x00000100 /* I-Cache Lock Flash Reset */ -#define L1CSR1_ICFI 0x00000002 /* Instruction Cache Flash Invalidate */ -#define L1CSR1_ICE 0x00000001 /* Instruction Cache Enable */ +#define L1CSR1_CPE 0x00010000 /* Instruction Cache Parity Enable */ +#define L1CSR1_ICUL 0x00000400 /* I-Cache Unable to Lock */ +#define L1CSR1_ICLFR 0x00000100 /* I-Cache Lock Flash Reset */ +#define L1CSR1_ICFI 0x00000002 /* Instruction Cache Flash Invalidate */ +#define L1CSR1_ICE 0x00000001 /* Instruction Cache Enable */ /* HID0 bits */ #define HID0_DEEPNAP (1 << 24) /* pre-2.06 */ @@ -2228,7 +2243,8 @@ enum { }; /*****************************************************************************/ -/* Memory access type : +/* + * Memory access type : * may be needed for precise access rights control and precise exceptions. */ enum { @@ -2244,8 +2260,9 @@ enum { ACCESS_CACHE = 0x60, /* Cache manipulation */ }; -/* Hardware interruption sources: - * all those exception can be raised simulteaneously +/* + * Hardware interrupt sources: + * all those exception can be raised simulteaneously */ /* Input pins definitions */ enum { @@ -2327,9 +2344,11 @@ enum { enum { /* POWER7 input pins */ POWER7_INPUT_INT = 0, - /* POWER7 probably has other inputs, but we don't care about them + /* + * POWER7 probably has other inputs, but we don't care about them * for any existing machine. We can wire these up when we need - * them */ + * them + */ POWER7_INPUT_NB, }; @@ -2409,6 +2428,12 @@ enum { target_ulong cpu_read_xer(CPUPPCState *env); void cpu_write_xer(CPUPPCState *env, target_ulong xer); +/* + * All 64-bit server processors compliant with arch 2.x, ie. 970 and newer, + * have PPC_SEGMENT_64B. + */ +#define is_book3s_arch2x(ctx) (!!((ctx)->insns_flags & PPC_SEGMENT_64B)) + static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { @@ -2623,7 +2648,7 @@ static inline ppc_avr_t *cpu_avr_ptr(CPUPPCState *env, int i) return (ppc_avr_t *)((uintptr_t)env + avr_full_offset(i)); } -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env); +void dump_mmu(CPUPPCState *env); void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len); #endif /* PPC_CPU_H */ diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index 9164fe701b..f102177572 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -1104,19 +1104,19 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ } \ } \ \ - while (offset < (size)/4) { \ + while (offset < (size) / 4) { \ n++; \ - digits[(size)/4-n] = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ - if (digits[(size)/4-n] > 10) { \ + digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ + if (digits[(size) / 4 - n] > 10) { \ dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ return; \ } else { \ - nonzero |= (digits[(size)/4-n] > 0); \ + nonzero |= (digits[(size) / 4 - n] > 0); \ } \ } \ \ if (nonzero) { \ - decNumberSetBCD(&dfp.t, digits+((size)/4)-n, n); \ + decNumberSetBCD(&dfp.t, digits + ((size) / 4) - n, n); \ } \ \ if (s && sgn) { \ @@ -1170,13 +1170,13 @@ DFP_HELPER_XEX(dxexq, 128) static void dfp_set_raw_exp_64(uint64_t *t, uint64_t raw) { *t &= 0x8003ffffffffffffULL; - *t |= (raw << (63-13)); + *t |= (raw << (63 - 13)); } static void dfp_set_raw_exp_128(uint64_t *t, uint64_t raw) { t[HI_IDX] &= 0x80003fffffffffffULL; - t[HI_IDX] |= (raw << (63-17)); + t[HI_IDX] |= (raw << (63 - 17)); } #define DFP_HELPER_IEX(op, size) \ diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index beafcf1ebd..ec2c177091 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -25,9 +25,9 @@ #include "internal.h" #include "helper_regs.h" -//#define DEBUG_OP -//#define DEBUG_SOFTWARE_TLB -//#define DEBUG_EXCEPTIONS +/* #define DEBUG_OP */ +/* #define DEBUG_SOFTWARE_TLB */ +/* #define DEBUG_EXCEPTIONS */ #ifdef DEBUG_EXCEPTIONS # define LOG_EXCP(...) qemu_log(__VA_ARGS__) @@ -126,8 +126,9 @@ static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail) return offset; } -/* Note that this function should be greatly optimized - * when called with a constant excp, from ppc_hw_interrupt +/* + * Note that this function should be greatly optimized when called + * with a constant excp, from ppc_hw_interrupt */ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) { @@ -147,7 +148,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) msr = env->msr & ~0x783f0000ULL; } - /* new interrupt handler msr preserves existing HV and ME unless + /* + * new interrupt handler msr preserves existing HV and ME unless * explicitly overriden */ new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB); @@ -166,7 +168,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) excp = powerpc_reset_wakeup(cs, env, excp, &msr); } - /* Exception targetting modifiers + /* + * Exception targetting modifiers * * LPES0 is supported on POWER7/8/9 * LPES1 is not supported (old iSeries mode) @@ -194,7 +197,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) ail = 0; } - /* Hypervisor emulation assistance interrupt only exists on server + /* + * Hypervisor emulation assistance interrupt only exists on server * arch 2.05 server or later. We also don't want to generate it if * we don't have HVB in msr_mask (PAPR mode). */ @@ -229,8 +233,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) break; case POWERPC_EXCP_MCHECK: /* Machine check exception */ if (msr_me == 0) { - /* Machine check exception is not enabled. - * Enter checkstop state. + /* + * Machine check exception is not enabled. Enter + * checkstop state. */ fprintf(stderr, "Machine check while not allowed. " "Entering checkstop state\n"); @@ -242,8 +247,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) cpu_interrupt_exittb(cs); } if (env->msr_mask & MSR_HVB) { - /* ISA specifies HV, but can be delivered to guest with HV clear - * (e.g., see FWNMI in PAPR). + /* + * ISA specifies HV, but can be delivered to guest with HV + * clear (e.g., see FWNMI in PAPR). */ new_msr |= (target_ulong)MSR_HVB; } @@ -294,9 +300,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) break; case POWERPC_EXCP_ALIGN: /* Alignment exception */ /* Get rS/rD and rA from faulting opcode */ - /* Note: the opcode fields will not be set properly for a direct - * store load/store, but nobody cares as nobody actually uses - * direct store segments. + /* + * Note: the opcode fields will not be set properly for a + * direct store load/store, but nobody cares as nobody + * actually uses direct store segments. */ env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; break; @@ -310,7 +317,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) return; } - /* FP exceptions always have NIP pointing to the faulting + /* + * FP exceptions always have NIP pointing to the faulting * instruction, so always use store_next and claim we are * precise in the MSR. */ @@ -341,7 +349,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) dump_syscall(env); lev = env->error_code; - /* We need to correct the NIP which in this case is supposed + /* + * We need to correct the NIP which in this case is supposed * to point to the next instruction */ env->nip += 4; @@ -425,8 +434,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) new_msr |= ((target_ulong)1 << MSR_ME); } if (env->msr_mask & MSR_HVB) { - /* ISA specifies HV, but can be delivered to guest with HV clear - * (e.g., see FWNMI in PAPR, NMI injection in QEMU). + /* + * ISA specifies HV, but can be delivered to guest with HV + * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU). */ new_msr |= (target_ulong)MSR_HVB; } else { @@ -675,7 +685,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) env->spr[asrr1] = env->spr[srr1]; } - /* Sort out endianness of interrupt, this differs depending on the + /* + * Sort out endianness of interrupt, this differs depending on the * CPU, the HV mode, etc... */ #ifdef TARGET_PPC64 @@ -716,8 +727,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } vector |= env->excp_prefix; - /* AIL only works if there is no HV transition and we are running with - * translations enabled + /* + * AIL only works if there is no HV transition and we are running + * with translations enabled */ if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) || ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { @@ -745,8 +757,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } } #endif - /* We don't use hreg_store_msr here as already have treated - * any special case that could occur. Just store MSR and update hflags + /* + * We don't use hreg_store_msr here as already have treated any + * special case that could occur. Just store MSR and update hflags * * Note: We *MUST* not use hreg_store_msr() as-is anyway because it * will prevent setting of the HV bit which some exceptions might need @@ -762,8 +775,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) /* Reset the reservation */ env->reserve_addr = -1; - /* Any interrupt is context synchronizing, check if TCG TLB - * needs a delayed flush on ppc64 + /* + * Any interrupt is context synchronizing, check if TCG TLB needs + * a delayed flush on ppc64 */ check_tlb_flush(env, false); } @@ -1015,8 +1029,9 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) cs = CPU(ppc_env_get_cpu(env)); cs->halted = 1; - /* The architecture specifies that HDEC interrupts are - * discarded in PM states + /* + * The architecture specifies that HDEC interrupts are discarded + * in PM states */ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); @@ -1047,8 +1062,9 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) #if defined(DEBUG_OP) cpu_dump_rfi(env->nip, env->msr); #endif - /* No need to raise an exception here, - * as rfi is always the last insn of a TB + /* + * No need to raise an exception here, as rfi is always the last + * insn of a TB */ cpu_interrupt_exittb(cs); /* Reset the reservation */ @@ -1067,8 +1083,9 @@ void helper_rfi(CPUPPCState *env) #if defined(TARGET_PPC64) void helper_rfid(CPUPPCState *env) { - /* The architeture defines a number of rules for which bits - * can change but in practice, we handle this in hreg_store_msr() + /* + * The architeture defines a number of rules for which bits can + * change but in practice, we handle this in hreg_store_msr() * which will be called by do_rfi(), so there is no need to filter * here */ @@ -1206,9 +1223,11 @@ static int book3s_dbell2irq(target_ulong rb) { int msg = rb & DBELL_TYPE_MASK; - /* A Directed Hypervisor Doorbell message is sent only if the + /* + * A Directed Hypervisor Doorbell message is sent only if the * message type is 5. All other types are reserved and the - * instruction is a no-op */ + * instruction is a no-op + */ return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1; } diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 2ed4f42275..0b7308f539 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -90,10 +90,12 @@ uint32_t helper_tosingle(uint64_t arg) ret = extract64(arg, 62, 2) << 30; ret |= extract64(arg, 29, 30); } else { - /* Zero or Denormal result. If the exponent is in bounds for - * a single-precision denormal result, extract the proper bits. - * If the input is not zero, and the exponent is out of bounds, - * then the result is undefined; this underflows to zero. + /* + * Zero or Denormal result. If the exponent is in bounds for + * a single-precision denormal result, extract the proper + * bits. If the input is not zero, and the exponent is out of + * bounds, then the result is undefined; this underflows to + * zero. */ ret = extract64(arg, 63, 1) << 31; if (unlikely(exp >= 874)) { @@ -1090,7 +1092,7 @@ uint32_t helper_ftsqrt(uint64_t frb) fe_flag = 1; } else if (unlikely(float64_is_neg(frb))) { fe_flag = 1; - } else if (!float64_is_zero(frb) && (e_b <= (-1022+52))) { + } else if (!float64_is_zero(frb) && (e_b <= (-1022 + 52))) { fe_flag = 1; } @@ -1789,7 +1791,8 @@ uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2) #define float64_to_float64(x, env) x -/* VSX_ADD_SUB - VSX floating point add/subract +/* + * VSX_ADD_SUB - VSX floating point add/subract * name - instruction mnemonic * op - operation (add or sub) * nels - number of elements (1, 2 or 4) @@ -1872,7 +1875,8 @@ void helper_xsaddqp(CPUPPCState *env, uint32_t opcode) do_float_check_status(env, GETPC()); } -/* VSX_MUL - VSX floating point multiply +/* + * VSX_MUL - VSX floating point multiply * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) @@ -1950,7 +1954,8 @@ void helper_xsmulqp(CPUPPCState *env, uint32_t opcode) do_float_check_status(env, GETPC()); } -/* VSX_DIV - VSX floating point divide +/* + * VSX_DIV - VSX floating point divide * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) @@ -2034,7 +2039,8 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode) do_float_check_status(env, GETPC()); } -/* VSX_RE - VSX floating point reciprocal estimate +/* + * VSX_RE - VSX floating point reciprocal estimate * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) @@ -2075,7 +2081,8 @@ VSX_RE(xsresp, 1, float64, VsrD(0), 1, 1) VSX_RE(xvredp, 2, float64, VsrD(i), 0, 0) VSX_RE(xvresp, 4, float32, VsrW(i), 0, 0) -/* VSX_SQRT - VSX floating point square root +/* + * VSX_SQRT - VSX floating point square root * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) @@ -2124,7 +2131,8 @@ VSX_SQRT(xssqrtsp, 1, float64, VsrD(0), 1, 1) VSX_SQRT(xvsqrtdp, 2, float64, VsrD(i), 0, 0) VSX_SQRT(xvsqrtsp, 4, float32, VsrW(i), 0, 0) -/* VSX_RSQRTE - VSX floating point reciprocal square root estimate +/* + *VSX_RSQRTE - VSX floating point reciprocal square root estimate * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) @@ -2174,7 +2182,8 @@ VSX_RSQRTE(xsrsqrtesp, 1, float64, VsrD(0), 1, 1) VSX_RSQRTE(xvrsqrtedp, 2, float64, VsrD(i), 0, 0) VSX_RSQRTE(xvrsqrtesp, 4, float32, VsrW(i), 0, 0) -/* VSX_TDIV - VSX floating point test for divide +/* + * VSX_TDIV - VSX floating point test for divide * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) @@ -2207,18 +2216,20 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ if (unlikely(tp##_is_any_nan(xa.fld) || \ tp##_is_any_nan(xb.fld))) { \ fe_flag = 1; \ - } else if ((e_b <= emin) || (e_b >= (emax-2))) { \ + } else if ((e_b <= emin) || (e_b >= (emax - 2))) { \ fe_flag = 1; \ } else if (!tp##_is_zero(xa.fld) && \ (((e_a - e_b) >= emax) || \ - ((e_a - e_b) <= (emin+1)) || \ - (e_a <= (emin+nbits)))) { \ + ((e_a - e_b) <= (emin + 1)) || \ + (e_a <= (emin + nbits)))) { \ fe_flag = 1; \ } \ \ if (unlikely(tp##_is_zero_or_denormal(xb.fld))) { \ - /* XB is not zero because of the above check and */ \ - /* so must be denormalized. */ \ + /* \ + * XB is not zero because of the above check and so \ + * must be denormalized. \ + */ \ fg_flag = 1; \ } \ } \ @@ -2231,7 +2242,8 @@ VSX_TDIV(xstdivdp, 1, float64, VsrD(0), -1022, 1023, 52) VSX_TDIV(xvtdivdp, 2, float64, VsrD(i), -1022, 1023, 52) VSX_TDIV(xvtdivsp, 4, float32, VsrW(i), -126, 127, 23) -/* VSX_TSQRT - VSX floating point test for square root +/* + * VSX_TSQRT - VSX floating point test for square root * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) @@ -2266,13 +2278,15 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } else if (unlikely(tp##_is_neg(xb.fld))) { \ fe_flag = 1; \ } else if (!tp##_is_zero(xb.fld) && \ - (e_b <= (emin+nbits))) { \ + (e_b <= (emin + nbits))) { \ fe_flag = 1; \ } \ \ if (unlikely(tp##_is_zero_or_denormal(xb.fld))) { \ - /* XB is not zero because of the above check and */ \ - /* therefore must be denormalized. */ \ + /* \ + * XB is not zero because of the above check and \ + * therefore must be denormalized. \ + */ \ fg_flag = 1; \ } \ } \ @@ -2285,7 +2299,8 @@ VSX_TSQRT(xstsqrtdp, 1, float64, VsrD(0), -1022, 52) VSX_TSQRT(xvtsqrtdp, 2, float64, VsrD(i), -1022, 52) VSX_TSQRT(xvtsqrtsp, 4, float32, VsrW(i), -126, 23) -/* VSX_MADD - VSX floating point muliply/add variations +/* + * VSX_MADD - VSX floating point muliply/add variations * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) @@ -2322,8 +2337,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ float_status tstat = env->fp_status; \ set_float_exception_flags(0, &tstat); \ if (r2sp && (tstat.float_rounding_mode == float_round_nearest_even)) {\ - /* Avoid double rounding errors by rounding the intermediate */ \ - /* result to odd. */ \ + /* \ + * Avoid double rounding errors by rounding the intermediate \ + * result to odd. \ + */ \ set_float_rounding_mode(float_round_to_zero, &tstat); \ xt_out.fld = tp##_muladd(xa.fld, b->fld, c->fld, \ maddflgs, &tstat); \ @@ -2388,7 +2405,8 @@ VSX_MADD(xvnmaddmsp, 4, float32, VsrW(i), NMADD_FLGS, 0, 0, 0) VSX_MADD(xvnmsubasp, 4, float32, VsrW(i), NMSUB_FLGS, 1, 0, 0) VSX_MADD(xvnmsubmsp, 4, float32, VsrW(i), NMSUB_FLGS, 0, 0, 0) -/* VSX_SCALAR_CMP_DP - VSX scalar floating point compare double precision +/* + * VSX_SCALAR_CMP_DP - VSX scalar floating point compare double precision * op - instruction mnemonic * cmp - comparison operation * exp - expected result of comparison @@ -2604,7 +2622,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ VSX_SCALAR_CMPQ(xscmpoqp, 1) VSX_SCALAR_CMPQ(xscmpuqp, 0) -/* VSX_MAX_MIN - VSX floating point maximum/minimum +/* + * VSX_MAX_MIN - VSX floating point maximum/minimum * name - instruction mnemonic * op - operation (max or min) * nels - number of elements (1, 2 or 4) @@ -2733,7 +2752,8 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ VSX_MAX_MINJ(xsmaxjdp, 1); VSX_MAX_MINJ(xsminjdp, 0); -/* VSX_CMP - VSX floating point compare +/* + * VSX_CMP - VSX floating point compare * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) @@ -2778,7 +2798,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - if ((opcode >> (31-21)) & 1) { \ + if ((opcode >> (31 - 21)) & 1) { \ env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \ } \ do_float_check_status(env, GETPC()); \ @@ -2793,7 +2813,8 @@ VSX_CMP(xvcmpgesp, 4, float32, VsrW(i), le, 1, 1) VSX_CMP(xvcmpgtsp, 4, float32, VsrW(i), lt, 1, 1) VSX_CMP(xvcmpnesp, 4, float32, VsrW(i), eq, 0, 0) -/* VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion +/* + * VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * stp - source type (float32 or float64) @@ -2829,10 +2850,11 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1) VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, VsrW(0), VsrD(0), 1) -VSX_CVT_FP_TO_FP(xvcvdpsp, 2, float64, float32, VsrD(i), VsrW(2*i), 0) -VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, VsrW(2*i), VsrD(i), 0) +VSX_CVT_FP_TO_FP(xvcvdpsp, 2, float64, float32, VsrD(i), VsrW(2 * i), 0) +VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, VsrW(2 * i), VsrD(i), 0) -/* VSX_CVT_FP_TO_FP_VECTOR - VSX floating point/floating point conversion +/* + * VSX_CVT_FP_TO_FP_VECTOR - VSX floating point/floating point conversion * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * stp - source type (float32 or float64) @@ -2868,7 +2890,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1) -/* VSX_CVT_FP_TO_FP_HP - VSX floating point/floating point conversion +/* + * VSX_CVT_FP_TO_FP_HP - VSX floating point/floating point conversion * involving one half precision value * op - instruction mnemonic * nels - number of elements (1, 2 or 4) @@ -2953,7 +2976,8 @@ uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) return float32_to_float64(xb >> 32, &tstat); } -/* VSX_CVT_FP_TO_INT - VSX floating point to integer conversion +/* + * VSX_CVT_FP_TO_INT - VSX floating point to integer conversion * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * stp - source type (float32 or float64) @@ -2996,17 +3020,18 @@ VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, VsrD(0), VsrD(0), 0ULL) VSX_CVT_FP_TO_INT(xscvdpuxws, 1, float64, uint32, VsrD(0), VsrW(1), 0U) VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, VsrD(i), VsrD(i), \ 0x8000000000000000ULL) -VSX_CVT_FP_TO_INT(xvcvdpsxws, 2, float64, int32, VsrD(i), VsrW(2*i), \ +VSX_CVT_FP_TO_INT(xvcvdpsxws, 2, float64, int32, VsrD(i), VsrW(2 * i), \ 0x80000000U) VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, VsrD(i), VsrD(i), 0ULL) -VSX_CVT_FP_TO_INT(xvcvdpuxws, 2, float64, uint32, VsrD(i), VsrW(2*i), 0U) -VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2*i), VsrD(i), \ +VSX_CVT_FP_TO_INT(xvcvdpuxws, 2, float64, uint32, VsrD(i), VsrW(2 * i), 0U) +VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2 * i), VsrD(i), \ 0x8000000000000000ULL) VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), 0x80000000U) -VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2*i), VsrD(i), 0ULL) +VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2 * i), VsrD(i), 0ULL) VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), 0U) -/* VSX_CVT_FP_TO_INT_VECTOR - VSX floating point to integer conversion +/* + * VSX_CVT_FP_TO_INT_VECTOR - VSX floating point to integer conversion * op - instruction mnemonic * stp - source type (float32 or float64) * ttp - target type (int32, uint32, int64 or uint64) @@ -3040,7 +3065,8 @@ VSX_CVT_FP_TO_INT_VECTOR(xscvqpswz, float128, int32, f128, VsrD(0), \ VSX_CVT_FP_TO_INT_VECTOR(xscvqpudz, float128, uint64, f128, VsrD(0), 0x0ULL) VSX_CVT_FP_TO_INT_VECTOR(xscvqpuwz, float128, uint32, f128, VsrD(0), 0x0ULL) -/* VSX_CVT_INT_TO_FP - VSX integer to floating point conversion +/* + * VSX_CVT_INT_TO_FP - VSX integer to floating point conversion * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * stp - source type (int32, uint32, int64 or uint64) @@ -3079,14 +3105,15 @@ VSX_CVT_INT_TO_FP(xscvsxdsp, 1, int64, float64, VsrD(0), VsrD(0), 1, 1) VSX_CVT_INT_TO_FP(xscvuxdsp, 1, uint64, float64, VsrD(0), VsrD(0), 1, 1) VSX_CVT_INT_TO_FP(xvcvsxddp, 2, int64, float64, VsrD(i), VsrD(i), 0, 0) VSX_CVT_INT_TO_FP(xvcvuxddp, 2, uint64, float64, VsrD(i), VsrD(i), 0, 0) -VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, VsrW(2*i), VsrD(i), 0, 0) -VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, VsrW(2*i), VsrD(i), 0, 0) -VSX_CVT_INT_TO_FP(xvcvsxdsp, 2, int64, float32, VsrD(i), VsrW(2*i), 0, 0) -VSX_CVT_INT_TO_FP(xvcvuxdsp, 2, uint64, float32, VsrD(i), VsrW(2*i), 0, 0) +VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, VsrW(2 * i), VsrD(i), 0, 0) +VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, VsrW(2 * i), VsrD(i), 0, 0) +VSX_CVT_INT_TO_FP(xvcvsxdsp, 2, int64, float32, VsrD(i), VsrW(2 * i), 0, 0) +VSX_CVT_INT_TO_FP(xvcvuxdsp, 2, uint64, float32, VsrD(i), VsrW(2 * i), 0, 0) VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, VsrW(i), VsrW(i), 0, 0) VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, VsrW(i), VsrW(i), 0, 0) -/* VSX_CVT_INT_TO_FP_VECTOR - VSX integer to floating point conversion +/* + * VSX_CVT_INT_TO_FP_VECTOR - VSX integer to floating point conversion * op - instruction mnemonic * stp - source type (int32, uint32, int64 or uint64) * ttp - target type (float32 or float64) @@ -3111,13 +3138,15 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ VSX_CVT_INT_TO_FP_VECTOR(xscvsdqp, int64, float128, VsrD(0), f128) VSX_CVT_INT_TO_FP_VECTOR(xscvudqp, uint64, float128, VsrD(0), f128) -/* For "use current rounding mode", define a value that will not be one of - * the existing rounding model enums. +/* + * For "use current rounding mode", define a value that will not be + * one of the existing rounding model enums. */ #define FLOAT_ROUND_CURRENT (float_round_nearest_even + float_round_down + \ float_round_up + float_round_to_zero) -/* VSX_ROUND - VSX floating point round +/* + * VSX_ROUND - VSX floating point round * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * tp - type (float32 or float64) @@ -3150,9 +3179,11 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ } \ \ - /* If this is not a "use current rounding mode" instruction, \ + /* \ + * If this is not a "use current rounding mode" instruction, \ * then inhibit setting of the XX bit and restore rounding \ - * mode from FPSCR */ \ + * mode from FPSCR \ + */ \ if (rmode != FLOAT_ROUND_CURRENT) { \ fpscr_set_rounding_mode(env); \ env->fp_status.float_exception_flags &= ~float_flag_inexact; \ @@ -3234,7 +3265,8 @@ void helper_xvxsigsp(CPUPPCState *env, uint32_t opcode) putVSR(xT(opcode), &xt, env); } -/* VSX_TEST_DC - VSX floating point test data class +/* + * VSX_TEST_DC - VSX floating point test data class * op - instruction mnemonic * nels - number of elements (1, 2 or 4) * xbn - VSR register number diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index fbf3821f4b..ce3625f44e 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -33,14 +33,14 @@ static int ppc_gdb_register_len_apple(int n) return 8; case 64 ... 95: return 16; - case 64+32: /* nip */ - case 65+32: /* msr */ - case 67+32: /* lr */ - case 68+32: /* ctr */ - case 70+32: /* fpscr */ + case 64 + 32: /* nip */ + case 65 + 32: /* msr */ + case 67 + 32: /* lr */ + case 68 + 32: /* ctr */ + case 70 + 32: /* fpscr */ return 8; - case 66+32: /* cr */ - case 69+32: /* xer */ + case 66 + 32: /* cr */ + case 69 + 32: /* xer */ return 4; default: return 0; @@ -84,11 +84,14 @@ static int ppc_gdb_register_len(int n) } } -/* We need to present the registers to gdb in the "current" memory ordering. - For user-only mode we get this for free; TARGET_WORDS_BIGENDIAN is set to - the proper ordering for the binary, and cannot be changed. - For system mode, TARGET_WORDS_BIGENDIAN is always set, and we must check - the current mode of the chip to see if we're running in little-endian. */ +/* + * We need to present the registers to gdb in the "current" memory + * ordering. For user-only mode we get this for free; + * TARGET_WORDS_BIGENDIAN is set to the proper ordering for the + * binary, and cannot be changed. For system mode, + * TARGET_WORDS_BIGENDIAN is always set, and we must check the current + * mode of the chip to see if we're running in little-endian. + */ void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len) { #ifndef CONFIG_USER_ONLY @@ -104,11 +107,12 @@ void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len) #endif } -/* Old gdb always expects FP registers. Newer (xml-aware) gdb only +/* + * Old gdb always expects FP registers. Newer (xml-aware) gdb only * expects whatever the target description contains. Due to a * historical mishap the FP registers appear in between core integer - * regs and PC, MSR, CR, and so forth. We hack round this by giving the - * FP regs zero size when talking to a newer gdb. + * regs and PC, MSR, CR, and so forth. We hack round this by giving + * the FP regs zero size when talking to a newer gdb. */ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) diff --git a/target/ppc/helper_regs.h b/target/ppc/helper_regs.h index a2205e1044..922da76c6c 100644 --- a/target/ppc/helper_regs.h +++ b/target/ppc/helper_regs.h @@ -44,10 +44,11 @@ static inline void hreg_swap_gpr_tgpr(CPUPPCState *env) static inline void hreg_compute_mem_idx(CPUPPCState *env) { - /* This is our encoding for server processors. The architecture + /* + * This is our encoding for server processors. The architecture * specifies that there is no such thing as userspace with - * translation off, however it appears that MacOS does it and - * some 32-bit CPUs support it. Weird... + * translation off, however it appears that MacOS does it and some + * 32-bit CPUs support it. Weird... * * 0 = Guest User space virtual mode * 1 = Guest Kernel space virtual mode @@ -143,7 +144,8 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, /* Change the exception prefix on PowerPC 601 */ env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; } - /* If PR=1 then EE, IR and DR must be 1 + /* + * If PR=1 then EE, IR and DR must be 1 * * Note: We only enforce this on 64-bit server processors. * It appears that: @@ -152,7 +154,7 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, * - 64-bit embedded implementations do not need any operation to be * performed when PR is set. */ - if ((env->insns_flags & PPC_SEGMENT_64B) && ((value >> MSR_PR) & 1)) { + if (is_book3s_arch2x(env) && ((value >> MSR_PR) & 1)) { value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR); } #endif diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 162add561e..f6a088ac08 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -137,7 +137,8 @@ uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe) /* if x = 0xab, returns 0xababababababababa */ #define pattern(x) (((x) & 0xff) * (~(target_ulong)0 / 0xff)) -/* substract 1 from each byte, and with inverse, check if MSB is set at each +/* + * subtract 1 from each byte, and with inverse, check if MSB is set at each * byte. * i.e. ((0x00 - 0x01) & ~(0x00)) & 0x80 * (0xFF & 0xFF) & 0x80 = 0x80 (zero found) @@ -156,7 +157,8 @@ uint32_t helper_cmpeqb(target_ulong ra, target_ulong rb) #undef haszero #undef hasvalue -/* Return invalid random number. +/* + * Return invalid random number. * * FIXME: Add rng backend or other mechanism to get cryptographically suitable * random number @@ -181,7 +183,7 @@ uint64_t helper_bpermd(uint64_t rs, uint64_t rb) uint64_t ra = 0; for (i = 0; i < 8; i++) { - int index = (rs >> (i*8)) & 0xFF; + int index = (rs >> (i * 8)) & 0xFF; if (index < 64) { if (rb & PPC_BIT(index)) { ra |= 1 << i; @@ -370,7 +372,8 @@ target_ulong helper_divso(CPUPPCState *env, target_ulong arg1, /* 602 specific instructions */ /* mfrom is the most crazy instruction ever seen, imho ! */ /* Real implementation uses a ROM table. Do the same */ -/* Extremely decomposed: +/* + * Extremely decomposed: * -arg / 256 * return 256 * log10(10 + 1.0) + 0.5 */ @@ -393,7 +396,7 @@ target_ulong helper_602_mfrom(target_ulong arg) for (index = 0; index < ARRAY_SIZE(r->element); index++) #else #define VECTOR_FOR_INORDER_I(index, element) \ - for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--) + for (index = ARRAY_SIZE(r->element) - 1; index >= 0; index--) #endif /* Saturating arithmetic helpers. */ @@ -634,7 +637,8 @@ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ } \ } -/* VABSDU - Vector absolute difference unsigned +/* + * VABSDU - Vector absolute difference unsigned * name - instruction mnemonic suffix (b: byte, h: halfword, w: word) * element - element type to access from vector */ @@ -739,7 +743,8 @@ void helper_vcmpne##suffix(CPUPPCState *env, ppc_avr_t *r, \ } \ } -/* VCMPNEZ - Vector compare not equal to zero +/* + * VCMPNEZ - Vector compare not equal to zero * suffix - instruction mnemonic suffix (b: byte, h: halfword, w: word) * element - element type to access from vector */ @@ -1138,7 +1143,7 @@ void helper_vpermr(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, #define VBPERMQ_DW(index) (((index) & 0x40) != 0) #define EXTRACT_BIT(avr, i, index) (extract64((avr)->u64[i], index, 1)) #else -#define VBPERMQ_INDEX(avr, i) ((avr)->u8[15-(i)]) +#define VBPERMQ_INDEX(avr, i) ((avr)->u8[15 - (i)]) #define VBPERMD_INDEX(i) (1 - i) #define VBPERMQ_DW(index) (((index) & 0x40) == 0) #define EXTRACT_BIT(avr, i, index) \ @@ -1169,7 +1174,7 @@ void helper_vbpermq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) int index = VBPERMQ_INDEX(b, i); if (index < 128) { - uint64_t mask = (1ull << (63-(index & 0x3F))); + uint64_t mask = (1ull << (63 - (index & 0x3F))); if (a->u64[VBPERMQ_DW(index)] & mask) { perm |= (0x8000 >> i); } @@ -1449,9 +1454,9 @@ void helper_vgbbd(ppc_avr_t *r, ppc_avr_t *b) VECTOR_FOR_INORDER_I(i, u8) { #if defined(HOST_WORDS_BIGENDIAN) - t[i>>3] |= VGBBD_MASKS[b->u8[i]] >> (i & 7); + t[i >> 3] |= VGBBD_MASKS[b->u8[i]] >> (i & 7); #else - t[i>>3] |= VGBBD_MASKS[b->u8[i]] >> (7-(i & 7)); + t[i >> 3] |= VGBBD_MASKS[b->u8[i]] >> (7 - (i & 7)); #endif } @@ -1463,19 +1468,19 @@ void helper_vgbbd(ppc_avr_t *r, ppc_avr_t *b) void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int i, j; \ - trgtyp prod[sizeof(ppc_avr_t)/sizeof(a->srcfld[0])]; \ + trgtyp prod[sizeof(ppc_avr_t) / sizeof(a->srcfld[0])]; \ \ VECTOR_FOR_INORDER_I(i, srcfld) { \ prod[i] = 0; \ for (j = 0; j < sizeof(a->srcfld[0]) * 8; j++) { \ - if (a->srcfld[i] & (1ull<<j)) { \ + if (a->srcfld[i] & (1ull << j)) { \ prod[i] ^= ((trgtyp)b->srcfld[i] << j); \ } \ } \ } \ \ VECTOR_FOR_INORDER_I(i, trgfld) { \ - r->trgfld[i] = prod[2*i] ^ prod[2*i+1]; \ + r->trgfld[i] = prod[2 * i] ^ prod[2 * i + 1]; \ } \ } @@ -1493,7 +1498,7 @@ void helper_vpmsumd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) VECTOR_FOR_INORDER_I(i, u64) { prod[i] = 0; for (j = 0; j < 64; j++) { - if (a->u64[i] & (1ull<<j)) { + if (a->u64[i] & (1ull << j)) { prod[i] ^= (((__uint128_t)b->u64[i]) << j); } } @@ -1508,7 +1513,7 @@ void helper_vpmsumd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) VECTOR_FOR_INORDER_I(i, u64) { prod[i].VsrD(1) = prod[i].VsrD(0) = 0; for (j = 0; j < 64; j++) { - if (a->u64[i] & (1ull<<j)) { + if (a->u64[i] & (1ull << j)) { ppc_avr_t bshift; if (j == 0) { bshift.VsrD(0) = 0; @@ -1548,9 +1553,9 @@ void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) VECTOR_FOR_INORDER_I(j, u32) { uint32_t e = x[i]->u32[j]; - result.u16[4*i+j] = (((e >> 9) & 0xfc00) | - ((e >> 6) & 0x3e0) | - ((e >> 3) & 0x1f)); + result.u16[4 * i + j] = (((e >> 9) & 0xfc00) | + ((e >> 6) & 0x3e0) | + ((e >> 3) & 0x1f)); } } *r = result; @@ -1568,7 +1573,7 @@ void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ VECTOR_FOR_INORDER_I(i, from) { \ result.to[i] = cvt(a0->from[i], &sat); \ - result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \ + result.to[i + ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat);\ } \ *r = result; \ if (dosat && sat) { \ @@ -1736,9 +1741,11 @@ VEXTU_X_DO(vextuhrx, 16, 0) VEXTU_X_DO(vextuwrx, 32, 0) #undef VEXTU_X_DO -/* The specification says that the results are undefined if all of the - * shift counts are not identical. We check to make sure that they are - * to conform to what real hardware appears to do. */ +/* + * The specification says that the results are undefined if all of the + * shift counts are not identical. We check to make sure that they + * are to conform to what real hardware appears to do. + */ #define VSHIFT(suffix, leftp) \ void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ @@ -1805,9 +1812,10 @@ void helper_vsrv(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) int i; unsigned int shift, bytes; - /* Use reverse order, as destination and source register can be same. Its - * being modified in place saving temporary, reverse order will guarantee - * that computed result is not fed back. + /* + * Use reverse order, as destination and source register can be + * same. Its being modified in place saving temporary, reverse + * order will guarantee that computed result is not fed back. */ for (i = ARRAY_SIZE(r->u8) - 1; i >= 0; i--) { shift = b->u8[i] & 0x7; /* extract shift value */ @@ -1840,7 +1848,7 @@ void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) #if defined(HOST_WORDS_BIGENDIAN) memmove(&r->u8[0], &a->u8[sh], 16 - sh); - memset(&r->u8[16-sh], 0, sh); + memset(&r->u8[16 - sh], 0, sh); #else memmove(&r->u8[sh], &a->u8[0], 16 - sh); memset(&r->u8[0], 0, sh); @@ -2112,7 +2120,7 @@ void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) ppc_avr_t result; \ \ for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \ - uint16_t e = b->u16[hi ? i : i+4]; \ + uint16_t e = b->u16[hi ? i : i + 4]; \ uint8_t a = (e >> 15) ? 0xff : 0; \ uint8_t r = (e >> 10) & 0x1f; \ uint8_t g = (e >> 5) & 0x1f; \ @@ -2463,7 +2471,7 @@ static void bcd_put_digit(ppc_avr_t *bcd, uint8_t digit, int n) { if (n & 1) { bcd->u8[BCD_DIG_BYTE(n)] &= 0x0F; - bcd->u8[BCD_DIG_BYTE(n)] |= (digit<<4); + bcd->u8[BCD_DIG_BYTE(n)] |= (digit << 4); } else { bcd->u8[BCD_DIG_BYTE(n)] &= 0xF0; bcd->u8[BCD_DIG_BYTE(n)] |= digit; @@ -3220,7 +3228,7 @@ void helper_vshasigmad(ppc_avr_t *r, ppc_avr_t *a, uint32_t st_six) for (i = 0; i < ARRAY_SIZE(r->u64); i++) { if (st == 0) { - if ((six & (0x8 >> (2*i))) == 0) { + if ((six & (0x8 >> (2 * i))) == 0) { r->VsrD(i) = ror64(a->VsrD(i), 1) ^ ror64(a->VsrD(i), 8) ^ (a->VsrD(i) >> 7); @@ -3230,7 +3238,7 @@ void helper_vshasigmad(ppc_avr_t *r, ppc_avr_t *a, uint32_t st_six) (a->VsrD(i) >> 6); } } else { /* st == 1 */ - if ((six & (0x8 >> (2*i))) == 0) { + if ((six & (0x8 >> (2 * i))) == 0) { r->VsrD(i) = ror64(a->VsrD(i), 28) ^ ror64(a->VsrD(i), 34) ^ ror64(a->VsrD(i), 39); diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 2427c8ee13..02e22e2017 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -49,24 +49,14 @@ #include "elf.h" #include "sysemu/kvm_int.h" -//#define DEBUG_KVM - -#ifdef DEBUG_KVM -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - #define PROC_DEVTREE_CPU "/proc/device-tree/cpus/" const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; -static int cap_interrupt_unset = false; -static int cap_interrupt_level = false; +static int cap_interrupt_unset; +static int cap_interrupt_level; static int cap_segstate; static int cap_booke_sregs; static int cap_ppc_smt; @@ -96,7 +86,8 @@ static int cap_large_decr; static uint32_t debug_inst_opcode; -/* XXX We have a race condition where we actually have a level triggered +/* + * XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest * takes but ignores it, goes to sleep and never gets notified that there's * still an interrupt pending. @@ -114,10 +105,12 @@ static void kvm_kick_cpu(void *opaque) qemu_cpu_kick(CPU(cpu)); } -/* Check whether we are running with KVM-PR (instead of KVM-HV). This +/* + * Check whether we are running with KVM-PR (instead of KVM-HV). This * should only be used for fallback tests - generally we should use * explicit capabilities for the features we want, rather than - * assuming what is/isn't available depending on the KVM variant. */ + * assuming what is/isn't available depending on the KVM variant. + */ static bool kvmppc_is_pr(KVMState *ks) { /* Assume KVM-PR if the GET_PVINFO capability is available */ @@ -143,8 +136,10 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR); cap_epr = kvm_check_extension(s, KVM_CAP_PPC_EPR); cap_ppc_watchdog = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_WATCHDOG); - /* Note: we don't set cap_papr here, because this capability is - * only activated after this by kvmppc_set_papr() */ + /* + * Note: we don't set cap_papr here, because this capability is + * only activated after this by kvmppc_set_papr() + */ cap_htab_fd = kvm_vm_check_extension(s, KVM_CAP_PPC_HTAB_FD); cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL); cap_ppc_smt = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT); @@ -160,7 +155,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s) * in KVM at this moment. * * TODO: call kvm_vm_check_extension() with the right capability - * after the kernel starts implementing it.*/ + * after the kernel starts implementing it. + */ cap_ppc_pvr_compat = false; if (!cap_interrupt_level) { @@ -186,10 +182,13 @@ static int kvm_arch_sync_sregs(PowerPCCPU *cpu) int ret; if (cenv->excp_model == POWERPC_EXCP_BOOKE) { - /* What we're really trying to say is "if we're on BookE, we use - the native PVR for now". This is the only sane way to check - it though, so we potentially confuse users that they can run - BookE guests on BookS. Let's hope nobody dares enough :) */ + /* + * What we're really trying to say is "if we're on BookE, we + * use the native PVR for now". This is the only sane way to + * check it though, so we potentially confuse users that they + * can run BookE guests on BookS. Let's hope nobody dares + * enough :) + */ return 0; } else { if (!cap_segstate) { @@ -421,12 +420,14 @@ void kvm_check_mmu(PowerPCCPU *cpu, Error **errp) } if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) { - /* Mostly what guest pagesizes we can use are related to the + /* + * Mostly what guest pagesizes we can use are related to the * host pages used to map guest RAM, which is handled in the * platform code. Cache-Inhibited largepages (64k) however are * used for I/O, so if they're mapped to the host at all it * will be a normal mapping, not a special hugepage one used - * for RAM. */ + * for RAM. + */ if (getpagesize() < 0x10000) { error_setg(errp, "KVM can't supply 64kiB CI pages, which guest expects"); @@ -440,9 +441,9 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu) return POWERPC_CPU(cpu)->vcpu_id; } -/* e500 supports 2 h/w breakpoint and 2 watchpoint. - * book3s supports only 1 watchpoint, so array size - * of 4 is sufficient for now. +/* + * e500 supports 2 h/w breakpoint and 2 watchpoint. book3s supports + * only 1 watchpoint, so array size of 4 is sufficient for now. */ #define MAX_HW_BKPTS 4 @@ -497,9 +498,12 @@ int kvm_arch_init_vcpu(CPUState *cs) break; case POWERPC_MMU_2_07: if (!cap_htm && !kvmppc_is_pr(cs->kvm_state)) { - /* KVM-HV has transactional memory on POWER8 also without the - * KVM_CAP_PPC_HTM extension, so enable it here instead as - * long as it's availble to userspace on the host. */ + /* + * KVM-HV has transactional memory on POWER8 also without + * the KVM_CAP_PPC_HTM extension, so enable it here + * instead as long as it's availble to userspace on the + * host. + */ if (qemu_getauxval(AT_HWCAP2) & PPC_FEATURE2_HAS_HTM) { cap_htm = true; } @@ -626,7 +630,7 @@ static int kvm_put_fp(CPUState *cs) reg.addr = (uintptr_t)&fpscr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to set FPSCR to KVM: %s\n", strerror(errno)); + trace_kvm_failed_fpscr_set(strerror(errno)); return ret; } @@ -647,8 +651,8 @@ static int kvm_put_fp(CPUState *cs) ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to set %s%d to KVM: %s\n", vsx ? "VSR" : "FPR", - i, strerror(errno)); + trace_kvm_failed_fp_set(vsx ? "VSR" : "FPR", i, + strerror(errno)); return ret; } } @@ -659,7 +663,7 @@ static int kvm_put_fp(CPUState *cs) reg.addr = (uintptr_t)&env->vscr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to set VSCR to KVM: %s\n", strerror(errno)); + trace_kvm_failed_vscr_set(strerror(errno)); return ret; } @@ -668,7 +672,7 @@ static int kvm_put_fp(CPUState *cs) reg.addr = (uintptr_t)cpu_avr_ptr(env, i); ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to set VR%d to KVM: %s\n", i, strerror(errno)); + trace_kvm_failed_vr_set(i, strerror(errno)); return ret; } } @@ -693,7 +697,7 @@ static int kvm_get_fp(CPUState *cs) reg.addr = (uintptr_t)&fpscr; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to get FPSCR from KVM: %s\n", strerror(errno)); + trace_kvm_failed_fpscr_get(strerror(errno)); return ret; } else { env->fpscr = fpscr; @@ -709,8 +713,8 @@ static int kvm_get_fp(CPUState *cs) ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to get %s%d from KVM: %s\n", - vsx ? "VSR" : "FPR", i, strerror(errno)); + trace_kvm_failed_fp_get(vsx ? "VSR" : "FPR", i, + strerror(errno)); return ret; } else { #ifdef HOST_WORDS_BIGENDIAN @@ -733,7 +737,7 @@ static int kvm_get_fp(CPUState *cs) reg.addr = (uintptr_t)&env->vscr; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to get VSCR from KVM: %s\n", strerror(errno)); + trace_kvm_failed_vscr_get(strerror(errno)); return ret; } @@ -742,8 +746,7 @@ static int kvm_get_fp(CPUState *cs) reg.addr = (uintptr_t)cpu_avr_ptr(env, i); ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to get VR%d from KVM: %s\n", - i, strerror(errno)); + trace_kvm_failed_vr_get(i, strerror(errno)); return ret; } } @@ -764,7 +767,7 @@ static int kvm_get_vpa(CPUState *cs) reg.addr = (uintptr_t)&spapr_cpu->vpa_addr; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to get VPA address from KVM: %s\n", strerror(errno)); + trace_kvm_failed_vpa_addr_get(strerror(errno)); return ret; } @@ -774,8 +777,7 @@ static int kvm_get_vpa(CPUState *cs) reg.addr = (uintptr_t)&spapr_cpu->slb_shadow_addr; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to get SLB shadow state from KVM: %s\n", - strerror(errno)); + trace_kvm_failed_slb_get(strerror(errno)); return ret; } @@ -785,8 +787,7 @@ static int kvm_get_vpa(CPUState *cs) reg.addr = (uintptr_t)&spapr_cpu->dtl_addr; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to get dispatch trace log state from KVM: %s\n", - strerror(errno)); + trace_kvm_failed_dtl_get(strerror(errno)); return ret; } @@ -800,10 +801,12 @@ static int kvm_put_vpa(CPUState *cs) struct kvm_one_reg reg; int ret; - /* SLB shadow or DTL can't be registered unless a master VPA is + /* + * SLB shadow or DTL can't be registered unless a master VPA is * registered. That means when restoring state, if a VPA *is* * registered, we need to set that up first. If not, we need to - * deregister the others before deregistering the master VPA */ + * deregister the others before deregistering the master VPA + */ assert(spapr_cpu->vpa_addr || !(spapr_cpu->slb_shadow_addr || spapr_cpu->dtl_addr)); @@ -812,7 +815,7 @@ static int kvm_put_vpa(CPUState *cs) reg.addr = (uintptr_t)&spapr_cpu->vpa_addr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to set VPA address to KVM: %s\n", strerror(errno)); + trace_kvm_failed_vpa_addr_set(strerror(errno)); return ret; } } @@ -823,7 +826,7 @@ static int kvm_put_vpa(CPUState *cs) reg.addr = (uintptr_t)&spapr_cpu->slb_shadow_addr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to set SLB shadow state to KVM: %s\n", strerror(errno)); + trace_kvm_failed_slb_set(strerror(errno)); return ret; } @@ -833,8 +836,7 @@ static int kvm_put_vpa(CPUState *cs) reg.addr = (uintptr_t)&spapr_cpu->dtl_addr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to set dispatch trace log state to KVM: %s\n", - strerror(errno)); + trace_kvm_failed_dtl_set(strerror(errno)); return ret; } @@ -843,7 +845,7 @@ static int kvm_put_vpa(CPUState *cs) reg.addr = (uintptr_t)&spapr_cpu->vpa_addr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret < 0) { - DPRINTF("Unable to set VPA address to KVM: %s\n", strerror(errno)); + trace_kvm_failed_null_vpa_addr_set(strerror(errno)); return ret; } } @@ -929,8 +931,9 @@ int kvm_arch_put_registers(CPUState *cs, int level) regs.pid = env->spr[SPR_BOOKE_PID]; - for (i = 0;i < 32; i++) + for (i = 0; i < 32; i++) { regs.gpr[i] = env->gpr[i]; + } regs.cr = 0; for (i = 0; i < 8; i++) { @@ -938,8 +941,9 @@ int kvm_arch_put_registers(CPUState *cs, int level) } ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); - if (ret < 0) + if (ret < 0) { return ret; + } kvm_put_fp(cs); @@ -962,10 +966,12 @@ int kvm_arch_put_registers(CPUState *cs, int level) if (cap_one_reg) { int i; - /* We deliberately ignore errors here, for kernels which have + /* + * We deliberately ignore errors here, for kernels which have * the ONE_REG calls, but don't support the specific * registers, there's a reasonable chance things will still - * work, at least until we try to migrate. */ + * work, at least until we try to migrate. + */ for (i = 0; i < 1024; i++) { uint64_t id = env->spr_cb[i].one_reg_id; @@ -996,7 +1002,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) if (cap_papr) { if (kvm_put_vpa(cs) < 0) { - DPRINTF("Warning: Unable to set VPA information to KVM\n"); + trace_kvm_failed_put_vpa(); } } @@ -1207,8 +1213,9 @@ int kvm_arch_get_registers(CPUState *cs) int i, ret; ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); - if (ret < 0) + if (ret < 0) { return ret; + } cr = regs.cr; for (i = 7; i >= 0; i--) { @@ -1236,8 +1243,9 @@ int kvm_arch_get_registers(CPUState *cs) env->spr[SPR_BOOKE_PID] = regs.pid; - for (i = 0;i < 32; i++) + for (i = 0; i < 32; i++) { env->gpr[i] = regs.gpr[i]; + } kvm_get_fp(cs); @@ -1262,10 +1270,12 @@ int kvm_arch_get_registers(CPUState *cs) if (cap_one_reg) { int i; - /* We deliberately ignore errors here, for kernels which have + /* + * We deliberately ignore errors here, for kernels which have * the ONE_REG calls, but don't support the specific * registers, there's a reasonable chance things will still - * work, at least until we try to migrate. */ + * work, at least until we try to migrate. + */ for (i = 0; i < 1024; i++) { uint64_t id = env->spr_cb[i].one_reg_id; @@ -1296,7 +1306,7 @@ int kvm_arch_get_registers(CPUState *cs) if (cap_papr) { if (kvm_get_vpa(cs) < 0) { - DPRINTF("Warning: Unable to get VPA information from KVM\n"); + trace_kvm_failed_get_vpa(); } } @@ -1339,20 +1349,24 @@ void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) qemu_mutex_lock_iothread(); - /* PowerPC QEMU tracks the various core input pins (interrupt, critical - * interrupt, reset, etc) in PPC-specific env->irq_input_state. */ + /* + * PowerPC QEMU tracks the various core input pins (interrupt, + * critical interrupt, reset, etc) in PPC-specific + * env->irq_input_state. + */ if (!cap_interrupt_level && run->ready_for_interrupt_injection && (cs->interrupt_request & CPU_INTERRUPT_HARD) && - (env->irq_input_state & (1<<PPC_INPUT_INT))) + (env->irq_input_state & (1 << PPC_INPUT_INT))) { - /* For now KVM disregards the 'irq' argument. However, in the - * future KVM could cache it in-kernel to avoid a heavyweight exit - * when reading the UIC. + /* + * For now KVM disregards the 'irq' argument. However, in the + * future KVM could cache it in-kernel to avoid a heavyweight + * exit when reading the UIC. */ irq = KVM_INTERRUPT_SET; - DPRINTF("injected interrupt %d\n", irq); + trace_kvm_injected_interrupt(irq); r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &irq); if (r < 0) { printf("cpu %d fail inject %x\n", cs->cpu_index, irq); @@ -1363,9 +1377,12 @@ void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) (NANOSECONDS_PER_SECOND / 50)); } - /* We don't know if there are more interrupts pending after this. However, - * the guest will return to userspace in the course of handling this one - * anyways, so we will get a chance to deliver the rest. */ + /* + * We don't know if there are more interrupts pending after + * this. However, the guest will return to userspace in the course + * of handling this one anyways, so we will get a chance to + * deliver the rest. + */ qemu_mutex_unlock_iothread(); } @@ -1394,18 +1411,22 @@ static int kvmppc_handle_halt(PowerPCCPU *cpu) } /* map dcr access to existing qemu dcr emulation */ -static int kvmppc_handle_dcr_read(CPUPPCState *env, uint32_t dcrn, uint32_t *data) +static int kvmppc_handle_dcr_read(CPUPPCState *env, + uint32_t dcrn, uint32_t *data) { - if (ppc_dcr_read(env->dcr_env, dcrn, data) < 0) + if (ppc_dcr_read(env->dcr_env, dcrn, data) < 0) { fprintf(stderr, "Read to unhandled DCR (0x%x)\n", dcrn); + } return 0; } -static int kvmppc_handle_dcr_write(CPUPPCState *env, uint32_t dcrn, uint32_t data) +static int kvmppc_handle_dcr_write(CPUPPCState *env, + uint32_t dcrn, uint32_t data) { - if (ppc_dcr_write(env->dcr_env, dcrn, data) < 0) + if (ppc_dcr_write(env->dcr_env, dcrn, data) < 0) { fprintf(stderr, "Write to unhandled DCR (0x%x)\n", dcrn); + } return 0; } @@ -1697,20 +1718,20 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) switch (run->exit_reason) { case KVM_EXIT_DCR: if (run->dcr.is_write) { - DPRINTF("handle dcr write\n"); + trace_kvm_handle_dcr_write(); ret = kvmppc_handle_dcr_write(env, run->dcr.dcrn, run->dcr.data); } else { - DPRINTF("handle dcr read\n"); + trace_kvm_handle_drc_read(); ret = kvmppc_handle_dcr_read(env, run->dcr.dcrn, &run->dcr.data); } break; case KVM_EXIT_HLT: - DPRINTF("handle halt\n"); + trace_kvm_handle_halt(); ret = kvmppc_handle_halt(cpu); break; #if defined(TARGET_PPC64) case KVM_EXIT_PAPR_HCALL: - DPRINTF("handle PAPR hypercall\n"); + trace_kvm_handle_papr_hcall(); run->papr_hcall.ret = spapr_hypercall(cpu, run->papr_hcall.nr, run->papr_hcall.args); @@ -1718,18 +1739,18 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) break; #endif case KVM_EXIT_EPR: - DPRINTF("handle epr\n"); + trace_kvm_handle_epr(); run->epr.epr = ldl_phys(cs->as, env->mpic_iack); ret = 0; break; case KVM_EXIT_WATCHDOG: - DPRINTF("handle watchdog expiry\n"); + trace_kvm_handle_watchdog_expiry(); watchdog_perform_action(); ret = 0; break; case KVM_EXIT_DEBUG: - DPRINTF("handle debug exception\n"); + trace_kvm_handle_debug_exception(); if (kvm_handle_debug(cpu, run)) { ret = EXCP_DEBUG; break; @@ -1832,7 +1853,7 @@ static int read_cpuinfo(const char *field, char *value, int len) ret = 0; break; } - } while(*line); + } while (*line); fclose(f); @@ -1849,7 +1870,8 @@ uint32_t kvmppc_get_tbfreq(void) return retval; } - if (!(ns = strchr(line, ':'))) { + ns = strchr(line, ':'); + if (!ns) { return retval; } @@ -1875,7 +1897,8 @@ static int kvmppc_find_cpu_dt(char *buf, int buf_len) struct dirent *dirp; DIR *dp; - if ((dp = opendir(PROC_DEVTREE_CPU)) == NULL) { + dp = opendir(PROC_DEVTREE_CPU); + if (!dp) { printf("Can't open directory " PROC_DEVTREE_CPU "\n"); return -1; } @@ -1929,10 +1952,11 @@ static uint64_t kvmppc_read_int_dt(const char *filename) return 0; } -/* Read a CPU node property from the host device tree that's a single +/* + * Read a CPU node property from the host device tree that's a single * integer (32-bit or 64-bit). Returns 0 if anything goes wrong - * (can't find or open the property, or doesn't understand the - * format) */ + * (can't find or open the property, or doesn't understand the format) + */ static uint64_t kvmppc_read_int_cpu_dt(const char *propname) { char buf[PATH_MAX], *tmp; @@ -1991,7 +2015,7 @@ int kvmppc_get_hasidle(CPUPPCState *env) int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) { - uint32_t *hc = (uint32_t*)buf; + uint32_t *hc = (uint32_t *)buf; struct kvm_ppc_pvinfo pvinfo; if (!kvmppc_get_pvinfo(env, &pvinfo)) { @@ -2064,8 +2088,10 @@ void kvmppc_set_papr(PowerPCCPU *cpu) exit(1); } - /* Update the capability flag so we sync the right information - * with kvm */ + /* + * Update the capability flag so we sync the right information + * with kvm + */ cap_papr = 1; } @@ -2133,10 +2159,12 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift) long rampagesize, best_page_shift; int i; - /* Find the largest hardware supported page size that's less than - * or equal to the (logical) backing page size of guest RAM */ + /* + * Find the largest hardware supported page size that's less than + * or equal to the (logical) backing page size of guest RAM + */ kvm_get_smmu_info(&info, &error_fatal); - rampagesize = qemu_getrampagesize(); + rampagesize = qemu_minrampagesize(); best_page_shift = 0; for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) { @@ -2184,7 +2212,8 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t page_shift, int fd; void *table; - /* Must set fd to -1 so we don't try to munmap when called for + /* + * Must set fd to -1 so we don't try to munmap when called for * destroying the table, which the upper layers -will- do */ *pfd = -1; @@ -2229,7 +2258,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t page_shift, len = nb_table * sizeof(uint64_t); /* FIXME: round this up to page size */ - table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + table = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (table == MAP_FAILED) { fprintf(stderr, "KVM: Failed to map TCE table for liobn 0x%x\n", liobn); @@ -2272,10 +2301,12 @@ int kvmppc_reset_htab(int shift_hint) int ret; ret = kvm_vm_ioctl(kvm_state, KVM_PPC_ALLOCATE_HTAB, &shift); if (ret == -ENOTTY) { - /* At least some versions of PR KVM advertise the + /* + * At least some versions of PR KVM advertise the * capability, but don't implement the ioctl(). Oops. * Return 0 so that we allocate the htab in qemu, as is - * correct for PR. */ + * correct for PR. + */ return 0; } else if (ret < 0) { return ret; @@ -2283,9 +2314,12 @@ int kvmppc_reset_htab(int shift_hint) return shift; } - /* We have a kernel that predates the htab reset calls. For PR + /* + * We have a kernel that predates the htab reset calls. For PR * KVM, we need to allocate the htab ourselves, for an HV KVM of - * this era, it has allocated a 16MB fixed size hash table already. */ + * this era, it has allocated a 16MB fixed size hash table + * already. + */ if (kvmppc_is_pr(kvm_state)) { /* PR - tell caller to allocate htab */ return 0; @@ -2667,8 +2701,8 @@ int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns) } } } while ((rc != 0) - && ((max_ns < 0) - || ((qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) < max_ns))); + && ((max_ns < 0) || + ((qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) < max_ns))); return (rc == 0) ? 1 : 0; } @@ -2677,7 +2711,7 @@ int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, uint16_t n_valid, uint16_t n_invalid) { struct kvm_get_htab_header *buf; - size_t chunksize = sizeof(*buf) + n_valid*HASH_PTE_SIZE_64; + size_t chunksize = sizeof(*buf) + n_valid * HASH_PTE_SIZE_64; ssize_t rc; buf = alloca(chunksize); @@ -2685,7 +2719,7 @@ int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, buf->n_valid = n_valid; buf->n_invalid = n_invalid; - qemu_get_buffer(f, (void *)(buf + 1), HASH_PTE_SIZE_64*n_valid); + qemu_get_buffer(f, (void *)(buf + 1), HASH_PTE_SIZE_64 * n_valid); rc = write(fd, buf, chunksize); if (rc < 0) { diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index 2c2ea30e87..22385134b4 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -117,7 +117,8 @@ static inline int kvmppc_get_hasidle(CPUPPCState *env) return 0; } -static inline int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) +static inline int kvmppc_get_hypercall(CPUPPCState *env, + uint8_t *buf, int buf_len) { return -1; } diff --git a/target/ppc/machine.c b/target/ppc/machine.c index a92d0ad3a3..25cdb9088b 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -24,22 +24,26 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) #endif target_ulong xer; - for (i = 0; i < 32; i++) + for (i = 0; i < 32; i++) { qemu_get_betls(f, &env->gpr[i]); + } #if !defined(TARGET_PPC64) - for (i = 0; i < 32; i++) + for (i = 0; i < 32; i++) { qemu_get_betls(f, &env->gprh[i]); + } #endif qemu_get_betls(f, &env->lr); qemu_get_betls(f, &env->ctr); - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { qemu_get_be32s(f, &env->crf[i]); + } qemu_get_betls(f, &xer); cpu_write_xer(env, xer); qemu_get_betls(f, &env->reserve_addr); qemu_get_betls(f, &env->msr); - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { qemu_get_betls(f, &env->tgpr[i]); + } for (i = 0; i < 32; i++) { union { float64 d; @@ -56,14 +60,19 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) qemu_get_sbe32s(f, &slb_nr); #endif qemu_get_betls(f, &sdr1); - for (i = 0; i < 32; i++) + for (i = 0; i < 32; i++) { qemu_get_betls(f, &env->sr[i]); - for (i = 0; i < 2; i++) - for (j = 0; j < 8; j++) + } + for (i = 0; i < 2; i++) { + for (j = 0; j < 8; j++) { qemu_get_betls(f, &env->DBAT[i][j]); - for (i = 0; i < 2; i++) - for (j = 0; j < 8; j++) + } + } + for (i = 0; i < 2; i++) { + for (j = 0; j < 8; j++) { qemu_get_betls(f, &env->IBAT[i][j]); + } + } qemu_get_sbe32s(f, &env->nb_tlb); qemu_get_sbe32s(f, &env->tlb_per_way); qemu_get_sbe32s(f, &env->nb_ways); @@ -71,17 +80,19 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) qemu_get_sbe32s(f, &env->id_tlbs); qemu_get_sbe32s(f, &env->nb_pids); if (env->tlb.tlb6) { - // XXX assumes 6xx + /* XXX assumes 6xx */ for (i = 0; i < env->nb_tlb; i++) { qemu_get_betls(f, &env->tlb.tlb6[i].pte0); qemu_get_betls(f, &env->tlb.tlb6[i].pte1); qemu_get_betls(f, &env->tlb.tlb6[i].EPN); } } - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { qemu_get_betls(f, &env->pb[i]); - for (i = 0; i < 1024; i++) + } + for (i = 0; i < 1024; i++) { qemu_get_betls(f, &env->spr[i]); + } if (!cpu->vhyp) { ppc_store_sdr1(env, sdr1); } @@ -94,8 +105,9 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) qemu_get_sbe32s(f, &env->error_code); qemu_get_be32s(f, &env->pending_interrupts); qemu_get_be32s(f, &env->irq_input_state); - for (i = 0; i < POWERPC_EXCP_NB; i++) + for (i = 0; i < POWERPC_EXCP_NB; i++) { qemu_get_betls(f, &env->excp_vectors[i]); + } qemu_get_betls(f, &env->excp_prefix); qemu_get_betls(f, &env->ivor_mask); qemu_get_betls(f, &env->ivpr_mask); @@ -253,22 +265,24 @@ static int cpu_pre_save(void *opaque) env->spr[SPR_BOOKE_SPEFSCR] = env->spe_fscr; for (i = 0; (i < 4) && (i < env->nb_BATs); i++) { - env->spr[SPR_DBAT0U + 2*i] = env->DBAT[0][i]; - env->spr[SPR_DBAT0U + 2*i + 1] = env->DBAT[1][i]; - env->spr[SPR_IBAT0U + 2*i] = env->IBAT[0][i]; - env->spr[SPR_IBAT0U + 2*i + 1] = env->IBAT[1][i]; + env->spr[SPR_DBAT0U + 2 * i] = env->DBAT[0][i]; + env->spr[SPR_DBAT0U + 2 * i + 1] = env->DBAT[1][i]; + env->spr[SPR_IBAT0U + 2 * i] = env->IBAT[0][i]; + env->spr[SPR_IBAT0U + 2 * i + 1] = env->IBAT[1][i]; } - for (i = 0; (i < 4) && ((i+4) < env->nb_BATs); i++) { - env->spr[SPR_DBAT4U + 2*i] = env->DBAT[0][i+4]; - env->spr[SPR_DBAT4U + 2*i + 1] = env->DBAT[1][i+4]; - env->spr[SPR_IBAT4U + 2*i] = env->IBAT[0][i+4]; - env->spr[SPR_IBAT4U + 2*i + 1] = env->IBAT[1][i+4]; + for (i = 0; (i < 4) && ((i + 4) < env->nb_BATs); i++) { + env->spr[SPR_DBAT4U + 2 * i] = env->DBAT[0][i + 4]; + env->spr[SPR_DBAT4U + 2 * i + 1] = env->DBAT[1][i + 4]; + env->spr[SPR_IBAT4U + 2 * i] = env->IBAT[0][i + 4]; + env->spr[SPR_IBAT4U + 2 * i + 1] = env->IBAT[1][i + 4]; } /* Hacks for migration compatibility between 2.6, 2.7 & 2.8 */ if (cpu->pre_2_8_migration) { - /* Mask out bits that got added to msr_mask since the versions - * which stupidly included it in the migration stream. */ + /* + * Mask out bits that got added to msr_mask since the versions + * which stupidly included it in the migration stream. + */ target_ulong metamask = 0 #if defined(TARGET_PPC64) | (1ULL << MSR_TS0) @@ -277,9 +291,10 @@ static int cpu_pre_save(void *opaque) ; cpu->mig_msr_mask = env->msr_mask & ~metamask; cpu->mig_insns_flags = env->insns_flags & insns_compat_mask; - /* CPU models supported by old machines all have PPC_MEM_TLBIE, - * so we set it unconditionally to allow backward migration from - * a POWER9 host to a POWER8 host. + /* + * CPU models supported by old machines all have + * PPC_MEM_TLBIE, so we set it unconditionally to allow + * backward migration from a POWER9 host to a POWER8 host. */ cpu->mig_insns_flags |= PPC_MEM_TLBIE; cpu->mig_insns_flags2 = env->insns_flags2 & insns_compat_mask2; @@ -379,23 +394,26 @@ static int cpu_post_load(void *opaque, int version_id) env->spe_fscr = env->spr[SPR_BOOKE_SPEFSCR]; for (i = 0; (i < 4) && (i < env->nb_BATs); i++) { - env->DBAT[0][i] = env->spr[SPR_DBAT0U + 2*i]; - env->DBAT[1][i] = env->spr[SPR_DBAT0U + 2*i + 1]; - env->IBAT[0][i] = env->spr[SPR_IBAT0U + 2*i]; - env->IBAT[1][i] = env->spr[SPR_IBAT0U + 2*i + 1]; + env->DBAT[0][i] = env->spr[SPR_DBAT0U + 2 * i]; + env->DBAT[1][i] = env->spr[SPR_DBAT0U + 2 * i + 1]; + env->IBAT[0][i] = env->spr[SPR_IBAT0U + 2 * i]; + env->IBAT[1][i] = env->spr[SPR_IBAT0U + 2 * i + 1]; } - for (i = 0; (i < 4) && ((i+4) < env->nb_BATs); i++) { - env->DBAT[0][i+4] = env->spr[SPR_DBAT4U + 2*i]; - env->DBAT[1][i+4] = env->spr[SPR_DBAT4U + 2*i + 1]; - env->IBAT[0][i+4] = env->spr[SPR_IBAT4U + 2*i]; - env->IBAT[1][i+4] = env->spr[SPR_IBAT4U + 2*i + 1]; + for (i = 0; (i < 4) && ((i + 4) < env->nb_BATs); i++) { + env->DBAT[0][i + 4] = env->spr[SPR_DBAT4U + 2 * i]; + env->DBAT[1][i + 4] = env->spr[SPR_DBAT4U + 2 * i + 1]; + env->IBAT[0][i + 4] = env->spr[SPR_IBAT4U + 2 * i]; + env->IBAT[1][i + 4] = env->spr[SPR_IBAT4U + 2 * i + 1]; } if (!cpu->vhyp) { ppc_store_sdr1(env, env->spr[SPR_SDR1]); } - /* Invalidate all supported msr bits except MSR_TGPR/MSR_HVB before restoring */ + /* + * Invalidate all supported msr bits except MSR_TGPR/MSR_HVB + * before restoring + */ msr = env->msr; env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB); ppc_store_msr(env, msr); @@ -409,7 +427,7 @@ static bool fpu_needed(void *opaque) { PowerPCCPU *cpu = opaque; - return (cpu->env.insns_flags & PPC_FLOAT); + return cpu->env.insns_flags & PPC_FLOAT; } static const VMStateDescription vmstate_fpu = { @@ -428,7 +446,7 @@ static bool altivec_needed(void *opaque) { PowerPCCPU *cpu = opaque; - return (cpu->env.insns_flags & PPC_ALTIVEC); + return cpu->env.insns_flags & PPC_ALTIVEC; } static int get_vscr(QEMUFile *f, void *opaque, size_t size, @@ -483,7 +501,7 @@ static bool vsx_needed(void *opaque) { PowerPCCPU *cpu = opaque; - return (cpu->env.insns_flags2 & PPC2_VSX); + return cpu->env.insns_flags2 & PPC2_VSX; } static const VMStateDescription vmstate_vsx = { @@ -591,7 +609,7 @@ static bool slb_needed(void *opaque) PowerPCCPU *cpu = opaque; /* We don't support any of the old segment table based 64-bit CPUs */ - return (cpu->env.mmu_model & POWERPC_MMU_64); + return cpu->env.mmu_model & POWERPC_MMU_64; } static int slb_post_load(void *opaque, int version_id) @@ -600,8 +618,10 @@ static int slb_post_load(void *opaque, int version_id) CPUPPCState *env = &cpu->env; int i; - /* We've pulled in the raw esid and vsid values from the migration - * stream, but we need to recompute the page size pointers */ + /* + * We've pulled in the raw esid and vsid values from the migration + * stream, but we need to recompute the page size pointers + */ for (i = 0; i < cpu->hash64_opts->slb_size; i++) { if (ppc_store_slb(cpu, i, env->slb[i].esid, env->slb[i].vsid) < 0) { /* Migration source had bad values in its SLB */ diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index 9c5a68579e..5b0f9ee50d 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -27,7 +27,7 @@ #include "internal.h" #include "qemu/atomic128.h" -//#define DEBUG_OP +/* #define DEBUG_OP */ static inline bool needs_byteswap(const CPUPPCState *env) { @@ -103,10 +103,11 @@ void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg) do_lsw(env, addr, nb, reg, GETPC()); } -/* PPC32 specification says we must generate an exception if - * rA is in the range of registers to be loaded. - * In an other hand, IBM says this is valid, but rA won't be loaded. - * For now, I'll follow the spec... +/* + * PPC32 specification says we must generate an exception if rA is in + * the range of registers to be loaded. In an other hand, IBM says + * this is valid, but rA won't be loaded. For now, I'll follow the + * spec... */ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb) @@ -199,7 +200,8 @@ void helper_dcbzep(CPUPPCState *env, target_ulong addr, uint32_t opcode) void helper_icbi(CPUPPCState *env, target_ulong addr) { addr &= ~(env->dcache_line_size - 1); - /* Invalidate one cache line : + /* + * Invalidate one cache line : * PowerPC specification says this is to be treated like a load * (not a fetch) by the MMU. To be sure it will be so, * do the load "by hand". @@ -346,17 +348,19 @@ uint32_t helper_stqcx_be_parallel(CPUPPCState *env, target_ulong addr, #define LO_IDX 0 #endif -/* We use msr_le to determine index ordering in a vector. However, - byteswapping is not simply controlled by msr_le. We also need to take - into account endianness of the target. This is done for the little-endian - PPC64 user-mode target. */ +/* + * We use msr_le to determine index ordering in a vector. However, + * byteswapping is not simply controlled by msr_le. We also need to + * take into account endianness of the target. This is done for the + * little-endian PPC64 user-mode target. + */ #define LVE(name, access, swap, element) \ void helper_##name(CPUPPCState *env, ppc_avr_t *r, \ target_ulong addr) \ { \ size_t n_elems = ARRAY_SIZE(r->element); \ - int adjust = HI_IDX*(n_elems - 1); \ + int adjust = HI_IDX * (n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ if (msr_le) { \ @@ -476,12 +480,13 @@ VSX_STXVL(stxvll, 1) void helper_tbegin(CPUPPCState *env) { - /* As a degenerate implementation, always fail tbegin. The reason + /* + * As a degenerate implementation, always fail tbegin. The reason * given is "Nesting overflow". The "persistent" bit is set, * providing a hint to the error handler to not retry. The TFIAR * captures the address of the failure, which is this tbegin - * instruction. Instruction execution will continue with the - * next instruction in memory, which is precisely what we want. + * instruction. Instruction execution will continue with the next + * instruction in memory, which is precisely what we want. */ env->spr[SPR_TEXASR] = diff --git a/target/ppc/mfrom_table.inc.c b/target/ppc/mfrom_table.inc.c index 6a1fa375c9..1653b974a4 100644 --- a/target/ppc/mfrom_table.inc.c +++ b/target/ppc/mfrom_table.inc.c @@ -1,5 +1,4 @@ -static const uint8_t mfrom_ROM_table[602] = -{ +static const uint8_t mfrom_ROM_table[602] = { 77, 77, 76, 76, 75, 75, 74, 74, 73, 73, 72, 72, 71, 71, 70, 70, 69, 69, 68, 68, 68, 67, 67, 66, diff --git a/target/ppc/mfrom_table_gen.c b/target/ppc/mfrom_table_gen.c index 631791808e..f96c4268ba 100644 --- a/target/ppc/mfrom_table_gen.c +++ b/target/ppc/mfrom_table_gen.c @@ -2,7 +2,7 @@ #include "qemu/osdep.h" #include <math.h> -int main (void) +int main(void) { double d; uint8_t n; @@ -10,7 +10,8 @@ int main (void) printf("static const uint8_t mfrom_ROM_table[602] =\n{\n "); for (i = 0; i < 602; i++) { - /* Extremely decomposed: + /* + * Extremely decomposed: * -T0 / 256 * T0 = 256 * log10(10 + 1.0) + 0.5 */ @@ -23,8 +24,9 @@ int main (void) d += 0.5; n = d; printf("%3d, ", n); - if ((i & 7) == 7) + if ((i & 7) == 7) { printf("\n "); + } } printf("\n};\n"); diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index c65d1ade15..0a81e98ee9 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -210,10 +210,11 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value) hreg_store_msr(env, value, 0); } -/* This code is lifted from MacOnLinux. It is called whenever - * THRM1,2 or 3 is read an fixes up the values in such a way - * that will make MacOS not hang. These registers exist on some - * 75x and 74xx processors. +/* + * This code is lifted from MacOnLinux. It is called whenever THRM1,2 + * or 3 is read an fixes up the values in such a way that will make + * MacOS not hang. These registers exist on some 75x and 74xx + * processors. */ void helper_fixup_thrm(CPUPPCState *env) { diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c index e8562a7c87..55cf156a0b 100644 --- a/target/ppc/mmu-hash32.c +++ b/target/ppc/mmu-hash32.c @@ -27,7 +27,7 @@ #include "mmu-hash32.h" #include "exec/log.h" -//#define DEBUG_BAT +/* #define DEBUG_BAT */ #ifdef DEBUG_BATS # define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__) @@ -228,8 +228,10 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr, qemu_log_mask(CPU_LOG_MMU, "direct store...\n"); if ((sr & 0x1FF00000) >> 20 == 0x07f) { - /* Memory-forced I/O controller interface access */ - /* If T=1 and BUID=x'07F', the 601 performs a memory access + /* + * Memory-forced I/O controller interface access + * + * If T=1 and BUID=x'07F', the 601 performs a memory access * to SR[28-31] LA[4-31], bypassing all protection mechanisms. */ *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF); @@ -265,9 +267,11 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr, } return 1; case ACCESS_CACHE: - /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */ - /* Should make the instruction do no-op. - * As it already do no-op, it's quite easy :-) + /* + * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi + * + * Should make the instruction do no-op. As it already do + * no-op, it's quite easy :-) */ *raddr = eaddr; return 0; @@ -341,6 +345,24 @@ static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off, return -1; } +static void ppc_hash32_set_r(PowerPCCPU *cpu, hwaddr pte_offset, uint32_t pte1) +{ + target_ulong base = ppc_hash32_hpt_base(cpu); + hwaddr offset = pte_offset + 6; + + /* The HW performs a non-atomic byte update */ + stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01); +} + +static void ppc_hash32_set_c(PowerPCCPU *cpu, hwaddr pte_offset, uint64_t pte1) +{ + target_ulong base = ppc_hash32_hpt_base(cpu); + hwaddr offset = pte_offset + 7; + + /* The HW performs a non-atomic byte update */ + stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80); +} + static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu, target_ulong sr, target_ulong eaddr, ppc_hash_pte32_t *pte) @@ -399,7 +421,6 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, hwaddr pte_offset; ppc_hash_pte32_t pte; int prot; - uint32_t new_pte1; const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC}; hwaddr raddr; @@ -515,18 +536,20 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, /* 8. Update PTE referenced and changed bits if necessary */ - new_pte1 = pte.pte1 | HPTE32_R_R; /* set referenced bit */ - if (rwx == 1) { - new_pte1 |= HPTE32_R_C; /* set changed (dirty) bit */ - } else { - /* Treat the page as read-only for now, so that a later write - * will pass through this function again to set the C bit */ - prot &= ~PAGE_WRITE; - } - - if (new_pte1 != pte.pte1) { - ppc_hash32_store_hpte1(cpu, pte_offset, new_pte1); + if (!(pte.pte1 & HPTE32_R_R)) { + ppc_hash32_set_r(cpu, pte_offset, pte.pte1); } + if (!(pte.pte1 & HPTE32_R_C)) { + if (rwx == 1) { + ppc_hash32_set_c(cpu, pte_offset, pte.pte1); + } else { + /* + * Treat the page as read-only for now, so that a later write + * will pass through this function again to set the C bit + */ + prot &= ~PAGE_WRITE; + } + } /* 9. Determine the real address from the PTE */ diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index a2b1ec5040..7899eb2918 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -22,6 +22,7 @@ #include "exec/exec-all.h" #include "exec/helper-proto.h" #include "qemu/error-report.h" +#include "qemu/qemu-print.h" #include "sysemu/hw_accel.h" #include "kvm_ppc.h" #include "mmu-hash64.h" @@ -29,7 +30,7 @@ #include "hw/hw.h" #include "mmu-book3s-v3.h" -//#define DEBUG_SLB +/* #define DEBUG_SLB */ #ifdef DEBUG_SLB # define LOG_SLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__) @@ -57,9 +58,11 @@ static ppc_slb_t *slb_lookup(PowerPCCPU *cpu, target_ulong eaddr) LOG_SLB("%s: slot %d %016" PRIx64 " %016" PRIx64 "\n", __func__, n, slb->esid, slb->vsid); - /* We check for 1T matches on all MMUs here - if the MMU + /* + * We check for 1T matches on all MMUs here - if the MMU * doesn't have 1T segment support, we will have prevented 1T - * entries from being inserted in the slbmte code. */ + * entries from being inserted in the slbmte code. + */ if (((slb->esid == esid_256M) && ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M)) || ((slb->esid == esid_1T) && @@ -71,7 +74,7 @@ static ppc_slb_t *slb_lookup(PowerPCCPU *cpu, target_ulong eaddr) return NULL; } -void dump_slb(FILE *f, fprintf_function cpu_fprintf, PowerPCCPU *cpu) +void dump_slb(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; int i; @@ -79,14 +82,14 @@ void dump_slb(FILE *f, fprintf_function cpu_fprintf, PowerPCCPU *cpu) cpu_synchronize_state(CPU(cpu)); - cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n"); + qemu_printf("SLB\tESID\t\t\tVSID\n"); for (i = 0; i < cpu->hash64_opts->slb_size; i++) { slbe = env->slb[i].esid; slbv = env->slb[i].vsid; if (slbe == 0 && slbv == 0) { continue; } - cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n", + qemu_printf("%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n", i, slbe, slbv); } } @@ -102,7 +105,8 @@ void helper_slbia(CPUPPCState *env) if (slb->esid & SLB_ESID_V) { slb->esid &= ~SLB_ESID_V; - /* XXX: given the fact that segment size is 256 MB or 1TB, + /* + * XXX: given the fact that segment size is 256 MB or 1TB, * and we still don't have a tlb_flush_mask(env, n, mask) * in QEMU, we just invalidate all TLBs */ @@ -125,7 +129,8 @@ static void __helper_slbie(CPUPPCState *env, target_ulong addr, if (slb->esid & SLB_ESID_V) { slb->esid &= ~SLB_ESID_V; - /* XXX: given the fact that segment size is 256 MB or 1TB, + /* + * XXX: given the fact that segment size is 256 MB or 1TB, * and we still don't have a tlb_flush_mask(env, n, mask) * in QEMU, we just invalidate all TLBs */ @@ -305,8 +310,10 @@ static int ppc_hash64_pte_prot(PowerPCCPU *cpu, { CPUPPCState *env = &cpu->env; unsigned pp, key; - /* Some pp bit combinations have undefined behaviour, so default - * to no access in those cases */ + /* + * Some pp bit combinations have undefined behaviour, so default + * to no access in those cases + */ int prot = 0; key = !!(msr_pr ? (slb->vsid & SLB_VSID_KP) @@ -375,7 +382,7 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte) } key = HPTE64_R_KEY(pte.pte1); - amrbits = (env->spr[SPR_AMR] >> 2*(31 - key)) & 0x3; + amrbits = (env->spr[SPR_AMR] >> 2 * (31 - key)) & 0x3; /* fprintf(stderr, "AMR protection: key=%d AMR=0x%" PRIx64 "\n", key, */ /* env->spr[SPR_AMR]); */ @@ -546,8 +553,9 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash, if (*pshift == 0) { continue; } - /* We don't do anything with pshift yet as qemu TLB only deals - * with 4K pages anyway + /* + * We don't do anything with pshift yet as qemu TLB only + * deals with 4K pages anyway */ pte->pte0 = pte0; pte->pte1 = pte1; @@ -571,8 +579,10 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu, uint64_t vsid, epnmask, epn, ptem; const PPCHash64SegmentPageSizes *sps = slb->sps; - /* The SLB store path should prevent any bad page size encodings - * getting in there, so: */ + /* + * The SLB store path should prevent any bad page size encodings + * getting in there, so: + */ assert(sps); /* If ISL is set in LPCR we need to clamp the page size to 4K */ @@ -715,6 +725,39 @@ static void ppc_hash64_set_dsi(CPUState *cs, uint64_t dar, uint64_t dsisr) } +static void ppc_hash64_set_r(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte1) +{ + hwaddr base, offset = ptex * HASH_PTE_SIZE_64 + 16; + + if (cpu->vhyp) { + PPCVirtualHypervisorClass *vhc = + PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + vhc->hpte_set_r(cpu->vhyp, ptex, pte1); + return; + } + base = ppc_hash64_hpt_base(cpu); + + + /* The HW performs a non-atomic byte update */ + stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01); +} + +static void ppc_hash64_set_c(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte1) +{ + hwaddr base, offset = ptex * HASH_PTE_SIZE_64 + 15; + + if (cpu->vhyp) { + PPCVirtualHypervisorClass *vhc = + PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + vhc->hpte_set_c(cpu->vhyp, ptex, pte1); + return; + } + base = ppc_hash64_hpt_base(cpu); + + /* The HW performs a non-atomic byte update */ + stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80); +} + int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx) { @@ -725,23 +768,25 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, hwaddr ptex; ppc_hash_pte64_t pte; int exec_prot, pp_prot, amr_prot, prot; - uint64_t new_pte1; const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC}; hwaddr raddr; assert((rwx == 0) || (rwx == 1) || (rwx == 2)); - /* Note on LPCR usage: 970 uses HID4, but our special variant - * of store_spr copies relevant fields into env->spr[SPR_LPCR]. - * Similarily we filter unimplemented bits when storing into - * LPCR depending on the MMU version. This code can thus just - * use the LPCR "as-is". + /* + * Note on LPCR usage: 970 uses HID4, but our special variant of + * store_spr copies relevant fields into env->spr[SPR_LPCR]. + * Similarily we filter unimplemented bits when storing into LPCR + * depending on the MMU version. This code can thus just use the + * LPCR "as-is". */ /* 1. Handle real mode accesses */ if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) { - /* Translation is supposedly "off" */ - /* In real mode the top 4 effective address bits are (mostly) ignored */ + /* + * Translation is supposedly "off", but in real mode the top 4 + * effective address bits are (mostly) ignored + */ raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL; /* In HV mode, add HRMOR if top EA bit is clear */ @@ -870,17 +915,19 @@ skip_slb_search: /* 6. Update PTE referenced and changed bits if necessary */ - new_pte1 = pte.pte1 | HPTE64_R_R; /* set referenced bit */ - if (rwx == 1) { - new_pte1 |= HPTE64_R_C; /* set changed (dirty) bit */ - } else { - /* Treat the page as read-only for now, so that a later write - * will pass through this function again to set the C bit */ - prot &= ~PAGE_WRITE; + if (!(pte.pte1 & HPTE64_R_R)) { + ppc_hash64_set_r(cpu, ptex, pte.pte1); } - - if (new_pte1 != pte.pte1) { - ppc_hash64_store_hpte(cpu, ptex, pte.pte0, new_pte1); + if (!(pte.pte1 & HPTE64_R_C)) { + if (rwx == 1) { + ppc_hash64_set_c(cpu, ptex, pte.pte1); + } else { + /* + * Treat the page as read-only for now, so that a later write + * will pass through this function again to set the C bit + */ + prot &= ~PAGE_WRITE; + } } /* 7. Determine the real address from the PTE */ @@ -939,24 +986,6 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr) & TARGET_PAGE_MASK; } -void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex, - uint64_t pte0, uint64_t pte1) -{ - hwaddr base; - hwaddr offset = ptex * HASH_PTE_SIZE_64; - - if (cpu->vhyp) { - PPCVirtualHypervisorClass *vhc = - PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); - vhc->store_hpte(cpu->vhyp, ptex, pte0, pte1); - return; - } - base = ppc_hash64_hpt_base(cpu); - - stq_phys(CPU(cpu)->as, base + offset, pte0); - stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1); -} - void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex, target_ulong pte0, target_ulong pte1) { @@ -1022,8 +1051,9 @@ static void ppc_hash64_update_vrma(PowerPCCPU *cpu) return; } - /* Make one up. Mostly ignore the ESID which will not be - * needed for translation + /* + * Make one up. Mostly ignore the ESID which will not be needed + * for translation */ vsid = SLB_VSID_VRMA; vrmasd = (lpcr & LPCR_VRMASD) >> LPCR_VRMASD_SHIFT; @@ -1079,11 +1109,12 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) } env->spr[SPR_RMOR] = ((lpcr >> 41) & 0xffffull) << 26; - /* XXX We could also write LPID from HID4 here + /* + * XXX We could also write LPID from HID4 here * but since we don't tag any translation on it * it doesn't actually matter - */ - /* XXX For proper emulation of 970 we also need + * + * XXX For proper emulation of 970 we also need * to dig HRMOR out of HID5 */ break; diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h index 6b555b7220..87729d48b3 100644 --- a/target/ppc/mmu-hash64.h +++ b/target/ppc/mmu-hash64.h @@ -4,14 +4,12 @@ #ifndef CONFIG_USER_ONLY #ifdef TARGET_PPC64 -void dump_slb(FILE *f, fprintf_function cpu_fprintf, PowerPCCPU *cpu); +void dump_slb(PowerPCCPU *cpu); int ppc_store_slb(PowerPCCPU *cpu, target_ulong slot, target_ulong esid, target_ulong vsid); hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr); int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw, int mmu_idx); -void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex, - uint64_t pte0, uint64_t pte1); void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong pte_index, target_ulong pte0, target_ulong pte1); diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index ca1fb2673f..066e324464 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -228,10 +228,10 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, ppc_v3_pate_t pate; assert((rwx == 0) || (rwx == 1) || (rwx == 2)); - assert(ppc64_use_proc_tbl(cpu)); - /* Real Mode Access */ - if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) { + /* HV or virtual hypervisor Real Mode Access */ + if ((msr_hv || cpu->vhyp) && + (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0)))) { /* In real mode top 4 effective addr bits (mostly) ignored */ raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL; @@ -241,6 +241,16 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, return 0; } + /* + * Check UPRT (we avoid the check in real mode to deal with + * transitional states during kexec. + */ + if (!ppc64_use_proc_tbl(cpu)) { + qemu_log_mask(LOG_GUEST_ERROR, + "LPCR:UPRT not set in radix mode ! LPCR=" + TARGET_FMT_lx "\n", env->spr[SPR_LPCR]); + } + /* Virtual Mode Access - get the fully qualified address */ if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) { ppc_radix64_raise_segi(cpu, rwx, eaddr); diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 4a6be4d63b..1dbc9acb75 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -29,14 +29,15 @@ #include "exec/log.h" #include "helper_regs.h" #include "qemu/error-report.h" +#include "qemu/qemu-print.h" #include "mmu-book3s-v3.h" #include "mmu-radix64.h" -//#define DEBUG_MMU -//#define DEBUG_BATS -//#define DEBUG_SOFTWARE_TLB -//#define DUMP_PAGE_TABLES -//#define FLUSH_ALL_TLBS +/* #define DEBUG_MMU */ +/* #define DEBUG_BATS */ +/* #define DEBUG_SOFTWARE_TLB */ +/* #define DUMP_PAGE_TABLES */ +/* #define FLUSH_ALL_TLBS */ #ifdef DEBUG_MMU # define LOG_MMU_STATE(cpu) log_cpu_state_mask(CPU_LOG_MMU, (cpu), 0) @@ -151,7 +152,8 @@ static int check_prot(int prot, int rw, int access_type) } static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0, - target_ulong pte1, int h, int rw, int type) + target_ulong pte1, int h, + int rw, int type) { target_ulong ptem, mmask; int access, ret, pteh, ptev, pp; @@ -331,7 +333,8 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, pte_is_valid(tlb->pte0) ? "valid" : "inval", tlb->EPN, eaddr, tlb->pte1, rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); - switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) { + switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, + 0, rw, access_type)) { case -3: /* TLB inconsistency */ return -1; @@ -346,9 +349,11 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, break; case 0: /* access granted */ - /* XXX: we should go on looping to check all TLBs consistency - * but we can speed-up the whole thing as the - * result would be undefined if TLBs are not consistent. + /* + * XXX: we should go on looping to check all TLBs + * consistency but we can speed-up the whole thing as + * the result would be undefined if TLBs are not + * consistent. */ ret = 0; best = nr; @@ -549,14 +554,18 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, qemu_log_mask(CPU_LOG_MMU, "direct store...\n"); /* Direct-store segment : absolutely *BUGGY* for now */ - /* Direct-store implies a 32-bit MMU. + /* + * Direct-store implies a 32-bit MMU. * Check the Segment Register's bus unit ID (BUID). */ sr = env->sr[eaddr >> 28]; if ((sr & 0x1FF00000) >> 20 == 0x07f) { - /* Memory-forced I/O controller interface access */ - /* If T=1 and BUID=x'07F', the 601 performs a memory access - * to SR[28-31] LA[4-31], bypassing all protection mechanisms. + /* + * Memory-forced I/O controller interface access + * + * If T=1 and BUID=x'07F', the 601 performs a memory + * access to SR[28-31] LA[4-31], bypassing all protection + * mechanisms. */ ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF); ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -577,9 +586,11 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, /* lwarx, ldarx or srwcx. */ return -4; case ACCESS_CACHE: - /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */ - /* Should make the instruction do no-op. - * As it already do no-op, it's quite easy :-) + /* + * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi + * + * Should make the instruction do no-op. As it already do + * no-op, it's quite easy :-) */ ctx->raddr = eaddr; return 0; @@ -941,12 +952,14 @@ static uint32_t mmubooke206_esr(int mmu_idx, bool rw) return esr; } -/* Get EPID register given the mmu_idx. If this is regular load, - * construct the EPID access bits from current processor state */ - -/* Get the effective AS and PR bits and the PID. The PID is returned only if - * EPID load is requested, otherwise the caller must detect the correct EPID. - * Return true if valid EPID is returned. */ +/* + * Get EPID register given the mmu_idx. If this is regular load, + * construct the EPID access bits from current processor state + * + * Get the effective AS and PR bits and the PID. The PID is returned + * only if EPID load is requested, otherwise the caller must detect + * the correct EPID. Return true if valid EPID is returned. + */ static bool mmubooke206_get_as(CPUPPCState *env, int mmu_idx, uint32_t *epid_out, bool *as_out, bool *pr_out) @@ -1116,19 +1129,18 @@ static const char *book3e_tsize_to_str[32] = { "1T", "2T" }; -static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf, - CPUPPCState *env) +static void mmubooke_dump_mmu(CPUPPCState *env) { ppcemb_tlb_t *entry; int i; if (kvm_enabled() && !env->kvm_sw_tlb) { - cpu_fprintf(f, "Cannot access KVM TLB\n"); + qemu_printf("Cannot access KVM TLB\n"); return; } - cpu_fprintf(f, "\nTLB:\n"); - cpu_fprintf(f, "Effective Physical Size PID Prot " + qemu_printf("\nTLB:\n"); + qemu_printf("Effective Physical Size PID Prot " "Attr\n"); entry = &env->tlb.tlbe[0]; @@ -1153,22 +1165,21 @@ static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf, } else { snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size / KiB); } - cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n", + qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n", (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID, entry->prot, entry->attr); } } -static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf, - CPUPPCState *env, int tlbn, int offset, +static void mmubooke206_dump_one_tlb(CPUPPCState *env, int tlbn, int offset, int tlbsize) { ppcmas_tlb_t *entry; int i; - cpu_fprintf(f, "\nTLB%d:\n", tlbn); - cpu_fprintf(f, "Effective Physical Size TID TS SRWX" + qemu_printf("\nTLB%d:\n", tlbn); + qemu_printf("Effective Physical Size TID TS SRWX" " URWX WIMGE U0123\n"); entry = &env->tlb.tlbm[offset]; @@ -1185,7 +1196,7 @@ static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf, ea = entry->mas2 & ~(size - 1); pa = entry->mas7_3 & ~(size - 1); - cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c" + qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c" "U%c%c%c %c%c%c%c%c U%c%c%c%c\n", (uint64_t)ea, (uint64_t)pa, book3e_tsize_to_str[tsize], @@ -1209,14 +1220,13 @@ static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf, } } -static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf, - CPUPPCState *env) +static void mmubooke206_dump_mmu(CPUPPCState *env) { int offset = 0; int i; if (kvm_enabled() && !env->kvm_sw_tlb) { - cpu_fprintf(f, "Cannot access KVM TLB\n"); + qemu_printf("Cannot access KVM TLB\n"); return; } @@ -1227,13 +1237,12 @@ static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf, continue; } - mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size); + mmubooke206_dump_one_tlb(env, i, offset, size); offset += size; } } -static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf, - CPUPPCState *env, int type) +static void mmu6xx_dump_BATs(CPUPPCState *env, int type) { target_ulong *BATlt, *BATut, *BATu, *BATl; target_ulong BEPIl, BEPIu, bl; @@ -1256,7 +1265,7 @@ static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf, BEPIu = *BATu & 0xF0000000; BEPIl = *BATu & 0x0FFE0000; bl = (*BATu & 0x00001FFC) << 15; - cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx + qemu_printf("%s BAT%d BATu " TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " " TARGET_FMT_lx " " TARGET_FMT_lx "\n", type == ACCESS_CODE ? "code" : "data", i, @@ -1264,44 +1273,43 @@ static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf, } } -static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf, - CPUPPCState *env) +static void mmu6xx_dump_mmu(CPUPPCState *env) { PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc6xx_tlb_t *tlb; target_ulong sr; int type, way, entry, i; - cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu)); - cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu)); + qemu_printf("HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu)); + qemu_printf("HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu)); - cpu_fprintf(f, "\nSegment registers:\n"); + qemu_printf("\nSegment registers:\n"); for (i = 0; i < 32; i++) { sr = env->sr[i]; if (sr & 0x80000000) { - cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x " + qemu_printf("%02d T=%d Ks=%d Kp=%d BUID=0x%03x " "CNTLR_SPEC=0x%05x\n", i, sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0, sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF), (uint32_t)(sr & 0xFFFFF)); } else { - cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i, + qemu_printf("%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i, sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0, sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0, (uint32_t)(sr & 0x00FFFFFF)); } } - cpu_fprintf(f, "\nBATs:\n"); - mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT); - mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE); + qemu_printf("\nBATs:\n"); + mmu6xx_dump_BATs(env, ACCESS_INT); + mmu6xx_dump_BATs(env, ACCESS_CODE); if (env->id_tlbs != 1) { - cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB" + qemu_printf("ERROR: 6xx MMU should have separated TLB" " for code and data\n"); } - cpu_fprintf(f, "\nTLBs [EPN EPN + SIZE]\n"); + qemu_printf("\nTLBs [EPN EPN + SIZE]\n"); for (type = 0; type < 2; type++) { for (way = 0; way < env->nb_ways; way++) { @@ -1310,7 +1318,7 @@ static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf, entry++) { tlb = &env->tlb.tlb6[entry]; - cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s [" + qemu_printf("%s TLB %02d/%02d way:%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx "]\n", type ? "code" : "data", entry % env->nb_tlb, env->nb_tlb, way, @@ -1321,31 +1329,31 @@ static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf, } } -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) +void dump_mmu(CPUPPCState *env) { switch (env->mmu_model) { case POWERPC_MMU_BOOKE: - mmubooke_dump_mmu(f, cpu_fprintf, env); + mmubooke_dump_mmu(env); break; case POWERPC_MMU_BOOKE206: - mmubooke206_dump_mmu(f, cpu_fprintf, env); + mmubooke206_dump_mmu(env); break; case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: - mmu6xx_dump_mmu(f, cpu_fprintf, env); + mmu6xx_dump_mmu(env); break; #if defined(TARGET_PPC64) case POWERPC_MMU_64B: case POWERPC_MMU_2_03: case POWERPC_MMU_2_06: case POWERPC_MMU_2_07: - dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env)); + dump_slb(ppc_env_get_cpu(env)); break; case POWERPC_MMU_3_00: if (ppc64_v3_radix(ppc_env_get_cpu(env))) { /* TODO - Unsupported */ } else { - dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env)); + dump_slb(ppc_env_get_cpu(env)); break; } #endif @@ -1373,8 +1381,9 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, case POWERPC_MMU_SOFT_4xx_Z: if (unlikely(msr_pe != 0)) { - /* 403 family add some particular protections, - * using PBL/PBU registers for accesses with no translation. + /* + * 403 family add some particular protections, using + * PBL/PBU registers for accesses with no translation. */ in_plb = /* Check PLB validity */ @@ -1457,7 +1466,8 @@ static int get_physical_address_wtlb( if (real_mode) { ret = check_physical(env, ctx, eaddr, rw); } else { - cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n"); + cpu_abort(CPU(cpu), + "PowerPC in real mode do not do any translation\n"); } return -1; default: @@ -1502,9 +1512,10 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) { - /* Some MMUs have separate TLBs for code and data. If we only try an - * ACCESS_INT, we may not be able to read instructions mapped by code - * TLBs, so we also try a ACCESS_CODE. + /* + * Some MMUs have separate TLBs for code and data. If we only + * try an ACCESS_INT, we may not be able to read instructions + * mapped by code TLBs, so we also try a ACCESS_CODE. */ if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_CODE) != 0)) { @@ -1809,6 +1820,13 @@ static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu, base = BATu & ~0x0001FFFF; end = base + mask + 0x00020000; + if (((end - base) >> TARGET_PAGE_BITS) > 1024) { + /* Flushing 1024 4K pages is slower than a complete flush */ + LOG_BATS("Flush all BATs\n"); + tlb_flush(CPU(cs)); + LOG_BATS("Flush done\n"); + return; + } LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", base, end, mask); for (page = base; page != end; page += TARGET_PAGE_SIZE) { @@ -1838,8 +1856,9 @@ void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value) #if !defined(FLUSH_ALL_TLBS) do_invalidate_BAT(env, env->IBAT[0][nr], mask); #endif - /* When storing valid upper BAT, mask BEPI and BRPN - * and invalidate all TLBs covered by this BAT + /* + * When storing valid upper BAT, mask BEPI and BRPN and + * invalidate all TLBs covered by this BAT */ mask = (value << 15) & 0x0FFE0000UL; env->IBAT[0][nr] = (value & 0x00001FFFUL) | @@ -1869,8 +1888,9 @@ void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value) dump_store_bat(env, 'D', 0, nr, value); if (env->DBAT[0][nr] != value) { - /* When storing valid upper BAT, mask BEPI and BRPN - * and invalidate all TLBs covered by this BAT + /* + * When storing valid upper BAT, mask BEPI and BRPN and + * invalidate all TLBs covered by this BAT */ mask = (value << 15) & 0x0FFE0000UL; #if !defined(FLUSH_ALL_TLBS) @@ -1917,8 +1937,9 @@ void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value) do_inval = 1; #endif } - /* When storing valid upper BAT, mask BEPI and BRPN - * and invalidate all TLBs covered by this BAT + /* + * When storing valid upper BAT, mask BEPI and BRPN and + * invalidate all TLBs covered by this BAT */ env->IBAT[0][nr] = (value & 0x00001FFFUL) | (value & ~0x0001FFFFUL & ~mask); @@ -2031,7 +2052,8 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { /* tlbie invalidate TLBs for all segments */ - /* XXX: given the fact that there are too many segments to invalidate, + /* + * XXX: given the fact that there are too many segments to invalidate, * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU, * we just invalidate all TLBs */ @@ -2048,10 +2070,11 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) break; case POWERPC_MMU_32B: case POWERPC_MMU_601: - /* Actual CPUs invalidate entire congruence classes based on the - * geometry of their TLBs and some OSes take that into account, - * we just mark the TLB to be flushed later (context synchronizing - * event or sync instruction on 32-bit). + /* + * Actual CPUs invalidate entire congruence classes based on + * the geometry of their TLBs and some OSes take that into + * account, we just mark the TLB to be flushed later (context + * synchronizing event or sync instruction on 32-bit). */ env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; break; @@ -2156,8 +2179,10 @@ void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value) #endif if (env->sr[srnum] != value) { env->sr[srnum] = value; -/* Invalidating 256MB of virtual memory in 4kB pages is way longer than - flusing the whole TLB. */ + /* + * Invalidating 256MB of virtual memory in 4kB pages is way + * longer than flusing the whole TLB. + */ #if !defined(FLUSH_ALL_TLBS) && 0 { target_ulong page, end; @@ -2268,10 +2293,12 @@ target_ulong helper_rac(CPUPPCState *env, target_ulong addr) int nb_BATs; target_ulong ret = 0; - /* We don't have to generate many instances of this instruction, + /* + * We don't have to generate many instances of this instruction, * as rac is supervisor only. + * + * XXX: FIX THIS: Pretend we have no BAT */ - /* XXX: FIX THIS: Pretend we have no BAT */ nb_BATs = env->nb_BATs; env->nb_BATs = 0; if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) { @@ -2426,7 +2453,8 @@ void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry, } tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT) & PPC4XX_TLBHI_SIZE_MASK); - /* We cannot handle TLB size < TARGET_PAGE_SIZE. + /* + * We cannot handle TLB size < TARGET_PAGE_SIZE. * If this ever occurs, we should implement TARGET_PAGE_BITS_VARY */ if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) { @@ -2746,7 +2774,8 @@ void helper_booke206_tlbwe(CPUPPCState *env) } if (tlb->mas1 & MAS1_VALID) { - /* Invalidate the page in QEMU TLB if it was a valid entry. + /* + * Invalidate the page in QEMU TLB if it was a valid entry. * * In "PowerPC e500 Core Family Reference Manual, Rev. 1", * Section "12.4.2 TLB Write Entry (tlbwe) Instruction": @@ -2755,7 +2784,8 @@ void helper_booke206_tlbwe(CPUPPCState *env) * "Note that when an L2 TLB entry is written, it may be displacing an * already valid entry in the same L2 TLB location (a victim). If a * valid L1 TLB entry corresponds to the L2 MMU victim entry, that L1 - * TLB entry is automatically invalidated." */ + * TLB entry is automatically invalidated." + */ flush_page(env, tlb); } @@ -2781,8 +2811,9 @@ void helper_booke206_tlbwe(CPUPPCState *env) mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E; if (!msr_cm) { - /* Executing a tlbwe instruction in 32-bit mode will set - * bits 0:31 of the TLB EPN field to zero. + /* + * Executing a tlbwe instruction in 32-bit mode will set bits + * 0:31 of the TLB EPN field to zero. */ mask &= 0xffffffff; } @@ -3026,10 +3057,13 @@ void helper_check_tlb_flush_global(CPUPPCState *env) /*****************************************************************************/ -/* try to fill the TLB and return an exception if error. If retaddr is - NULL, it means that the function was called in C code (i.e. not - from generated code or from helper.c) */ -/* XXX: fix it to restore all registers */ +/* + * try to fill the TLB and return an exception if error. If retaddr is + * NULL, it means that the function was called in C code (i.e. not + * from generated code or from helper.c) + * + * XXX: fix it to restore all registers + */ void tlb_fill(CPUState *cs, target_ulong addr, int size, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { diff --git a/target/ppc/monitor.c b/target/ppc/monitor.c index 04deec8030..ee9d6e81d2 100644 --- a/target/ppc/monitor.c +++ b/target/ppc/monitor.c @@ -27,32 +27,33 @@ #include "monitor/hmp-target.h" #include "hmp.h" -static target_long monitor_get_ccr (const struct MonitorDef *md, int val) +static target_long monitor_get_ccr(const struct MonitorDef *md, int val) { CPUArchState *env = mon_get_cpu_env(); unsigned int u; int i; u = 0; - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { u |= env->crf[i] << (32 - (4 * (i + 1))); + } return u; } -static target_long monitor_get_decr (const struct MonitorDef *md, int val) +static target_long monitor_get_decr(const struct MonitorDef *md, int val) { CPUArchState *env = mon_get_cpu_env(); return cpu_ppc_load_decr(env); } -static target_long monitor_get_tbu (const struct MonitorDef *md, int val) +static target_long monitor_get_tbu(const struct MonitorDef *md, int val) { CPUArchState *env = mon_get_cpu_env(); return cpu_ppc_load_tbu(env); } -static target_long monitor_get_tbl (const struct MonitorDef *md, int val) +static target_long monitor_get_tbl(const struct MonitorDef *md, int val) { CPUArchState *env = mon_get_cpu_env(); return cpu_ppc_load_tbl(env); @@ -66,7 +67,7 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) monitor_printf(mon, "No CPU available\n"); return; } - dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1); + dump_mmu(env1); } const MonitorDef monitor_defs[] = { diff --git a/target/ppc/trace-events b/target/ppc/trace-events index 35ee898566..7b3cfe11fd 100644 --- a/target/ppc/trace-events +++ b/target/ppc/trace-events @@ -1,5 +1,30 @@ # See docs/devel/tracing.txt for syntax documentation. -# target/ppc/kvm.c -kvm_failed_spr_set(int str, const char *msg) "Warning: Unable to set SPR %d to KVM: %s" -kvm_failed_spr_get(int str, const char *msg) "Warning: Unable to retrieve SPR %d from KVM: %s" +# kvm.c +kvm_failed_spr_set(int spr, const char *msg) "Warning: Unable to set SPR %d to KVM: %s" +kvm_failed_spr_get(int spr, const char *msg) "Warning: Unable to retrieve SPR %d from KVM: %s" +kvm_failed_fpscr_set(const char *msg) "Unable to set FPSCR to KVM: %s" +kvm_failed_fp_set(const char *fpname, int fpnum, const char *msg) "Unable to set %s%d to KVM: %s" +kvm_failed_vscr_set(const char *msg) "Unable to set VSCR to KVM: %s" +kvm_failed_vr_set(int vr, const char *msg) "Unable to set VR%d to KVM: %s" +kvm_failed_fpscr_get(const char *msg) "Unable to get FPSCR from KVM: %s" +kvm_failed_fp_get(const char *fpname, int fpnum, const char *msg) "Unable to get %s%d from KVM: %s" +kvm_failed_vscr_get(const char *msg) "Unable to get VSCR from KVM: %s" +kvm_failed_vr_get(int vr, const char *msg) "Unable to get VR%d from KVM: %s" +kvm_failed_vpa_addr_get(const char *msg) "Unable to get VPA address from KVM: %s" +kvm_failed_slb_get(const char *msg) "Unable to get SLB shadow state from KVM: %s" +kvm_failed_dtl_get(const char *msg) "Unable to get dispatch trace log state from KVM: %s" +kvm_failed_vpa_addr_set(const char *msg) "Unable to set VPA address to KVM: %s" +kvm_failed_slb_set(const char *msg) "Unable to set SLB shadow state to KVM: %s" +kvm_failed_dtl_set(const char *msg) "Unable to set dispatch trace log state to KVM: %s" +kvm_failed_null_vpa_addr_set(const char *msg) "Unable to set VPA address to KVM: %s" +kvm_failed_put_vpa(void) "Warning: Unable to set VPA information to KVM" +kvm_failed_get_vpa(void) "Warning: Unable to get VPA information from KVM" +kvm_injected_interrupt(int irq) "injected interrupt %d" +kvm_handle_dcr_write(void) "handle dcr write" +kvm_handle_drc_read(void) "handle dcr read" +kvm_handle_halt(void) "handle halt" +kvm_handle_papr_hcall(void) "handle PAPR hypercall" +kvm_handle_epr(void) "handle epr" +kvm_handle_watchdog_expiry(void) "handle watchdog expiry" +kvm_handle_debug_exception(void) "handle debug exception" diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 98b37cebc2..8d08625c33 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -42,8 +42,8 @@ #define GDBSTUB_SINGLE_STEP 0x4 /* Include definitions for instructions classes and implementations flags */ -//#define PPC_DEBUG_DISAS -//#define DO_PPC_STATISTICS +/* #define PPC_DEBUG_DISAS */ +/* #define DO_PPC_STATISTICS */ #ifdef PPC_DEBUG_DISAS # define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) @@ -54,9 +54,9 @@ /* Code translation helpers */ /* global register indexes */ -static char cpu_reg_names[10*3 + 22*4 /* GPR */ - + 10*4 + 22*5 /* SPE GPRh */ - + 8*5 /* CRF */]; +static char cpu_reg_names[10 * 3 + 22 * 4 /* GPR */ + + 10 * 4 + 22 * 5 /* SPE GPRh */ + + 8 * 5 /* CRF */]; static TCGv cpu_gpr[32]; static TCGv cpu_gprh[32]; static TCGv_i32 cpu_crf[8]; @@ -78,7 +78,7 @@ static TCGv_i32 cpu_access_type; void ppc_translate_init(void) { int i; - char* p; + char *p; size_t cpu_reg_names_size; p = cpu_reg_names; @@ -146,7 +146,8 @@ void ppc_translate_init(void) offsetof(CPUPPCState, fpscr), "fpscr"); cpu_access_type = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUPPCState, access_type), "access_type"); + offsetof(CPUPPCState, access_type), + "access_type"); } /* internal defines */ @@ -246,8 +247,9 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error) { TCGv_i32 t0, t1; - /* These are all synchronous exceptions, we set the PC back to - * the faulting instruction + /* + * These are all synchronous exceptions, we set the PC back to the + * faulting instruction */ if (ctx->exception == POWERPC_EXCP_NONE) { gen_update_nip(ctx, ctx->base.pc_next - 4); @@ -264,8 +266,9 @@ static void gen_exception(DisasContext *ctx, uint32_t excp) { TCGv_i32 t0; - /* These are all synchronous exceptions, we set the PC back to - * the faulting instruction + /* + * These are all synchronous exceptions, we set the PC back to the + * faulting instruction */ if (ctx->exception == POWERPC_EXCP_NONE) { gen_update_nip(ctx, ctx->base.pc_next - 4); @@ -320,8 +323,9 @@ static void gen_debug_exception(DisasContext *ctx) { TCGv_i32 t0; - /* These are all synchronous exceptions, we set the PC back to - * the faulting instruction + /* + * These are all synchronous exceptions, we set the PC back to the + * faulting instruction */ if ((ctx->exception != POWERPC_EXCP_BRANCH) && (ctx->exception != POWERPC_EXCP_SYNC)) { @@ -602,9 +606,11 @@ static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf) tcg_gen_movi_tl(t0, CRF_EQ); tcg_gen_movi_tl(t1, CRF_LT); - tcg_gen_movcond_tl((s ? TCG_COND_LT : TCG_COND_LTU), t0, arg0, arg1, t1, t0); + tcg_gen_movcond_tl((s ? TCG_COND_LT : TCG_COND_LTU), + t0, arg0, arg1, t1, t0); tcg_gen_movi_tl(t1, CRF_GT); - tcg_gen_movcond_tl((s ? TCG_COND_GT : TCG_COND_GTU), t0, arg0, arg1, t1, t0); + tcg_gen_movcond_tl((s ? TCG_COND_GT : TCG_COND_GTU), + t0, arg0, arg1, t1, t0); tcg_gen_trunc_tl_i32(t, t0); tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_so); @@ -840,9 +846,11 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1, if (compute_ca) { if (NARROW_MODE(ctx)) { - /* Caution: a non-obvious corner case of the spec is that we - must produce the *entire* 64-bit addition, but produce the - carry into bit 32. */ + /* + * Caution: a non-obvious corner case of the spec is that + * we must produce the *entire* 64-bit addition, but + * produce the carry into bit 32. + */ TCGv t1 = tcg_temp_new(); tcg_gen_xor_tl(t1, arg1, arg2); /* add without carry */ tcg_gen_add_tl(t0, arg1, arg2); @@ -1017,12 +1025,13 @@ static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1, tcg_temp_free_i32(t2); tcg_temp_free_i32(t3); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, ret); + } } /* Div functions */ #define GEN_INT_ARITH_DIVW(name, opc3, sign, compute_ov) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ gen_op_arith_divw(ctx, cpu_gpr[rD(ctx->opcode)], \ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ @@ -1091,12 +1100,13 @@ static inline void gen_op_arith_divd(DisasContext *ctx, TCGv ret, TCGv arg1, tcg_temp_free_i64(t2); tcg_temp_free_i64(t3); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, ret); + } } #define GEN_INT_ARITH_DIVD(name, opc3, sign, compute_ov) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ gen_op_arith_divd(ctx, cpu_gpr[rD(ctx->opcode)], \ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ @@ -1219,8 +1229,9 @@ static void gen_mulhw(DisasContext *ctx) tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1); tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* mulhwu mulhwu. */ @@ -1235,8 +1246,9 @@ static void gen_mulhwu(DisasContext *ctx) tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1); tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* mullw mullw. */ @@ -1255,8 +1267,9 @@ static void gen_mullw(DisasContext *ctx) tcg_gen_mul_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); #endif - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* mullwo mullwo. */ @@ -1284,8 +1297,9 @@ static void gen_mullwo(DisasContext *ctx) tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* mulli */ @@ -1325,8 +1339,9 @@ static void gen_mulld(DisasContext *ctx) { tcg_gen_mul_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* mulldo mulldo. */ @@ -1369,9 +1384,11 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, if (compute_ca) { /* dest = ~arg1 + arg2 [+ ca]. */ if (NARROW_MODE(ctx)) { - /* Caution: a non-obvious corner case of the spec is that we - must produce the *entire* 64-bit addition, but produce the - carry into bit 32. */ + /* + * Caution: a non-obvious corner case of the spec is that + * we must produce the *entire* 64-bit addition, but + * produce the carry into bit 32. + */ TCGv inv1 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); tcg_gen_not_tl(inv1, arg1); @@ -1404,8 +1421,10 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, cpu_ca32, 1); } } else if (add_ca) { - /* Since we're ignoring carry-out, we can simplify the - standard ~arg1 + arg2 + ca to arg2 - arg1 + ca - 1. */ + /* + * Since we're ignoring carry-out, we can simplify the + * standard ~arg1 + arg2 + ca to arg2 - arg1 + ca - 1. + */ tcg_gen_sub_tl(t0, arg2, arg1); tcg_gen_add_tl(t0, t0, cpu_ca); tcg_gen_subi_tl(t0, t0, 1); @@ -1493,7 +1512,7 @@ static void gen_nego(DisasContext *ctx) /*** Integer logical ***/ #define GEN_LOGICAL2(name, tcg_op, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ tcg_op(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], \ cpu_gpr[rB(ctx->opcode)]); \ @@ -1502,7 +1521,7 @@ static void glue(gen_, name)(DisasContext *ctx) } #define GEN_LOGICAL1(name, tcg_op, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ tcg_op(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); \ if (unlikely(Rc(ctx->opcode) != 0)) \ @@ -1517,14 +1536,16 @@ GEN_LOGICAL2(andc, tcg_gen_andc_tl, 0x01, PPC_INTEGER); /* andi. */ static void gen_andi_(DisasContext *ctx) { - tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], UIMM(ctx->opcode)); + tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], + UIMM(ctx->opcode)); gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } /* andis. */ static void gen_andis_(DisasContext *ctx) { - tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], UIMM(ctx->opcode) << 16); + tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], + UIMM(ctx->opcode) << 16); gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } @@ -1538,8 +1559,9 @@ static void gen_cntlzw(DisasContext *ctx) tcg_gen_extu_i32_tl(cpu_gpr[rA(ctx->opcode)], t); tcg_temp_free_i32(t); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* cnttzw */ @@ -1591,12 +1613,14 @@ static void gen_or(DisasContext *ctx) rb = rB(ctx->opcode); /* Optimisation for mr. ri case */ if (rs != ra || rs != rb) { - if (rs != rb) + if (rs != rb) { tcg_gen_or_tl(cpu_gpr[ra], cpu_gpr[rs], cpu_gpr[rb]); - else + } else { tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rs]); - if (unlikely(Rc(ctx->opcode) != 0)) + } + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[ra]); + } } else if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rs]); #if defined(TARGET_PPC64) @@ -1654,10 +1678,11 @@ static void gen_or(DisasContext *ctx) tcg_temp_free(t0); } #if !defined(CONFIG_USER_ONLY) - /* Pause out of TCG otherwise spin loops with smt_low eat too much - * CPU and the kernel hangs. This applies to all encodings other - * than no-op, e.g., miso(rs=26), yield(27), mdoio(29), mdoom(30), - * and all currently undefined. + /* + * Pause out of TCG otherwise spin loops with smt_low eat too + * much CPU and the kernel hangs. This applies to all + * encodings other than no-op, e.g., miso(rs=26), yield(27), + * mdoio(29), mdoom(30), and all currently undefined. */ gen_pause(ctx); #endif @@ -1671,12 +1696,15 @@ GEN_LOGICAL2(orc, tcg_gen_orc_tl, 0x0C, PPC_INTEGER); static void gen_xor(DisasContext *ctx) { /* Optimisation for "set to zero" case */ - if (rS(ctx->opcode) != rB(ctx->opcode)) - tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); - else + if (rS(ctx->opcode) != rB(ctx->opcode)) { + tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], + cpu_gpr[rB(ctx->opcode)]); + } else { tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0); - if (unlikely(Rc(ctx->opcode) != 0)) + } + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* ori */ @@ -1699,7 +1727,8 @@ static void gen_oris(DisasContext *ctx) /* NOP */ return; } - tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16); + tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], + uimm << 16); } /* xori */ @@ -1723,7 +1752,8 @@ static void gen_xoris(DisasContext *ctx) /* NOP */ return; } - tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16); + tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], + uimm << 16); } /* popcntb : PowerPC 2.03 specification */ @@ -1798,8 +1828,9 @@ GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B); static void gen_cntlzd(DisasContext *ctx) { tcg_gen_clzi_i64(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], 64); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* cnttzd */ @@ -1838,7 +1869,7 @@ static void gen_rlwimi(DisasContext *ctx) uint32_t mb = MB(ctx->opcode); uint32_t me = ME(ctx->opcode); - if (sh == (31-me) && mb <= me) { + if (sh == (31 - me) && mb <= me) { tcg_gen_deposit_tl(t_ra, t_ra, t_rs, sh, me - mb + 1); } else { target_ulong mask; @@ -2141,8 +2172,9 @@ static void gen_slw(DisasContext *ctx) tcg_temp_free(t1); tcg_temp_free(t0); tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* sraw & sraw. */ @@ -2150,8 +2182,9 @@ static void gen_sraw(DisasContext *ctx) { gen_helper_sraw(cpu_gpr[rA(ctx->opcode)], cpu_env, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* srawi & srawi. */ @@ -2206,8 +2239,9 @@ static void gen_srw(DisasContext *ctx) tcg_gen_shr_tl(cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t1); tcg_temp_free(t0); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } #if defined(TARGET_PPC64) @@ -2226,8 +2260,9 @@ static void gen_sld(DisasContext *ctx) tcg_gen_shl_tl(cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t1); tcg_temp_free(t0); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* srad & srad. */ @@ -2235,8 +2270,9 @@ static void gen_srad(DisasContext *ctx) { gen_helper_srad(cpu_gpr[rA(ctx->opcode)], cpu_env, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* sradi & sradi. */ static inline void gen_sradi(DisasContext *ctx, int n) @@ -2317,8 +2353,9 @@ static void gen_srd(DisasContext *ctx) tcg_gen_shr_tl(cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t1); tcg_temp_free(t0); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } #endif @@ -2463,7 +2500,7 @@ GEN_QEMU_STORE_64(st64r, BSWAP_MEMOP(MO_Q)) #endif #define GEN_LD(name, ldop, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv EA; \ gen_set_access_type(ctx, ACCESS_INT); \ @@ -2474,7 +2511,7 @@ static void glue(gen_, name)(DisasContext *ctx) } #define GEN_LDU(name, ldop, opc, type) \ -static void glue(gen_, name##u)(DisasContext *ctx) \ +static void glue(gen_, name##u)(DisasContext *ctx) \ { \ TCGv EA; \ if (unlikely(rA(ctx->opcode) == 0 || \ @@ -2494,7 +2531,7 @@ static void glue(gen_, name##u)(DisasContext *ctx) } #define GEN_LDUX(name, ldop, opc2, opc3, type) \ -static void glue(gen_, name##ux)(DisasContext *ctx) \ +static void glue(gen_, name##ux)(DisasContext *ctx) \ { \ TCGv EA; \ if (unlikely(rA(ctx->opcode) == 0 || \ @@ -2598,8 +2635,9 @@ static void gen_ld(DisasContext *ctx) /* ld - ldu */ gen_qemu_ld64_i64(ctx, cpu_gpr[rD(ctx->opcode)], EA); } - if (Rc(ctx->opcode)) + if (Rc(ctx->opcode)) { tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); + } tcg_temp_free(EA); } @@ -2669,7 +2707,7 @@ static void gen_lq(DisasContext *ctx) /*** Integer store ***/ #define GEN_ST(name, stop, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv EA; \ gen_set_access_type(ctx, ACCESS_INT); \ @@ -2680,7 +2718,7 @@ static void glue(gen_, name)(DisasContext *ctx) } #define GEN_STU(name, stop, opc, type) \ -static void glue(gen_, stop##u)(DisasContext *ctx) \ +static void glue(gen_, stop##u)(DisasContext *ctx) \ { \ TCGv EA; \ if (unlikely(rA(ctx->opcode) == 0)) { \ @@ -2699,7 +2737,7 @@ static void glue(gen_, stop##u)(DisasContext *ctx) } #define GEN_STUX(name, stop, opc2, opc3, type) \ -static void glue(gen_, name##ux)(DisasContext *ctx) \ +static void glue(gen_, name##ux)(DisasContext *ctx) \ { \ TCGv EA; \ if (unlikely(rA(ctx->opcode) == 0)) { \ @@ -2847,8 +2885,9 @@ static void gen_std(DisasContext *ctx) EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0x03); gen_qemu_st64_i64(ctx, cpu_gpr[rs], EA); - if (Rc(ctx->opcode)) + if (Rc(ctx->opcode)) { tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); + } tcg_temp_free(EA); } } @@ -2916,10 +2955,11 @@ static void gen_stmw(DisasContext *ctx) /*** Integer load and store strings ***/ /* lswi */ -/* PowerPC32 specification says we must generate an exception if - * rA is in the range of registers to be loaded. - * In an other hand, IBM says this is valid, but rA won't be loaded. - * For now, I'll follow the spec... +/* + * PowerPC32 specification says we must generate an exception if rA is + * in the range of registers to be loaded. In an other hand, IBM says + * this is valid, but rA won't be loaded. For now, I'll follow the + * spec... */ static void gen_lswi(DisasContext *ctx) { @@ -2934,8 +2974,9 @@ static void gen_lswi(DisasContext *ctx) gen_align_no_le(ctx); return; } - if (nb == 0) + if (nb == 0) { nb = 32; + } nr = DIV_ROUND_UP(nb, 4); if (unlikely(lsw_reg_in_range(start, nr, ra))) { gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX); @@ -2989,8 +3030,9 @@ static void gen_stswi(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); t0 = tcg_temp_new(); gen_addr_register(ctx, t0); - if (nb == 0) + if (nb == 0) { nb = 32; + } t1 = tcg_const_i32(nb); t2 = tcg_const_i32(rS(ctx->opcode)); gen_helper_stsw(cpu_env, t0, t1, t2); @@ -3363,8 +3405,10 @@ static void gen_conditional_store(DisasContext *ctx, TCGMemOp memop) gen_set_label(l1); - /* Address mismatch implies failure. But we still need to provide the - memory barrier semantics of the instruction. */ + /* + * Address mismatch implies failure. But we still need to provide + * the memory barrier semantics of the instruction. + */ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); @@ -3639,8 +3683,9 @@ static void gen_rvwinkle(DisasContext *ctx) static inline void gen_update_cfar(DisasContext *ctx, target_ulong nip) { #if defined(TARGET_PPC64) - if (ctx->has_cfar) + if (ctx->has_cfar) { tcg_gen_movi_tl(cpu_cfar, nip); + } #endif } @@ -3732,35 +3777,69 @@ static void gen_bcond(DisasContext *ctx, int type) if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) { target = tcg_temp_local_new(); - if (type == BCOND_CTR) + if (type == BCOND_CTR) { tcg_gen_mov_tl(target, cpu_ctr); - else if (type == BCOND_TAR) + } else if (type == BCOND_TAR) { gen_load_spr(target, SPR_TAR); - else + } else { tcg_gen_mov_tl(target, cpu_lr); + } } else { target = NULL; } - if (LK(ctx->opcode)) + if (LK(ctx->opcode)) { gen_setlr(ctx, ctx->base.pc_next); + } l1 = gen_new_label(); if ((bo & 0x4) == 0) { /* Decrement and test CTR */ TCGv temp = tcg_temp_new(); - if (unlikely(type == BCOND_CTR)) { - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); - return; - } - tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1); - if (NARROW_MODE(ctx)) { - tcg_gen_ext32u_tl(temp, cpu_ctr); - } else { - tcg_gen_mov_tl(temp, cpu_ctr); - } - if (bo & 0x2) { - tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1); + + if (type == BCOND_CTR) { + /* + * All ISAs up to v3 describe this form of bcctr as invalid but + * some processors, ie. 64-bit server processors compliant with + * arch 2.x, do implement a "test and decrement" logic instead, + * as described in their respective UMs. This logic involves CTR + * to act as both the branch target and a counter, which makes + * it basically useless and thus never used in real code. + * + * This form was hence chosen to trigger extra micro-architectural + * side-effect on real HW needed for the Spectre v2 workaround. + * It is up to guests that implement such workaround, ie. linux, to + * use this form in a way it just triggers the side-effect without + * doing anything else harmful. + */ + if (unlikely(!is_book3s_arch2x(ctx))) { + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); + tcg_temp_free(temp); + tcg_temp_free(target); + return; + } + + if (NARROW_MODE(ctx)) { + tcg_gen_ext32u_tl(temp, cpu_ctr); + } else { + tcg_gen_mov_tl(temp, cpu_ctr); + } + if (bo & 0x2) { + tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1); + } else { + tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1); + } + tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1); } else { - tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1); + tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1); + if (NARROW_MODE(ctx)) { + tcg_gen_ext32u_tl(temp, cpu_ctr); + } else { + tcg_gen_mov_tl(temp, cpu_ctr); + } + if (bo & 0x2) { + tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1); + } else { + tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1); + } } tcg_temp_free(temp); } @@ -3825,7 +3904,7 @@ static void gen_bctar(DisasContext *ctx) /*** Condition register logical ***/ #define GEN_CRLOGIC(name, tcg_op, opc) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ uint8_t bitmask; \ int sh; \ @@ -3886,10 +3965,11 @@ static void gen_rfi(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) GEN_PRIV; #else - /* This instruction doesn't exist anymore on 64-bit server + /* + * This instruction doesn't exist anymore on 64-bit server * processors compliant with arch 2.x */ - if (ctx->insns_flags & PPC_SEGMENT_64B) { + if (is_book3s_arch2x(ctx)) { gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); return; } @@ -4125,7 +4205,7 @@ static void gen_mfcr(DisasContext *ctx) if (likely(ctx->opcode & 0x00100000)) { crm = CRM(ctx->opcode); if (likely(crm && ((crm & (crm - 1)) == 0))) { - crn = ctz32 (crm); + crn = ctz32(crm); tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], cpu_crf[7 - crn]); tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], crn * 4); @@ -4190,7 +4270,8 @@ static inline void gen_op_mfspr(DisasContext *ctx) (*read_cb)(ctx, rD(ctx->opcode), sprn); } else { /* Privilege exception */ - /* This is a hack to avoid warnings when running Linux: + /* + * This is a hack to avoid warnings when running Linux: * this OS breaks the PowerPC virtualisation model, * allowing userland application to read the PVR */ @@ -4213,8 +4294,9 @@ static inline void gen_op_mfspr(DisasContext *ctx) "Trying to read invalid spr %d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn, ctx->base.pc_next - 4); - /* The behaviour depends on MSR:PR and SPR# bit 0x10, - * it can generate a priv, a hv emu or a no-op + /* + * The behaviour depends on MSR:PR and SPR# bit 0x10, it can + * generate a priv, a hv emu or a no-op */ if (sprn & 0x10) { if (ctx->pr) { @@ -4248,7 +4330,7 @@ static void gen_mtcrf(DisasContext *ctx) if (likely((ctx->opcode & 0x00100000))) { if (crm && ((crm & (crm - 1)) == 0)) { TCGv_i32 temp = tcg_temp_new_i32(); - crn = ctz32 (crm); + crn = ctz32(crm); tcg_gen_trunc_tl_i32(temp, cpu_gpr[rS(ctx->opcode)]); tcg_gen_shri_i32(temp, temp, crn * 4); tcg_gen_andi_i32(cpu_crf[7 - crn], temp, 0xf); @@ -4277,14 +4359,17 @@ static void gen_mtmsrd(DisasContext *ctx) if (ctx->opcode & 0x00010000) { /* Special form that does not need any synchronisation */ TCGv t0 = tcg_temp_new(); - tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE)); - tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(target_ulong)((1 << MSR_RI) | (1 << MSR_EE))); + tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], + (1 << MSR_RI) | (1 << MSR_EE)); + tcg_gen_andi_tl(cpu_msr, cpu_msr, + ~(target_ulong)((1 << MSR_RI) | (1 << MSR_EE))); tcg_gen_or_tl(cpu_msr, cpu_msr, t0); tcg_temp_free(t0); } else { - /* XXX: we need to update nip before the store - * if we enter power saving mode, we will exit the loop - * directly from ppc_store_msr + /* + * XXX: we need to update nip before the store if we enter + * power saving mode, we will exit the loop directly from + * ppc_store_msr */ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); @@ -4310,16 +4395,19 @@ static void gen_mtmsr(DisasContext *ctx) if (ctx->opcode & 0x00010000) { /* Special form that does not need any synchronisation */ TCGv t0 = tcg_temp_new(); - tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE)); - tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(target_ulong)((1 << MSR_RI) | (1 << MSR_EE))); + tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], + (1 << MSR_RI) | (1 << MSR_EE)); + tcg_gen_andi_tl(cpu_msr, cpu_msr, + ~(target_ulong)((1 << MSR_RI) | (1 << MSR_EE))); tcg_gen_or_tl(cpu_msr, cpu_msr, t0); tcg_temp_free(t0); } else { TCGv msr = tcg_temp_new(); - /* XXX: we need to update nip before the store - * if we enter power saving mode, we will exit the loop - * directly from ppc_store_msr + /* + * XXX: we need to update nip before the store if we enter + * power saving mode, we will exit the loop directly from + * ppc_store_msr */ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); @@ -4383,8 +4471,9 @@ static void gen_mtspr(DisasContext *ctx) TARGET_FMT_lx "\n", sprn, sprn, ctx->base.pc_next - 4); - /* The behaviour depends on MSR:PR and SPR# bit 0x10, - * it can generate a priv, a hv emu or a no-op + /* + * The behaviour depends on MSR:PR and SPR# bit 0x10, it can + * generate a priv, a hv emu or a no-op */ if (sprn & 0x10) { if (ctx->pr) { @@ -4494,36 +4583,40 @@ static void gen_dcbstep(DisasContext *ctx) /* dcbt */ static void gen_dcbt(DisasContext *ctx) { - /* interpreted as no-op */ - /* XXX: specification say this is treated as a load by the MMU - * but does not generate any exception + /* + * interpreted as no-op + * XXX: specification say this is treated as a load by the MMU but + * does not generate any exception */ } /* dcbtep */ static void gen_dcbtep(DisasContext *ctx) { - /* interpreted as no-op */ - /* XXX: specification say this is treated as a load by the MMU - * but does not generate any exception + /* + * interpreted as no-op + * XXX: specification say this is treated as a load by the MMU but + * does not generate any exception */ } /* dcbtst */ static void gen_dcbtst(DisasContext *ctx) { - /* interpreted as no-op */ - /* XXX: specification say this is treated as a load by the MMU - * but does not generate any exception + /* + * interpreted as no-op + * XXX: specification say this is treated as a load by the MMU but + * does not generate any exception */ } /* dcbtstep */ static void gen_dcbtstep(DisasContext *ctx) { - /* interpreted as no-op */ - /* XXX: specification say this is treated as a load by the MMU - * but does not generate any exception + /* + * interpreted as no-op + * XXX: specification say this is treated as a load by the MMU but + * does not generate any exception */ } @@ -4621,8 +4714,9 @@ static void gen_icbiep(DisasContext *ctx) /* dcba */ static void gen_dcba(DisasContext *ctx) { - /* interpreted as no-op */ - /* XXX: specification say this is treated as a store by the MMU + /* + * interpreted as no-op + * XXX: specification say this is treated as a store by the MMU * but does not generate any exception */ } @@ -4989,8 +5083,9 @@ static void gen_abs(DisasContext *ctx) gen_set_label(l1); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); gen_set_label(l2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* abso - abso. */ @@ -5012,8 +5107,9 @@ static void gen_abso(DisasContext *ctx) gen_set_label(l2); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); gen_set_label(l3); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* clcs */ @@ -5030,8 +5126,9 @@ static void gen_div(DisasContext *ctx) { gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* divo - divo. */ @@ -5039,8 +5136,9 @@ static void gen_divo(DisasContext *ctx) { gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* divs - divs. */ @@ -5048,8 +5146,9 @@ static void gen_divs(DisasContext *ctx) { gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* divso - divso. */ @@ -5057,8 +5156,9 @@ static void gen_divso(DisasContext *ctx) { gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* doz - doz. */ @@ -5066,14 +5166,17 @@ static void gen_doz(DisasContext *ctx) { TCGLabel *l1 = gen_new_label(); TCGLabel *l2 = gen_new_label(); - tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1); - tcg_gen_sub_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)], l1); + tcg_gen_sub_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)]); tcg_gen_br(l2); gen_set_label(l1); tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0); gen_set_label(l2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* dozo - dozo. */ @@ -5086,7 +5189,8 @@ static void gen_dozo(DisasContext *ctx) TCGv t2 = tcg_temp_new(); /* Start with XER OV disabled, the most likely case */ tcg_gen_movi_tl(cpu_ov, 0); - tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1); + tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)], l1); tcg_gen_sub_tl(t0, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); tcg_gen_xor_tl(t1, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); tcg_gen_xor_tl(t2, cpu_gpr[rA(ctx->opcode)], t0); @@ -5102,8 +5206,9 @@ static void gen_dozo(DisasContext *ctx) tcg_temp_free(t0); tcg_temp_free(t1); tcg_temp_free(t2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* dozi */ @@ -5118,8 +5223,9 @@ static void gen_dozi(DisasContext *ctx) gen_set_label(l1); tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0); gen_set_label(l2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* lscbx - lscbx. */ @@ -5137,8 +5243,9 @@ static void gen_lscbx(DisasContext *ctx) tcg_temp_free_i32(t3); tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F); tcg_gen_or_tl(cpu_xer, cpu_xer, t0); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, t0); + } tcg_temp_free(t0); } @@ -5164,8 +5271,9 @@ static void gen_maskg(DisasContext *ctx) tcg_temp_free(t1); tcg_temp_free(t2); tcg_temp_free(t3); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* maskir - maskir. */ @@ -5178,8 +5286,9 @@ static void gen_maskir(DisasContext *ctx) tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* mul - mul. */ @@ -5198,8 +5307,9 @@ static void gen_mul(DisasContext *ctx) tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); tcg_temp_free(t2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* mulo - mulo. */ @@ -5226,8 +5336,9 @@ static void gen_mulo(DisasContext *ctx) tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); tcg_temp_free(t2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* nabs - nabs. */ @@ -5241,8 +5352,9 @@ static void gen_nabs(DisasContext *ctx) gen_set_label(l1); tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); gen_set_label(l2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* nabso - nabso. */ @@ -5258,8 +5370,9 @@ static void gen_nabso(DisasContext *ctx) gen_set_label(l2); /* nabs never overflows */ tcg_gen_movi_tl(cpu_ov, 0); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } } /* rlmi - rlmi. */ @@ -5271,11 +5384,13 @@ static void gen_rlmi(DisasContext *ctx) tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F); tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0); tcg_gen_andi_tl(t0, t0, MASK(mb, me)); - tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~MASK(mb, me)); + tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + ~MASK(mb, me)); tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], t0); tcg_temp_free(t0); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* rrib - rrib. */ @@ -5292,8 +5407,9 @@ static void gen_rrib(DisasContext *ctx) tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* sle - sle. */ @@ -5310,8 +5426,9 @@ static void gen_sle(DisasContext *ctx) gen_store_spr(SPR_MQ, t1); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* sleq - sleq. */ @@ -5332,8 +5449,9 @@ static void gen_sleq(DisasContext *ctx) tcg_temp_free(t0); tcg_temp_free(t1); tcg_temp_free(t2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* sliq - sliq. */ @@ -5349,8 +5467,9 @@ static void gen_sliq(DisasContext *ctx) gen_store_spr(SPR_MQ, t1); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* slliq - slliq. */ @@ -5367,8 +5486,9 @@ static void gen_slliq(DisasContext *ctx) tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* sllq - sllq. */ @@ -5396,8 +5516,9 @@ static void gen_sllq(DisasContext *ctx) tcg_temp_free(t0); tcg_temp_free(t1); tcg_temp_free(t2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* slq - slq. */ @@ -5419,8 +5540,9 @@ static void gen_slq(DisasContext *ctx) gen_set_label(l1); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* sraiq - sraiq. */ @@ -5442,8 +5564,9 @@ static void gen_sraiq(DisasContext *ctx) tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* sraq - sraq. */ @@ -5475,8 +5598,9 @@ static void gen_sraq(DisasContext *ctx) gen_set_label(l2); tcg_temp_free(t1); tcg_temp_free(t2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* sre - sre. */ @@ -5493,8 +5617,9 @@ static void gen_sre(DisasContext *ctx) gen_store_spr(SPR_MQ, t1); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* srea - srea. */ @@ -5508,8 +5633,9 @@ static void gen_srea(DisasContext *ctx) tcg_gen_sar_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t1); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* sreq */ @@ -5530,8 +5656,9 @@ static void gen_sreq(DisasContext *ctx) tcg_temp_free(t0); tcg_temp_free(t1); tcg_temp_free(t2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* sriq */ @@ -5547,8 +5674,9 @@ static void gen_sriq(DisasContext *ctx) gen_store_spr(SPR_MQ, t1); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* srliq */ @@ -5565,8 +5693,9 @@ static void gen_srliq(DisasContext *ctx) tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* srlq */ @@ -5595,8 +5724,9 @@ static void gen_srlq(DisasContext *ctx) tcg_temp_free(t0); tcg_temp_free(t1); tcg_temp_free(t2); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* srq */ @@ -5618,8 +5748,9 @@ static void gen_srq(DisasContext *ctx) gen_set_label(l1); tcg_temp_free(t0); tcg_temp_free(t1); - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); + } } /* PowerPC 602 specific instructions */ @@ -5737,8 +5868,9 @@ static void gen_mfsri(DisasContext *ctx) tcg_gen_extract_tl(t0, t0, 28, 4); gen_helper_load_sr(cpu_gpr[rd], cpu_env, t0); tcg_temp_free(t0); - if (ra != 0 && ra != rd) + if (ra != 0 && ra != rd) { tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]); + } #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6115,9 +6247,10 @@ static void gen_dcread(DisasContext *ctx) /* icbt */ static void gen_icbt_40x(DisasContext *ctx) { - /* interpreted as no-op */ - /* XXX: specification say this is treated as a load by the MMU - * but does not generate any exception + /* + * interpreted as no-op + * XXX: specification say this is treated as a load by the MMU but + * does not generate any exception */ } @@ -6408,7 +6541,7 @@ static void gen_tlbilx_booke206(DisasContext *ctx) t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - switch((ctx->opcode >> 21) & 0x3) { + switch ((ctx->opcode >> 21) & 0x3) { case 0: gen_helper_booke206_tlbilx0(cpu_env, t0); break; @@ -6442,8 +6575,9 @@ static void gen_wrtee(DisasContext *ctx) tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE)); tcg_gen_or_tl(cpu_msr, cpu_msr, t0); tcg_temp_free(t0); - /* Stop translation to have a chance to raise an exception - * if we just set msr_ee to 1 + /* + * Stop translation to have a chance to raise an exception if we + * just set msr_ee to 1 */ gen_stop_exception(ctx); #endif /* defined(CONFIG_USER_ONLY) */ @@ -6497,9 +6631,10 @@ static void gen_msync_4xx(DisasContext *ctx) /* icbt */ static void gen_icbt_440(DisasContext *ctx) { - /* interpreted as no-op */ - /* XXX: specification say this is treated as a load by the MMU - * but does not generate any exception + /* + * interpreted as no-op + * XXX: specification say this is treated as a load by the MMU but + * does not generate any exception */ } @@ -6511,8 +6646,7 @@ static void gen_msgclr(DisasContext *ctx) GEN_PRIV; #else CHK_HV; - /* 64-bit server processors compliant with arch 2.x */ - if (ctx->insns_flags & PPC_SEGMENT_64B) { + if (is_book3s_arch2x(ctx)) { gen_helper_book3s_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]); } else { gen_helper_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]); @@ -6526,8 +6660,7 @@ static void gen_msgsnd(DisasContext *ctx) GEN_PRIV; #else CHK_HV; - /* 64-bit server processors compliant with arch 2.x */ - if (ctx->insns_flags & PPC_SEGMENT_64B) { + if (is_book3s_arch2x(ctx)) { gen_helper_book3s_msgsnd(cpu_gpr[rB(ctx->opcode)]); } else { gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]); @@ -6595,7 +6728,8 @@ static inline void gen_##name(DisasContext *ctx) \ gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); \ return; \ } \ - /* Because tbegin always fails in QEMU, these user \ + /* \ + * Because tbegin always fails in QEMU, these user \ * space instructions all have a simple implementation: \ * \ * CR[0] = 0b0 || MSR[TS] || 0b0 \ @@ -6611,17 +6745,18 @@ GEN_TM_NOOP(tabortwci); GEN_TM_NOOP(tabortdc); GEN_TM_NOOP(tabortdci); GEN_TM_NOOP(tsr); + static inline void gen_cp_abort(DisasContext *ctx) { - // Do Nothing + /* Do Nothing */ } #define GEN_CP_PASTE_NOOP(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ - /* Generate invalid exception until \ - * we have an implementation of the copy \ - * paste facility \ + /* \ + * Generate invalid exception until we have an \ + * implementation of the copy paste facility \ */ \ gen_invalid(ctx); \ } @@ -6635,8 +6770,9 @@ static void gen_tcheck(DisasContext *ctx) gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); return; } - /* Because tbegin always fails, the tcheck implementation - * is simple: + /* + * Because tbegin always fails, the tcheck implementation is + * simple: * * CR[CRF] = TDOOMED || MSR[TS] || 0b0 * = 0b1 || 0b00 || 0b0 @@ -6648,7 +6784,7 @@ static void gen_tcheck(DisasContext *ctx) #define GEN_TM_PRIV_NOOP(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ - gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); \ + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); \ } #else @@ -6661,7 +6797,8 @@ static inline void gen_##name(DisasContext *ctx) \ gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); \ return; \ } \ - /* Because tbegin always fails, the implementation is \ + /* \ + * Because tbegin always fails, the implementation is \ * simple: \ * \ * CR[0] = 0b0 || MSR[TS] || 0b0 \ @@ -6943,8 +7080,10 @@ GEN_HANDLER2(slbmfev, "slbmfev", 0x1F, 0x13, 0x1A, 0x001F0001, PPC_SEGMENT_64B), GEN_HANDLER2(slbfee_, "slbfee.", 0x1F, 0x13, 0x1E, 0x001F0000, PPC_SEGMENT_64B), #endif GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA), -/* XXX Those instructions will need to be handled differently for - * different ISA versions */ +/* + * XXX Those instructions will need to be handled differently for + * different ISA versions + */ GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x001F0001, PPC_MEM_TLBIE), GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x001F0001, PPC_MEM_TLBIE), GEN_HANDLER_E(tlbiel, 0x1F, 0x12, 0x08, 0x00100001, PPC_NONE, PPC2_ISA300), @@ -7384,8 +7523,7 @@ GEN_HANDLER2_E(trechkpt, "trechkpt", 0x1F, 0x0E, 0x1F, 0x03FFF800, \ /*****************************************************************************/ /* Misc PowerPC helpers */ -void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags) { #define RGPL 4 #define RFPL 4 @@ -7394,113 +7532,116 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env = &cpu->env; int i; - cpu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR " - TARGET_FMT_lx " XER " TARGET_FMT_lx " CPU#%d\n", - env->nip, env->lr, env->ctr, cpu_read_xer(env), - cs->cpu_index); - cpu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF " - TARGET_FMT_lx " iidx %d didx %d\n", - env->msr, env->spr[SPR_HID0], - env->hflags, env->immu_idx, env->dmmu_idx); + qemu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR " + TARGET_FMT_lx " XER " TARGET_FMT_lx " CPU#%d\n", + env->nip, env->lr, env->ctr, cpu_read_xer(env), + cs->cpu_index); + qemu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF " + TARGET_FMT_lx " iidx %d didx %d\n", + env->msr, env->spr[SPR_HID0], + env->hflags, env->immu_idx, env->dmmu_idx); #if !defined(NO_TIMER_DUMP) - cpu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 + qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 #if !defined(CONFIG_USER_ONLY) - " DECR " TARGET_FMT_lu + " DECR " TARGET_FMT_lu #endif - "\n", - cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) + "\n", + cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) #if !defined(CONFIG_USER_ONLY) - , cpu_ppc_load_decr(env) + , cpu_ppc_load_decr(env) #endif - ); + ); #endif for (i = 0; i < 32; i++) { - if ((i & (RGPL - 1)) == 0) - cpu_fprintf(f, "GPR%02d", i); - cpu_fprintf(f, " %016" PRIx64, ppc_dump_gpr(env, i)); - if ((i & (RGPL - 1)) == (RGPL - 1)) - cpu_fprintf(f, "\n"); + if ((i & (RGPL - 1)) == 0) { + qemu_fprintf(f, "GPR%02d", i); + } + qemu_fprintf(f, " %016" PRIx64, ppc_dump_gpr(env, i)); + if ((i & (RGPL - 1)) == (RGPL - 1)) { + qemu_fprintf(f, "\n"); + } } - cpu_fprintf(f, "CR "); + qemu_fprintf(f, "CR "); for (i = 0; i < 8; i++) - cpu_fprintf(f, "%01x", env->crf[i]); - cpu_fprintf(f, " ["); + qemu_fprintf(f, "%01x", env->crf[i]); + qemu_fprintf(f, " ["); for (i = 0; i < 8; i++) { char a = '-'; - if (env->crf[i] & 0x08) + if (env->crf[i] & 0x08) { a = 'L'; - else if (env->crf[i] & 0x04) + } else if (env->crf[i] & 0x04) { a = 'G'; - else if (env->crf[i] & 0x02) + } else if (env->crf[i] & 0x02) { a = 'E'; - cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); + } + qemu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); } - cpu_fprintf(f, " ] RES " TARGET_FMT_lx "\n", - env->reserve_addr); + qemu_fprintf(f, " ] RES " TARGET_FMT_lx "\n", + env->reserve_addr); if (flags & CPU_DUMP_FPU) { for (i = 0; i < 32; i++) { if ((i & (RFPL - 1)) == 0) { - cpu_fprintf(f, "FPR%02d", i); + qemu_fprintf(f, "FPR%02d", i); } - cpu_fprintf(f, " %016" PRIx64, *cpu_fpr_ptr(env, i)); + qemu_fprintf(f, " %016" PRIx64, *cpu_fpr_ptr(env, i)); if ((i & (RFPL - 1)) == (RFPL - 1)) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } - cpu_fprintf(f, "FPSCR " TARGET_FMT_lx "\n", env->fpscr); + qemu_fprintf(f, "FPSCR " TARGET_FMT_lx "\n", env->fpscr); } #if !defined(CONFIG_USER_ONLY) - cpu_fprintf(f, " SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx - " PVR " TARGET_FMT_lx " VRSAVE " TARGET_FMT_lx "\n", - env->spr[SPR_SRR0], env->spr[SPR_SRR1], - env->spr[SPR_PVR], env->spr[SPR_VRSAVE]); + qemu_fprintf(f, " SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx + " PVR " TARGET_FMT_lx " VRSAVE " TARGET_FMT_lx "\n", + env->spr[SPR_SRR0], env->spr[SPR_SRR1], + env->spr[SPR_PVR], env->spr[SPR_VRSAVE]); - cpu_fprintf(f, "SPRG0 " TARGET_FMT_lx " SPRG1 " TARGET_FMT_lx - " SPRG2 " TARGET_FMT_lx " SPRG3 " TARGET_FMT_lx "\n", - env->spr[SPR_SPRG0], env->spr[SPR_SPRG1], - env->spr[SPR_SPRG2], env->spr[SPR_SPRG3]); + qemu_fprintf(f, "SPRG0 " TARGET_FMT_lx " SPRG1 " TARGET_FMT_lx + " SPRG2 " TARGET_FMT_lx " SPRG3 " TARGET_FMT_lx "\n", + env->spr[SPR_SPRG0], env->spr[SPR_SPRG1], + env->spr[SPR_SPRG2], env->spr[SPR_SPRG3]); - cpu_fprintf(f, "SPRG4 " TARGET_FMT_lx " SPRG5 " TARGET_FMT_lx - " SPRG6 " TARGET_FMT_lx " SPRG7 " TARGET_FMT_lx "\n", - env->spr[SPR_SPRG4], env->spr[SPR_SPRG5], - env->spr[SPR_SPRG6], env->spr[SPR_SPRG7]); + qemu_fprintf(f, "SPRG4 " TARGET_FMT_lx " SPRG5 " TARGET_FMT_lx + " SPRG6 " TARGET_FMT_lx " SPRG7 " TARGET_FMT_lx "\n", + env->spr[SPR_SPRG4], env->spr[SPR_SPRG5], + env->spr[SPR_SPRG6], env->spr[SPR_SPRG7]); #if defined(TARGET_PPC64) if (env->excp_model == POWERPC_EXCP_POWER7 || env->excp_model == POWERPC_EXCP_POWER8 || env->excp_model == POWERPC_EXCP_POWER9) { - cpu_fprintf(f, "HSRR0 " TARGET_FMT_lx " HSRR1 " TARGET_FMT_lx "\n", - env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); + qemu_fprintf(f, "HSRR0 " TARGET_FMT_lx " HSRR1 " TARGET_FMT_lx "\n", + env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); } #endif if (env->excp_model == POWERPC_EXCP_BOOKE) { - cpu_fprintf(f, "CSRR0 " TARGET_FMT_lx " CSRR1 " TARGET_FMT_lx - " MCSRR0 " TARGET_FMT_lx " MCSRR1 " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1], - env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); - - cpu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx - " ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_TCR], env->spr[SPR_BOOKE_TSR], - env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]); - - cpu_fprintf(f, " PIR " TARGET_FMT_lx " DECAR " TARGET_FMT_lx - " IVPR " TARGET_FMT_lx " EPCR " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_PIR], env->spr[SPR_BOOKE_DECAR], - env->spr[SPR_BOOKE_IVPR], env->spr[SPR_BOOKE_EPCR]); - - cpu_fprintf(f, " MCSR " TARGET_FMT_lx " SPRG8 " TARGET_FMT_lx - " EPR " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_MCSR], env->spr[SPR_BOOKE_SPRG8], - env->spr[SPR_BOOKE_EPR]); + qemu_fprintf(f, "CSRR0 " TARGET_FMT_lx " CSRR1 " TARGET_FMT_lx + " MCSRR0 " TARGET_FMT_lx " MCSRR1 " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1], + env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); + + qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx + " ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_TCR], env->spr[SPR_BOOKE_TSR], + env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]); + + qemu_fprintf(f, " PIR " TARGET_FMT_lx " DECAR " TARGET_FMT_lx + " IVPR " TARGET_FMT_lx " EPCR " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_PIR], env->spr[SPR_BOOKE_DECAR], + env->spr[SPR_BOOKE_IVPR], env->spr[SPR_BOOKE_EPCR]); + + qemu_fprintf(f, " MCSR " TARGET_FMT_lx " SPRG8 " TARGET_FMT_lx + " EPR " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_MCSR], env->spr[SPR_BOOKE_SPRG8], + env->spr[SPR_BOOKE_EPR]); /* FSL-specific */ - cpu_fprintf(f, " MCAR " TARGET_FMT_lx " PID1 " TARGET_FMT_lx - " PID2 " TARGET_FMT_lx " SVR " TARGET_FMT_lx "\n", - env->spr[SPR_Exxx_MCAR], env->spr[SPR_BOOKE_PID1], - env->spr[SPR_BOOKE_PID2], env->spr[SPR_E500_SVR]); + qemu_fprintf(f, " MCAR " TARGET_FMT_lx " PID1 " TARGET_FMT_lx + " PID2 " TARGET_FMT_lx " SVR " TARGET_FMT_lx "\n", + env->spr[SPR_Exxx_MCAR], env->spr[SPR_BOOKE_PID1], + env->spr[SPR_BOOKE_PID2], env->spr[SPR_E500_SVR]); /* * IVORs are left out as they are large and do not change often -- @@ -7510,12 +7651,13 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, #if defined(TARGET_PPC64) if (env->flags & POWERPC_FLAG_CFAR) { - cpu_fprintf(f, " CFAR " TARGET_FMT_lx"\n", env->cfar); + qemu_fprintf(f, " CFAR " TARGET_FMT_lx"\n", env->cfar); } #endif - if (env->spr_cb[SPR_LPCR].name) - cpu_fprintf(f, " LPCR " TARGET_FMT_lx "\n", env->spr[SPR_LPCR]); + if (env->spr_cb[SPR_LPCR].name) { + qemu_fprintf(f, " LPCR " TARGET_FMT_lx "\n", env->spr[SPR_LPCR]); + } switch (env->mmu_model) { case POWERPC_MMU_32B: @@ -7530,29 +7672,29 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, case POWERPC_MMU_3_00: #endif if (env->spr_cb[SPR_SDR1].name) { /* SDR1 Exists */ - cpu_fprintf(f, " SDR1 " TARGET_FMT_lx " ", env->spr[SPR_SDR1]); + qemu_fprintf(f, " SDR1 " TARGET_FMT_lx " ", env->spr[SPR_SDR1]); } if (env->spr_cb[SPR_PTCR].name) { /* PTCR Exists */ - cpu_fprintf(f, " PTCR " TARGET_FMT_lx " ", env->spr[SPR_PTCR]); + qemu_fprintf(f, " PTCR " TARGET_FMT_lx " ", env->spr[SPR_PTCR]); } - cpu_fprintf(f, " DAR " TARGET_FMT_lx " DSISR " TARGET_FMT_lx "\n", - env->spr[SPR_DAR], env->spr[SPR_DSISR]); + qemu_fprintf(f, " DAR " TARGET_FMT_lx " DSISR " TARGET_FMT_lx "\n", + env->spr[SPR_DAR], env->spr[SPR_DSISR]); break; case POWERPC_MMU_BOOKE206: - cpu_fprintf(f, " MAS0 " TARGET_FMT_lx " MAS1 " TARGET_FMT_lx - " MAS2 " TARGET_FMT_lx " MAS3 " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1], - env->spr[SPR_BOOKE_MAS2], env->spr[SPR_BOOKE_MAS3]); - - cpu_fprintf(f, " MAS4 " TARGET_FMT_lx " MAS6 " TARGET_FMT_lx - " MAS7 " TARGET_FMT_lx " PID " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_MAS4], env->spr[SPR_BOOKE_MAS6], - env->spr[SPR_BOOKE_MAS7], env->spr[SPR_BOOKE_PID]); - - cpu_fprintf(f, "MMUCFG " TARGET_FMT_lx " TLB0CFG " TARGET_FMT_lx - " TLB1CFG " TARGET_FMT_lx "\n", - env->spr[SPR_MMUCFG], env->spr[SPR_BOOKE_TLB0CFG], - env->spr[SPR_BOOKE_TLB1CFG]); + qemu_fprintf(f, " MAS0 " TARGET_FMT_lx " MAS1 " TARGET_FMT_lx + " MAS2 " TARGET_FMT_lx " MAS3 " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1], + env->spr[SPR_BOOKE_MAS2], env->spr[SPR_BOOKE_MAS3]); + + qemu_fprintf(f, " MAS4 " TARGET_FMT_lx " MAS6 " TARGET_FMT_lx + " MAS7 " TARGET_FMT_lx " PID " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_MAS4], env->spr[SPR_BOOKE_MAS6], + env->spr[SPR_BOOKE_MAS7], env->spr[SPR_BOOKE_PID]); + + qemu_fprintf(f, "MMUCFG " TARGET_FMT_lx " TLB0CFG " TARGET_FMT_lx + " TLB1CFG " TARGET_FMT_lx "\n", + env->spr[SPR_MMUCFG], env->spr[SPR_BOOKE_TLB0CFG], + env->spr[SPR_BOOKE_TLB1CFG]); break; default: break; @@ -7563,8 +7705,7 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, #undef RFPL } -void ppc_cpu_dump_statistics(CPUState *cs, FILE*f, - fprintf_function cpu_fprintf, int flags) +void ppc_cpu_dump_statistics(CPUState *cs, int flags) { #if defined(DO_PPC_STATISTICS) PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -7582,27 +7723,30 @@ void ppc_cpu_dump_statistics(CPUState *cs, FILE*f, t3 = ind_table(handler); for (op3 = 0; op3 < 32; op3++) { handler = t3[op3]; - if (handler->count == 0) + if (handler->count == 0) { continue; - cpu_fprintf(f, "%02x %02x %02x (%02x %04d) %16s: " + } + qemu_printf("%02x %02x %02x (%02x %04d) %16s: " "%016" PRIx64 " %" PRId64 "\n", op1, op2, op3, op1, (op3 << 5) | op2, handler->oname, handler->count, handler->count); } } else { - if (handler->count == 0) + if (handler->count == 0) { continue; - cpu_fprintf(f, "%02x %02x (%02x %04d) %16s: " + } + qemu_printf("%02x %02x (%02x %04d) %16s: " "%016" PRIx64 " %" PRId64 "\n", op1, op2, op1, op2, handler->oname, handler->count, handler->count); } } } else { - if (handler->count == 0) + if (handler->count == 0) { continue; - cpu_fprintf(f, "%02x (%02x ) %16s: %016" PRIx64 + } + qemu_printf("%02x (%02x ) %16s: %016" PRIx64 " %" PRId64 "\n", op1, op1, handler->oname, handler->count, handler->count); @@ -7641,14 +7785,16 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) || (env->mmu_model & POWERPC_MMU_64B); ctx->fpu_enabled = !!msr_fp; - if ((env->flags & POWERPC_FLAG_SPE) && msr_spe) + if ((env->flags & POWERPC_FLAG_SPE) && msr_spe) { ctx->spe_enabled = !!msr_spe; - else + } else { ctx->spe_enabled = false; - if ((env->flags & POWERPC_FLAG_VRE) && msr_vr) + } + if ((env->flags & POWERPC_FLAG_VRE) && msr_vr) { ctx->altivec_enabled = !!msr_vr; - else + } else { ctx->altivec_enabled = false; + } if ((env->flags & POWERPC_FLAG_VSX) && msr_vsx) { ctx->vsx_enabled = !!msr_vsx; } else { @@ -7662,12 +7808,14 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) } #endif ctx->gtse = !!(env->spr[SPR_LPCR] & LPCR_GTSE); - if ((env->flags & POWERPC_FLAG_SE) && msr_se) + if ((env->flags & POWERPC_FLAG_SE) && msr_se) { ctx->singlestep_enabled = CPU_SINGLE_STEP; - else + } else { ctx->singlestep_enabled = 0; - if ((env->flags & POWERPC_FLAG_BE) && msr_be) + } + if ((env->flags & POWERPC_FLAG_BE) && msr_be) { ctx->singlestep_enabled |= CPU_BRANCH_STEP; + } if ((env->flags & POWERPC_FLAG_DE) && msr_de) { ctx->singlestep_enabled = 0; target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0]; @@ -7682,7 +7830,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) if (unlikely(ctx->base.singlestep_enabled)) { ctx->singlestep_enabled |= GDBSTUB_SINGLE_STEP; } -#if defined (DO_SINGLE_STEP) && 0 +#if defined(DO_SINGLE_STEP) && 0 /* Single step trace mode */ msr_se = 1; #endif @@ -7707,10 +7855,12 @@ static bool ppc_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, gen_debug_exception(ctx); dcbase->is_jmp = DISAS_NORETURN; - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ + /* + * The address covered by the breakpoint must be included in + * [tb->pc, tb->pc + tb->size) in order to for it to be properly + * cleared -- thus we increment the PC here so that the logic + * setting tb->size below does the right thing. + */ ctx->base.pc_next += 4; return true; } @@ -7834,11 +7984,11 @@ static const TranslatorOps ppc_tr_ops = { .disas_log = ppc_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { DisasContext ctx; - translator_loop(&ppc_tr_ops, &ctx.base, cs, tb); + translator_loop(&ppc_tr_ops, &ctx.base, cs, tb, max_insns); } void restore_state_to_opc(CPUPPCState *env, TranslationBlock *tb, diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c index 0f21a4e477..9dcff947c0 100644 --- a/target/ppc/translate/fp-impl.inc.c +++ b/target/ppc/translate/fp-impl.inc.c @@ -585,11 +585,13 @@ static void gen_mcrfs(DisasContext *ctx) shift = 4 * nibble; tcg_gen_shri_tl(tmp, cpu_fpscr, shift); tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], tmp); - tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], 0xf); + tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], + 0xf); tcg_temp_free(tmp); tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr); /* Only the exception bits (including FX) should be cleared if read */ - tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr, ~((0xF << shift) & FP_EX_CLEAR_BITS)); + tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr, + ~((0xF << shift) & FP_EX_CLEAR_BITS)); /* FEX and VX need to be updated, so don't set fpscr directly */ tmask = tcg_const_i32(1 << nibble); gen_helper_store_fpscr(cpu_env, tnew_fpscr, tmask); @@ -735,7 +737,7 @@ static void gen_mtfsfi(DisasContext *ctx) /*** Floating-point load ***/ #define GEN_LDF(name, ldop, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv EA; \ TCGv_i64 t0; \ @@ -754,7 +756,7 @@ static void glue(gen_, name)(DisasContext *ctx) } #define GEN_LDUF(name, ldop, opc, type) \ -static void glue(gen_, name##u)(DisasContext *ctx) \ +static void glue(gen_, name##u)(DisasContext *ctx) \ { \ TCGv EA; \ TCGv_i64 t0; \ @@ -778,7 +780,7 @@ static void glue(gen_, name##u)(DisasContext *ctx) } #define GEN_LDUXF(name, ldop, opc, type) \ -static void glue(gen_, name##ux)(DisasContext *ctx) \ +static void glue(gen_, name##ux)(DisasContext *ctx) \ { \ TCGv EA; \ TCGv_i64 t0; \ @@ -802,7 +804,7 @@ static void glue(gen_, name##ux)(DisasContext *ctx) } #define GEN_LDXF(name, ldop, opc2, opc3, type) \ -static void glue(gen_, name##x)(DisasContext *ctx) \ +static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ TCGv_i64 t0; \ @@ -872,8 +874,10 @@ static void gen_lfdp(DisasContext *ctx) EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0); t0 = tcg_temp_new_i64(); - /* We only need to swap high and low halves. gen_qemu_ld64_i64 does - necessary 64-bit byteswap already. */ + /* + * We only need to swap high and low halves. gen_qemu_ld64_i64 + * does necessary 64-bit byteswap already. + */ if (unlikely(ctx->le_mode)) { gen_qemu_ld64_i64(ctx, t0, EA); set_fpr(rD(ctx->opcode) + 1, t0); @@ -904,8 +908,10 @@ static void gen_lfdpx(DisasContext *ctx) EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); t0 = tcg_temp_new_i64(); - /* We only need to swap high and low halves. gen_qemu_ld64_i64 does - necessary 64-bit byteswap already. */ + /* + * We only need to swap high and low halves. gen_qemu_ld64_i64 + * does necessary 64-bit byteswap already. + */ if (unlikely(ctx->le_mode)) { gen_qemu_ld64_i64(ctx, t0, EA); set_fpr(rD(ctx->opcode) + 1, t0); @@ -966,7 +972,7 @@ static void gen_lfiwzx(DisasContext *ctx) } /*** Floating-point store ***/ #define GEN_STF(name, stop, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv EA; \ TCGv_i64 t0; \ @@ -985,7 +991,7 @@ static void glue(gen_, name)(DisasContext *ctx) } #define GEN_STUF(name, stop, opc, type) \ -static void glue(gen_, name##u)(DisasContext *ctx) \ +static void glue(gen_, name##u)(DisasContext *ctx) \ { \ TCGv EA; \ TCGv_i64 t0; \ @@ -1009,7 +1015,7 @@ static void glue(gen_, name##u)(DisasContext *ctx) } #define GEN_STUXF(name, stop, opc, type) \ -static void glue(gen_, name##ux)(DisasContext *ctx) \ +static void glue(gen_, name##ux)(DisasContext *ctx) \ { \ TCGv EA; \ TCGv_i64 t0; \ @@ -1033,7 +1039,7 @@ static void glue(gen_, name##ux)(DisasContext *ctx) } #define GEN_STXF(name, stop, opc2, opc3, type) \ -static void glue(gen_, name##x)(DisasContext *ctx) \ +static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ TCGv_i64 t0; \ @@ -1103,8 +1109,10 @@ static void gen_stfdp(DisasContext *ctx) EA = tcg_temp_new(); t0 = tcg_temp_new_i64(); gen_addr_imm_index(ctx, EA, 0); - /* We only need to swap high and low halves. gen_qemu_st64_i64 does - necessary 64-bit byteswap already. */ + /* + * We only need to swap high and low halves. gen_qemu_st64_i64 + * does necessary 64-bit byteswap already. + */ if (unlikely(ctx->le_mode)) { get_fpr(t0, rD(ctx->opcode) + 1); gen_qemu_st64_i64(ctx, t0, EA); @@ -1135,8 +1143,10 @@ static void gen_stfdpx(DisasContext *ctx) EA = tcg_temp_new(); t0 = tcg_temp_new_i64(); gen_addr_reg_index(ctx, EA); - /* We only need to swap high and low halves. gen_qemu_st64_i64 does - necessary 64-bit byteswap already. */ + /* + * We only need to swap high and low halves. gen_qemu_st64_i64 + * does necessary 64-bit byteswap already. + */ if (unlikely(ctx->le_mode)) { get_fpr(t0, rD(ctx->opcode) + 1); gen_qemu_st64_i64(ctx, t0, EA); @@ -1204,8 +1214,9 @@ static void gen_lfqu(DisasContext *ctx) gen_addr_add(ctx, t1, t0, 8); gen_qemu_ld64_i64(ctx, t2, t1); set_fpr((rd + 1) % 32, t2); - if (ra != 0) + if (ra != 0) { tcg_gen_mov_tl(cpu_gpr[ra], t0); + } tcg_temp_free(t0); tcg_temp_free(t1); tcg_temp_free_i64(t2); @@ -1229,8 +1240,9 @@ static void gen_lfqux(DisasContext *ctx) gen_qemu_ld64_i64(ctx, t2, t1); set_fpr((rd + 1) % 32, t2); tcg_temp_free(t1); - if (ra != 0) + if (ra != 0) { tcg_gen_mov_tl(cpu_gpr[ra], t0); + } tcg_temp_free(t0); tcg_temp_free_i64(t2); } diff --git a/target/ppc/translate/spe-impl.inc.c b/target/ppc/translate/spe-impl.inc.c index 8c1c16c63e..7ab0a29b5f 100644 --- a/target/ppc/translate/spe-impl.inc.c +++ b/target/ppc/translate/spe-impl.inc.c @@ -18,7 +18,8 @@ static inline void gen_evmra(DisasContext *ctx) TCGv_i64 tmp = tcg_temp_new_i64(); /* tmp := rA_lo + rA_hi << 32 */ - tcg_gen_concat_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); + tcg_gen_concat_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)], + cpu_gprh[rA(ctx->opcode)]); /* spe_acc := tmp */ tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); @@ -780,7 +781,7 @@ static inline void gen_op_evstwwo(DisasContext *ctx, TCGv addr) } #define GEN_SPEOP_LDST(name, opc2, sh) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv t0; \ if (unlikely(!ctx->spe_enabled)) { \ @@ -1089,7 +1090,8 @@ static inline void gen_efsabs(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } - tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL); + tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + (target_long)~0x80000000LL); } static inline void gen_efsnabs(DisasContext *ctx) { @@ -1097,7 +1099,8 @@ static inline void gen_efsnabs(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } - tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); + tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + 0x80000000); } static inline void gen_efsneg(DisasContext *ctx) { @@ -1105,7 +1108,8 @@ static inline void gen_efsneg(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } - tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); + tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + 0x80000000); } /* Conversion */ diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c index eb10c533ca..bd3ff40e68 100644 --- a/target/ppc/translate/vmx-impl.inc.c +++ b/target/ppc/translate/vmx-impl.inc.c @@ -15,7 +15,7 @@ static inline TCGv_ptr gen_avr_ptr(int reg) } #define GEN_VR_LDX(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv EA; \ TCGv_i64 avr; \ @@ -28,8 +28,10 @@ static void glue(gen_, name)(DisasContext *ctx) EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ tcg_gen_andi_tl(EA, EA, ~0xf); \ - /* We only need to swap high and low halves. gen_qemu_ld64_i64 does \ - necessary 64-bit byteswap already. */ \ + /* \ + * We only need to swap high and low halves. gen_qemu_ld64_i64 \ + * does necessary 64-bit byteswap already. \ + */ \ if (ctx->le_mode) { \ gen_qemu_ld64_i64(ctx, avr, EA); \ set_avr64(rD(ctx->opcode), avr, false); \ @@ -61,8 +63,10 @@ static void gen_st##name(DisasContext *ctx) \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ tcg_gen_andi_tl(EA, EA, ~0xf); \ - /* We only need to swap high and low halves. gen_qemu_st64_i64 does \ - necessary 64-bit byteswap already. */ \ + /* \ + * We only need to swap high and low halves. gen_qemu_st64_i64 \ + * does necessary 64-bit byteswap already. \ + */ \ if (ctx->le_mode) { \ get_avr64(avr, rD(ctx->opcode), false); \ gen_qemu_st64_i64(ctx, avr, EA); \ @@ -296,7 +300,7 @@ GEN_VXFORM_V(vnand, MO_64, tcg_gen_gvec_nand, 2, 22); GEN_VXFORM_V(vorc, MO_64, tcg_gen_gvec_orc, 2, 21); #define GEN_VXFORM(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv_ptr ra, rb, rd; \ if (unlikely(!ctx->altivec_enabled)) { \ @@ -306,7 +310,7 @@ static void glue(gen_, name)(DisasContext *ctx) ra = gen_avr_ptr(rA(ctx->opcode)); \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name (rd, ra, rb); \ + gen_helper_##name(rd, ra, rb); \ tcg_temp_free_ptr(ra); \ tcg_temp_free_ptr(rb); \ tcg_temp_free_ptr(rd); \ @@ -758,7 +762,7 @@ GEN_VXFORM_DUPI(vspltish, tcg_gen_gvec_dup16i, 6, 13); GEN_VXFORM_DUPI(vspltisw, tcg_gen_gvec_dup32i, 6, 14); #define GEN_VXFORM_NOA(name, opc2, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv_ptr rb, rd; \ if (unlikely(!ctx->altivec_enabled)) { \ @@ -767,9 +771,9 @@ static void glue(gen_, name)(DisasContext *ctx) } \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name (rd, rb); \ + gen_helper_##name(rd, rb); \ tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ + tcg_temp_free_ptr(rd); \ } #define GEN_VXFORM_NOA_ENV(name, opc2, opc3) \ @@ -943,7 +947,7 @@ static void gen_vsldoi(DisasContext *ctx) rb = gen_avr_ptr(rB(ctx->opcode)); rd = gen_avr_ptr(rD(ctx->opcode)); sh = tcg_const_i32(VSH(ctx->opcode)); - gen_helper_vsldoi (rd, ra, rb, sh); + gen_helper_vsldoi(rd, ra, rb, sh); tcg_temp_free_ptr(ra); tcg_temp_free_ptr(rb); tcg_temp_free_ptr(rd); diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c index 508e9199c8..11d9b75d01 100644 --- a/target/ppc/translate/vsx-impl.inc.c +++ b/target/ppc/translate/vsx-impl.inc.c @@ -356,8 +356,8 @@ static void gen_##name(DisasContext *ctx) \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ + get_cpu_vsrh(t0, xS(ctx->opcode)); \ gen_qemu_##operation(ctx, t0, EA); \ - set_cpu_vsrh(xS(ctx->opcode), t0); \ tcg_temp_free(EA); \ tcg_temp_free_i64(t0); \ } @@ -751,7 +751,7 @@ static void gen_xxpermdi(DisasContext *ctx) #define SGN_MASK_SP 0x8000000080000000ull #define VSX_SCALAR_MOVE(name, op, sgn_mask) \ -static void glue(gen_, name)(DisasContext * ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv_i64 xb, sgm; \ if (unlikely(!ctx->vsx_enabled)) { \ @@ -848,7 +848,7 @@ VSX_SCALAR_MOVE_QP(xsnegqp, OP_NEG, SGN_MASK_DP) VSX_SCALAR_MOVE_QP(xscpsgnqp, OP_CPSGN, SGN_MASK_DP) #define VSX_VECTOR_MOVE(name, op, sgn_mask) \ -static void glue(gen_, name)(DisasContext * ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv_i64 xbh, xbl, sgm; \ if (unlikely(!ctx->vsx_enabled)) { \ @@ -910,7 +910,7 @@ VSX_VECTOR_MOVE(xvnegsp, OP_NEG, SGN_MASK_SP) VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP) #define GEN_VSX_HELPER_2(name, op1, op2, inval, type) \ -static void gen_##name(DisasContext * ctx) \ +static void gen_##name(DisasContext *ctx) \ { \ TCGv_i32 opc; \ if (unlikely(!ctx->vsx_enabled)) { \ @@ -923,7 +923,7 @@ static void gen_##name(DisasContext * ctx) \ } #define GEN_VSX_HELPER_XT_XB_ENV(name, op1, op2, inval, type) \ -static void gen_##name(DisasContext * ctx) \ +static void gen_##name(DisasContext *ctx) \ { \ TCGv_i64 t0; \ TCGv_i64 t1; \ @@ -1230,7 +1230,7 @@ static void gen_xxbrw(DisasContext *ctx) } #define VSX_LOGICAL(name, vece, tcg_op) \ -static void glue(gen_, name)(DisasContext * ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ if (unlikely(!ctx->vsx_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ @@ -1251,7 +1251,7 @@ VSX_LOGICAL(xxlnand, MO_64, tcg_gen_gvec_nand) VSX_LOGICAL(xxlorc, MO_64, tcg_gen_gvec_orc) #define VSX_XXMRG(name, high) \ -static void glue(gen_, name)(DisasContext * ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ TCGv_i64 a0, a1, b0, b1, tmp; \ if (unlikely(!ctx->vsx_enabled)) { \ @@ -1444,7 +1444,8 @@ static void gen_##name(DisasContext *ctx) \ xb = tcg_const_tl(xB(ctx->opcode)); \ t0 = tcg_temp_new_i32(); \ t1 = tcg_temp_new_i64(); \ - /* uimm > 15 out of bound and for \ + /* \ + * uimm > 15 out of bound and for \ * uimm > 12 handle as per hardware in helper \ */ \ if (uimm > 15) { \ diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index 0bd555eb19..0394a9ddad 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -18,7 +18,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "disas/bfd.h" +#include "disas/dis-asm.h" #include "exec/gdbstub.h" #include "kvm_ppc.h" #include "sysemu/arch_init.h" @@ -28,6 +28,7 @@ #include "mmu-hash32.h" #include "mmu-hash64.h" #include "qemu/error-report.h" +#include "qemu/qemu-print.h" #include "qapi/error.h" #include "qapi/qmp/qnull.h" #include "qapi/visitor.h" @@ -40,12 +41,13 @@ #include "fpu/softfloat.h" #include "qapi/qapi-commands-target.h" -//#define PPC_DUMP_CPU -//#define PPC_DEBUG_SPR -//#define PPC_DUMP_SPR_ACCESSES +/* #define PPC_DUMP_CPU */ +/* #define PPC_DEBUG_SPR */ +/* #define PPC_DUMP_SPR_ACCESSES */ /* #define USE_APPLE_GDB */ -/* Generic callbacks: +/* + * Generic callbacks: * do nothing but store/retrieve spr value */ static void spr_load_dump_spr(int sprn) @@ -57,7 +59,7 @@ static void spr_load_dump_spr(int sprn) #endif } -static void spr_read_generic (DisasContext *ctx, int gprn, int sprn) +static void spr_read_generic(DisasContext *ctx, int gprn, int sprn) { gen_load_spr(cpu_gpr[gprn], sprn); spr_load_dump_spr(sprn); @@ -229,13 +231,13 @@ static void spr_read_tbu(DisasContext *ctx, int gprn, int sprn) } } -__attribute__ (( unused )) +ATTRIBUTE_UNUSED static void spr_read_atbl(DisasContext *ctx, int gprn, int sprn) { gen_helper_load_atbl(cpu_gpr[gprn], cpu_env); } -__attribute__ (( unused )) +ATTRIBUTE_UNUSED static void spr_read_atbu(DisasContext *ctx, int gprn, int sprn) { gen_helper_load_atbu(cpu_gpr[gprn], cpu_env); @@ -266,20 +268,20 @@ static void spr_write_tbu(DisasContext *ctx, int sprn, int gprn) } } -__attribute__ (( unused )) +ATTRIBUTE_UNUSED static void spr_write_atbl(DisasContext *ctx, int sprn, int gprn) { gen_helper_store_atbl(cpu_env, cpu_gpr[gprn]); } -__attribute__ (( unused )) +ATTRIBUTE_UNUSED static void spr_write_atbu(DisasContext *ctx, int sprn, int gprn) { gen_helper_store_atbu(cpu_env, cpu_gpr[gprn]); } #if defined(TARGET_PPC64) -__attribute__ (( unused )) +ATTRIBUTE_UNUSED static void spr_read_purr(DisasContext *ctx, int gprn, int sprn) { gen_helper_load_purr(cpu_gpr[gprn], cpu_env); @@ -318,12 +320,16 @@ static void spr_write_hdecr(DisasContext *ctx, int sprn, int gprn) /* IBAT0L...IBAT7L */ static void spr_read_ibat(DisasContext *ctx, int gprn, int sprn) { - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2])); + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, + IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2])); } static void spr_read_ibat_h(DisasContext *ctx, int gprn, int sprn) { - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, IBAT[sprn & 1][((sprn - SPR_IBAT4U) / 2) + 4])); + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, + IBAT[sprn & 1][((sprn - SPR_IBAT4U) / 2) + 4])); } static void spr_write_ibatu(DisasContext *ctx, int sprn, int gprn) @@ -358,12 +364,16 @@ static void spr_write_ibatl_h(DisasContext *ctx, int sprn, int gprn) /* DBAT0L...DBAT7L */ static void spr_read_dbat(DisasContext *ctx, int gprn, int sprn) { - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, DBAT[sprn & 1][(sprn - SPR_DBAT0U) / 2])); + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, + DBAT[sprn & 1][(sprn - SPR_DBAT0U) / 2])); } static void spr_read_dbat_h(DisasContext *ctx, int gprn, int sprn) { - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, DBAT[sprn & 1][((sprn - SPR_DBAT4U) / 2) + 4])); + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, + DBAT[sprn & 1][((sprn - SPR_DBAT4U) / 2) + 4])); } static void spr_write_dbatu(DisasContext *ctx, int sprn, int gprn) @@ -472,7 +482,9 @@ static void spr_write_hid0_601(DisasContext *ctx, int sprn, int gprn) #if !defined(CONFIG_USER_ONLY) static void spr_read_601_ubat(DisasContext *ctx, int gprn, int sprn) { - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2])); + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, + IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2])); } static void spr_write_601_ubatu(DisasContext *ctx, int sprn, int gprn) @@ -531,7 +543,8 @@ static void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn) #if !defined(CONFIG_USER_ONLY) static void spr_read_403_pbr(DisasContext *ctx, int gprn, int sprn) { - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, pb[sprn - SPR_403_PBL1])); + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, pb[sprn - SPR_403_PBL1])); } static void spr_write_403_pbr(DisasContext *ctx, int sprn, int gprn) @@ -660,14 +673,20 @@ static inline void vscr_init(CPUPPCState *env, uint32_t val) static inline void _spr_register(CPUPPCState *env, int num, const char *name, - void (*uea_read)(DisasContext *ctx, int gprn, int sprn), - void (*uea_write)(DisasContext *ctx, int sprn, int gprn), + void (*uea_read)(DisasContext *ctx, + int gprn, int sprn), + void (*uea_write)(DisasContext *ctx, + int sprn, int gprn), #if !defined(CONFIG_USER_ONLY) - void (*oea_read)(DisasContext *ctx, int gprn, int sprn), - void (*oea_write)(DisasContext *ctx, int sprn, int gprn), - void (*hea_read)(DisasContext *opaque, int gprn, int sprn), - void (*hea_write)(DisasContext *opaque, int sprn, int gprn), + void (*oea_read)(DisasContext *ctx, + int gprn, int sprn), + void (*oea_write)(DisasContext *ctx, + int sprn, int gprn), + void (*hea_read)(DisasContext *opaque, + int gprn, int sprn), + void (*hea_write)(DisasContext *opaque, + int sprn, int gprn), #endif #if defined(CONFIG_KVM) uint64_t one_reg_id, @@ -677,7 +696,7 @@ static inline void _spr_register(CPUPPCState *env, int num, ppc_spr_t *spr; spr = &env->spr_cb[num]; - if (spr->name != NULL ||env-> spr[num] != 0x00000000 || + if (spr->name != NULL || env->spr[num] != 0x00000000 || #if !defined(CONFIG_USER_ONLY) spr->oea_read != NULL || spr->oea_write != NULL || #endif @@ -773,8 +792,10 @@ static void gen_spr_sdr1(CPUPPCState *env) { #ifndef CONFIG_USER_ONLY if (env->has_hv_mode) { - /* SDR1 is a hypervisor resource on CPUs which have a - * hypervisor mode */ + /* + * SDR1 is a hypervisor resource on CPUs which have a + * hypervisor mode + */ spr_register_hv(env, SPR_SDR1, "SDR1", SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, @@ -1122,7 +1143,8 @@ static void spr_write_amr(DisasContext *ctx, int sprn, int gprn) TCGv t1 = tcg_temp_new(); TCGv t2 = tcg_temp_new(); - /* Note, the HV=1 PR=0 case is handled earlier by simply using + /* + * Note, the HV=1 PR=0 case is handled earlier by simply using * spr_write_generic for HV mode in the SPR table */ @@ -1156,7 +1178,8 @@ static void spr_write_uamor(DisasContext *ctx, int sprn, int gprn) TCGv t1 = tcg_temp_new(); TCGv t2 = tcg_temp_new(); - /* Note, the HV=1 case is handled earlier by simply using + /* + * Note, the HV=1 case is handled earlier by simply using * spr_write_generic for HV mode in the SPR table */ @@ -1186,7 +1209,8 @@ static void spr_write_iamr(DisasContext *ctx, int sprn, int gprn) TCGv t1 = tcg_temp_new(); TCGv t2 = tcg_temp_new(); - /* Note, the HV=1 case is handled earlier by simply using + /* + * Note, the HV=1 case is handled earlier by simply using * spr_write_generic for HV mode in the SPR table */ @@ -1214,10 +1238,13 @@ static void spr_write_iamr(DisasContext *ctx, int sprn, int gprn) static void gen_spr_amr(CPUPPCState *env) { #ifndef CONFIG_USER_ONLY - /* Virtual Page Class Key protection */ - /* The AMR is accessible either via SPR 13 or SPR 29. 13 is + /* + * Virtual Page Class Key protection + * + * The AMR is accessible either via SPR 13 or SPR 29. 13 is * userspace accessible, 29 is privileged. So we only need to set - * the kvm ONE_REG id on one of them, we use 29 */ + * the kvm ONE_REG id on one of them, we use 29 + */ spr_register(env, SPR_UAMR, "UAMR", &spr_read_generic, &spr_write_amr, &spr_read_generic, &spr_write_amr, @@ -1901,7 +1928,8 @@ static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask, /* TLB assist registers */ /* XXX : not implemented */ for (i = 0; i < 8; i++) { - void (*uea_write)(DisasContext *ctx, int sprn, int gprn) = &spr_write_generic32; + void (*uea_write)(DisasContext *ctx, int sprn, int gprn) = + &spr_write_generic32; if (i == 2 && (mas_mask & (1 << i)) && (env->insns_flags & PPC_64B)) { uea_write = &spr_write_generic; } @@ -2797,7 +2825,6 @@ static void gen_spr_8xx(CPUPPCState *env) 0x00000000); } -// XXX: TODO /* * AMR => SPR 29 (Power 2.04) * CTRL => SPR 136 (Power 2.04) @@ -3343,16 +3370,18 @@ static int check_pow_nocheck(CPUPPCState *env) static int check_pow_hid0(CPUPPCState *env) { - if (env->spr[SPR_HID0] & 0x00E00000) + if (env->spr[SPR_HID0] & 0x00E00000) { return 1; + } return 0; } static int check_pow_hid0_74xx(CPUPPCState *env) { - if (env->spr[SPR_HID0] & 0x00600000) + if (env->spr[SPR_HID0] & 0x00600000) { return 1; + } return 0; } @@ -4601,7 +4630,8 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data) dc->desc = "e200 core"; pcc->init_proc = init_proc_e200; pcc->check_pow = check_pow_hid0; - /* XXX: unimplemented instructions: + /* + * XXX: unimplemented instructions: * dcblc * dcbtlst * dcbtstls @@ -4796,18 +4826,18 @@ static void init_proc_e500(CPUPPCState *env, int version) * gen_spr_BookE(env, 0x0000000F0000FD7FULL); */ switch (version) { - case fsl_e500v1: - case fsl_e500v2: - default: - ivor_mask = 0x0000000F0000FFFFULL; - break; - case fsl_e500mc: - case fsl_e5500: - ivor_mask = 0x000003FE0000FFFFULL; - break; - case fsl_e6500: - ivor_mask = 0x000003FF0000FFFFULL; - break; + case fsl_e500v1: + case fsl_e500v2: + default: + ivor_mask = 0x0000000F0000FFFFULL; + break; + case fsl_e500mc: + case fsl_e5500: + ivor_mask = 0x000003FE0000FFFFULL; + break; + case fsl_e6500: + ivor_mask = 0x000003FF0000FFFFULL; + break; } gen_spr_BookE(env, ivor_mask); gen_spr_usprg3(env); @@ -4847,7 +4877,8 @@ static void init_proc_e500(CPUPPCState *env, int version) tlbncfg[1] = 0x40028040; break; default: - cpu_abort(CPU(cpu), "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]); + cpu_abort(CPU(cpu), "Unknown CPU: " TARGET_FMT_lx "\n", + env->spr[SPR_PVR]); } #endif /* Cache sizes */ @@ -4871,7 +4902,8 @@ static void init_proc_e500(CPUPPCState *env, int version) l1cfg1 |= 0x0B83820; break; default: - cpu_abort(CPU(cpu), "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]); + cpu_abort(CPU(cpu), "Unknown CPU: " TARGET_FMT_lx "\n", + env->spr[SPR_PVR]); } gen_spr_BookE206(env, 0x000000DF, tlbncfg, mmucfg); /* XXX : not implemented */ @@ -5251,7 +5283,8 @@ static void init_proc_601(CPUPPCState *env) 0x00000000); /* Memory management */ init_excp_601(env); - /* XXX: beware that dcache line size is 64 + /* + * XXX: beware that dcache line size is 64 * but dcbz uses 32 bytes "sectors" * XXX: this breaks clcs instruction ! */ @@ -5788,7 +5821,8 @@ static void init_proc_750(CPUPPCState *env) 0x00000000); /* Memory management */ gen_low_BATs(env); - /* XXX: high BATs are also present but are known to be bugged on + /* + * XXX: high BATs are also present but are known to be bugged on * die version 1.x */ init_excp_7x0(env); @@ -5970,7 +6004,8 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) dc->desc = "PowerPC 750 CL"; pcc->init_proc = init_proc_750cl; pcc->check_pow = check_pow_hid0; - /* XXX: not implemented: + /* + * XXX: not implemented: * cache lock instructions: * dcbz_l * floating point paired instructions @@ -7568,8 +7603,10 @@ static void gen_spr_book3s_altivec(CPUPPCState *env) &spr_read_generic, &spr_write_generic, KVM_REG_PPC_VRSAVE, 0x00000000); - /* Can't find information on what this should be on reset. This - * value is the one used by 74xx processors. */ + /* + * Can't find information on what this should be on reset. This + * value is the one used by 74xx processors. + */ vscr_init(env, 0x00010000); } @@ -8974,8 +9011,9 @@ static void init_ppc_proc(PowerPCCPU *cpu) env->irq_inputs = NULL; /* Set all exception vectors to an invalid address */ - for (i = 0; i < POWERPC_EXCP_NB; i++) + for (i = 0; i < POWERPC_EXCP_NB; i++) { env->excp_vectors[i] = (target_ulong)(-1ULL); + } env->ivor_mask = 0x00000000; env->ivpr_mask = 0x00000000; /* Default MMU definitions */ @@ -9107,8 +9145,9 @@ static void init_ppc_proc(PowerPCCPU *cpu) #if !defined(CONFIG_USER_ONLY) if (env->nb_tlb != 0) { int nb_tlb = env->nb_tlb; - if (env->id_tlbs != 0) + if (env->id_tlbs != 0) { nb_tlb *= 2; + } switch (env->tlb_type) { case TLB_6XX: env->tlb.tlb6 = g_new0(ppc6xx_tlb_t, nb_tlb); @@ -9200,8 +9239,9 @@ static void fill_new_table(opc_handler_t **table, int len) { int i; - for (i = 0; i < len; i++) + for (i = 0; i < len; i++) { table[i] = &invalid_handler; + } } static int create_new_table(opc_handler_t **table, unsigned char idx) @@ -9218,8 +9258,9 @@ static int create_new_table(opc_handler_t **table, unsigned char idx) static int insert_in_table(opc_handler_t **table, unsigned char idx, opc_handler_t *handler) { - if (table[idx] != &invalid_handler) + if (table[idx] != &invalid_handler) { return -1; + } table[idx] = handler; return 0; @@ -9340,17 +9381,20 @@ static int register_insn(opc_handler_t **ppc_opcodes, opcode_t *insn) } } else { if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2, - insn->opc3, &insn->handler) < 0) + insn->opc3, &insn->handler) < 0) { return -1; + } } } else { if (register_ind_insn(ppc_opcodes, insn->opc1, - insn->opc2, &insn->handler) < 0) + insn->opc2, &insn->handler) < 0) { return -1; + } } } else { - if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) + if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) { return -1; + } } return 0; @@ -9362,8 +9406,9 @@ static int test_opcode_table(opc_handler_t **table, int len) for (i = 0, count = 0; i < len; i++) { /* Consistency fixup */ - if (table[i] == NULL) + if (table[i] == NULL) { table[i] = &invalid_handler; + } if (table[i] != &invalid_handler) { if (is_indirect_opcode(table[i])) { tmp = test_opcode_table(ind_table(table[i]), @@ -9385,8 +9430,9 @@ static int test_opcode_table(opc_handler_t **table, int len) static void fix_opcode_tables(opc_handler_t **ppc_opcodes) { - if (test_opcode_table(ppc_opcodes, PPC_CPU_OPCODES_LEN) == 0) + if (test_opcode_table(ppc_opcodes, PPC_CPU_OPCODES_LEN) == 0) { printf("*** WARNING: no opcode defined !\n"); + } } /*****************************************************************************/ @@ -9725,14 +9771,15 @@ static int ppc_fixup_cpu(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; - /* TCG doesn't (yet) emulate some groups of instructions that - * are implemented on some otherwise supported CPUs (e.g. VSX - * and decimal floating point instructions on POWER7). We - * remove unsupported instruction groups from the cpu state's - * instruction masks and hope the guest can cope. For at - * least the pseries machine, the unavailability of these - * instructions can be advertised to the guest via the device - * tree. */ + /* + * TCG doesn't (yet) emulate some groups of instructions that are + * implemented on some otherwise supported CPUs (e.g. VSX and + * decimal floating point instructions on POWER7). We remove + * unsupported instruction groups from the cpu state's instruction + * masks and hope the guest can cope. For at least the pseries + * machine, the unavailability of these instructions can be + * advertised to the guest via the device tree. + */ if ((env->insns_flags & ~PPC_TCG_INSNS) || (env->insns_flags2 & ~PPC_TCG_INSNS2)) { warn_report("Disabling some instructions which are not " @@ -9927,31 +9974,37 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp) " Bus model : %s\n", excp_model, bus_model); printf(" MSR features :\n"); - if (env->flags & POWERPC_FLAG_SPE) + if (env->flags & POWERPC_FLAG_SPE) { printf(" signal processing engine enable" "\n"); - else if (env->flags & POWERPC_FLAG_VRE) + } else if (env->flags & POWERPC_FLAG_VRE) { printf(" vector processor enable\n"); - if (env->flags & POWERPC_FLAG_TGPR) + } + if (env->flags & POWERPC_FLAG_TGPR) { printf(" temporary GPRs\n"); - else if (env->flags & POWERPC_FLAG_CE) + } else if (env->flags & POWERPC_FLAG_CE) { printf(" critical input enable\n"); - if (env->flags & POWERPC_FLAG_SE) + } + if (env->flags & POWERPC_FLAG_SE) { printf(" single-step trace mode\n"); - else if (env->flags & POWERPC_FLAG_DWE) + } else if (env->flags & POWERPC_FLAG_DWE) { printf(" debug wait enable\n"); - else if (env->flags & POWERPC_FLAG_UBLE) + } else if (env->flags & POWERPC_FLAG_UBLE) { printf(" user BTB lock enable\n"); - if (env->flags & POWERPC_FLAG_BE) + } + if (env->flags & POWERPC_FLAG_BE) { printf(" branch-step trace mode\n"); - else if (env->flags & POWERPC_FLAG_DE) + } else if (env->flags & POWERPC_FLAG_DE) { printf(" debug interrupt enable\n"); - if (env->flags & POWERPC_FLAG_PX) + } + if (env->flags & POWERPC_FLAG_PX) { printf(" inclusive protection\n"); - else if (env->flags & POWERPC_FLAG_PMM) + } else if (env->flags & POWERPC_FLAG_PMM) { printf(" performance monitor mark\n"); - if (env->flags == POWERPC_FLAG_NONE) + } + if (env->flags == POWERPC_FLAG_NONE) { printf(" none\n"); + } printf(" Time-base/decrementer clock source: %s\n", env->flags & POWERPC_FLAG_RTC_CLK ? "RTC clock" : "bus clock"); dump_ppc_insns(env); @@ -10093,8 +10146,9 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name) const char *p; unsigned long pvr; - /* Lookup by PVR if cpu_model is valid 8 digit hex number - * (excl: 0x prefix if present) + /* + * Lookup by PVR if cpu_model is valid 8 digit hex number (excl: + * 0x prefix if present) */ if (!qemu_strtoul(name, &p, 16, &pvr)) { int len = p - name; @@ -10215,7 +10269,6 @@ static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b) static void ppc_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - CPUListState *s = user_data; PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); DeviceClass *family = DEVICE_CLASS(ppc_cpu_get_family_class(pcc)); const char *typename = object_class_get_name(oc); @@ -10228,8 +10281,7 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) name = g_strndup(typename, strlen(typename) - strlen(POWERPC_CPU_TYPE_SUFFIX)); - (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", - name, pcc->pvr); + qemu_printf("PowerPC %-16s PVR %08x\n", name, pcc->pvr); for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) { PowerPCCPUAlias *alias = &ppc_cpu_aliases[i]; ObjectClass *alias_oc = ppc_cpu_class_by_name(alias->model); @@ -10242,33 +10294,28 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) * avoid printing the wrong alias here and use "preferred" instead */ if (strcmp(alias->alias, family->desc) == 0) { - (*s->cpu_fprintf)(s->file, - "PowerPC %-16s (alias for preferred %s CPU)\n", - alias->alias, family->desc); + qemu_printf("PowerPC %-16s (alias for preferred %s CPU)\n", + alias->alias, family->desc); } else { - (*s->cpu_fprintf)(s->file, "PowerPC %-16s (alias for %s)\n", - alias->alias, name); + qemu_printf("PowerPC %-16s (alias for %s)\n", + alias->alias, name); } } g_free(name); } -void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void ppc_cpu_list(void) { - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; GSList *list; list = object_class_get_list(TYPE_POWERPC_CPU, false); list = g_slist_sort(list, ppc_cpu_list_compare); - g_slist_foreach(list, ppc_cpu_list_entry, &s); + g_slist_foreach(list, ppc_cpu_list_entry, NULL); g_slist_free(list); #ifdef CONFIG_KVM - cpu_fprintf(f, "\n"); - cpu_fprintf(f, "PowerPC %-16s\n", "host"); + qemu_printf("\n"); + qemu_printf("PowerPC %-16s\n", "host"); #endif } @@ -10445,14 +10492,14 @@ static void ppc_cpu_instance_init(Object *obj) env->bfd_mach = pcc->bfd_mach; env->check_pow = pcc->check_pow; - /* Mark HV mode as supported if the CPU has an MSR_HV bit - * in the msr_mask. The mask can later be cleared by PAPR - * mode but the hv mode support will remain, thus enforcing - * that we cannot use priv. instructions in guest in PAPR - * mode. For 970 we currently simply don't set HV in msr_mask - * thus simulating an "Apple mode" 970. If we ever want to - * support 970 HV mode, we'll have to add a processor attribute - * of some sort. + /* + * Mark HV mode as supported if the CPU has an MSR_HV bit in the + * msr_mask. The mask can later be cleared by PAPR mode but the hv + * mode support will remain, thus enforcing that we cannot use + * priv. instructions in guest in PAPR mode. For 970 we currently + * simply don't set HV in msr_mask thus simulating an "Apple mode" + * 970. If we ever want to support 970 HV mode, we'll have to add + * a processor attribute of some sort. */ #if !defined(CONFIG_USER_ONLY) env->has_hv_mode = !!(env->msr_mask & MSR_HVB); @@ -10579,7 +10626,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) cc->tcg_initialize = ppc_translate_init; #endif cc->disas_set_info = ppc_disas_set_info; - + dc->fw_name = "PowerPC,UNKNOWN"; } diff --git a/target/riscv/Makefile.objs b/target/riscv/Makefile.objs index 4072abe3e4..9c6c109327 100644 --- a/target/riscv/Makefile.objs +++ b/target/riscv/Makefile.objs @@ -1 +1,20 @@ obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o pmp.o + +DECODETREE = $(SRC_PATH)/scripts/decodetree.py + +decode32-y = $(SRC_PATH)/target/riscv/insn32.decode +decode32-$(TARGET_RISCV64) += $(SRC_PATH)/target/riscv/insn32-64.decode + +target/riscv/decode_insn32.inc.c: $(decode32-y) $(DECODETREE) + $(call quiet-command, \ + $(PYTHON) $(DECODETREE) -o $@ --decode decode_insn32 $(decode32-y), \ + "GEN", $(TARGET_DIR)$@) + +target/riscv/decode_insn16.inc.c: \ + $(SRC_PATH)/target/riscv/insn16.decode $(DECODETREE) + $(call quiet-command, \ + $(PYTHON) $(DECODETREE) -o $@ --decode decode_insn16 --insnwidth 16 $<, \ + "GEN", $(TARGET_DIR)$@) + +target/riscv/translate.o: target/riscv/decode_insn32.inc.c \ + target/riscv/decode_insn16.inc.c diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cc3ddc0ae4..1bcf4eaeb8 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/qemu-print.h" #include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" @@ -80,12 +81,6 @@ const char * const riscv_intr_names[] = { "reserved" }; -typedef struct RISCVCPUInfo { - const int bit_widths; - const char *name; - void (*initfn)(Object *obj); -} RISCVCPUInfo; - static void set_misa(CPURISCVState *env, target_ulong misa) { env->misa_mask = env->misa = misa; @@ -199,40 +194,39 @@ static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) return oc; } -static void riscv_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags) +static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; int i; - cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", env->pc); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", env->pc); #ifndef CONFIG_USER_ONLY - cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid); - cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus); - cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", - (target_ulong)atomic_read(&env->mip)); - cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); - cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); - cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); - cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec ", env->mtvec); - cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc ", env->mepc); - cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause ", env->mcause); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", + (target_ulong)atomic_read(&env->mip)); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec ", env->mtvec); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc ", env->mepc); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause ", env->mcause); #endif for (i = 0; i < 32; i++) { - cpu_fprintf(f, " %s " TARGET_FMT_lx, - riscv_int_regnames[i], env->gpr[i]); + qemu_fprintf(f, " %s " TARGET_FMT_lx, + riscv_int_regnames[i], env->gpr[i]); if ((i & 3) == 3) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } if (flags & CPU_DUMP_FPU) { for (i = 0; i < 32; i++) { - cpu_fprintf(f, " %s %016" PRIx64, - riscv_fpr_regnames[i], env->fpr[i]); + qemu_fprintf(f, " %s %016" PRIx64, + riscv_fpr_regnames[i], env->fpr[i]); if ((i & 3) == 3) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } } @@ -311,6 +305,8 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) return; } + riscv_cpu_register_gdb_regs_for_features(cs); + qemu_init_vcpu(cs); cpu_reset(cs); @@ -351,7 +347,12 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb; cc->gdb_read_register = riscv_cpu_gdb_read_register; cc->gdb_write_register = riscv_cpu_gdb_write_register; - cc->gdb_num_core_regs = 65; + cc->gdb_num_core_regs = 33; +#if defined(TARGET_RISCV32) + cc->gdb_core_xml_file = "riscv-32bit-cpu.xml"; +#elif defined(TARGET_RISCV64) + cc->gdb_core_xml_file = "riscv-64bit-cpu.xml"; +#endif cc->gdb_stop_before_watchpoint = true; cc->disas_set_info = riscv_cpu_disas_set_info; #ifdef CONFIG_USER_ONLY @@ -382,11 +383,6 @@ char *riscv_isa_string(RISCVCPU *cpu) return isa_str; } -typedef struct RISCVCPUListState { - fprintf_function cpu_fprintf; - FILE *file; -} RISCVCPUListState; - static gint riscv_cpu_list_compare(gconstpointer a, gconstpointer b) { ObjectClass *class_a = (ObjectClass *)a; @@ -400,24 +396,19 @@ static gint riscv_cpu_list_compare(gconstpointer a, gconstpointer b) static void riscv_cpu_list_entry(gpointer data, gpointer user_data) { - RISCVCPUListState *s = user_data; const char *typename = object_class_get_name(OBJECT_CLASS(data)); int len = strlen(typename) - strlen(RISCV_CPU_TYPE_SUFFIX); - (*s->cpu_fprintf)(s->file, "%.*s\n", len, typename); + qemu_printf("%.*s\n", len, typename); } -void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void riscv_cpu_list(void) { - RISCVCPUListState s = { - .cpu_fprintf = cpu_fprintf, - .file = f, - }; GSList *list; list = object_class_get_list(TYPE_RISCV_CPU, false); list = g_slist_sort(list, riscv_cpu_list_compare); - g_slist_foreach(list, riscv_cpu_list_entry, &s); + g_slist_foreach(list, riscv_cpu_list_entry, NULL); g_slist_free(list); } diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 5c2aebf132..7d9f48973f 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -123,6 +123,10 @@ struct CPURISCVState { uint32_t features; +#ifdef CONFIG_USER_ONLY + uint32_t elf_flags; +#endif + #ifndef CONFIG_USER_ONLY target_ulong priv; target_ulong resetvec; @@ -140,6 +144,7 @@ struct CPURISCVState { * mip is 32-bits to allow atomic_read on 32-bit hosts. */ uint32_t mip; + uint32_t miclaim; target_ulong mie; target_ulong mideleg; @@ -172,6 +177,9 @@ struct CPURISCVState { /* physical memory protection */ pmp_table_t pmp_state; + + /* True if in debugger mode. */ + bool debugger; #endif float_status fp_status; @@ -256,13 +264,14 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, int riscv_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, int rw, int mmu_idx); char *riscv_isa_string(RISCVCPU *cpu); -void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void riscv_cpu_list(void); #define cpu_signal_handler riscv_cpu_signal_handler #define cpu_list riscv_cpu_list #define cpu_mmu_index riscv_cpu_mmu_index #ifndef CONFIG_USER_ONLY +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts); uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value); #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */ #endif @@ -293,6 +302,8 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask); +int riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask); static inline void riscv_csr_write(CPURISCVState *env, int csrno, target_ulong val) @@ -325,6 +336,8 @@ typedef struct { void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops); void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops); +void riscv_cpu_register_gdb_regs_for_features(CPUState *cs); + #include "exec/cpu-all.h" #endif /* RISCV_CPU_H */ diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 7afcb2468d..7180fccf54 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -135,16 +135,22 @@ /* Legacy Counter Setup (priv v1.9.1) */ #define CSR_MUCOUNTEREN 0x320 #define CSR_MSCOUNTEREN 0x321 +#define CSR_MHCOUNTEREN 0x322 /* Machine Trap Handling */ #define CSR_MSCRATCH 0x340 #define CSR_MEPC 0x341 #define CSR_MCAUSE 0x342 -#define CSR_MBADADDR 0x343 +#define CSR_MTVAL 0x343 #define CSR_MIP 0x344 +/* Legacy Machine Trap Handling (priv v1.9.1) */ +#define CSR_MBADADDR 0x343 + /* Supervisor Trap Setup */ #define CSR_SSTATUS 0x100 +#define CSR_SEDELEG 0x102 +#define CSR_SIDELEG 0x103 #define CSR_SIE 0x104 #define CSR_STVEC 0x105 #define CSR_SCOUNTEREN 0x106 @@ -153,9 +159,12 @@ #define CSR_SSCRATCH 0x140 #define CSR_SEPC 0x141 #define CSR_SCAUSE 0x142 -#define CSR_SBADADDR 0x143 +#define CSR_STVAL 0x143 #define CSR_SIP 0x144 +/* Legacy Supervisor Trap Handling (priv v1.9.1) */ +#define CSR_SBADADDR 0x143 + /* Supervisor Protection and Translation */ #define CSR_SPTBR 0x180 #define CSR_SATP 0x180 @@ -282,6 +291,28 @@ #define CSR_MHPMCOUNTER30H 0xb9e #define CSR_MHPMCOUNTER31H 0xb9f +/* Legacy Hypervisor Trap Setup (priv v1.9.1) */ +#define CSR_HSTATUS 0x200 +#define CSR_HEDELEG 0x202 +#define CSR_HIDELEG 0x203 +#define CSR_HIE 0x204 +#define CSR_HTVEC 0x205 + +/* Legacy Hypervisor Trap Handling (priv v1.9.1) */ +#define CSR_HSCRATCH 0x240 +#define CSR_HEPC 0x241 +#define CSR_HCAUSE 0x242 +#define CSR_HBADADDR 0x243 +#define CSR_HIP 0x244 + +/* Legacy Machine Protection and Translation (priv v1.9.1) */ +#define CSR_MBASE 0x380 +#define CSR_MBOUND 0x381 +#define CSR_MIBASE 0x382 +#define CSR_MIBOUND 0x383 +#define CSR_MDBASE 0x384 +#define CSR_MDBOUND 0x385 + /* mstatus CSR bits */ #define MSTATUS_UIE 0x00000001 #define MSTATUS_SIE 0x00000002 diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index f49e98ed59..b17f169681 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -22,8 +22,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "tcg-op.h" - -#define RISCV_DEBUG_INTERRUPT 0 +#include "trace.h" int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) { @@ -72,6 +71,17 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request) #if !defined(CONFIG_USER_ONLY) +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) +{ + CPURISCVState *env = &cpu->env; + if (env->miclaim & interrupts) { + return -1; + } else { + env->miclaim |= interrupts; + return 0; + } +} + /* iothread_mutex must be held */ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) { @@ -84,9 +94,9 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) cmp = atomic_cmpxchg(&env->mip, old, new); } while (old != cmp); - if (new && !old) { + if (new) { cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); - } else if (!new && old) { + } else { cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); } @@ -443,121 +453,85 @@ void riscv_cpu_do_interrupt(CPUState *cs) RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - if (RISCV_DEBUG_INTERRUPT) { - int log_cause = cs->exception_index & RISCV_EXCP_INT_MASK; - if (cs->exception_index & RISCV_EXCP_INT_FLAG) { - qemu_log_mask(LOG_TRACE, "core " - TARGET_FMT_ld ": trap %s, epc 0x" TARGET_FMT_lx "\n", - env->mhartid, riscv_intr_names[log_cause], env->pc); - } else { - qemu_log_mask(LOG_TRACE, "core " - TARGET_FMT_ld ": intr %s, epc 0x" TARGET_FMT_lx "\n", - env->mhartid, riscv_excp_names[log_cause], env->pc); + /* cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide + * so we mask off the MSB and separate into trap type and cause. + */ + bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG); + target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK; + target_ulong deleg = async ? env->mideleg : env->medeleg; + target_ulong tval = 0; + + static const int ecall_cause_map[] = { + [PRV_U] = RISCV_EXCP_U_ECALL, + [PRV_S] = RISCV_EXCP_S_ECALL, + [PRV_H] = RISCV_EXCP_H_ECALL, + [PRV_M] = RISCV_EXCP_M_ECALL + }; + + if (!async) { + /* set tval to badaddr for traps with address information */ + switch (cause) { + case RISCV_EXCP_INST_ADDR_MIS: + case RISCV_EXCP_INST_ACCESS_FAULT: + case RISCV_EXCP_LOAD_ADDR_MIS: + case RISCV_EXCP_STORE_AMO_ADDR_MIS: + case RISCV_EXCP_LOAD_ACCESS_FAULT: + case RISCV_EXCP_STORE_AMO_ACCESS_FAULT: + case RISCV_EXCP_INST_PAGE_FAULT: + case RISCV_EXCP_LOAD_PAGE_FAULT: + case RISCV_EXCP_STORE_PAGE_FAULT: + tval = env->badaddr; + break; + default: + break; } - } - - target_ulong fixed_cause = 0; - if (cs->exception_index & (RISCV_EXCP_INT_FLAG)) { - /* hacky for now. the MSB (bit 63) indicates interrupt but cs->exception - index is only 32 bits wide */ - fixed_cause = cs->exception_index & RISCV_EXCP_INT_MASK; - fixed_cause |= ((target_ulong)1) << (TARGET_LONG_BITS - 1); - } else { - /* fixup User ECALL -> correct priv ECALL */ - if (cs->exception_index == RISCV_EXCP_U_ECALL) { - switch (env->priv) { - case PRV_U: - fixed_cause = RISCV_EXCP_U_ECALL; - break; - case PRV_S: - fixed_cause = RISCV_EXCP_S_ECALL; - break; - case PRV_H: - fixed_cause = RISCV_EXCP_H_ECALL; - break; - case PRV_M: - fixed_cause = RISCV_EXCP_M_ECALL; - break; - } - } else { - fixed_cause = cs->exception_index; + /* ecall is dispatched as one cause so translate based on mode */ + if (cause == RISCV_EXCP_U_ECALL) { + assert(env->priv <= 3); + cause = ecall_cause_map[env->priv]; } } - target_ulong backup_epc = env->pc; - - target_ulong bit = fixed_cause; - target_ulong deleg = env->medeleg; - - int hasbadaddr = - (fixed_cause == RISCV_EXCP_INST_ADDR_MIS) || - (fixed_cause == RISCV_EXCP_INST_ACCESS_FAULT) || - (fixed_cause == RISCV_EXCP_LOAD_ADDR_MIS) || - (fixed_cause == RISCV_EXCP_STORE_AMO_ADDR_MIS) || - (fixed_cause == RISCV_EXCP_LOAD_ACCESS_FAULT) || - (fixed_cause == RISCV_EXCP_STORE_AMO_ACCESS_FAULT) || - (fixed_cause == RISCV_EXCP_INST_PAGE_FAULT) || - (fixed_cause == RISCV_EXCP_LOAD_PAGE_FAULT) || - (fixed_cause == RISCV_EXCP_STORE_PAGE_FAULT); - - if (bit & ((target_ulong)1 << (TARGET_LONG_BITS - 1))) { - deleg = env->mideleg; - bit &= ~((target_ulong)1 << (TARGET_LONG_BITS - 1)); - } + trace_riscv_trap(env->mhartid, async, cause, env->pc, tval, cause < 16 ? + (async ? riscv_intr_names : riscv_excp_names)[cause] : "(unknown)"); - if (env->priv <= PRV_S && bit < 64 && ((deleg >> bit) & 1)) { + if (env->priv <= PRV_S && + cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) { /* handle the trap in S-mode */ - /* No need to check STVEC for misaligned - lower 2 bits cannot be set */ - env->pc = env->stvec; - env->scause = fixed_cause; - env->sepc = backup_epc; - - if (hasbadaddr) { - if (RISCV_DEBUG_INTERRUPT) { - qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x" - TARGET_FMT_lx "\n", env->mhartid, env->badaddr); - } - env->sbadaddr = env->badaddr; - } else { - /* otherwise we must clear sbadaddr/stval - * todo: support populating stval on illegal instructions */ - env->sbadaddr = 0; - } - target_ulong s = env->mstatus; s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ? get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv)); s = set_field(s, MSTATUS_SPP, env->priv); s = set_field(s, MSTATUS_SIE, 0); env->mstatus = s; + env->scause = cause | ~(((target_ulong)-1) >> async); + env->sepc = env->pc; + env->sbadaddr = tval; + env->pc = (env->stvec >> 2 << 2) + + ((async && (env->stvec & 3) == 1) ? cause * 4 : 0); riscv_cpu_set_mode(env, PRV_S); } else { - /* No need to check MTVEC for misaligned - lower 2 bits cannot be set */ - env->pc = env->mtvec; - env->mepc = backup_epc; - env->mcause = fixed_cause; - - if (hasbadaddr) { - if (RISCV_DEBUG_INTERRUPT) { - qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x" - TARGET_FMT_lx "\n", env->mhartid, env->badaddr); - } - env->mbadaddr = env->badaddr; - } else { - /* otherwise we must clear mbadaddr/mtval - * todo: support populating mtval on illegal instructions */ - env->mbadaddr = 0; - } - + /* handle the trap in M-mode */ target_ulong s = env->mstatus; s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ? get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv)); s = set_field(s, MSTATUS_MPP, env->priv); s = set_field(s, MSTATUS_MIE, 0); env->mstatus = s; + env->mcause = cause | ~(((target_ulong)-1) >> async); + env->mepc = env->pc; + env->mbadaddr = tval; + env->pc = (env->mtvec >> 2 << 2) + + ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0); riscv_cpu_set_mode(env, PRV_M); } - /* TODO yield load reservation */ + + /* NOTE: it is not necessary to yield load reservations here. It is only + * necessary for an SC from "another hart" to cause a load reservation + * to be yielded. Refer to the memory consistency model section of the + * RISC-V ISA Specification. + */ + #endif cs->exception_index = EXCP_NONE; /* mark handled to qemu */ } diff --git a/target/riscv/cpu_user.h b/target/riscv/cpu_user.h index c2199610ab..52d380aa98 100644 --- a/target/riscv/cpu_user.h +++ b/target/riscv/cpu_user.h @@ -10,4 +10,5 @@ #define xA4 14 #define xA5 15 #define xA6 16 -#define xA7 17 /* syscall number goes here */ +#define xA7 17 /* syscall number for RVI ABI */ +#define xT0 5 /* syscall number for RVE ABI */ diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 960d2b0aa9..e1d91b6c60 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -46,7 +46,7 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops) static int fs(CPURISCVState *env, int csrno) { #if !defined(CONFIG_USER_ONLY) - if (!(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { return -1; } #endif @@ -92,7 +92,7 @@ static int pmp(CPURISCVState *env, int csrno) static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) - if (!(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { return -1; } #endif @@ -103,7 +103,7 @@ static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val) static int write_fflags(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) - if (!(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { return -1; } env->mstatus |= MSTATUS_FS; @@ -115,7 +115,7 @@ static int write_fflags(CPURISCVState *env, int csrno, target_ulong val) static int read_frm(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) - if (!(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { return -1; } #endif @@ -126,7 +126,7 @@ static int read_frm(CPURISCVState *env, int csrno, target_ulong *val) static int write_frm(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) - if (!(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { return -1; } env->mstatus |= MSTATUS_FS; @@ -138,7 +138,7 @@ static int write_frm(CPURISCVState *env, int csrno, target_ulong val) static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) - if (!(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { return -1; } #endif @@ -150,7 +150,7 @@ static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val) static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) - if (!(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { return -1; } env->mstatus |= MSTATUS_FS; @@ -435,10 +435,10 @@ static int read_mtvec(CPURISCVState *env, int csrno, target_ulong *val) static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ - if ((val & 3) == 0) { - env->mtvec = val >> 2 << 2; + if ((val & 3) < 2) { + env->mtvec = val; } else { - qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: vectored traps not supported"); + qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: reserved mode not supported\n"); } return 0; } @@ -550,16 +550,10 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask) { RISCVCPU *cpu = riscv_env_get_cpu(env); - target_ulong mask = write_mask & delegable_ints; + /* Allow software control of delegable interrupts not claimed by hardware */ + target_ulong mask = write_mask & delegable_ints & ~env->miclaim; uint32_t old_mip; - /* We can't allow the supervisor to control SEIP as this would allow the - * supervisor to clear a pending external interrupt which will result in - * lost a interrupt in the case a PLIC is attached. The SEIP bit must be - * hardware controlled when a PLIC is attached. This should be an option - * for CPUs with software-delegated Supervisor External Interrupts. */ - mask &= ~MIP_SEIP; - if (mask) { qemu_mutex_lock_iothread(); old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); @@ -613,10 +607,10 @@ static int read_stvec(CPURISCVState *env, int csrno, target_ulong *val) static int write_stvec(CPURISCVState *env, int csrno, target_ulong val) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ - if ((val & 3) == 0) { - env->stvec = val >> 2 << 2; + if ((val & 3) < 2) { + env->stvec = val; } else { - qemu_log_mask(LOG_UNIMP, "CSR_STVEC: vectored traps not supported"); + qemu_log_mask(LOG_UNIMP, "CSR_STVEC: reserved mode not supported\n"); } return 0; } @@ -827,6 +821,24 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, return 0; } +/* + * Debugger support. If not in user mode, set env->debugger before the + * riscv_csrrw call and clear it after the call. + */ +int riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) +{ + int ret; +#if !defined(CONFIG_USER_ONLY) + env->debugger = true; +#endif + ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask); +#if !defined(CONFIG_USER_ONLY) + env->debugger = false; +#endif + return ret; +} + /* Control and Status Register function table */ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { /* User Floating-Point CSRs */ diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index 3cabb21cd0..dfcdd834cf 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -21,6 +21,255 @@ #include "exec/gdbstub.h" #include "cpu.h" +/* + * The GDB CSR xml files list them in documentation order, not numerical order, + * and are missing entries for unnamed CSRs. So we need to map the gdb numbers + * to the hardware numbers. + */ + +static int csr_register_map[] = { + CSR_USTATUS, + CSR_UIE, + CSR_UTVEC, + CSR_USCRATCH, + CSR_UEPC, + CSR_UCAUSE, + CSR_UTVAL, + CSR_UIP, + CSR_FFLAGS, + CSR_FRM, + CSR_FCSR, + CSR_CYCLE, + CSR_TIME, + CSR_INSTRET, + CSR_HPMCOUNTER3, + CSR_HPMCOUNTER4, + CSR_HPMCOUNTER5, + CSR_HPMCOUNTER6, + CSR_HPMCOUNTER7, + CSR_HPMCOUNTER8, + CSR_HPMCOUNTER9, + CSR_HPMCOUNTER10, + CSR_HPMCOUNTER11, + CSR_HPMCOUNTER12, + CSR_HPMCOUNTER13, + CSR_HPMCOUNTER14, + CSR_HPMCOUNTER15, + CSR_HPMCOUNTER16, + CSR_HPMCOUNTER17, + CSR_HPMCOUNTER18, + CSR_HPMCOUNTER19, + CSR_HPMCOUNTER20, + CSR_HPMCOUNTER21, + CSR_HPMCOUNTER22, + CSR_HPMCOUNTER23, + CSR_HPMCOUNTER24, + CSR_HPMCOUNTER25, + CSR_HPMCOUNTER26, + CSR_HPMCOUNTER27, + CSR_HPMCOUNTER28, + CSR_HPMCOUNTER29, + CSR_HPMCOUNTER30, + CSR_HPMCOUNTER31, + CSR_CYCLEH, + CSR_TIMEH, + CSR_INSTRETH, + CSR_HPMCOUNTER3H, + CSR_HPMCOUNTER4H, + CSR_HPMCOUNTER5H, + CSR_HPMCOUNTER6H, + CSR_HPMCOUNTER7H, + CSR_HPMCOUNTER8H, + CSR_HPMCOUNTER9H, + CSR_HPMCOUNTER10H, + CSR_HPMCOUNTER11H, + CSR_HPMCOUNTER12H, + CSR_HPMCOUNTER13H, + CSR_HPMCOUNTER14H, + CSR_HPMCOUNTER15H, + CSR_HPMCOUNTER16H, + CSR_HPMCOUNTER17H, + CSR_HPMCOUNTER18H, + CSR_HPMCOUNTER19H, + CSR_HPMCOUNTER20H, + CSR_HPMCOUNTER21H, + CSR_HPMCOUNTER22H, + CSR_HPMCOUNTER23H, + CSR_HPMCOUNTER24H, + CSR_HPMCOUNTER25H, + CSR_HPMCOUNTER26H, + CSR_HPMCOUNTER27H, + CSR_HPMCOUNTER28H, + CSR_HPMCOUNTER29H, + CSR_HPMCOUNTER30H, + CSR_HPMCOUNTER31H, + CSR_SSTATUS, + CSR_SEDELEG, + CSR_SIDELEG, + CSR_SIE, + CSR_STVEC, + CSR_SCOUNTEREN, + CSR_SSCRATCH, + CSR_SEPC, + CSR_SCAUSE, + CSR_STVAL, + CSR_SIP, + CSR_SATP, + CSR_MVENDORID, + CSR_MARCHID, + CSR_MIMPID, + CSR_MHARTID, + CSR_MSTATUS, + CSR_MISA, + CSR_MEDELEG, + CSR_MIDELEG, + CSR_MIE, + CSR_MTVEC, + CSR_MCOUNTEREN, + CSR_MSCRATCH, + CSR_MEPC, + CSR_MCAUSE, + CSR_MTVAL, + CSR_MIP, + CSR_PMPCFG0, + CSR_PMPCFG1, + CSR_PMPCFG2, + CSR_PMPCFG3, + CSR_PMPADDR0, + CSR_PMPADDR1, + CSR_PMPADDR2, + CSR_PMPADDR3, + CSR_PMPADDR4, + CSR_PMPADDR5, + CSR_PMPADDR6, + CSR_PMPADDR7, + CSR_PMPADDR8, + CSR_PMPADDR9, + CSR_PMPADDR10, + CSR_PMPADDR11, + CSR_PMPADDR12, + CSR_PMPADDR13, + CSR_PMPADDR14, + CSR_PMPADDR15, + CSR_MCYCLE, + CSR_MINSTRET, + CSR_MHPMCOUNTER3, + CSR_MHPMCOUNTER4, + CSR_MHPMCOUNTER5, + CSR_MHPMCOUNTER6, + CSR_MHPMCOUNTER7, + CSR_MHPMCOUNTER8, + CSR_MHPMCOUNTER9, + CSR_MHPMCOUNTER10, + CSR_MHPMCOUNTER11, + CSR_MHPMCOUNTER12, + CSR_MHPMCOUNTER13, + CSR_MHPMCOUNTER14, + CSR_MHPMCOUNTER15, + CSR_MHPMCOUNTER16, + CSR_MHPMCOUNTER17, + CSR_MHPMCOUNTER18, + CSR_MHPMCOUNTER19, + CSR_MHPMCOUNTER20, + CSR_MHPMCOUNTER21, + CSR_MHPMCOUNTER22, + CSR_MHPMCOUNTER23, + CSR_MHPMCOUNTER24, + CSR_MHPMCOUNTER25, + CSR_MHPMCOUNTER26, + CSR_MHPMCOUNTER27, + CSR_MHPMCOUNTER28, + CSR_MHPMCOUNTER29, + CSR_MHPMCOUNTER30, + CSR_MHPMCOUNTER31, + CSR_MCYCLEH, + CSR_MINSTRETH, + CSR_MHPMCOUNTER3H, + CSR_MHPMCOUNTER4H, + CSR_MHPMCOUNTER5H, + CSR_MHPMCOUNTER6H, + CSR_MHPMCOUNTER7H, + CSR_MHPMCOUNTER8H, + CSR_MHPMCOUNTER9H, + CSR_MHPMCOUNTER10H, + CSR_MHPMCOUNTER11H, + CSR_MHPMCOUNTER12H, + CSR_MHPMCOUNTER13H, + CSR_MHPMCOUNTER14H, + CSR_MHPMCOUNTER15H, + CSR_MHPMCOUNTER16H, + CSR_MHPMCOUNTER17H, + CSR_MHPMCOUNTER18H, + CSR_MHPMCOUNTER19H, + CSR_MHPMCOUNTER20H, + CSR_MHPMCOUNTER21H, + CSR_MHPMCOUNTER22H, + CSR_MHPMCOUNTER23H, + CSR_MHPMCOUNTER24H, + CSR_MHPMCOUNTER25H, + CSR_MHPMCOUNTER26H, + CSR_MHPMCOUNTER27H, + CSR_MHPMCOUNTER28H, + CSR_MHPMCOUNTER29H, + CSR_MHPMCOUNTER30H, + CSR_MHPMCOUNTER31H, + CSR_MHPMEVENT3, + CSR_MHPMEVENT4, + CSR_MHPMEVENT5, + CSR_MHPMEVENT6, + CSR_MHPMEVENT7, + CSR_MHPMEVENT8, + CSR_MHPMEVENT9, + CSR_MHPMEVENT10, + CSR_MHPMEVENT11, + CSR_MHPMEVENT12, + CSR_MHPMEVENT13, + CSR_MHPMEVENT14, + CSR_MHPMEVENT15, + CSR_MHPMEVENT16, + CSR_MHPMEVENT17, + CSR_MHPMEVENT18, + CSR_MHPMEVENT19, + CSR_MHPMEVENT20, + CSR_MHPMEVENT21, + CSR_MHPMEVENT22, + CSR_MHPMEVENT23, + CSR_MHPMEVENT24, + CSR_MHPMEVENT25, + CSR_MHPMEVENT26, + CSR_MHPMEVENT27, + CSR_MHPMEVENT28, + CSR_MHPMEVENT29, + CSR_MHPMEVENT30, + CSR_MHPMEVENT31, + CSR_TSELECT, + CSR_TDATA1, + CSR_TDATA2, + CSR_TDATA3, + CSR_DCSR, + CSR_DPC, + CSR_DSCRATCH, + CSR_HSTATUS, + CSR_HEDELEG, + CSR_HIDELEG, + CSR_HIE, + CSR_HTVEC, + CSR_HSCRATCH, + CSR_HEPC, + CSR_HCAUSE, + CSR_HBADADDR, + CSR_HIP, + CSR_MBASE, + CSR_MBOUND, + CSR_MIBASE, + CSR_MIBOUND, + CSR_MDBASE, + CSR_MDBOUND, + CSR_MUCOUNTEREN, + CSR_MSCOUNTEREN, + CSR_MHCOUNTEREN, +}; + int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) { RISCVCPU *cpu = RISCV_CPU(cs); @@ -30,13 +279,6 @@ int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) return gdb_get_regl(mem_buf, env->gpr[n]); } else if (n == 32) { return gdb_get_regl(mem_buf, env->pc); - } else if (n < 65) { - return gdb_get_reg64(mem_buf, env->fpr[n - 33]); - } else if (n < 4096 + 65) { - target_ulong val = 0; - if (riscv_csrrw(env, n - 65, &val, 0, 0) == 0) { - return gdb_get_regl(mem_buf, val); - } } return 0; } @@ -55,14 +297,100 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) } else if (n == 32) { env->pc = ldtul_p(mem_buf); return sizeof(target_ulong); - } else if (n < 65) { - env->fpr[n - 33] = ldq_p(mem_buf); /* always 64-bit */ + } + return 0; +} + +static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n) +{ + if (n < 32) { + return gdb_get_reg64(mem_buf, env->fpr[n]); + /* there is hole between ft11 and fflags in fpu.xml */ + } else if (n < 36 && n > 32) { + target_ulong val = 0; + int result; + /* + * CSR_FFLAGS is at index 8 in csr_register, and gdb says it is FP + * register 33, so we recalculate the map index. + * This also works for CSR_FRM and CSR_FCSR. + */ + result = riscv_csrrw_debug(env, n - 33 + 8, &val, 0, 0); + if (result == 0) { + return gdb_get_regl(mem_buf, val); + } + } + return 0; +} + +static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n) +{ + if (n < 32) { + env->fpr[n] = ldq_p(mem_buf); /* always 64-bit */ return sizeof(uint64_t); - } else if (n < 4096 + 65) { + /* there is hole between ft11 and fflags in fpu.xml */ + } else if (n < 36 && n > 32) { target_ulong val = ldtul_p(mem_buf); - if (riscv_csrrw(env, n - 65, NULL, val, -1) == 0) { + int result; + /* + * CSR_FFLAGS is at index 8 in csr_register, and gdb says it is FP + * register 33, so we recalculate the map index. + * This also works for CSR_FRM and CSR_FCSR. + */ + result = riscv_csrrw_debug(env, n - 33 + 8, NULL, val, -1); + if (result == 0) { return sizeof(target_ulong); } } return 0; } + +static int riscv_gdb_get_csr(CPURISCVState *env, uint8_t *mem_buf, int n) +{ + if (n < ARRAY_SIZE(csr_register_map)) { + target_ulong val = 0; + int result; + + result = riscv_csrrw_debug(env, csr_register_map[n], &val, 0, 0); + if (result == 0) { + return gdb_get_regl(mem_buf, val); + } + } + return 0; +} + +static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n) +{ + if (n < ARRAY_SIZE(csr_register_map)) { + target_ulong val = ldtul_p(mem_buf); + int result; + + result = riscv_csrrw_debug(env, csr_register_map[n], NULL, val, -1); + if (result == 0) { + return sizeof(target_ulong); + } + } + return 0; +} + +void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; +#if defined(TARGET_RISCV32) + if (env->misa & RVF) { + gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, + 36, "riscv-32bit-fpu.xml", 0); + } + + gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr, + 4096, "riscv-32bit-csr.xml", 0); +#elif defined(TARGET_RISCV64) + if (env->misa & RVF) { + gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, + 36, "riscv-64bit-fpu.xml", 0); + } + + gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr, + 4096, "riscv-64bit-csr.xml", 0); +#endif +} diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode new file mode 100644 index 0000000000..17cc52cf2a --- /dev/null +++ b/target/riscv/insn16.decode @@ -0,0 +1,129 @@ +# +# RISC-V translation routines for the RVXI Base Integer Instruction Set. +# +# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de +# Bastian Koppelmann, kbastian@mail.uni-paderborn.de +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2 or later, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see <http://www.gnu.org/licenses/>. + +# Fields: +%rd 7:5 +%rs1_3 7:3 !function=ex_rvc_register +%rs2_3 2:3 !function=ex_rvc_register +%rs2_5 2:5 + +# Immediates: +%imm_ci 12:s1 2:5 +%nzuimm_ciw 7:4 11:2 5:1 6:1 !function=ex_shift_2 +%uimm_cl_d 5:2 10:3 !function=ex_shift_3 +%uimm_cl_w 5:1 10:3 6:1 !function=ex_shift_2 +%imm_cb 12:s1 5:2 2:1 10:2 3:2 !function=ex_shift_1 +%imm_cj 12:s1 8:1 9:2 6:1 7:1 2:1 11:1 3:3 !function=ex_shift_1 + +%nzuimm_6bit 12:1 2:5 +%uimm_6bit_ld 2:3 12:1 5:2 !function=ex_shift_3 +%uimm_6bit_lw 2:2 12:1 4:3 !function=ex_shift_2 +%uimm_6bit_sd 7:3 10:3 !function=ex_shift_3 +%uimm_6bit_sw 7:2 9:4 !function=ex_shift_2 + +%imm_addi16sp 12:s1 3:2 5:1 2:1 6:1 !function=ex_shift_4 +%imm_lui 12:s1 2:5 !function=ex_shift_12 + + + +# Argument sets: +&cl rs1 rd +&cl_dw uimm rs1 rd +&ci imm rd +&ciw nzuimm rd +&cs rs1 rs2 +&cs_dw uimm rs1 rs2 +&cb imm rs1 +&cr rd rs2 +&cj imm +&c_shift shamt rd + +&c_ld uimm rd +&c_sd uimm rs2 + +&caddi16sp_lui imm_lui imm_addi16sp rd +&cflwsp_ldsp uimm_flwsp uimm_ldsp rd +&cfswsp_sdsp uimm_fswsp uimm_sdsp rs2 + +# Formats 16: +@cr .... ..... ..... .. &cr rs2=%rs2_5 %rd +@ci ... . ..... ..... .. &ci imm=%imm_ci %rd +@ciw ... ........ ... .. &ciw nzuimm=%nzuimm_ciw rd=%rs2_3 +@cl_d ... ... ... .. ... .. &cl_dw uimm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3 +@cl_w ... ... ... .. ... .. &cl_dw uimm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3 +@cl ... ... ... .. ... .. &cl rs1=%rs1_3 rd=%rs2_3 +@cs ... ... ... .. ... .. &cs rs1=%rs1_3 rs2=%rs2_3 +@cs_2 ... ... ... .. ... .. &cr rd=%rs1_3 rs2=%rs2_3 +@cs_d ... ... ... .. ... .. &cs_dw uimm=%uimm_cl_d rs1=%rs1_3 rs2=%rs2_3 +@cs_w ... ... ... .. ... .. &cs_dw uimm=%uimm_cl_w rs1=%rs1_3 rs2=%rs2_3 +@cb ... ... ... .. ... .. &cb imm=%imm_cb rs1=%rs1_3 +@cj ... ........... .. &cj imm=%imm_cj + +@c_ld ... . ..... ..... .. &c_ld uimm=%uimm_6bit_ld %rd +@c_lw ... . ..... ..... .. &c_ld uimm=%uimm_6bit_lw %rd +@c_sd ... . ..... ..... .. &c_sd uimm=%uimm_6bit_sd rs2=%rs2_5 +@c_sw ... . ..... ..... .. &c_sd uimm=%uimm_6bit_sw rs2=%rs2_5 + +@c_addi16sp_lui ... . ..... ..... .. &caddi16sp_lui %imm_lui %imm_addi16sp %rd +@c_flwsp_ldsp ... . ..... ..... .. &cflwsp_ldsp uimm_flwsp=%uimm_6bit_lw \ + uimm_ldsp=%uimm_6bit_ld %rd +@c_fswsp_sdsp ... . ..... ..... .. &cfswsp_sdsp uimm_fswsp=%uimm_6bit_sw \ + uimm_sdsp=%uimm_6bit_sd rs2=%rs2_5 + +@c_shift ... . .. ... ..... .. &c_shift rd=%rs1_3 shamt=%nzuimm_6bit +@c_shift2 ... . .. ... ..... .. &c_shift rd=%rd shamt=%nzuimm_6bit + +@c_andi ... . .. ... ..... .. &ci imm=%imm_ci rd=%rs1_3 + +# *** RV64C Standard Extension (Quadrant 0) *** +c_addi4spn 000 ........ ... 00 @ciw +c_fld 001 ... ... .. ... 00 @cl_d +c_lw 010 ... ... .. ... 00 @cl_w +c_flw_ld 011 --- ... -- ... 00 @cl #Note: Must parse uimm manually +c_fsd 101 ... ... .. ... 00 @cs_d +c_sw 110 ... ... .. ... 00 @cs_w +c_fsw_sd 111 --- ... -- ... 00 @cs #Note: Must parse uimm manually + +# *** RV64C Standard Extension (Quadrant 1) *** +c_addi 000 . ..... ..... 01 @ci +c_jal_addiw 001 . ..... ..... 01 @ci #Note: parse rd and/or imm manually +c_li 010 . ..... ..... 01 @ci +c_addi16sp_lui 011 . ..... ..... 01 @c_addi16sp_lui # shares opc with C.LUI +c_srli 100 . 00 ... ..... 01 @c_shift +c_srai 100 . 01 ... ..... 01 @c_shift +c_andi 100 . 10 ... ..... 01 @c_andi +c_sub 100 0 11 ... 00 ... 01 @cs_2 +c_xor 100 0 11 ... 01 ... 01 @cs_2 +c_or 100 0 11 ... 10 ... 01 @cs_2 +c_and 100 0 11 ... 11 ... 01 @cs_2 +c_subw 100 1 11 ... 00 ... 01 @cs_2 +c_addw 100 1 11 ... 01 ... 01 @cs_2 +c_j 101 ........... 01 @cj +c_beqz 110 ... ... ..... 01 @cb +c_bnez 111 ... ... ..... 01 @cb + +# *** RV64C Standard Extension (Quadrant 2) *** +c_slli 000 . ..... ..... 10 @c_shift2 +c_fldsp 001 . ..... ..... 10 @c_ld +c_lwsp 010 . ..... ..... 10 @c_lw +c_flwsp_ldsp 011 . ..... ..... 10 @c_flwsp_ldsp #C.LDSP:RV64;C.FLWSP:RV32 +c_jr_mv 100 0 ..... ..... 10 @cr +c_ebreak_jalr_add 100 1 ..... ..... 10 @cr +c_fsdsp 101 ...... ..... 10 @c_sd +c_swsp 110 . ..... ..... 10 @c_sw +c_fswsp_sdsp 111 . ..... ..... 10 @c_fswsp_sdsp #C.SDSP:RV64;C.FSWSP:RV32 diff --git a/target/riscv/insn32-64.decode b/target/riscv/insn32-64.decode new file mode 100644 index 0000000000..380bf791bc --- /dev/null +++ b/target/riscv/insn32-64.decode @@ -0,0 +1,72 @@ +# +# RISC-V translation routines for the RV Instruction Set. +# +# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de +# Bastian Koppelmann, kbastian@mail.uni-paderborn.de +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2 or later, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see <http://www.gnu.org/licenses/>. + +# This is concatenated with insn32.decode for risc64 targets. +# Most of the fields and formats are there. + +%sh5 20:5 + +@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd + +# *** RV64I Base Instruction Set (in addition to RV32I) *** +lwu ............ ..... 110 ..... 0000011 @i +ld ............ ..... 011 ..... 0000011 @i +sd ....... ..... ..... 011 ..... 0100011 @s +addiw ............ ..... 000 ..... 0011011 @i +slliw 0000000 ..... ..... 001 ..... 0011011 @sh5 +srliw 0000000 ..... ..... 101 ..... 0011011 @sh5 +sraiw 0100000 ..... ..... 101 ..... 0011011 @sh5 +addw 0000000 ..... ..... 000 ..... 0111011 @r +subw 0100000 ..... ..... 000 ..... 0111011 @r +sllw 0000000 ..... ..... 001 ..... 0111011 @r +srlw 0000000 ..... ..... 101 ..... 0111011 @r +sraw 0100000 ..... ..... 101 ..... 0111011 @r + +# *** RV64M Standard Extension (in addition to RV32M) *** +mulw 0000001 ..... ..... 000 ..... 0111011 @r +divw 0000001 ..... ..... 100 ..... 0111011 @r +divuw 0000001 ..... ..... 101 ..... 0111011 @r +remw 0000001 ..... ..... 110 ..... 0111011 @r +remuw 0000001 ..... ..... 111 ..... 0111011 @r + +# *** RV64A Standard Extension (in addition to RV32A) *** +lr_d 00010 . . 00000 ..... 011 ..... 0101111 @atom_ld +sc_d 00011 . . ..... ..... 011 ..... 0101111 @atom_st +amoswap_d 00001 . . ..... ..... 011 ..... 0101111 @atom_st +amoadd_d 00000 . . ..... ..... 011 ..... 0101111 @atom_st +amoxor_d 00100 . . ..... ..... 011 ..... 0101111 @atom_st +amoand_d 01100 . . ..... ..... 011 ..... 0101111 @atom_st +amoor_d 01000 . . ..... ..... 011 ..... 0101111 @atom_st +amomin_d 10000 . . ..... ..... 011 ..... 0101111 @atom_st +amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st +amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st +amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st + +# *** RV64F Standard Extension (in addition to RV32F) *** +fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm +fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm +fcvt_s_l 1101000 00010 ..... ... ..... 1010011 @r2_rm +fcvt_s_lu 1101000 00011 ..... ... ..... 1010011 @r2_rm + +# *** RV64D Standard Extension (in addition to RV32D) *** +fcvt_l_d 1100001 00010 ..... ... ..... 1010011 @r2_rm +fcvt_lu_d 1100001 00011 ..... ... ..... 1010011 @r2_rm +fmv_x_d 1110001 00000 ..... 000 ..... 1010011 @r2 +fcvt_d_l 1101001 00010 ..... ... ..... 1010011 @r2_rm +fcvt_d_lu 1101001 00011 ..... ... ..... 1010011 @r2_rm +fmv_d_x 1111001 00000 ..... 000 ..... 1010011 @r2 diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode new file mode 100644 index 0000000000..6f3ab7aa52 --- /dev/null +++ b/target/riscv/insn32.decode @@ -0,0 +1,201 @@ +# +# RISC-V translation routines for the RVXI Base Integer Instruction Set. +# +# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de +# Bastian Koppelmann, kbastian@mail.uni-paderborn.de +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2 or later, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see <http://www.gnu.org/licenses/>. + +# Fields: +%rs3 27:5 +%rs2 20:5 +%rs1 15:5 +%rd 7:5 + +%sh10 20:10 +%csr 20:12 +%rm 12:3 + +# immediates: +%imm_i 20:s12 +%imm_s 25:s7 7:5 +%imm_b 31:s1 7:1 25:6 8:4 !function=ex_shift_1 +%imm_j 31:s1 12:8 20:1 21:10 !function=ex_shift_1 +%imm_u 12:s20 !function=ex_shift_12 + +# Argument sets: +&b imm rs2 rs1 +&i imm rs1 rd +&r rd rs1 rs2 +&shift shamt rs1 rd +&atomic aq rl rs2 rs1 rd + +# Formats 32: +@r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd +@i ............ ..... ... ..... ....... &i imm=%imm_i %rs1 %rd +@b ....... ..... ..... ... ..... ....... &b imm=%imm_b %rs2 %rs1 +@s ....... ..... ..... ... ..... ....... imm=%imm_s %rs2 %rs1 +@u .................... ..... ....... imm=%imm_u %rd +@j .................... ..... ....... imm=%imm_j %rd + +@sh ...... ...... ..... ... ..... ....... &shift shamt=%sh10 %rs1 %rd +@csr ............ ..... ... ..... ....... %csr %rs1 %rd + +@atom_ld ..... aq:1 rl:1 ..... ........ ..... ....... &atomic rs2=0 %rs1 %rd +@atom_st ..... aq:1 rl:1 ..... ........ ..... ....... &atomic %rs2 %rs1 %rd + +@r4_rm ..... .. ..... ..... ... ..... ....... %rs3 %rs2 %rs1 %rm %rd +@r_rm ....... ..... ..... ... ..... ....... %rs2 %rs1 %rm %rd +@r2_rm ....... ..... ..... ... ..... ....... %rs1 %rm %rd +@r2 ....... ..... ..... ... ..... ....... %rs1 %rd + +@sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1 +@sfence_vm ....... ..... ..... ... ..... ....... %rs1 + + +# *** Privileged Instructions *** +ecall 000000000000 00000 000 00000 1110011 +ebreak 000000000001 00000 000 00000 1110011 +uret 0000000 00010 00000 000 00000 1110011 +sret 0001000 00010 00000 000 00000 1110011 +hret 0010000 00010 00000 000 00000 1110011 +mret 0011000 00010 00000 000 00000 1110011 +wfi 0001000 00101 00000 000 00000 1110011 +sfence_vma 0001001 ..... ..... 000 00000 1110011 @sfence_vma +sfence_vm 0001000 00100 ..... 000 00000 1110011 @sfence_vm + +# *** RV32I Base Instruction Set *** +lui .................... ..... 0110111 @u +auipc .................... ..... 0010111 @u +jal .................... ..... 1101111 @j +jalr ............ ..... 000 ..... 1100111 @i +beq ....... ..... ..... 000 ..... 1100011 @b +bne ....... ..... ..... 001 ..... 1100011 @b +blt ....... ..... ..... 100 ..... 1100011 @b +bge ....... ..... ..... 101 ..... 1100011 @b +bltu ....... ..... ..... 110 ..... 1100011 @b +bgeu ....... ..... ..... 111 ..... 1100011 @b +lb ............ ..... 000 ..... 0000011 @i +lh ............ ..... 001 ..... 0000011 @i +lw ............ ..... 010 ..... 0000011 @i +lbu ............ ..... 100 ..... 0000011 @i +lhu ............ ..... 101 ..... 0000011 @i +sb ....... ..... ..... 000 ..... 0100011 @s +sh ....... ..... ..... 001 ..... 0100011 @s +sw ....... ..... ..... 010 ..... 0100011 @s +addi ............ ..... 000 ..... 0010011 @i +slti ............ ..... 010 ..... 0010011 @i +sltiu ............ ..... 011 ..... 0010011 @i +xori ............ ..... 100 ..... 0010011 @i +ori ............ ..... 110 ..... 0010011 @i +andi ............ ..... 111 ..... 0010011 @i +slli 00.... ...... ..... 001 ..... 0010011 @sh +srli 00.... ...... ..... 101 ..... 0010011 @sh +srai 01.... ...... ..... 101 ..... 0010011 @sh +add 0000000 ..... ..... 000 ..... 0110011 @r +sub 0100000 ..... ..... 000 ..... 0110011 @r +sll 0000000 ..... ..... 001 ..... 0110011 @r +slt 0000000 ..... ..... 010 ..... 0110011 @r +sltu 0000000 ..... ..... 011 ..... 0110011 @r +xor 0000000 ..... ..... 100 ..... 0110011 @r +srl 0000000 ..... ..... 101 ..... 0110011 @r +sra 0100000 ..... ..... 101 ..... 0110011 @r +or 0000000 ..... ..... 110 ..... 0110011 @r +and 0000000 ..... ..... 111 ..... 0110011 @r +fence ---- pred:4 succ:4 ----- 000 ----- 0001111 +fence_i ---- ---- ---- ----- 001 ----- 0001111 +csrrw ............ ..... 001 ..... 1110011 @csr +csrrs ............ ..... 010 ..... 1110011 @csr +csrrc ............ ..... 011 ..... 1110011 @csr +csrrwi ............ ..... 101 ..... 1110011 @csr +csrrsi ............ ..... 110 ..... 1110011 @csr +csrrci ............ ..... 111 ..... 1110011 @csr + +# *** RV32M Standard Extension *** +mul 0000001 ..... ..... 000 ..... 0110011 @r +mulh 0000001 ..... ..... 001 ..... 0110011 @r +mulhsu 0000001 ..... ..... 010 ..... 0110011 @r +mulhu 0000001 ..... ..... 011 ..... 0110011 @r +div 0000001 ..... ..... 100 ..... 0110011 @r +divu 0000001 ..... ..... 101 ..... 0110011 @r +rem 0000001 ..... ..... 110 ..... 0110011 @r +remu 0000001 ..... ..... 111 ..... 0110011 @r + +# *** RV32A Standard Extension *** +lr_w 00010 . . 00000 ..... 010 ..... 0101111 @atom_ld +sc_w 00011 . . ..... ..... 010 ..... 0101111 @atom_st +amoswap_w 00001 . . ..... ..... 010 ..... 0101111 @atom_st +amoadd_w 00000 . . ..... ..... 010 ..... 0101111 @atom_st +amoxor_w 00100 . . ..... ..... 010 ..... 0101111 @atom_st +amoand_w 01100 . . ..... ..... 010 ..... 0101111 @atom_st +amoor_w 01000 . . ..... ..... 010 ..... 0101111 @atom_st +amomin_w 10000 . . ..... ..... 010 ..... 0101111 @atom_st +amomax_w 10100 . . ..... ..... 010 ..... 0101111 @atom_st +amominu_w 11000 . . ..... ..... 010 ..... 0101111 @atom_st +amomaxu_w 11100 . . ..... ..... 010 ..... 0101111 @atom_st + +# *** RV32F Standard Extension *** +flw ............ ..... 010 ..... 0000111 @i +fsw ....... ..... ..... 010 ..... 0100111 @s +fmadd_s ..... 00 ..... ..... ... ..... 1000011 @r4_rm +fmsub_s ..... 00 ..... ..... ... ..... 1000111 @r4_rm +fnmsub_s ..... 00 ..... ..... ... ..... 1001011 @r4_rm +fnmadd_s ..... 00 ..... ..... ... ..... 1001111 @r4_rm +fadd_s 0000000 ..... ..... ... ..... 1010011 @r_rm +fsub_s 0000100 ..... ..... ... ..... 1010011 @r_rm +fmul_s 0001000 ..... ..... ... ..... 1010011 @r_rm +fdiv_s 0001100 ..... ..... ... ..... 1010011 @r_rm +fsqrt_s 0101100 00000 ..... ... ..... 1010011 @r2_rm +fsgnj_s 0010000 ..... ..... 000 ..... 1010011 @r +fsgnjn_s 0010000 ..... ..... 001 ..... 1010011 @r +fsgnjx_s 0010000 ..... ..... 010 ..... 1010011 @r +fmin_s 0010100 ..... ..... 000 ..... 1010011 @r +fmax_s 0010100 ..... ..... 001 ..... 1010011 @r +fcvt_w_s 1100000 00000 ..... ... ..... 1010011 @r2_rm +fcvt_wu_s 1100000 00001 ..... ... ..... 1010011 @r2_rm +fmv_x_w 1110000 00000 ..... 000 ..... 1010011 @r2 +feq_s 1010000 ..... ..... 010 ..... 1010011 @r +flt_s 1010000 ..... ..... 001 ..... 1010011 @r +fle_s 1010000 ..... ..... 000 ..... 1010011 @r +fclass_s 1110000 00000 ..... 001 ..... 1010011 @r2 +fcvt_s_w 1101000 00000 ..... ... ..... 1010011 @r2_rm +fcvt_s_wu 1101000 00001 ..... ... ..... 1010011 @r2_rm +fmv_w_x 1111000 00000 ..... 000 ..... 1010011 @r2 + +# *** RV32D Standard Extension *** +fld ............ ..... 011 ..... 0000111 @i +fsd ....... ..... ..... 011 ..... 0100111 @s +fmadd_d ..... 01 ..... ..... ... ..... 1000011 @r4_rm +fmsub_d ..... 01 ..... ..... ... ..... 1000111 @r4_rm +fnmsub_d ..... 01 ..... ..... ... ..... 1001011 @r4_rm +fnmadd_d ..... 01 ..... ..... ... ..... 1001111 @r4_rm +fadd_d 0000001 ..... ..... ... ..... 1010011 @r_rm +fsub_d 0000101 ..... ..... ... ..... 1010011 @r_rm +fmul_d 0001001 ..... ..... ... ..... 1010011 @r_rm +fdiv_d 0001101 ..... ..... ... ..... 1010011 @r_rm +fsqrt_d 0101101 00000 ..... ... ..... 1010011 @r2_rm +fsgnj_d 0010001 ..... ..... 000 ..... 1010011 @r +fsgnjn_d 0010001 ..... ..... 001 ..... 1010011 @r +fsgnjx_d 0010001 ..... ..... 010 ..... 1010011 @r +fmin_d 0010101 ..... ..... 000 ..... 1010011 @r +fmax_d 0010101 ..... ..... 001 ..... 1010011 @r +fcvt_s_d 0100000 00001 ..... ... ..... 1010011 @r2_rm +fcvt_d_s 0100001 00000 ..... ... ..... 1010011 @r2_rm +feq_d 1010001 ..... ..... 010 ..... 1010011 @r +flt_d 1010001 ..... ..... 001 ..... 1010011 @r +fle_d 1010001 ..... ..... 000 ..... 1010011 @r +fclass_d 1110001 00000 ..... 001 ..... 1010011 @r2 +fcvt_w_d 1100001 00000 ..... ... ..... 1010011 @r2_rm +fcvt_wu_d 1100001 00001 ..... ... ..... 1010011 @r2_rm +fcvt_d_w 1101001 00000 ..... ... ..... 1010011 @r2_rm +fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm diff --git a/target/riscv/insn_trans/trans_privileged.inc.c b/target/riscv/insn_trans/trans_privileged.inc.c new file mode 100644 index 0000000000..acb605923e --- /dev/null +++ b/target/riscv/insn_trans/trans_privileged.inc.c @@ -0,0 +1,110 @@ +/* + * RISC-V translation routines for the RISC-V privileged instructions. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de + * Bastian Koppelmann, kbastian@mail.uni-paderborn.de + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +static bool trans_ecall(DisasContext *ctx, arg_ecall *a) +{ + /* always generates U-level ECALL, fixed in do_interrupt handler */ + generate_exception(ctx, RISCV_EXCP_U_ECALL); + tcg_gen_exit_tb(NULL, 0); /* no chaining */ + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} + +static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a) +{ + generate_exception(ctx, RISCV_EXCP_BREAKPOINT); + tcg_gen_exit_tb(NULL, 0); /* no chaining */ + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} + +static bool trans_uret(DisasContext *ctx, arg_uret *a) +{ + return false; +} + +static bool trans_sret(DisasContext *ctx, arg_sret *a) +{ +#ifndef CONFIG_USER_ONLY + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + + if (has_ext(ctx, RVS)) { + gen_helper_sret(cpu_pc, cpu_env, cpu_pc); + tcg_gen_exit_tb(NULL, 0); /* no chaining */ + ctx->base.is_jmp = DISAS_NORETURN; + } else { + return false; + } + return true; +#else + return false; +#endif +} + +static bool trans_hret(DisasContext *ctx, arg_hret *a) +{ + return false; +} + +static bool trans_mret(DisasContext *ctx, arg_mret *a) +{ +#ifndef CONFIG_USER_ONLY + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + gen_helper_mret(cpu_pc, cpu_env, cpu_pc); + tcg_gen_exit_tb(NULL, 0); /* no chaining */ + ctx->base.is_jmp = DISAS_NORETURN; + return true; +#else + return false; +#endif +} + +static bool trans_wfi(DisasContext *ctx, arg_wfi *a) +{ +#ifndef CONFIG_USER_ONLY + tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); + gen_helper_wfi(cpu_env); + return true; +#else + return false; +#endif +} + +static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a) +{ +#ifndef CONFIG_USER_ONLY + if (ctx->priv_ver == PRIV_VERSION_1_10_0) { + gen_helper_tlb_flush(cpu_env); + return true; + } +#endif + return false; +} + +static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a) +{ +#ifndef CONFIG_USER_ONLY + if (ctx->priv_ver <= PRIV_VERSION_1_09_1) { + gen_helper_tlb_flush(cpu_env); + return true; + } +#endif + return false; +} diff --git a/target/riscv/insn_trans/trans_rva.inc.c b/target/riscv/insn_trans/trans_rva.inc.c new file mode 100644 index 0000000000..f6dbbc065e --- /dev/null +++ b/target/riscv/insn_trans/trans_rva.inc.c @@ -0,0 +1,218 @@ +/* + * RISC-V translation routines for the RV64A Standard Extension. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de + * Bastian Koppelmann, kbastian@mail.uni-paderborn.de + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, TCGMemOp mop) +{ + TCGv src1 = tcg_temp_new(); + /* Put addr in load_res, data in load_val. */ + gen_get_gpr(src1, a->rs1); + if (a->rl) { + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + } + tcg_gen_qemu_ld_tl(load_val, src1, ctx->mem_idx, mop); + if (a->aq) { + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); + } + tcg_gen_mov_tl(load_res, src1); + gen_set_gpr(a->rd, load_val); + + tcg_temp_free(src1); + return true; +} + +static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, TCGMemOp mop) +{ + TCGv src1 = tcg_temp_new(); + TCGv src2 = tcg_temp_new(); + TCGv dat = tcg_temp_new(); + TCGLabel *l1 = gen_new_label(); + TCGLabel *l2 = gen_new_label(); + + gen_get_gpr(src1, a->rs1); + tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1); + + gen_get_gpr(src2, a->rs2); + /* + * Note that the TCG atomic primitives are SC, + * so we can ignore AQ/RL along this path. + */ + tcg_gen_atomic_cmpxchg_tl(src1, load_res, load_val, src2, + ctx->mem_idx, mop); + tcg_gen_setcond_tl(TCG_COND_NE, dat, src1, load_val); + gen_set_gpr(a->rd, dat); + tcg_gen_br(l2); + + gen_set_label(l1); + /* + * Address comparion failure. However, we still need to + * provide the memory barrier implied by AQ/RL. + */ + tcg_gen_mb(TCG_MO_ALL + a->aq * TCG_BAR_LDAQ + a->rl * TCG_BAR_STRL); + tcg_gen_movi_tl(dat, 1); + gen_set_gpr(a->rd, dat); + + gen_set_label(l2); + tcg_temp_free(dat); + tcg_temp_free(src1); + tcg_temp_free(src2); + return true; +} + +static bool gen_amo(DisasContext *ctx, arg_atomic *a, + void(*func)(TCGv, TCGv, TCGv, TCGArg, TCGMemOp), + TCGMemOp mop) +{ + TCGv src1 = tcg_temp_new(); + TCGv src2 = tcg_temp_new(); + + gen_get_gpr(src1, a->rs1); + gen_get_gpr(src2, a->rs2); + + (*func)(src2, src1, src2, ctx->mem_idx, mop); + + gen_set_gpr(a->rd, src2); + tcg_temp_free(src1); + tcg_temp_free(src2); + return true; +} + +static bool trans_lr_w(DisasContext *ctx, arg_lr_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_lr(ctx, a, (MO_ALIGN | MO_TESL)); +} + +static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_sc(ctx, a, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amoswap_w(DisasContext *ctx, arg_amoswap_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amoadd_w(DisasContext *ctx, arg_amoadd_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amoxor_w(DisasContext *ctx, arg_amoxor_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amoand_w(DisasContext *ctx, arg_amoand_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amoor_w(DisasContext *ctx, arg_amoor_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amomin_w(DisasContext *ctx, arg_amomin_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amomax_w(DisasContext *ctx, arg_amomax_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amominu_w(DisasContext *ctx, arg_amominu_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TESL)); +} + +static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a) +{ + REQUIRE_EXT(ctx, RVA); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL)); +} + +#ifdef TARGET_RISCV64 + +static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a) +{ + return gen_lr(ctx, a, MO_ALIGN | MO_TEQ); +} + +static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a) +{ + return gen_sc(ctx, a, (MO_ALIGN | MO_TEQ)); +} + +static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a) +{ + return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEQ)); +} + +static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a) +{ + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEQ)); +} + +static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a) +{ + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEQ)); +} + +static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a) +{ + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEQ)); +} + +static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a) +{ + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEQ)); +} + +static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a) +{ + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEQ)); +} + +static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a) +{ + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEQ)); +} + +static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a) +{ + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEQ)); +} + +static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a) +{ + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEQ)); +} +#endif diff --git a/target/riscv/insn_trans/trans_rvc.inc.c b/target/riscv/insn_trans/trans_rvc.inc.c new file mode 100644 index 0000000000..ebcd977b2f --- /dev/null +++ b/target/riscv/insn_trans/trans_rvc.inc.c @@ -0,0 +1,347 @@ +/* + * RISC-V translation routines for the RVC Compressed Instruction Set. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de + * Bastian Koppelmann, kbastian@mail.uni-paderborn.de + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +static bool trans_c_addi4spn(DisasContext *ctx, arg_c_addi4spn *a) +{ + if (a->nzuimm == 0) { + /* Reserved in ISA */ + return false; + } + arg_addi arg = { .rd = a->rd, .rs1 = 2, .imm = a->nzuimm }; + return trans_addi(ctx, &arg); +} + +static bool trans_c_fld(DisasContext *ctx, arg_c_fld *a) +{ + arg_fld arg = { .rd = a->rd, .rs1 = a->rs1, .imm = a->uimm }; + return trans_fld(ctx, &arg); +} + +static bool trans_c_lw(DisasContext *ctx, arg_c_lw *a) +{ + arg_lw arg = { .rd = a->rd, .rs1 = a->rs1, .imm = a->uimm }; + return trans_lw(ctx, &arg); +} + +static bool trans_c_flw_ld(DisasContext *ctx, arg_c_flw_ld *a) +{ +#ifdef TARGET_RISCV32 + /* C.FLW ( RV32FC-only ) */ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + arg_c_lw tmp; + decode_insn16_extract_cl_w(&tmp, ctx->opcode); + arg_flw arg = { .rd = tmp.rd, .rs1 = tmp.rs1, .imm = tmp.uimm }; + return trans_flw(ctx, &arg); +#else + /* C.LD ( RV64C/RV128C-only ) */ + arg_c_fld tmp; + decode_insn16_extract_cl_d(&tmp, ctx->opcode); + arg_ld arg = { .rd = tmp.rd, .rs1 = tmp.rs1, .imm = tmp.uimm }; + return trans_ld(ctx, &arg); +#endif +} + +static bool trans_c_fsd(DisasContext *ctx, arg_c_fsd *a) +{ + arg_fsd arg = { .rs1 = a->rs1, .rs2 = a->rs2, .imm = a->uimm }; + return trans_fsd(ctx, &arg); +} + +static bool trans_c_sw(DisasContext *ctx, arg_c_sw *a) +{ + arg_sw arg = { .rs1 = a->rs1, .rs2 = a->rs2, .imm = a->uimm }; + return trans_sw(ctx, &arg); +} + +static bool trans_c_fsw_sd(DisasContext *ctx, arg_c_fsw_sd *a) +{ +#ifdef TARGET_RISCV32 + /* C.FSW ( RV32FC-only ) */ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + arg_c_sw tmp; + decode_insn16_extract_cs_w(&tmp, ctx->opcode); + arg_fsw arg = { .rs1 = tmp.rs1, .rs2 = tmp.rs2, .imm = tmp.uimm }; + return trans_fsw(ctx, &arg); +#else + /* C.SD ( RV64C/RV128C-only ) */ + arg_c_fsd tmp; + decode_insn16_extract_cs_d(&tmp, ctx->opcode); + arg_sd arg = { .rs1 = tmp.rs1, .rs2 = tmp.rs2, .imm = tmp.uimm }; + return trans_sd(ctx, &arg); +#endif +} + +static bool trans_c_addi(DisasContext *ctx, arg_c_addi *a) +{ + if (a->imm == 0) { + /* Hint: insn is valid but does not affect state */ + return true; + } + arg_addi arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm }; + return trans_addi(ctx, &arg); +} + +static bool trans_c_jal_addiw(DisasContext *ctx, arg_c_jal_addiw *a) +{ +#ifdef TARGET_RISCV32 + /* C.JAL */ + arg_c_j tmp; + decode_insn16_extract_cj(&tmp, ctx->opcode); + arg_jal arg = { .rd = 1, .imm = tmp.imm }; + return trans_jal(ctx, &arg); +#else + /* C.ADDIW */ + arg_addiw arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm }; + return trans_addiw(ctx, &arg); +#endif +} + +static bool trans_c_li(DisasContext *ctx, arg_c_li *a) +{ + if (a->rd == 0) { + /* Hint: insn is valid but does not affect state */ + return true; + } + arg_addi arg = { .rd = a->rd, .rs1 = 0, .imm = a->imm }; + return trans_addi(ctx, &arg); +} + +static bool trans_c_addi16sp_lui(DisasContext *ctx, arg_c_addi16sp_lui *a) +{ + if (a->rd == 2) { + /* C.ADDI16SP */ + arg_addi arg = { .rd = 2, .rs1 = 2, .imm = a->imm_addi16sp }; + return trans_addi(ctx, &arg); + } else if (a->imm_lui != 0) { + /* C.LUI */ + if (a->rd == 0) { + /* Hint: insn is valid but does not affect state */ + return true; + } + arg_lui arg = { .rd = a->rd, .imm = a->imm_lui }; + return trans_lui(ctx, &arg); + } + return false; +} + +static bool trans_c_srli(DisasContext *ctx, arg_c_srli *a) +{ + int shamt = a->shamt; + if (shamt == 0) { + /* For RV128 a shamt of 0 means a shift by 64 */ + shamt = 64; + } + /* Ensure, that shamt[5] is zero for RV32 */ + if (shamt >= TARGET_LONG_BITS) { + return false; + } + + arg_srli arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt }; + return trans_srli(ctx, &arg); +} + +static bool trans_c_srai(DisasContext *ctx, arg_c_srai *a) +{ + int shamt = a->shamt; + if (shamt == 0) { + /* For RV128 a shamt of 0 means a shift by 64 */ + shamt = 64; + } + /* Ensure, that shamt[5] is zero for RV32 */ + if (shamt >= TARGET_LONG_BITS) { + return false; + } + + arg_srai arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt }; + return trans_srai(ctx, &arg); +} + +static bool trans_c_andi(DisasContext *ctx, arg_c_andi *a) +{ + arg_andi arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm }; + return trans_andi(ctx, &arg); +} + +static bool trans_c_sub(DisasContext *ctx, arg_c_sub *a) +{ + arg_sub arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; + return trans_sub(ctx, &arg); +} + +static bool trans_c_xor(DisasContext *ctx, arg_c_xor *a) +{ + arg_xor arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; + return trans_xor(ctx, &arg); +} + +static bool trans_c_or(DisasContext *ctx, arg_c_or *a) +{ + arg_or arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; + return trans_or(ctx, &arg); +} + +static bool trans_c_and(DisasContext *ctx, arg_c_and *a) +{ + arg_and arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; + return trans_and(ctx, &arg); +} + +static bool trans_c_subw(DisasContext *ctx, arg_c_subw *a) +{ +#ifdef TARGET_RISCV64 + arg_subw arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; + return trans_subw(ctx, &arg); +#else + return false; +#endif +} + +static bool trans_c_addw(DisasContext *ctx, arg_c_addw *a) +{ +#ifdef TARGET_RISCV64 + arg_addw arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; + return trans_addw(ctx, &arg); +#else + return false; +#endif +} + +static bool trans_c_j(DisasContext *ctx, arg_c_j *a) +{ + arg_jal arg = { .rd = 0, .imm = a->imm }; + return trans_jal(ctx, &arg); +} + +static bool trans_c_beqz(DisasContext *ctx, arg_c_beqz *a) +{ + arg_beq arg = { .rs1 = a->rs1, .rs2 = 0, .imm = a->imm }; + return trans_beq(ctx, &arg); +} + +static bool trans_c_bnez(DisasContext *ctx, arg_c_bnez *a) +{ + arg_bne arg = { .rs1 = a->rs1, .rs2 = 0, .imm = a->imm }; + return trans_bne(ctx, &arg); +} + +static bool trans_c_slli(DisasContext *ctx, arg_c_slli *a) +{ + int shamt = a->shamt; + if (shamt == 0) { + /* For RV128 a shamt of 0 means a shift by 64 */ + shamt = 64; + } + /* Ensure, that shamt[5] is zero for RV32 */ + if (shamt >= TARGET_LONG_BITS) { + return false; + } + + arg_slli arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt }; + return trans_slli(ctx, &arg); +} + +static bool trans_c_fldsp(DisasContext *ctx, arg_c_fldsp *a) +{ + arg_fld arg = { .rd = a->rd, .rs1 = 2, .imm = a->uimm }; + return trans_fld(ctx, &arg); +} + +static bool trans_c_lwsp(DisasContext *ctx, arg_c_lwsp *a) +{ + arg_lw arg = { .rd = a->rd, .rs1 = 2, .imm = a->uimm }; + return trans_lw(ctx, &arg); +} + +static bool trans_c_flwsp_ldsp(DisasContext *ctx, arg_c_flwsp_ldsp *a) +{ +#ifdef TARGET_RISCV32 + /* C.FLWSP */ + arg_flw arg_flw = { .rd = a->rd, .rs1 = 2, .imm = a->uimm_flwsp }; + return trans_flw(ctx, &arg_flw); +#else + /* C.LDSP */ + arg_ld arg_ld = { .rd = a->rd, .rs1 = 2, .imm = a->uimm_ldsp }; + return trans_ld(ctx, &arg_ld); +#endif + return false; +} + +static bool trans_c_jr_mv(DisasContext *ctx, arg_c_jr_mv *a) +{ + if (a->rd != 0 && a->rs2 == 0) { + /* C.JR */ + arg_jalr arg = { .rd = 0, .rs1 = a->rd, .imm = 0 }; + return trans_jalr(ctx, &arg); + } else if (a->rd != 0 && a->rs2 != 0) { + /* C.MV */ + arg_add arg = { .rd = a->rd, .rs1 = 0, .rs2 = a->rs2 }; + return trans_add(ctx, &arg); + } + return false; +} + +static bool trans_c_ebreak_jalr_add(DisasContext *ctx, arg_c_ebreak_jalr_add *a) +{ + if (a->rd == 0 && a->rs2 == 0) { + /* C.EBREAK */ + arg_ebreak arg = { }; + return trans_ebreak(ctx, &arg); + } else if (a->rd != 0) { + if (a->rs2 == 0) { + /* C.JALR */ + arg_jalr arg = { .rd = 1, .rs1 = a->rd, .imm = 0 }; + return trans_jalr(ctx, &arg); + } else { + /* C.ADD */ + arg_add arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 }; + return trans_add(ctx, &arg); + } + } + return false; +} + +static bool trans_c_fsdsp(DisasContext *ctx, arg_c_fsdsp *a) +{ + arg_fsd arg = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm }; + return trans_fsd(ctx, &arg); +} + +static bool trans_c_swsp(DisasContext *ctx, arg_c_swsp *a) +{ + arg_sw arg = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm }; + return trans_sw(ctx, &arg); +} + +static bool trans_c_fswsp_sdsp(DisasContext *ctx, arg_c_fswsp_sdsp *a) +{ +#ifdef TARGET_RISCV32 + /* C.FSWSP */ + arg_fsw a_fsw = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm_fswsp }; + return trans_fsw(ctx, &a_fsw); +#else + /* C.SDSP */ + arg_sd a_sd = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm_sdsp }; + return trans_sd(ctx, &a_sd); +#endif +} diff --git a/target/riscv/insn_trans/trans_rvd.inc.c b/target/riscv/insn_trans/trans_rvd.inc.c new file mode 100644 index 0000000000..393fa0248c --- /dev/null +++ b/target/riscv/insn_trans/trans_rvd.inc.c @@ -0,0 +1,442 @@ +/* + * RISC-V translation routines for the RV64D Standard Extension. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de + * Bastian Koppelmann, kbastian@mail.uni-paderborn.de + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +static bool trans_fld(DisasContext *ctx, arg_fld *a) +{ + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + tcg_gen_addi_tl(t0, t0, a->imm); + + tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEQ); + + mark_fs_dirty(ctx); + tcg_temp_free(t0); + return true; +} + +static bool trans_fsd(DisasContext *ctx, arg_fsd *a) +{ + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + tcg_gen_addi_tl(t0, t0, a->imm); + + tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEQ); + + mark_fs_dirty(ctx); + tcg_temp_free(t0); + return true; +} + +static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + gen_set_rm(ctx, a->rm); + gen_helper_fmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], + cpu_fpr[a->rs2], cpu_fpr[a->rs3]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + gen_set_rm(ctx, a->rm); + gen_helper_fmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], + cpu_fpr[a->rs2], cpu_fpr[a->rs3]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + gen_set_rm(ctx, a->rm); + gen_helper_fnmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], + cpu_fpr[a->rs2], cpu_fpr[a->rs3]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + gen_set_rm(ctx, a->rm); + gen_helper_fnmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], + cpu_fpr[a->rs2], cpu_fpr[a->rs3]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + gen_set_rm(ctx, a->rm); + gen_helper_fadd_d(cpu_fpr[a->rd], cpu_env, + cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + gen_set_rm(ctx, a->rm); + gen_helper_fsub_d(cpu_fpr[a->rd], cpu_env, + cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + gen_set_rm(ctx, a->rm); + gen_helper_fmul_d(cpu_fpr[a->rd], cpu_env, + cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + gen_set_rm(ctx, a->rm); + gen_helper_fdiv_d(cpu_fpr[a->rd], cpu_env, + cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + gen_set_rm(ctx, a->rm); + gen_helper_fsqrt_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); + + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fsgnj_d(DisasContext *ctx, arg_fsgnj_d *a) +{ + if (a->rs1 == a->rs2) { /* FMOV */ + tcg_gen_mov_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1]); + } else { + tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rs2], + cpu_fpr[a->rs1], 0, 63); + } + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fsgnjn_d(DisasContext *ctx, arg_fsgnjn_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + if (a->rs1 == a->rs2) { /* FNEG */ + tcg_gen_xori_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], INT64_MIN); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_not_i64(t0, cpu_fpr[a->rs2]); + tcg_gen_deposit_i64(cpu_fpr[a->rd], t0, cpu_fpr[a->rs1], 0, 63); + tcg_temp_free_i64(t0); + } + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fsgnjx_d(DisasContext *ctx, arg_fsgnjx_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + if (a->rs1 == a->rs2) { /* FABS */ + tcg_gen_andi_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], ~INT64_MIN); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_andi_i64(t0, cpu_fpr[a->rs2], INT64_MIN); + tcg_gen_xor_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], t0); + tcg_temp_free_i64(t0); + } + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + gen_helper_fmin_d(cpu_fpr[a->rd], cpu_env, + cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + gen_helper_fmax_d(cpu_fpr[a->rd], cpu_env, + cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_s_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); + + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_d_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); + + mark_fs_dirty(ctx); + return true; +} + +static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_helper_feq_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + + return true; +} + +static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_helper_flt_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + + return true; +} + +static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_helper_fle_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + + return true; +} + +static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_helper_fclass_d(t0, cpu_fpr[a->rs1]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + return true; +} + +static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_w_d(t0, cpu_env, cpu_fpr[a->rs1]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + + return true; +} + +static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_wu_d(t0, cpu_env, cpu_fpr[a->rs1]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + + return true; +} + +static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_d_w(cpu_fpr[a->rd], cpu_env, t0); + tcg_temp_free(t0); + + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_d_wu(cpu_fpr[a->rd], cpu_env, t0); + tcg_temp_free(t0); + + mark_fs_dirty(ctx); + return true; +} + +#ifdef TARGET_RISCV64 + +static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_l_d(t0, cpu_env, cpu_fpr[a->rs1]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + return true; +} + +static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_lu_d(t0, cpu_env, cpu_fpr[a->rs1]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + return true; +} + +static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + gen_set_gpr(a->rd, cpu_fpr[a->rs1]); + return true; +} + +static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_d_l(cpu_fpr[a->rd], cpu_env, t0); + tcg_temp_free(t0); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_d_lu(cpu_fpr[a->rd], cpu_env, t0); + tcg_temp_free(t0); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + + tcg_gen_mov_tl(cpu_fpr[a->rd], t0); + tcg_temp_free(t0); + mark_fs_dirty(ctx); + return true; +} +#endif diff --git a/target/riscv/insn_trans/trans_rvf.inc.c b/target/riscv/insn_trans/trans_rvf.inc.c new file mode 100644 index 0000000000..172dbfa919 --- /dev/null +++ b/target/riscv/insn_trans/trans_rvf.inc.c @@ -0,0 +1,439 @@ +/* + * RISC-V translation routines for the RV64F Standard Extension. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de + * Bastian Koppelmann, kbastian@mail.uni-paderborn.de + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define REQUIRE_FPU do {\ + if (ctx->mstatus_fs == 0) \ + return false; \ +} while (0) + +static bool trans_flw(DisasContext *ctx, arg_flw *a) +{ + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + tcg_gen_addi_tl(t0, t0, a->imm); + + tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEUL); + /* RISC-V requires NaN-boxing of narrower width floating point values */ + tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 0xffffffff00000000ULL); + + tcg_temp_free(t0); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fsw(DisasContext *ctx, arg_fsw *a) +{ + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + tcg_gen_addi_tl(t0, t0, a->imm); + + tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEUL); + + tcg_temp_free(t0); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fmadd_s(DisasContext *ctx, arg_fmadd_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + gen_set_rm(ctx, a->rm); + gen_helper_fmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], + cpu_fpr[a->rs2], cpu_fpr[a->rs3]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fmsub_s(DisasContext *ctx, arg_fmsub_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + gen_set_rm(ctx, a->rm); + gen_helper_fmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], + cpu_fpr[a->rs2], cpu_fpr[a->rs3]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fnmsub_s(DisasContext *ctx, arg_fnmsub_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + gen_set_rm(ctx, a->rm); + gen_helper_fnmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], + cpu_fpr[a->rs2], cpu_fpr[a->rs3]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fnmadd_s(DisasContext *ctx, arg_fnmadd_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + gen_set_rm(ctx, a->rm); + gen_helper_fnmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], + cpu_fpr[a->rs2], cpu_fpr[a->rs3]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + gen_set_rm(ctx, a->rm); + gen_helper_fadd_s(cpu_fpr[a->rd], cpu_env, + cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + gen_set_rm(ctx, a->rm); + gen_helper_fsub_s(cpu_fpr[a->rd], cpu_env, + cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + gen_set_rm(ctx, a->rm); + gen_helper_fmul_s(cpu_fpr[a->rd], cpu_env, + cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + gen_set_rm(ctx, a->rm); + gen_helper_fdiv_s(cpu_fpr[a->rd], cpu_env, + cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + gen_set_rm(ctx, a->rm); + gen_helper_fsqrt_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fsgnj_s(DisasContext *ctx, arg_fsgnj_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + if (a->rs1 == a->rs2) { /* FMOV */ + tcg_gen_mov_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1]); + } else { /* FSGNJ */ + tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rs2], cpu_fpr[a->rs1], + 0, 31); + } + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fsgnjn_s(DisasContext *ctx, arg_fsgnjn_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + if (a->rs1 == a->rs2) { /* FNEG */ + tcg_gen_xori_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], INT32_MIN); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_not_i64(t0, cpu_fpr[a->rs2]); + tcg_gen_deposit_i64(cpu_fpr[a->rd], t0, cpu_fpr[a->rs1], 0, 31); + tcg_temp_free_i64(t0); + } + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fsgnjx_s(DisasContext *ctx, arg_fsgnjx_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + if (a->rs1 == a->rs2) { /* FABS */ + tcg_gen_andi_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], ~INT32_MIN); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_andi_i64(t0, cpu_fpr[a->rs2], INT32_MIN); + tcg_gen_xor_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], t0); + tcg_temp_free_i64(t0); + } + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + gen_helper_fmin_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], + cpu_fpr[a->rs2]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + gen_helper_fmax_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], + cpu_fpr[a->rs2]); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_fcvt_w_s(DisasContext *ctx, arg_fcvt_w_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + TCGv t0 = tcg_temp_new(); + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_w_s(t0, cpu_env, cpu_fpr[a->rs1]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + + return true; +} + +static bool trans_fcvt_wu_s(DisasContext *ctx, arg_fcvt_wu_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + TCGv t0 = tcg_temp_new(); + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_wu_s(t0, cpu_env, cpu_fpr[a->rs1]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + + return true; +} + +static bool trans_fmv_x_w(DisasContext *ctx, arg_fmv_x_w *a) +{ + /* NOTE: This was FMV.X.S in an earlier version of the ISA spec! */ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + TCGv t0 = tcg_temp_new(); + +#if defined(TARGET_RISCV64) + tcg_gen_ext32s_tl(t0, cpu_fpr[a->rs1]); +#else + tcg_gen_extrl_i64_i32(t0, cpu_fpr[a->rs1]); +#endif + + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + + return true; +} + +static bool trans_feq_s(DisasContext *ctx, arg_feq_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + TCGv t0 = tcg_temp_new(); + gen_helper_feq_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + return true; +} + +static bool trans_flt_s(DisasContext *ctx, arg_flt_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + TCGv t0 = tcg_temp_new(); + gen_helper_flt_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + return true; +} + +static bool trans_fle_s(DisasContext *ctx, arg_fle_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + TCGv t0 = tcg_temp_new(); + gen_helper_fle_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + return true; +} + +static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + TCGv t0 = tcg_temp_new(); + + gen_helper_fclass_s(t0, cpu_fpr[a->rs1]); + + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + + return true; +} + +static bool trans_fcvt_s_w(DisasContext *ctx, arg_fcvt_s_w *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_s_w(cpu_fpr[a->rd], cpu_env, t0); + + mark_fs_dirty(ctx); + tcg_temp_free(t0); + + return true; +} + +static bool trans_fcvt_s_wu(DisasContext *ctx, arg_fcvt_s_wu *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_s_wu(cpu_fpr[a->rd], cpu_env, t0); + + mark_fs_dirty(ctx); + tcg_temp_free(t0); + + return true; +} + +static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a) +{ + /* NOTE: This was FMV.S.X in an earlier version of the ISA spec! */ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + +#if defined(TARGET_RISCV64) + tcg_gen_mov_i64(cpu_fpr[a->rd], t0); +#else + tcg_gen_extu_i32_i64(cpu_fpr[a->rd], t0); +#endif + + mark_fs_dirty(ctx); + tcg_temp_free(t0); + + return true; +} + +#ifdef TARGET_RISCV64 +static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + TCGv t0 = tcg_temp_new(); + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_l_s(t0, cpu_env, cpu_fpr[a->rs1]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + return true; +} + +static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + TCGv t0 = tcg_temp_new(); + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_lu_s(t0, cpu_env, cpu_fpr[a->rs1]); + gen_set_gpr(a->rd, t0); + tcg_temp_free(t0); + return true; +} + +static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_s_l(cpu_fpr[a->rd], cpu_env, t0); + + mark_fs_dirty(ctx); + tcg_temp_free(t0); + return true; +} + +static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a) +{ + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + + TCGv t0 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + + gen_set_rm(ctx, a->rm); + gen_helper_fcvt_s_lu(cpu_fpr[a->rd], cpu_env, t0); + + mark_fs_dirty(ctx); + tcg_temp_free(t0); + return true; +} +#endif diff --git a/target/riscv/insn_trans/trans_rvi.inc.c b/target/riscv/insn_trans/trans_rvi.inc.c new file mode 100644 index 0000000000..d420a4d8b2 --- /dev/null +++ b/target/riscv/insn_trans/trans_rvi.inc.c @@ -0,0 +1,568 @@ +/* + * RISC-V translation routines for the RVXI Base Integer Instruction Set. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de + * Bastian Koppelmann, kbastian@mail.uni-paderborn.de + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +static bool trans_lui(DisasContext *ctx, arg_lui *a) +{ + if (a->rd != 0) { + tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm); + } + return true; +} + +static bool trans_auipc(DisasContext *ctx, arg_auipc *a) +{ + if (a->rd != 0) { + tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm + ctx->base.pc_next); + } + return true; +} + +static bool trans_jal(DisasContext *ctx, arg_jal *a) +{ + gen_jal(ctx, a->rd, a->imm); + return true; +} + +static bool trans_jalr(DisasContext *ctx, arg_jalr *a) +{ + /* no chaining with JALR */ + TCGLabel *misaligned = NULL; + TCGv t0 = tcg_temp_new(); + + + gen_get_gpr(cpu_pc, a->rs1); + tcg_gen_addi_tl(cpu_pc, cpu_pc, a->imm); + tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2); + + if (!has_ext(ctx, RVC)) { + misaligned = gen_new_label(); + tcg_gen_andi_tl(t0, cpu_pc, 0x2); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned); + } + + if (a->rd != 0) { + tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn); + } + tcg_gen_lookup_and_goto_ptr(); + + if (misaligned) { + gen_set_label(misaligned); + gen_exception_inst_addr_mis(ctx); + } + ctx->base.is_jmp = DISAS_NORETURN; + + tcg_temp_free(t0); + return true; +} + +static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond) +{ + TCGLabel *l = gen_new_label(); + TCGv source1, source2; + source1 = tcg_temp_new(); + source2 = tcg_temp_new(); + gen_get_gpr(source1, a->rs1); + gen_get_gpr(source2, a->rs2); + + tcg_gen_brcond_tl(cond, source1, source2, l); + gen_goto_tb(ctx, 1, ctx->pc_succ_insn); + gen_set_label(l); /* branch taken */ + + if (!has_ext(ctx, RVC) && ((ctx->base.pc_next + a->imm) & 0x3)) { + /* misaligned */ + gen_exception_inst_addr_mis(ctx); + } else { + gen_goto_tb(ctx, 0, ctx->base.pc_next + a->imm); + } + ctx->base.is_jmp = DISAS_NORETURN; + + tcg_temp_free(source1); + tcg_temp_free(source2); + + return true; +} + +static bool trans_beq(DisasContext *ctx, arg_beq *a) +{ + return gen_branch(ctx, a, TCG_COND_EQ); +} + +static bool trans_bne(DisasContext *ctx, arg_bne *a) +{ + return gen_branch(ctx, a, TCG_COND_NE); +} + +static bool trans_blt(DisasContext *ctx, arg_blt *a) +{ + return gen_branch(ctx, a, TCG_COND_LT); +} + +static bool trans_bge(DisasContext *ctx, arg_bge *a) +{ + return gen_branch(ctx, a, TCG_COND_GE); +} + +static bool trans_bltu(DisasContext *ctx, arg_bltu *a) +{ + return gen_branch(ctx, a, TCG_COND_LTU); +} + +static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a) +{ + return gen_branch(ctx, a, TCG_COND_GEU); +} + +static bool gen_load(DisasContext *ctx, arg_lb *a, TCGMemOp memop) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + tcg_gen_addi_tl(t0, t0, a->imm); + + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, memop); + gen_set_gpr(a->rd, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_lb(DisasContext *ctx, arg_lb *a) +{ + return gen_load(ctx, a, MO_SB); +} + +static bool trans_lh(DisasContext *ctx, arg_lh *a) +{ + return gen_load(ctx, a, MO_TESW); +} + +static bool trans_lw(DisasContext *ctx, arg_lw *a) +{ + return gen_load(ctx, a, MO_TESL); +} + +static bool trans_lbu(DisasContext *ctx, arg_lbu *a) +{ + return gen_load(ctx, a, MO_UB); +} + +static bool trans_lhu(DisasContext *ctx, arg_lhu *a) +{ + return gen_load(ctx, a, MO_TEUW); +} + +static bool gen_store(DisasContext *ctx, arg_sb *a, TCGMemOp memop) +{ + TCGv t0 = tcg_temp_new(); + TCGv dat = tcg_temp_new(); + gen_get_gpr(t0, a->rs1); + tcg_gen_addi_tl(t0, t0, a->imm); + gen_get_gpr(dat, a->rs2); + + tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx, memop); + tcg_temp_free(t0); + tcg_temp_free(dat); + return true; +} + + +static bool trans_sb(DisasContext *ctx, arg_sb *a) +{ + return gen_store(ctx, a, MO_SB); +} + +static bool trans_sh(DisasContext *ctx, arg_sh *a) +{ + return gen_store(ctx, a, MO_TESW); +} + +static bool trans_sw(DisasContext *ctx, arg_sw *a) +{ + return gen_store(ctx, a, MO_TESL); +} + +#ifdef TARGET_RISCV64 +static bool trans_lwu(DisasContext *ctx, arg_lwu *a) +{ + return gen_load(ctx, a, MO_TEUL); +} + +static bool trans_ld(DisasContext *ctx, arg_ld *a) +{ + return gen_load(ctx, a, MO_TEQ); +} + +static bool trans_sd(DisasContext *ctx, arg_sd *a) +{ + return gen_store(ctx, a, MO_TEQ); +} +#endif + +static bool trans_addi(DisasContext *ctx, arg_addi *a) +{ + return gen_arith_imm(ctx, a, &tcg_gen_add_tl); +} + +static void gen_slt(TCGv ret, TCGv s1, TCGv s2) +{ + tcg_gen_setcond_tl(TCG_COND_LT, ret, s1, s2); +} + +static void gen_sltu(TCGv ret, TCGv s1, TCGv s2) +{ + tcg_gen_setcond_tl(TCG_COND_LTU, ret, s1, s2); +} + + +static bool trans_slti(DisasContext *ctx, arg_slti *a) +{ + return gen_arith_imm(ctx, a, &gen_slt); +} + +static bool trans_sltiu(DisasContext *ctx, arg_sltiu *a) +{ + return gen_arith_imm(ctx, a, &gen_sltu); +} + +static bool trans_xori(DisasContext *ctx, arg_xori *a) +{ + return gen_arith_imm(ctx, a, &tcg_gen_xor_tl); +} +static bool trans_ori(DisasContext *ctx, arg_ori *a) +{ + return gen_arith_imm(ctx, a, &tcg_gen_or_tl); +} +static bool trans_andi(DisasContext *ctx, arg_andi *a) +{ + return gen_arith_imm(ctx, a, &tcg_gen_and_tl); +} +static bool trans_slli(DisasContext *ctx, arg_slli *a) +{ + if (a->shamt >= TARGET_LONG_BITS) { + return false; + } + + if (a->rd != 0) { + TCGv t = tcg_temp_new(); + gen_get_gpr(t, a->rs1); + + tcg_gen_shli_tl(t, t, a->shamt); + + gen_set_gpr(a->rd, t); + tcg_temp_free(t); + } /* NOP otherwise */ + return true; +} + +static bool trans_srli(DisasContext *ctx, arg_srli *a) +{ + if (a->shamt >= TARGET_LONG_BITS) { + return false; + } + + if (a->rd != 0) { + TCGv t = tcg_temp_new(); + gen_get_gpr(t, a->rs1); + + tcg_gen_shri_tl(t, t, a->shamt); + gen_set_gpr(a->rd, t); + tcg_temp_free(t); + } /* NOP otherwise */ + return true; +} + +static bool trans_srai(DisasContext *ctx, arg_srai *a) +{ + if (a->shamt >= TARGET_LONG_BITS) { + return false; + } + + if (a->rd != 0) { + TCGv t = tcg_temp_new(); + gen_get_gpr(t, a->rs1); + + tcg_gen_sari_tl(t, t, a->shamt); + gen_set_gpr(a->rd, t); + tcg_temp_free(t); + } /* NOP otherwise */ + return true; +} + +static bool trans_add(DisasContext *ctx, arg_add *a) +{ + return gen_arith(ctx, a, &tcg_gen_add_tl); +} + +static bool trans_sub(DisasContext *ctx, arg_sub *a) +{ + return gen_arith(ctx, a, &tcg_gen_sub_tl); +} + +static bool trans_sll(DisasContext *ctx, arg_sll *a) +{ + return gen_shift(ctx, a, &tcg_gen_shl_tl); +} + +static bool trans_slt(DisasContext *ctx, arg_slt *a) +{ + return gen_arith(ctx, a, &gen_slt); +} + +static bool trans_sltu(DisasContext *ctx, arg_sltu *a) +{ + return gen_arith(ctx, a, &gen_sltu); +} + +static bool trans_xor(DisasContext *ctx, arg_xor *a) +{ + return gen_arith(ctx, a, &tcg_gen_xor_tl); +} + +static bool trans_srl(DisasContext *ctx, arg_srl *a) +{ + return gen_shift(ctx, a, &tcg_gen_shr_tl); +} + +static bool trans_sra(DisasContext *ctx, arg_sra *a) +{ + return gen_shift(ctx, a, &tcg_gen_sar_tl); +} + +static bool trans_or(DisasContext *ctx, arg_or *a) +{ + return gen_arith(ctx, a, &tcg_gen_or_tl); +} + +static bool trans_and(DisasContext *ctx, arg_and *a) +{ + return gen_arith(ctx, a, &tcg_gen_and_tl); +} + +#ifdef TARGET_RISCV64 +static bool trans_addiw(DisasContext *ctx, arg_addiw *a) +{ + return gen_arith_imm(ctx, a, &gen_addw); +} + +static bool trans_slliw(DisasContext *ctx, arg_slliw *a) +{ + TCGv source1; + source1 = tcg_temp_new(); + gen_get_gpr(source1, a->rs1); + + tcg_gen_shli_tl(source1, source1, a->shamt); + tcg_gen_ext32s_tl(source1, source1); + gen_set_gpr(a->rd, source1); + + tcg_temp_free(source1); + return true; +} + +static bool trans_srliw(DisasContext *ctx, arg_srliw *a) +{ + TCGv t = tcg_temp_new(); + gen_get_gpr(t, a->rs1); + tcg_gen_extract_tl(t, t, a->shamt, 32 - a->shamt); + /* sign-extend for W instructions */ + tcg_gen_ext32s_tl(t, t); + gen_set_gpr(a->rd, t); + tcg_temp_free(t); + return true; +} + +static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a) +{ + TCGv t = tcg_temp_new(); + gen_get_gpr(t, a->rs1); + tcg_gen_sextract_tl(t, t, a->shamt, 32 - a->shamt); + gen_set_gpr(a->rd, t); + tcg_temp_free(t); + return true; +} + +static bool trans_addw(DisasContext *ctx, arg_addw *a) +{ + return gen_arith(ctx, a, &gen_addw); +} + +static bool trans_subw(DisasContext *ctx, arg_subw *a) +{ + return gen_arith(ctx, a, &gen_subw); +} + +static bool trans_sllw(DisasContext *ctx, arg_sllw *a) +{ + TCGv source1 = tcg_temp_new(); + TCGv source2 = tcg_temp_new(); + + gen_get_gpr(source1, a->rs1); + gen_get_gpr(source2, a->rs2); + + tcg_gen_andi_tl(source2, source2, 0x1F); + tcg_gen_shl_tl(source1, source1, source2); + + tcg_gen_ext32s_tl(source1, source1); + gen_set_gpr(a->rd, source1); + tcg_temp_free(source1); + tcg_temp_free(source2); + return true; +} + +static bool trans_srlw(DisasContext *ctx, arg_srlw *a) +{ + TCGv source1 = tcg_temp_new(); + TCGv source2 = tcg_temp_new(); + + gen_get_gpr(source1, a->rs1); + gen_get_gpr(source2, a->rs2); + + /* clear upper 32 */ + tcg_gen_ext32u_tl(source1, source1); + tcg_gen_andi_tl(source2, source2, 0x1F); + tcg_gen_shr_tl(source1, source1, source2); + + tcg_gen_ext32s_tl(source1, source1); + gen_set_gpr(a->rd, source1); + tcg_temp_free(source1); + tcg_temp_free(source2); + return true; +} + +static bool trans_sraw(DisasContext *ctx, arg_sraw *a) +{ + TCGv source1 = tcg_temp_new(); + TCGv source2 = tcg_temp_new(); + + gen_get_gpr(source1, a->rs1); + gen_get_gpr(source2, a->rs2); + + /* + * first, trick to get it to act like working on 32 bits (get rid of + * upper 32, sign extend to fill space) + */ + tcg_gen_ext32s_tl(source1, source1); + tcg_gen_andi_tl(source2, source2, 0x1F); + tcg_gen_sar_tl(source1, source1, source2); + + gen_set_gpr(a->rd, source1); + tcg_temp_free(source1); + tcg_temp_free(source2); + + return true; +} +#endif + +static bool trans_fence(DisasContext *ctx, arg_fence *a) +{ + /* FENCE is a full memory barrier. */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); + return true; +} + +static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a) +{ + /* + * FENCE_I is a no-op in QEMU, + * however we need to end the translation block + */ + tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); + tcg_gen_exit_tb(NULL, 0); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} + +#define RISCV_OP_CSR_PRE do {\ + source1 = tcg_temp_new(); \ + csr_store = tcg_temp_new(); \ + dest = tcg_temp_new(); \ + rs1_pass = tcg_temp_new(); \ + gen_get_gpr(source1, a->rs1); \ + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); \ + tcg_gen_movi_tl(rs1_pass, a->rs1); \ + tcg_gen_movi_tl(csr_store, a->csr); \ + gen_io_start();\ +} while (0) + +#define RISCV_OP_CSR_POST do {\ + gen_io_end(); \ + gen_set_gpr(a->rd, dest); \ + tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \ + tcg_gen_exit_tb(NULL, 0); \ + ctx->base.is_jmp = DISAS_NORETURN; \ + tcg_temp_free(source1); \ + tcg_temp_free(csr_store); \ + tcg_temp_free(dest); \ + tcg_temp_free(rs1_pass); \ +} while (0) + + +static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a) +{ + TCGv source1, csr_store, dest, rs1_pass; + RISCV_OP_CSR_PRE; + gen_helper_csrrw(dest, cpu_env, source1, csr_store); + RISCV_OP_CSR_POST; + return true; +} + +static bool trans_csrrs(DisasContext *ctx, arg_csrrs *a) +{ + TCGv source1, csr_store, dest, rs1_pass; + RISCV_OP_CSR_PRE; + gen_helper_csrrs(dest, cpu_env, source1, csr_store, rs1_pass); + RISCV_OP_CSR_POST; + return true; +} + +static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a) +{ + TCGv source1, csr_store, dest, rs1_pass; + RISCV_OP_CSR_PRE; + gen_helper_csrrc(dest, cpu_env, source1, csr_store, rs1_pass); + RISCV_OP_CSR_POST; + return true; +} + +static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a) +{ + TCGv source1, csr_store, dest, rs1_pass; + RISCV_OP_CSR_PRE; + gen_helper_csrrw(dest, cpu_env, rs1_pass, csr_store); + RISCV_OP_CSR_POST; + return true; +} + +static bool trans_csrrsi(DisasContext *ctx, arg_csrrsi *a) +{ + TCGv source1, csr_store, dest, rs1_pass; + RISCV_OP_CSR_PRE; + gen_helper_csrrs(dest, cpu_env, rs1_pass, csr_store, rs1_pass); + RISCV_OP_CSR_POST; + return true; +} + +static bool trans_csrrci(DisasContext *ctx, arg_csrrci *a) +{ + TCGv source1, csr_store, dest, rs1_pass; + RISCV_OP_CSR_PRE; + gen_helper_csrrc(dest, cpu_env, rs1_pass, csr_store, rs1_pass); + RISCV_OP_CSR_POST; + return true; +} diff --git a/target/riscv/insn_trans/trans_rvm.inc.c b/target/riscv/insn_trans/trans_rvm.inc.c new file mode 100644 index 0000000000..47cd6edc72 --- /dev/null +++ b/target/riscv/insn_trans/trans_rvm.inc.c @@ -0,0 +1,120 @@ +/* + * RISC-V translation routines for the RV64M Standard Extension. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de + * Bastian Koppelmann, kbastian@mail.uni-paderborn.de + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +static bool trans_mul(DisasContext *ctx, arg_mul *a) +{ + REQUIRE_EXT(ctx, RVM); + return gen_arith(ctx, a, &tcg_gen_mul_tl); +} + +static bool trans_mulh(DisasContext *ctx, arg_mulh *a) +{ + REQUIRE_EXT(ctx, RVM); + TCGv source1 = tcg_temp_new(); + TCGv source2 = tcg_temp_new(); + gen_get_gpr(source1, a->rs1); + gen_get_gpr(source2, a->rs2); + + tcg_gen_muls2_tl(source2, source1, source1, source2); + + gen_set_gpr(a->rd, source1); + tcg_temp_free(source1); + tcg_temp_free(source2); + return true; +} + +static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a) +{ + REQUIRE_EXT(ctx, RVM); + return gen_arith(ctx, a, &gen_mulhsu); +} + +static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a) +{ + REQUIRE_EXT(ctx, RVM); + TCGv source1 = tcg_temp_new(); + TCGv source2 = tcg_temp_new(); + gen_get_gpr(source1, a->rs1); + gen_get_gpr(source2, a->rs2); + + tcg_gen_mulu2_tl(source2, source1, source1, source2); + + gen_set_gpr(a->rd, source1); + tcg_temp_free(source1); + tcg_temp_free(source2); + return true; +} + +static bool trans_div(DisasContext *ctx, arg_div *a) +{ + REQUIRE_EXT(ctx, RVM); + return gen_arith(ctx, a, &gen_div); +} + +static bool trans_divu(DisasContext *ctx, arg_divu *a) +{ + REQUIRE_EXT(ctx, RVM); + return gen_arith(ctx, a, &gen_divu); +} + +static bool trans_rem(DisasContext *ctx, arg_rem *a) +{ + REQUIRE_EXT(ctx, RVM); + return gen_arith(ctx, a, &gen_rem); +} + +static bool trans_remu(DisasContext *ctx, arg_remu *a) +{ + REQUIRE_EXT(ctx, RVM); + return gen_arith(ctx, a, &gen_remu); +} + +#ifdef TARGET_RISCV64 +static bool trans_mulw(DisasContext *ctx, arg_mulw *a) +{ + REQUIRE_EXT(ctx, RVM); + return gen_arith(ctx, a, &gen_mulw); +} + +static bool trans_divw(DisasContext *ctx, arg_divw *a) +{ + REQUIRE_EXT(ctx, RVM); + return gen_arith_div_w(ctx, a, &gen_div); +} + +static bool trans_divuw(DisasContext *ctx, arg_divuw *a) +{ + REQUIRE_EXT(ctx, RVM); + return gen_arith_div_uw(ctx, a, &gen_divu); +} + +static bool trans_remw(DisasContext *ctx, arg_remw *a) +{ + REQUIRE_EXT(ctx, RVM); + return gen_arith_div_w(ctx, a, &gen_rem); +} + +static bool trans_remuw(DisasContext *ctx, arg_remuw *a) +{ + REQUIRE_EXT(ctx, RVM); + return gen_arith_div_uw(ctx, a, &gen_remu); +} +#endif diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 15a5366616..b11c4ae22f 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -113,10 +113,11 @@ static void pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) env->pmp_state.pmp[pmp_index].cfg_reg = val; pmp_update_rule(env, pmp_index); } else { - PMP_DEBUG("ignoring write - locked"); + qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n"); } } else { - PMP_DEBUG("ignoring write - out of bounds"); + qemu_log_mask(LOG_GUEST_ERROR, + "ignoring pmpcfg write - out of bounds\n"); } } @@ -249,7 +250,8 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, /* partially inside */ if ((s + e) == 1) { - PMP_DEBUG("pmp violation - access is partially inside"); + qemu_log_mask(LOG_GUEST_ERROR, + "pmp violation - access is partially inside\n"); ret = 0; break; } @@ -306,7 +308,8 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index, env->mhartid, reg_index, val); if ((reg_index & 1) && (sizeof(target_ulong) == 8)) { - PMP_DEBUG("ignoring write - incorrect address"); + qemu_log_mask(LOG_GUEST_ERROR, + "ignoring pmpcfg write - incorrect address\n"); return; } @@ -353,10 +356,12 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, env->pmp_state.pmp[addr_index].addr_reg = val; pmp_update_rule(env, addr_index); } else { - PMP_DEBUG("ignoring write - locked"); + qemu_log_mask(LOG_GUEST_ERROR, + "ignoring pmpaddr write - locked\n"); } } else { - PMP_DEBUG("ignoring write - out of bounds"); + qemu_log_mask(LOG_GUEST_ERROR, + "ignoring pmpaddr write - out of bounds\n"); } } @@ -372,7 +377,8 @@ target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index) if (addr_index < MAX_RISCV_PMPS) { return env->pmp_state.pmp[addr_index].addr_reg; } else { - PMP_DEBUG("ignoring read - out of bounds"); + qemu_log_mask(LOG_GUEST_ERROR, + "ignoring pmpaddr read - out of bounds\n"); return 0; } } diff --git a/target/riscv/trace-events b/target/riscv/trace-events new file mode 100644 index 0000000000..48af0373df --- /dev/null +++ b/target/riscv/trace-events @@ -0,0 +1,2 @@ +# target/riscv/cpu_helper.c +riscv_trap(uint64_t hartid, bool async, uint64_t cause, uint64_t epc, uint64_t tval, const char *desc) "hart:%"PRId64", async:%d, cause:%"PRId64", epc:0x%"PRIx64", tval:0x%"PRIx64", desc=%s" diff --git a/target/riscv/translate.c b/target/riscv/translate.c index b7176cbf98..967eac7bc3 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -56,6 +56,7 @@ typedef struct DisasContext { int frm; } DisasContext; +#ifdef TARGET_RISCV64 /* convert riscv funct3 to qemu memop for load/store */ static const int tcg_memop_lookup[8] = { [0 ... 7] = -1, @@ -69,6 +70,7 @@ static const int tcg_memop_lookup[8] = { [6] = MO_TEUL, #endif }; +#endif #ifdef TARGET_RISCV64 #define CASE_OP_32_64(X) case X: case glue(X, W) @@ -186,367 +188,112 @@ static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2) tcg_temp_free(rh); } -static void gen_fsgnj(DisasContext *ctx, uint32_t rd, uint32_t rs1, - uint32_t rs2, int rm, uint64_t min) -{ - switch (rm) { - case 0: /* fsgnj */ - if (rs1 == rs2) { /* FMOV */ - tcg_gen_mov_i64(cpu_fpr[rd], cpu_fpr[rs1]); - } else { - tcg_gen_deposit_i64(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1], - 0, min == INT32_MIN ? 31 : 63); - } - break; - case 1: /* fsgnjn */ - if (rs1 == rs2) { /* FNEG */ - tcg_gen_xori_i64(cpu_fpr[rd], cpu_fpr[rs1], min); - } else { - TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_not_i64(t0, cpu_fpr[rs2]); - tcg_gen_deposit_i64(cpu_fpr[rd], t0, cpu_fpr[rs1], - 0, min == INT32_MIN ? 31 : 63); - tcg_temp_free_i64(t0); - } - break; - case 2: /* fsgnjx */ - if (rs1 == rs2) { /* FABS */ - tcg_gen_andi_i64(cpu_fpr[rd], cpu_fpr[rs1], ~min); - } else { - TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_andi_i64(t0, cpu_fpr[rs2], min); - tcg_gen_xor_i64(cpu_fpr[rd], cpu_fpr[rs1], t0); - tcg_temp_free_i64(t0); - } - break; - default: - gen_exception_illegal(ctx); - } -} - -static void gen_arith(DisasContext *ctx, uint32_t opc, int rd, int rs1, - int rs2) -{ - TCGv source1, source2, cond1, cond2, zeroreg, resultopt1; - source1 = tcg_temp_new(); - source2 = tcg_temp_new(); - gen_get_gpr(source1, rs1); - gen_get_gpr(source2, rs2); - - switch (opc) { - CASE_OP_32_64(OPC_RISC_ADD): - tcg_gen_add_tl(source1, source1, source2); - break; - CASE_OP_32_64(OPC_RISC_SUB): - tcg_gen_sub_tl(source1, source1, source2); - break; -#if defined(TARGET_RISCV64) - case OPC_RISC_SLLW: - tcg_gen_andi_tl(source2, source2, 0x1F); - tcg_gen_shl_tl(source1, source1, source2); - break; -#endif - case OPC_RISC_SLL: - tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1); - tcg_gen_shl_tl(source1, source1, source2); - break; - case OPC_RISC_SLT: - tcg_gen_setcond_tl(TCG_COND_LT, source1, source1, source2); - break; - case OPC_RISC_SLTU: - tcg_gen_setcond_tl(TCG_COND_LTU, source1, source1, source2); - break; - case OPC_RISC_XOR: - tcg_gen_xor_tl(source1, source1, source2); - break; -#if defined(TARGET_RISCV64) - case OPC_RISC_SRLW: - /* clear upper 32 */ - tcg_gen_ext32u_tl(source1, source1); - tcg_gen_andi_tl(source2, source2, 0x1F); - tcg_gen_shr_tl(source1, source1, source2); - break; -#endif - case OPC_RISC_SRL: - tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1); - tcg_gen_shr_tl(source1, source1, source2); - break; -#if defined(TARGET_RISCV64) - case OPC_RISC_SRAW: - /* first, trick to get it to act like working on 32 bits (get rid of - upper 32, sign extend to fill space) */ - tcg_gen_ext32s_tl(source1, source1); - tcg_gen_andi_tl(source2, source2, 0x1F); - tcg_gen_sar_tl(source1, source1, source2); - break; -#endif - case OPC_RISC_SRA: - tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1); - tcg_gen_sar_tl(source1, source1, source2); - break; - case OPC_RISC_OR: - tcg_gen_or_tl(source1, source1, source2); - break; - case OPC_RISC_AND: - tcg_gen_and_tl(source1, source1, source2); - break; - CASE_OP_32_64(OPC_RISC_MUL): - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - tcg_gen_mul_tl(source1, source1, source2); - break; - case OPC_RISC_MULH: - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - tcg_gen_muls2_tl(source2, source1, source1, source2); - break; - case OPC_RISC_MULHSU: - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - gen_mulhsu(source1, source1, source2); - break; - case OPC_RISC_MULHU: - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - tcg_gen_mulu2_tl(source2, source1, source1, source2); - break; -#if defined(TARGET_RISCV64) - case OPC_RISC_DIVW: - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - tcg_gen_ext32s_tl(source1, source1); - tcg_gen_ext32s_tl(source2, source2); - /* fall through to DIV */ -#endif - case OPC_RISC_DIV: - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - /* Handle by altering args to tcg_gen_div to produce req'd results: - * For overflow: want source1 in source1 and 1 in source2 - * For div by zero: want -1 in source1 and 1 in source2 -> -1 result */ - cond1 = tcg_temp_new(); - cond2 = tcg_temp_new(); - zeroreg = tcg_const_tl(0); - resultopt1 = tcg_temp_new(); - - tcg_gen_movi_tl(resultopt1, (target_ulong)-1); - tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L)); - tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1, - ((target_ulong)1) << (TARGET_LONG_BITS - 1)); - tcg_gen_and_tl(cond1, cond1, cond2); /* cond1 = overflow */ - tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, 0); /* cond2 = div 0 */ - /* if div by zero, set source1 to -1, otherwise don't change */ - tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond2, zeroreg, source1, - resultopt1); - /* if overflow or div by zero, set source2 to 1, else don't change */ - tcg_gen_or_tl(cond1, cond1, cond2); - tcg_gen_movi_tl(resultopt1, (target_ulong)1); - tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2, - resultopt1); - tcg_gen_div_tl(source1, source1, source2); - - tcg_temp_free(cond1); - tcg_temp_free(cond2); - tcg_temp_free(zeroreg); - tcg_temp_free(resultopt1); - break; -#if defined(TARGET_RISCV64) - case OPC_RISC_DIVUW: - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - tcg_gen_ext32u_tl(source1, source1); - tcg_gen_ext32u_tl(source2, source2); - /* fall through to DIVU */ -#endif - case OPC_RISC_DIVU: - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - cond1 = tcg_temp_new(); - zeroreg = tcg_const_tl(0); - resultopt1 = tcg_temp_new(); - - tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); - tcg_gen_movi_tl(resultopt1, (target_ulong)-1); - tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, source1, - resultopt1); - tcg_gen_movi_tl(resultopt1, (target_ulong)1); - tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2, - resultopt1); - tcg_gen_divu_tl(source1, source1, source2); - - tcg_temp_free(cond1); - tcg_temp_free(zeroreg); - tcg_temp_free(resultopt1); - break; -#if defined(TARGET_RISCV64) - case OPC_RISC_REMW: - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - tcg_gen_ext32s_tl(source1, source1); - tcg_gen_ext32s_tl(source2, source2); - /* fall through to REM */ -#endif - case OPC_RISC_REM: - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - cond1 = tcg_temp_new(); - cond2 = tcg_temp_new(); - zeroreg = tcg_const_tl(0); - resultopt1 = tcg_temp_new(); - - tcg_gen_movi_tl(resultopt1, 1L); - tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)-1); - tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1, - (target_ulong)1 << (TARGET_LONG_BITS - 1)); - tcg_gen_and_tl(cond2, cond1, cond2); /* cond1 = overflow */ - tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); /* cond2 = div 0 */ - /* if overflow or div by zero, set source2 to 1, else don't change */ - tcg_gen_or_tl(cond2, cond1, cond2); - tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond2, zeroreg, source2, - resultopt1); - tcg_gen_rem_tl(resultopt1, source1, source2); - /* if div by zero, just return the original dividend */ - tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, resultopt1, - source1); - - tcg_temp_free(cond1); - tcg_temp_free(cond2); - tcg_temp_free(zeroreg); - tcg_temp_free(resultopt1); - break; -#if defined(TARGET_RISCV64) - case OPC_RISC_REMUW: - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - tcg_gen_ext32u_tl(source1, source1); - tcg_gen_ext32u_tl(source2, source2); - /* fall through to REMU */ -#endif - case OPC_RISC_REMU: - if (!has_ext(ctx, RVM)) { - goto do_illegal; - } - cond1 = tcg_temp_new(); - zeroreg = tcg_const_tl(0); - resultopt1 = tcg_temp_new(); - - tcg_gen_movi_tl(resultopt1, (target_ulong)1); - tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); - tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2, - resultopt1); - tcg_gen_remu_tl(resultopt1, source1, source2); - /* if div by zero, just return the original dividend */ - tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, resultopt1, - source1); - - tcg_temp_free(cond1); - tcg_temp_free(zeroreg); - tcg_temp_free(resultopt1); - break; - do_illegal: - default: - gen_exception_illegal(ctx); - return; - } - - if (opc & 0x8) { /* sign extend for W instructions */ - tcg_gen_ext32s_tl(source1, source1); - } - - gen_set_gpr(rd, source1); - tcg_temp_free(source1); - tcg_temp_free(source2); -} - -static void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd, - int rs1, target_long imm) -{ - TCGv source1 = tcg_temp_new(); - int shift_len = TARGET_LONG_BITS; - int shift_a; - - gen_get_gpr(source1, rs1); - - switch (opc) { - case OPC_RISC_ADDI: -#if defined(TARGET_RISCV64) - case OPC_RISC_ADDIW: -#endif - tcg_gen_addi_tl(source1, source1, imm); - break; - case OPC_RISC_SLTI: - tcg_gen_setcondi_tl(TCG_COND_LT, source1, source1, imm); - break; - case OPC_RISC_SLTIU: - tcg_gen_setcondi_tl(TCG_COND_LTU, source1, source1, imm); - break; - case OPC_RISC_XORI: - tcg_gen_xori_tl(source1, source1, imm); - break; - case OPC_RISC_ORI: - tcg_gen_ori_tl(source1, source1, imm); - break; - case OPC_RISC_ANDI: - tcg_gen_andi_tl(source1, source1, imm); - break; -#if defined(TARGET_RISCV64) - case OPC_RISC_SLLIW: - shift_len = 32; - /* FALLTHRU */ -#endif - case OPC_RISC_SLLI: - if (imm >= shift_len) { - goto do_illegal; - } - tcg_gen_shli_tl(source1, source1, imm); - break; -#if defined(TARGET_RISCV64) - case OPC_RISC_SHIFT_RIGHT_IW: - shift_len = 32; - /* FALLTHRU */ -#endif - case OPC_RISC_SHIFT_RIGHT_I: - /* differentiate on IMM */ - shift_a = imm & 0x400; - imm &= 0x3ff; - if (imm >= shift_len) { - goto do_illegal; - } - if (imm != 0) { - if (shift_a) { - /* SRAI[W] */ - tcg_gen_sextract_tl(source1, source1, imm, shift_len - imm); - } else { - /* SRLI[W] */ - tcg_gen_extract_tl(source1, source1, imm, shift_len - imm); - } - /* No further sign-extension needed for W instructions. */ - opc &= ~0x8; - } - break; - default: - do_illegal: - gen_exception_illegal(ctx); - return; - } - - if (opc & 0x8) { /* sign-extend for W instructions */ - tcg_gen_ext32s_tl(source1, source1); - } - - gen_set_gpr(rd, source1); - tcg_temp_free(source1); +static void gen_div(TCGv ret, TCGv source1, TCGv source2) +{ + TCGv cond1, cond2, zeroreg, resultopt1; + /* + * Handle by altering args to tcg_gen_div to produce req'd results: + * For overflow: want source1 in source1 and 1 in source2 + * For div by zero: want -1 in source1 and 1 in source2 -> -1 result + */ + cond1 = tcg_temp_new(); + cond2 = tcg_temp_new(); + zeroreg = tcg_const_tl(0); + resultopt1 = tcg_temp_new(); + + tcg_gen_movi_tl(resultopt1, (target_ulong)-1); + tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L)); + tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1, + ((target_ulong)1) << (TARGET_LONG_BITS - 1)); + tcg_gen_and_tl(cond1, cond1, cond2); /* cond1 = overflow */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, 0); /* cond2 = div 0 */ + /* if div by zero, set source1 to -1, otherwise don't change */ + tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond2, zeroreg, source1, + resultopt1); + /* if overflow or div by zero, set source2 to 1, else don't change */ + tcg_gen_or_tl(cond1, cond1, cond2); + tcg_gen_movi_tl(resultopt1, (target_ulong)1); + tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2, + resultopt1); + tcg_gen_div_tl(ret, source1, source2); + + tcg_temp_free(cond1); + tcg_temp_free(cond2); + tcg_temp_free(zeroreg); + tcg_temp_free(resultopt1); +} + +static void gen_divu(TCGv ret, TCGv source1, TCGv source2) +{ + TCGv cond1, zeroreg, resultopt1; + cond1 = tcg_temp_new(); + + zeroreg = tcg_const_tl(0); + resultopt1 = tcg_temp_new(); + + tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); + tcg_gen_movi_tl(resultopt1, (target_ulong)-1); + tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, source1, + resultopt1); + tcg_gen_movi_tl(resultopt1, (target_ulong)1); + tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2, + resultopt1); + tcg_gen_divu_tl(ret, source1, source2); + + tcg_temp_free(cond1); + tcg_temp_free(zeroreg); + tcg_temp_free(resultopt1); +} + +static void gen_rem(TCGv ret, TCGv source1, TCGv source2) +{ + TCGv cond1, cond2, zeroreg, resultopt1; + + cond1 = tcg_temp_new(); + cond2 = tcg_temp_new(); + zeroreg = tcg_const_tl(0); + resultopt1 = tcg_temp_new(); + + tcg_gen_movi_tl(resultopt1, 1L); + tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)-1); + tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1, + (target_ulong)1 << (TARGET_LONG_BITS - 1)); + tcg_gen_and_tl(cond2, cond1, cond2); /* cond1 = overflow */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); /* cond2 = div 0 */ + /* if overflow or div by zero, set source2 to 1, else don't change */ + tcg_gen_or_tl(cond2, cond1, cond2); + tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond2, zeroreg, source2, + resultopt1); + tcg_gen_rem_tl(resultopt1, source1, source2); + /* if div by zero, just return the original dividend */ + tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1, + source1); + + tcg_temp_free(cond1); + tcg_temp_free(cond2); + tcg_temp_free(zeroreg); + tcg_temp_free(resultopt1); +} + +static void gen_remu(TCGv ret, TCGv source1, TCGv source2) +{ + TCGv cond1, zeroreg, resultopt1; + cond1 = tcg_temp_new(); + zeroreg = tcg_const_tl(0); + resultopt1 = tcg_temp_new(); + + tcg_gen_movi_tl(resultopt1, (target_ulong)1); + tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); + tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2, + resultopt1); + tcg_gen_remu_tl(resultopt1, source1, source2); + /* if div by zero, just return the original dividend */ + tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1, + source1); + + tcg_temp_free(cond1); + tcg_temp_free(zeroreg); + tcg_temp_free(resultopt1); } static void gen_jal(DisasContext *ctx, int rd, target_ulong imm) @@ -569,92 +316,8 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm) ctx->base.is_jmp = DISAS_NORETURN; } -static void gen_jalr(DisasContext *ctx, uint32_t opc, int rd, int rs1, - target_long imm) -{ - /* no chaining with JALR */ - TCGLabel *misaligned = NULL; - TCGv t0 = tcg_temp_new(); - - switch (opc) { - case OPC_RISC_JALR: - gen_get_gpr(cpu_pc, rs1); - tcg_gen_addi_tl(cpu_pc, cpu_pc, imm); - tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2); - - if (!has_ext(ctx, RVC)) { - misaligned = gen_new_label(); - tcg_gen_andi_tl(t0, cpu_pc, 0x2); - tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned); - } - - if (rd != 0) { - tcg_gen_movi_tl(cpu_gpr[rd], ctx->pc_succ_insn); - } - tcg_gen_lookup_and_goto_ptr(); - - if (misaligned) { - gen_set_label(misaligned); - gen_exception_inst_addr_mis(ctx); - } - ctx->base.is_jmp = DISAS_NORETURN; - break; - - default: - gen_exception_illegal(ctx); - break; - } - tcg_temp_free(t0); -} - -static void gen_branch(DisasContext *ctx, uint32_t opc, int rs1, int rs2, - target_long bimm) -{ - TCGLabel *l = gen_new_label(); - TCGv source1, source2; - source1 = tcg_temp_new(); - source2 = tcg_temp_new(); - gen_get_gpr(source1, rs1); - gen_get_gpr(source2, rs2); - - switch (opc) { - case OPC_RISC_BEQ: - tcg_gen_brcond_tl(TCG_COND_EQ, source1, source2, l); - break; - case OPC_RISC_BNE: - tcg_gen_brcond_tl(TCG_COND_NE, source1, source2, l); - break; - case OPC_RISC_BLT: - tcg_gen_brcond_tl(TCG_COND_LT, source1, source2, l); - break; - case OPC_RISC_BGE: - tcg_gen_brcond_tl(TCG_COND_GE, source1, source2, l); - break; - case OPC_RISC_BLTU: - tcg_gen_brcond_tl(TCG_COND_LTU, source1, source2, l); - break; - case OPC_RISC_BGEU: - tcg_gen_brcond_tl(TCG_COND_GEU, source1, source2, l); - break; - default: - gen_exception_illegal(ctx); - return; - } - tcg_temp_free(source1); - tcg_temp_free(source2); - - gen_goto_tb(ctx, 1, ctx->pc_succ_insn); - gen_set_label(l); /* branch taken */ - if (!has_ext(ctx, RVC) && ((ctx->base.pc_next + bimm) & 0x3)) { - /* misaligned */ - gen_exception_inst_addr_mis(ctx); - } else { - gen_goto_tb(ctx, 0, ctx->base.pc_next + bimm); - } - ctx->base.is_jmp = DISAS_NORETURN; -} - -static void gen_load(DisasContext *ctx, uint32_t opc, int rd, int rs1, +#ifdef TARGET_RISCV64 +static void gen_load_c(DisasContext *ctx, uint32_t opc, int rd, int rs1, target_long imm) { TCGv t0 = tcg_temp_new(); @@ -674,7 +337,7 @@ static void gen_load(DisasContext *ctx, uint32_t opc, int rd, int rs1, tcg_temp_free(t1); } -static void gen_store(DisasContext *ctx, uint32_t opc, int rs1, int rs2, +static void gen_store_c(DisasContext *ctx, uint32_t opc, int rs1, int rs2, target_long imm) { TCGv t0 = tcg_temp_new(); @@ -693,6 +356,7 @@ static void gen_store(DisasContext *ctx, uint32_t opc, int rs1, int rs2, tcg_temp_free(t0); tcg_temp_free(dat); } +#endif #ifndef CONFIG_USER_ONLY /* The states of mstatus_fs are: @@ -719,6 +383,7 @@ static void mark_fs_dirty(DisasContext *ctx) static inline void mark_fs_dirty(DisasContext *ctx) { } #endif +#if !defined(TARGET_RISCV64) static void gen_fp_load(DisasContext *ctx, uint32_t opc, int rd, int rs1, target_long imm) { @@ -793,143 +458,7 @@ static void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1, tcg_temp_free(t0); } - -static void gen_atomic(DisasContext *ctx, uint32_t opc, - int rd, int rs1, int rs2) -{ - TCGv src1, src2, dat; - TCGLabel *l1, *l2; - TCGMemOp mop; - bool aq, rl; - - /* Extract the size of the atomic operation. */ - switch (extract32(opc, 12, 3)) { - case 2: /* 32-bit */ - mop = MO_ALIGN | MO_TESL; - break; -#if defined(TARGET_RISCV64) - case 3: /* 64-bit */ - mop = MO_ALIGN | MO_TEQ; - break; #endif - default: - gen_exception_illegal(ctx); - return; - } - rl = extract32(opc, 25, 1); - aq = extract32(opc, 26, 1); - - src1 = tcg_temp_new(); - src2 = tcg_temp_new(); - - switch (MASK_OP_ATOMIC_NO_AQ_RL_SZ(opc)) { - case OPC_RISC_LR: - /* Put addr in load_res, data in load_val. */ - gen_get_gpr(src1, rs1); - if (rl) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); - } - tcg_gen_qemu_ld_tl(load_val, src1, ctx->mem_idx, mop); - if (aq) { - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); - } - tcg_gen_mov_tl(load_res, src1); - gen_set_gpr(rd, load_val); - break; - - case OPC_RISC_SC: - l1 = gen_new_label(); - l2 = gen_new_label(); - dat = tcg_temp_new(); - - gen_get_gpr(src1, rs1); - tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1); - - gen_get_gpr(src2, rs2); - /* Note that the TCG atomic primitives are SC, - so we can ignore AQ/RL along this path. */ - tcg_gen_atomic_cmpxchg_tl(src1, load_res, load_val, src2, - ctx->mem_idx, mop); - tcg_gen_setcond_tl(TCG_COND_NE, dat, src1, load_val); - gen_set_gpr(rd, dat); - tcg_gen_br(l2); - - gen_set_label(l1); - /* Address comparion failure. However, we still need to - provide the memory barrier implied by AQ/RL. */ - tcg_gen_mb(TCG_MO_ALL + aq * TCG_BAR_LDAQ + rl * TCG_BAR_STRL); - tcg_gen_movi_tl(dat, 1); - gen_set_gpr(rd, dat); - - gen_set_label(l2); - tcg_temp_free(dat); - break; - - case OPC_RISC_AMOSWAP: - /* Note that the TCG atomic primitives are SC, - so we can ignore AQ/RL along this path. */ - gen_get_gpr(src1, rs1); - gen_get_gpr(src2, rs2); - tcg_gen_atomic_xchg_tl(src2, src1, src2, ctx->mem_idx, mop); - gen_set_gpr(rd, src2); - break; - case OPC_RISC_AMOADD: - gen_get_gpr(src1, rs1); - gen_get_gpr(src2, rs2); - tcg_gen_atomic_fetch_add_tl(src2, src1, src2, ctx->mem_idx, mop); - gen_set_gpr(rd, src2); - break; - case OPC_RISC_AMOXOR: - gen_get_gpr(src1, rs1); - gen_get_gpr(src2, rs2); - tcg_gen_atomic_fetch_xor_tl(src2, src1, src2, ctx->mem_idx, mop); - gen_set_gpr(rd, src2); - break; - case OPC_RISC_AMOAND: - gen_get_gpr(src1, rs1); - gen_get_gpr(src2, rs2); - tcg_gen_atomic_fetch_and_tl(src2, src1, src2, ctx->mem_idx, mop); - gen_set_gpr(rd, src2); - break; - case OPC_RISC_AMOOR: - gen_get_gpr(src1, rs1); - gen_get_gpr(src2, rs2); - tcg_gen_atomic_fetch_or_tl(src2, src1, src2, ctx->mem_idx, mop); - gen_set_gpr(rd, src2); - break; - case OPC_RISC_AMOMIN: - gen_get_gpr(src1, rs1); - gen_get_gpr(src2, rs2); - tcg_gen_atomic_fetch_smin_tl(src2, src1, src2, ctx->mem_idx, mop); - gen_set_gpr(rd, src2); - break; - case OPC_RISC_AMOMAX: - gen_get_gpr(src1, rs1); - gen_get_gpr(src2, rs2); - tcg_gen_atomic_fetch_smax_tl(src2, src1, src2, ctx->mem_idx, mop); - gen_set_gpr(rd, src2); - break; - case OPC_RISC_AMOMINU: - gen_get_gpr(src1, rs1); - gen_get_gpr(src2, rs2); - tcg_gen_atomic_fetch_umin_tl(src2, src1, src2, ctx->mem_idx, mop); - gen_set_gpr(rd, src2); - break; - case OPC_RISC_AMOMAXU: - gen_get_gpr(src1, rs1); - gen_get_gpr(src2, rs2); - tcg_gen_atomic_fetch_umax_tl(src2, src1, src2, ctx->mem_idx, mop); - gen_set_gpr(rd, src2); - break; - - default: - gen_exception_illegal(ctx); - break; - } - - tcg_temp_free(src1); - tcg_temp_free(src2); -} static void gen_set_rm(DisasContext *ctx, int rm) { @@ -944,659 +473,6 @@ static void gen_set_rm(DisasContext *ctx, int rm) tcg_temp_free_i32(t0); } -static void gen_fp_fmadd(DisasContext *ctx, uint32_t opc, int rd, - int rs1, int rs2, int rs3, int rm) -{ - switch (opc) { - case OPC_RISC_FMADD_S: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fmadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], - cpu_fpr[rs2], cpu_fpr[rs3]); - break; - case OPC_RISC_FMADD_D: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fmadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], - cpu_fpr[rs2], cpu_fpr[rs3]); - break; - do_illegal: - default: - gen_exception_illegal(ctx); - break; - } -} - -static void gen_fp_fmsub(DisasContext *ctx, uint32_t opc, int rd, - int rs1, int rs2, int rs3, int rm) -{ - switch (opc) { - case OPC_RISC_FMSUB_S: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fmsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], - cpu_fpr[rs2], cpu_fpr[rs3]); - break; - case OPC_RISC_FMSUB_D: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fmsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], - cpu_fpr[rs2], cpu_fpr[rs3]); - break; - do_illegal: - default: - gen_exception_illegal(ctx); - break; - } -} - -static void gen_fp_fnmsub(DisasContext *ctx, uint32_t opc, int rd, - int rs1, int rs2, int rs3, int rm) -{ - switch (opc) { - case OPC_RISC_FNMSUB_S: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fnmsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], - cpu_fpr[rs2], cpu_fpr[rs3]); - break; - case OPC_RISC_FNMSUB_D: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fnmsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], - cpu_fpr[rs2], cpu_fpr[rs3]); - break; - do_illegal: - default: - gen_exception_illegal(ctx); - break; - } -} - -static void gen_fp_fnmadd(DisasContext *ctx, uint32_t opc, int rd, - int rs1, int rs2, int rs3, int rm) -{ - switch (opc) { - case OPC_RISC_FNMADD_S: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fnmadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], - cpu_fpr[rs2], cpu_fpr[rs3]); - break; - case OPC_RISC_FNMADD_D: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fnmadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], - cpu_fpr[rs2], cpu_fpr[rs3]); - break; - do_illegal: - default: - gen_exception_illegal(ctx); - break; - } -} - -static void gen_fp_arith(DisasContext *ctx, uint32_t opc, int rd, - int rs1, int rs2, int rm) -{ - TCGv t0 = NULL; - bool fp_output = true; - - if (ctx->mstatus_fs == 0) { - goto do_illegal; - } - - switch (opc) { - case OPC_RISC_FADD_S: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case OPC_RISC_FSUB_S: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case OPC_RISC_FMUL_S: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fmul_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case OPC_RISC_FDIV_S: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fdiv_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case OPC_RISC_FSQRT_S: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fsqrt_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1]); - break; - case OPC_RISC_FSGNJ_S: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - gen_fsgnj(ctx, rd, rs1, rs2, rm, INT32_MIN); - break; - - case OPC_RISC_FMIN_S: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - /* also handles: OPC_RISC_FMAX_S */ - switch (rm) { - case 0x0: - gen_helper_fmin_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case 0x1: - gen_helper_fmax_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - default: - goto do_illegal; - } - break; - - case OPC_RISC_FEQ_S: - /* also handles: OPC_RISC_FLT_S, OPC_RISC_FLE_S */ - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - t0 = tcg_temp_new(); - switch (rm) { - case 0x0: - gen_helper_fle_s(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case 0x1: - gen_helper_flt_s(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case 0x2: - gen_helper_feq_s(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - default: - goto do_illegal; - } - gen_set_gpr(rd, t0); - tcg_temp_free(t0); - fp_output = false; - break; - - case OPC_RISC_FCVT_W_S: - /* also OPC_RISC_FCVT_WU_S, OPC_RISC_FCVT_L_S, OPC_RISC_FCVT_LU_S */ - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - t0 = tcg_temp_new(); - switch (rs2) { - case 0: /* FCVT_W_S */ - gen_set_rm(ctx, rm); - gen_helper_fcvt_w_s(t0, cpu_env, cpu_fpr[rs1]); - break; - case 1: /* FCVT_WU_S */ - gen_set_rm(ctx, rm); - gen_helper_fcvt_wu_s(t0, cpu_env, cpu_fpr[rs1]); - break; -#if defined(TARGET_RISCV64) - case 2: /* FCVT_L_S */ - gen_set_rm(ctx, rm); - gen_helper_fcvt_l_s(t0, cpu_env, cpu_fpr[rs1]); - break; - case 3: /* FCVT_LU_S */ - gen_set_rm(ctx, rm); - gen_helper_fcvt_lu_s(t0, cpu_env, cpu_fpr[rs1]); - break; -#endif - default: - goto do_illegal; - } - gen_set_gpr(rd, t0); - tcg_temp_free(t0); - fp_output = false; - break; - - case OPC_RISC_FCVT_S_W: - /* also OPC_RISC_FCVT_S_WU, OPC_RISC_FCVT_S_L, OPC_RISC_FCVT_S_LU */ - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - t0 = tcg_temp_new(); - gen_get_gpr(t0, rs1); - switch (rs2) { - case 0: /* FCVT_S_W */ - gen_set_rm(ctx, rm); - gen_helper_fcvt_s_w(cpu_fpr[rd], cpu_env, t0); - break; - case 1: /* FCVT_S_WU */ - gen_set_rm(ctx, rm); - gen_helper_fcvt_s_wu(cpu_fpr[rd], cpu_env, t0); - break; -#if defined(TARGET_RISCV64) - case 2: /* FCVT_S_L */ - gen_set_rm(ctx, rm); - gen_helper_fcvt_s_l(cpu_fpr[rd], cpu_env, t0); - break; - case 3: /* FCVT_S_LU */ - gen_set_rm(ctx, rm); - gen_helper_fcvt_s_lu(cpu_fpr[rd], cpu_env, t0); - break; -#endif - default: - goto do_illegal; - } - tcg_temp_free(t0); - break; - - case OPC_RISC_FMV_X_S: - /* also OPC_RISC_FCLASS_S */ - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - t0 = tcg_temp_new(); - switch (rm) { - case 0: /* FMV */ -#if defined(TARGET_RISCV64) - tcg_gen_ext32s_tl(t0, cpu_fpr[rs1]); -#else - tcg_gen_extrl_i64_i32(t0, cpu_fpr[rs1]); -#endif - break; - case 1: - gen_helper_fclass_s(t0, cpu_fpr[rs1]); - break; - default: - goto do_illegal; - } - gen_set_gpr(rd, t0); - tcg_temp_free(t0); - fp_output = false; - break; - - case OPC_RISC_FMV_S_X: - if (!has_ext(ctx, RVF)) { - goto do_illegal; - } - t0 = tcg_temp_new(); - gen_get_gpr(t0, rs1); -#if defined(TARGET_RISCV64) - tcg_gen_mov_i64(cpu_fpr[rd], t0); -#else - tcg_gen_extu_i32_i64(cpu_fpr[rd], t0); -#endif - tcg_temp_free(t0); - break; - - /* double */ - case OPC_RISC_FADD_D: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case OPC_RISC_FSUB_D: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case OPC_RISC_FMUL_D: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fmul_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case OPC_RISC_FDIV_D: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fdiv_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case OPC_RISC_FSQRT_D: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - gen_set_rm(ctx, rm); - gen_helper_fsqrt_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1]); - break; - case OPC_RISC_FSGNJ_D: - gen_fsgnj(ctx, rd, rs1, rs2, rm, INT64_MIN); - break; - - case OPC_RISC_FMIN_D: - /* also OPC_RISC_FMAX_D */ - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - switch (rm) { - case 0: - gen_helper_fmin_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case 1: - gen_helper_fmax_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - default: - goto do_illegal; - } - break; - - case OPC_RISC_FCVT_S_D: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - switch (rs2) { - case 1: - gen_set_rm(ctx, rm); - gen_helper_fcvt_s_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1]); - break; - default: - goto do_illegal; - } - break; - - case OPC_RISC_FCVT_D_S: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - switch (rs2) { - case 0: - gen_set_rm(ctx, rm); - gen_helper_fcvt_d_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1]); - break; - default: - goto do_illegal; - } - break; - - case OPC_RISC_FEQ_D: - /* also OPC_RISC_FLT_D, OPC_RISC_FLE_D */ - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - t0 = tcg_temp_new(); - switch (rm) { - case 0: - gen_helper_fle_d(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case 1: - gen_helper_flt_d(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - case 2: - gen_helper_feq_d(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); - break; - default: - goto do_illegal; - } - gen_set_gpr(rd, t0); - tcg_temp_free(t0); - fp_output = false; - break; - - case OPC_RISC_FCVT_W_D: - /* also OPC_RISC_FCVT_WU_D, OPC_RISC_FCVT_L_D, OPC_RISC_FCVT_LU_D */ - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - t0 = tcg_temp_new(); - switch (rs2) { - case 0: - gen_set_rm(ctx, rm); - gen_helper_fcvt_w_d(t0, cpu_env, cpu_fpr[rs1]); - break; - case 1: - gen_set_rm(ctx, rm); - gen_helper_fcvt_wu_d(t0, cpu_env, cpu_fpr[rs1]); - break; -#if defined(TARGET_RISCV64) - case 2: - gen_set_rm(ctx, rm); - gen_helper_fcvt_l_d(t0, cpu_env, cpu_fpr[rs1]); - break; - case 3: - gen_set_rm(ctx, rm); - gen_helper_fcvt_lu_d(t0, cpu_env, cpu_fpr[rs1]); - break; -#endif - default: - goto do_illegal; - } - gen_set_gpr(rd, t0); - tcg_temp_free(t0); - fp_output = false; - break; - - case OPC_RISC_FCVT_D_W: - /* also OPC_RISC_FCVT_D_WU, OPC_RISC_FCVT_D_L, OPC_RISC_FCVT_D_LU */ - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - t0 = tcg_temp_new(); - gen_get_gpr(t0, rs1); - switch (rs2) { - case 0: - gen_set_rm(ctx, rm); - gen_helper_fcvt_d_w(cpu_fpr[rd], cpu_env, t0); - break; - case 1: - gen_set_rm(ctx, rm); - gen_helper_fcvt_d_wu(cpu_fpr[rd], cpu_env, t0); - break; -#if defined(TARGET_RISCV64) - case 2: - gen_set_rm(ctx, rm); - gen_helper_fcvt_d_l(cpu_fpr[rd], cpu_env, t0); - break; - case 3: - gen_set_rm(ctx, rm); - gen_helper_fcvt_d_lu(cpu_fpr[rd], cpu_env, t0); - break; -#endif - default: - goto do_illegal; - } - tcg_temp_free(t0); - break; - - case OPC_RISC_FMV_X_D: - /* also OPC_RISC_FCLASS_D */ - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - switch (rm) { -#if defined(TARGET_RISCV64) - case 0: /* FMV */ - gen_set_gpr(rd, cpu_fpr[rs1]); - break; -#endif - case 1: - t0 = tcg_temp_new(); - gen_helper_fclass_d(t0, cpu_fpr[rs1]); - gen_set_gpr(rd, t0); - tcg_temp_free(t0); - break; - default: - goto do_illegal; - } - fp_output = false; - break; - -#if defined(TARGET_RISCV64) - case OPC_RISC_FMV_D_X: - if (!has_ext(ctx, RVD)) { - goto do_illegal; - } - t0 = tcg_temp_new(); - gen_get_gpr(t0, rs1); - tcg_gen_mov_tl(cpu_fpr[rd], t0); - tcg_temp_free(t0); - break; -#endif - - default: - do_illegal: - if (t0) { - tcg_temp_free(t0); - } - gen_exception_illegal(ctx); - return; - } - - if (fp_output) { - mark_fs_dirty(ctx); - } -} - -static void gen_system(DisasContext *ctx, uint32_t opc, int rd, int rs1, - int csr) -{ - TCGv source1, csr_store, dest, rs1_pass, imm_rs1; - source1 = tcg_temp_new(); - csr_store = tcg_temp_new(); - dest = tcg_temp_new(); - rs1_pass = tcg_temp_new(); - imm_rs1 = tcg_temp_new(); - gen_get_gpr(source1, rs1); - tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); - tcg_gen_movi_tl(rs1_pass, rs1); - tcg_gen_movi_tl(csr_store, csr); /* copy into temp reg to feed to helper */ - -#ifndef CONFIG_USER_ONLY - /* Extract funct7 value and check whether it matches SFENCE.VMA */ - if ((opc == OPC_RISC_ECALL) && ((csr >> 5) == 9)) { - if (ctx->priv_ver == PRIV_VERSION_1_10_0) { - /* sfence.vma */ - /* TODO: handle ASID specific fences */ - gen_helper_tlb_flush(cpu_env); - return; - } else { - gen_exception_illegal(ctx); - } - } -#endif - - switch (opc) { - case OPC_RISC_ECALL: - switch (csr) { - case 0x0: /* ECALL */ - /* always generates U-level ECALL, fixed in do_interrupt handler */ - generate_exception(ctx, RISCV_EXCP_U_ECALL); - tcg_gen_exit_tb(NULL, 0); /* no chaining */ - ctx->base.is_jmp = DISAS_NORETURN; - break; - case 0x1: /* EBREAK */ - generate_exception(ctx, RISCV_EXCP_BREAKPOINT); - tcg_gen_exit_tb(NULL, 0); /* no chaining */ - ctx->base.is_jmp = DISAS_NORETURN; - break; -#ifndef CONFIG_USER_ONLY - case 0x002: /* URET */ - gen_exception_illegal(ctx); - break; - case 0x102: /* SRET */ - if (has_ext(ctx, RVS)) { - gen_helper_sret(cpu_pc, cpu_env, cpu_pc); - tcg_gen_exit_tb(NULL, 0); /* no chaining */ - ctx->base.is_jmp = DISAS_NORETURN; - } else { - gen_exception_illegal(ctx); - } - break; - case 0x202: /* HRET */ - gen_exception_illegal(ctx); - break; - case 0x302: /* MRET */ - gen_helper_mret(cpu_pc, cpu_env, cpu_pc); - tcg_gen_exit_tb(NULL, 0); /* no chaining */ - ctx->base.is_jmp = DISAS_NORETURN; - break; - case 0x7b2: /* DRET */ - gen_exception_illegal(ctx); - break; - case 0x105: /* WFI */ - tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); - gen_helper_wfi(cpu_env); - break; - case 0x104: /* SFENCE.VM */ - if (ctx->priv_ver <= PRIV_VERSION_1_09_1) { - gen_helper_tlb_flush(cpu_env); - } else { - gen_exception_illegal(ctx); - } - break; -#endif - default: - gen_exception_illegal(ctx); - break; - } - break; - default: - tcg_gen_movi_tl(imm_rs1, rs1); - gen_io_start(); - switch (opc) { - case OPC_RISC_CSRRW: - gen_helper_csrrw(dest, cpu_env, source1, csr_store); - break; - case OPC_RISC_CSRRS: - gen_helper_csrrs(dest, cpu_env, source1, csr_store, rs1_pass); - break; - case OPC_RISC_CSRRC: - gen_helper_csrrc(dest, cpu_env, source1, csr_store, rs1_pass); - break; - case OPC_RISC_CSRRWI: - gen_helper_csrrw(dest, cpu_env, imm_rs1, csr_store); - break; - case OPC_RISC_CSRRSI: - gen_helper_csrrs(dest, cpu_env, imm_rs1, csr_store, rs1_pass); - break; - case OPC_RISC_CSRRCI: - gen_helper_csrrc(dest, cpu_env, imm_rs1, csr_store, rs1_pass); - break; - default: - gen_exception_illegal(ctx); - return; - } - gen_io_end(); - gen_set_gpr(rd, dest); - /* end tb since we may be changing priv modes, to get mmu_index right */ - tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); - tcg_gen_exit_tb(NULL, 0); /* no chaining */ - ctx->base.is_jmp = DISAS_NORETURN; - break; - } - tcg_temp_free(source1); - tcg_temp_free(csr_store); - tcg_temp_free(dest); - tcg_temp_free(rs1_pass); - tcg_temp_free(imm_rs1); -} - static void decode_RV32_64C0(DisasContext *ctx) { uint8_t funct3 = extract32(ctx->opcode, 13, 3); @@ -1604,31 +480,10 @@ static void decode_RV32_64C0(DisasContext *ctx) uint8_t rs1s = GET_C_RS1S(ctx->opcode); switch (funct3) { - case 0: - /* illegal */ - if (ctx->opcode == 0) { - gen_exception_illegal(ctx); - } else { - /* C.ADDI4SPN -> addi rd', x2, zimm[9:2]*/ - gen_arith_imm(ctx, OPC_RISC_ADDI, rd_rs2, 2, - GET_C_ADDI4SPN_IMM(ctx->opcode)); - } - break; - case 1: - /* C.FLD -> fld rd', offset[7:3](rs1')*/ - gen_fp_load(ctx, OPC_RISC_FLD, rd_rs2, rs1s, - GET_C_LD_IMM(ctx->opcode)); - /* C.LQ(RV128) */ - break; - case 2: - /* C.LW -> lw rd', offset[6:2](rs1') */ - gen_load(ctx, OPC_RISC_LW, rd_rs2, rs1s, - GET_C_LW_IMM(ctx->opcode)); - break; case 3: #if defined(TARGET_RISCV64) /* C.LD(RV64/128) -> ld rd', offset[7:3](rs1')*/ - gen_load(ctx, OPC_RISC_LD, rd_rs2, rs1s, + gen_load_c(ctx, OPC_RISC_LD, rd_rs2, rs1s, GET_C_LD_IMM(ctx->opcode)); #else /* C.FLW (RV32) -> flw rd', offset[6:2](rs1')*/ @@ -1636,25 +491,10 @@ static void decode_RV32_64C0(DisasContext *ctx) GET_C_LW_IMM(ctx->opcode)); #endif break; - case 4: - /* reserved */ - gen_exception_illegal(ctx); - break; - case 5: - /* C.FSD(RV32/64) -> fsd rs2', offset[7:3](rs1') */ - gen_fp_store(ctx, OPC_RISC_FSD, rs1s, rd_rs2, - GET_C_LD_IMM(ctx->opcode)); - /* C.SQ (RV128) */ - break; - case 6: - /* C.SW -> sw rs2', offset[6:2](rs1')*/ - gen_store(ctx, OPC_RISC_SW, rs1s, rd_rs2, - GET_C_LW_IMM(ctx->opcode)); - break; case 7: #if defined(TARGET_RISCV64) /* C.SD (RV64/128) -> sd rs2', offset[7:3](rs1')*/ - gen_store(ctx, OPC_RISC_SD, rs1s, rd_rs2, + gen_store_c(ctx, OPC_RISC_SD, rs1s, rd_rs2, GET_C_LD_IMM(ctx->opcode)); #else /* C.FSW (RV32) -> fsw rs2', offset[6:2](rs1')*/ @@ -1665,340 +505,173 @@ static void decode_RV32_64C0(DisasContext *ctx) } } -static void decode_RV32_64C1(DisasContext *ctx) +static void decode_RV32_64C(DisasContext *ctx) { - uint8_t funct3 = extract32(ctx->opcode, 13, 3); - uint8_t rd_rs1 = GET_C_RS1(ctx->opcode); - uint8_t rs1s, rs2s; - uint8_t funct2; + uint8_t op = extract32(ctx->opcode, 0, 2); - switch (funct3) { + switch (op) { case 0: - /* C.ADDI -> addi rd, rd, nzimm[5:0] */ - gen_arith_imm(ctx, OPC_RISC_ADDI, rd_rs1, rd_rs1, - GET_C_IMM(ctx->opcode)); - break; - case 1: -#if defined(TARGET_RISCV64) - /* C.ADDIW (RV64/128) -> addiw rd, rd, imm[5:0]*/ - gen_arith_imm(ctx, OPC_RISC_ADDIW, rd_rs1, rd_rs1, - GET_C_IMM(ctx->opcode)); -#else - /* C.JAL(RV32) -> jal x1, offset[11:1] */ - gen_jal(ctx, 1, GET_C_J_IMM(ctx->opcode)); -#endif - break; - case 2: - /* C.LI -> addi rd, x0, imm[5:0]*/ - gen_arith_imm(ctx, OPC_RISC_ADDI, rd_rs1, 0, GET_C_IMM(ctx->opcode)); - break; - case 3: - if (rd_rs1 == 2) { - /* C.ADDI16SP -> addi x2, x2, nzimm[9:4]*/ - gen_arith_imm(ctx, OPC_RISC_ADDI, 2, 2, - GET_C_ADDI16SP_IMM(ctx->opcode)); - } else if (rd_rs1 != 0) { - /* C.LUI (rs1/rd =/= {0,2}) -> lui rd, nzimm[17:12]*/ - tcg_gen_movi_tl(cpu_gpr[rd_rs1], - GET_C_IMM(ctx->opcode) << 12); - } - break; - case 4: - funct2 = extract32(ctx->opcode, 10, 2); - rs1s = GET_C_RS1S(ctx->opcode); - switch (funct2) { - case 0: /* C.SRLI(RV32) -> srli rd', rd', shamt[5:0] */ - gen_arith_imm(ctx, OPC_RISC_SHIFT_RIGHT_I, rs1s, rs1s, - GET_C_ZIMM(ctx->opcode)); - /* C.SRLI64(RV128) */ - break; - case 1: - /* C.SRAI -> srai rd', rd', shamt[5:0]*/ - gen_arith_imm(ctx, OPC_RISC_SHIFT_RIGHT_I, rs1s, rs1s, - GET_C_ZIMM(ctx->opcode) | 0x400); - /* C.SRAI64(RV128) */ - break; - case 2: - /* C.ANDI -> andi rd', rd', imm[5:0]*/ - gen_arith_imm(ctx, OPC_RISC_ANDI, rs1s, rs1s, - GET_C_IMM(ctx->opcode)); - break; - case 3: - funct2 = extract32(ctx->opcode, 5, 2); - rs2s = GET_C_RS2S(ctx->opcode); - switch (funct2) { - case 0: - /* C.SUB -> sub rd', rd', rs2' */ - if (extract32(ctx->opcode, 12, 1) == 0) { - gen_arith(ctx, OPC_RISC_SUB, rs1s, rs1s, rs2s); - } -#if defined(TARGET_RISCV64) - else { - gen_arith(ctx, OPC_RISC_SUBW, rs1s, rs1s, rs2s); - } -#endif - break; - case 1: - /* C.XOR -> xor rs1', rs1', rs2' */ - if (extract32(ctx->opcode, 12, 1) == 0) { - gen_arith(ctx, OPC_RISC_XOR, rs1s, rs1s, rs2s); - } -#if defined(TARGET_RISCV64) - else { - /* C.ADDW (RV64/128) */ - gen_arith(ctx, OPC_RISC_ADDW, rs1s, rs1s, rs2s); - } -#endif - break; - case 2: - /* C.OR -> or rs1', rs1', rs2' */ - gen_arith(ctx, OPC_RISC_OR, rs1s, rs1s, rs2s); - break; - case 3: - /* C.AND -> and rs1', rs1', rs2' */ - gen_arith(ctx, OPC_RISC_AND, rs1s, rs1s, rs2s); - break; - } - break; - } - break; - case 5: - /* C.J -> jal x0, offset[11:1]*/ - gen_jal(ctx, 0, GET_C_J_IMM(ctx->opcode)); - break; - case 6: - /* C.BEQZ -> beq rs1', x0, offset[8:1]*/ - rs1s = GET_C_RS1S(ctx->opcode); - gen_branch(ctx, OPC_RISC_BEQ, rs1s, 0, GET_C_B_IMM(ctx->opcode)); - break; - case 7: - /* C.BNEZ -> bne rs1', x0, offset[8:1]*/ - rs1s = GET_C_RS1S(ctx->opcode); - gen_branch(ctx, OPC_RISC_BNE, rs1s, 0, GET_C_B_IMM(ctx->opcode)); + decode_RV32_64C0(ctx); break; } } -static void decode_RV32_64C2(DisasContext *ctx) +#define EX_SH(amount) \ + static int ex_shift_##amount(int imm) \ + { \ + return imm << amount; \ + } +EX_SH(1) +EX_SH(2) +EX_SH(3) +EX_SH(4) +EX_SH(12) + +#define REQUIRE_EXT(ctx, ext) do { \ + if (!has_ext(ctx, ext)) { \ + return false; \ + } \ +} while (0) + +static int ex_rvc_register(int reg) { - uint8_t rd, rs2; - uint8_t funct3 = extract32(ctx->opcode, 13, 3); + return 8 + reg; +} +bool decode_insn32(DisasContext *ctx, uint32_t insn); +/* Include the auto-generated decoder for 32 bit insn */ +#include "decode_insn32.inc.c" - rd = GET_RD(ctx->opcode); +static bool gen_arith_imm(DisasContext *ctx, arg_i *a, + void(*func)(TCGv, TCGv, TCGv)) +{ + TCGv source1, source2; + source1 = tcg_temp_new(); + source2 = tcg_temp_new(); - switch (funct3) { - case 0: /* C.SLLI -> slli rd, rd, shamt[5:0] - C.SLLI64 -> */ - gen_arith_imm(ctx, OPC_RISC_SLLI, rd, rd, GET_C_ZIMM(ctx->opcode)); - break; - case 1: /* C.FLDSP(RV32/64DC) -> fld rd, offset[8:3](x2) */ - gen_fp_load(ctx, OPC_RISC_FLD, rd, 2, GET_C_LDSP_IMM(ctx->opcode)); - break; - case 2: /* C.LWSP -> lw rd, offset[7:2](x2) */ - gen_load(ctx, OPC_RISC_LW, rd, 2, GET_C_LWSP_IMM(ctx->opcode)); - break; - case 3: -#if defined(TARGET_RISCV64) - /* C.LDSP(RVC64) -> ld rd, offset[8:3](x2) */ - gen_load(ctx, OPC_RISC_LD, rd, 2, GET_C_LDSP_IMM(ctx->opcode)); -#else - /* C.FLWSP(RV32FC) -> flw rd, offset[7:2](x2) */ - gen_fp_load(ctx, OPC_RISC_FLW, rd, 2, GET_C_LWSP_IMM(ctx->opcode)); -#endif - break; - case 4: - rs2 = GET_C_RS2(ctx->opcode); - - if (extract32(ctx->opcode, 12, 1) == 0) { - if (rs2 == 0) { - /* C.JR -> jalr x0, rs1, 0*/ - gen_jalr(ctx, OPC_RISC_JALR, 0, rd, 0); - } else { - /* C.MV -> add rd, x0, rs2 */ - gen_arith(ctx, OPC_RISC_ADD, rd, 0, rs2); - } - } else { - if (rd == 0) { - /* C.EBREAK -> ebreak*/ - gen_system(ctx, OPC_RISC_ECALL, 0, 0, 0x1); - } else { - if (rs2 == 0) { - /* C.JALR -> jalr x1, rs1, 0*/ - gen_jalr(ctx, OPC_RISC_JALR, 1, rd, 0); - } else { - /* C.ADD -> add rd, rd, rs2 */ - gen_arith(ctx, OPC_RISC_ADD, rd, rd, rs2); - } - } - } - break; - case 5: - /* C.FSDSP -> fsd rs2, offset[8:3](x2)*/ - gen_fp_store(ctx, OPC_RISC_FSD, 2, GET_C_RS2(ctx->opcode), - GET_C_SDSP_IMM(ctx->opcode)); - /* C.SQSP */ - break; - case 6: /* C.SWSP -> sw rs2, offset[7:2](x2)*/ - gen_store(ctx, OPC_RISC_SW, 2, GET_C_RS2(ctx->opcode), - GET_C_SWSP_IMM(ctx->opcode)); - break; - case 7: -#if defined(TARGET_RISCV64) - /* C.SDSP(Rv64/128) -> sd rs2, offset[8:3](x2)*/ - gen_store(ctx, OPC_RISC_SD, 2, GET_C_RS2(ctx->opcode), - GET_C_SDSP_IMM(ctx->opcode)); -#else - /* C.FSWSP(RV32) -> fsw rs2, offset[7:2](x2) */ - gen_fp_store(ctx, OPC_RISC_FSW, 2, GET_C_RS2(ctx->opcode), - GET_C_SWSP_IMM(ctx->opcode)); -#endif - break; - } + gen_get_gpr(source1, a->rs1); + tcg_gen_movi_tl(source2, a->imm); + + (*func)(source1, source1, source2); + + gen_set_gpr(a->rd, source1); + tcg_temp_free(source1); + tcg_temp_free(source2); + return true; } -static void decode_RV32_64C(DisasContext *ctx) +#ifdef TARGET_RISCV64 +static void gen_addw(TCGv ret, TCGv arg1, TCGv arg2) { - uint8_t op = extract32(ctx->opcode, 0, 2); + tcg_gen_add_tl(ret, arg1, arg2); + tcg_gen_ext32s_tl(ret, ret); +} - switch (op) { - case 0: - decode_RV32_64C0(ctx); - break; - case 1: - decode_RV32_64C1(ctx); - break; - case 2: - decode_RV32_64C2(ctx); - break; - } +static void gen_subw(TCGv ret, TCGv arg1, TCGv arg2) +{ + tcg_gen_sub_tl(ret, arg1, arg2); + tcg_gen_ext32s_tl(ret, ret); } -static void decode_RV32_64G(DisasContext *ctx) +static void gen_mulw(TCGv ret, TCGv arg1, TCGv arg2) { - int rs1; - int rs2; - int rd; - uint32_t op; - target_long imm; - - /* We do not do misaligned address check here: the address should never be - * misaligned at this point. Instructions that set PC must do the check, - * since epc must be the address of the instruction that caused us to - * perform the misaligned instruction fetch */ - - op = MASK_OP_MAJOR(ctx->opcode); - rs1 = GET_RS1(ctx->opcode); - rs2 = GET_RS2(ctx->opcode); - rd = GET_RD(ctx->opcode); - imm = GET_IMM(ctx->opcode); + tcg_gen_mul_tl(ret, arg1, arg2); + tcg_gen_ext32s_tl(ret, ret); +} + +static bool gen_arith_div_w(DisasContext *ctx, arg_r *a, + void(*func)(TCGv, TCGv, TCGv)) +{ + TCGv source1, source2; + source1 = tcg_temp_new(); + source2 = tcg_temp_new(); + + gen_get_gpr(source1, a->rs1); + gen_get_gpr(source2, a->rs2); + tcg_gen_ext32s_tl(source1, source1); + tcg_gen_ext32s_tl(source2, source2); + + (*func)(source1, source1, source2); + + tcg_gen_ext32s_tl(source1, source1); + gen_set_gpr(a->rd, source1); + tcg_temp_free(source1); + tcg_temp_free(source2); + return true; +} + +static bool gen_arith_div_uw(DisasContext *ctx, arg_r *a, + void(*func)(TCGv, TCGv, TCGv)) +{ + TCGv source1, source2; + source1 = tcg_temp_new(); + source2 = tcg_temp_new(); + + gen_get_gpr(source1, a->rs1); + gen_get_gpr(source2, a->rs2); + tcg_gen_ext32u_tl(source1, source1); + tcg_gen_ext32u_tl(source2, source2); + + (*func)(source1, source1, source2); + + tcg_gen_ext32s_tl(source1, source1); + gen_set_gpr(a->rd, source1); + tcg_temp_free(source1); + tcg_temp_free(source2); + return true; +} - switch (op) { - case OPC_RISC_LUI: - if (rd == 0) { - break; /* NOP */ - } - tcg_gen_movi_tl(cpu_gpr[rd], sextract64(ctx->opcode, 12, 20) << 12); - break; - case OPC_RISC_AUIPC: - if (rd == 0) { - break; /* NOP */ - } - tcg_gen_movi_tl(cpu_gpr[rd], (sextract64(ctx->opcode, 12, 20) << 12) + - ctx->base.pc_next); - break; - case OPC_RISC_JAL: - imm = GET_JAL_IMM(ctx->opcode); - gen_jal(ctx, rd, imm); - break; - case OPC_RISC_JALR: - gen_jalr(ctx, MASK_OP_JALR(ctx->opcode), rd, rs1, imm); - break; - case OPC_RISC_BRANCH: - gen_branch(ctx, MASK_OP_BRANCH(ctx->opcode), rs1, rs2, - GET_B_IMM(ctx->opcode)); - break; - case OPC_RISC_LOAD: - gen_load(ctx, MASK_OP_LOAD(ctx->opcode), rd, rs1, imm); - break; - case OPC_RISC_STORE: - gen_store(ctx, MASK_OP_STORE(ctx->opcode), rs1, rs2, - GET_STORE_IMM(ctx->opcode)); - break; - case OPC_RISC_ARITH_IMM: -#if defined(TARGET_RISCV64) - case OPC_RISC_ARITH_IMM_W: -#endif - if (rd == 0) { - break; /* NOP */ - } - gen_arith_imm(ctx, MASK_OP_ARITH_IMM(ctx->opcode), rd, rs1, imm); - break; - case OPC_RISC_ARITH: -#if defined(TARGET_RISCV64) - case OPC_RISC_ARITH_W: #endif - if (rd == 0) { - break; /* NOP */ - } - gen_arith(ctx, MASK_OP_ARITH(ctx->opcode), rd, rs1, rs2); - break; - case OPC_RISC_FP_LOAD: - gen_fp_load(ctx, MASK_OP_FP_LOAD(ctx->opcode), rd, rs1, imm); - break; - case OPC_RISC_FP_STORE: - gen_fp_store(ctx, MASK_OP_FP_STORE(ctx->opcode), rs1, rs2, - GET_STORE_IMM(ctx->opcode)); - break; - case OPC_RISC_ATOMIC: - if (!has_ext(ctx, RVA)) { - goto do_illegal; - } - gen_atomic(ctx, MASK_OP_ATOMIC(ctx->opcode), rd, rs1, rs2); - break; - case OPC_RISC_FMADD: - gen_fp_fmadd(ctx, MASK_OP_FP_FMADD(ctx->opcode), rd, rs1, rs2, - GET_RS3(ctx->opcode), GET_RM(ctx->opcode)); - break; - case OPC_RISC_FMSUB: - gen_fp_fmsub(ctx, MASK_OP_FP_FMSUB(ctx->opcode), rd, rs1, rs2, - GET_RS3(ctx->opcode), GET_RM(ctx->opcode)); - break; - case OPC_RISC_FNMSUB: - gen_fp_fnmsub(ctx, MASK_OP_FP_FNMSUB(ctx->opcode), rd, rs1, rs2, - GET_RS3(ctx->opcode), GET_RM(ctx->opcode)); - break; - case OPC_RISC_FNMADD: - gen_fp_fnmadd(ctx, MASK_OP_FP_FNMADD(ctx->opcode), rd, rs1, rs2, - GET_RS3(ctx->opcode), GET_RM(ctx->opcode)); - break; - case OPC_RISC_FP_ARITH: - gen_fp_arith(ctx, MASK_OP_FP_ARITH(ctx->opcode), rd, rs1, rs2, - GET_RM(ctx->opcode)); - break; - case OPC_RISC_FENCE: - if (ctx->opcode & 0x1000) { - /* FENCE_I is a no-op in QEMU, - * however we need to end the translation block */ - tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); - tcg_gen_exit_tb(NULL, 0); - ctx->base.is_jmp = DISAS_NORETURN; - } else { - /* FENCE is a full memory barrier. */ - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); - } - break; - case OPC_RISC_SYSTEM: - gen_system(ctx, MASK_OP_SYSTEM(ctx->opcode), rd, rs1, - (ctx->opcode & 0xFFF00000) >> 20); - break; - do_illegal: - default: - gen_exception_illegal(ctx); - break; - } + +static bool gen_arith(DisasContext *ctx, arg_r *a, + void(*func)(TCGv, TCGv, TCGv)) +{ + TCGv source1, source2; + source1 = tcg_temp_new(); + source2 = tcg_temp_new(); + + gen_get_gpr(source1, a->rs1); + gen_get_gpr(source2, a->rs2); + + (*func)(source1, source1, source2); + + gen_set_gpr(a->rd, source1); + tcg_temp_free(source1); + tcg_temp_free(source2); + return true; +} + +static bool gen_shift(DisasContext *ctx, arg_r *a, + void(*func)(TCGv, TCGv, TCGv)) +{ + TCGv source1 = tcg_temp_new(); + TCGv source2 = tcg_temp_new(); + + gen_get_gpr(source1, a->rs1); + gen_get_gpr(source2, a->rs2); + + tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1); + (*func)(source1, source1, source2); + + gen_set_gpr(a->rd, source1); + tcg_temp_free(source1); + tcg_temp_free(source2); + return true; } +/* Include insn module translation function */ +#include "insn_trans/trans_rvi.inc.c" +#include "insn_trans/trans_rvm.inc.c" +#include "insn_trans/trans_rva.inc.c" +#include "insn_trans/trans_rvf.inc.c" +#include "insn_trans/trans_rvd.inc.c" +#include "insn_trans/trans_privileged.inc.c" + +bool decode_insn16(DisasContext *ctx, uint16_t insn); +/* auto-generated decoder*/ +#include "decode_insn16.inc.c" +#include "insn_trans/trans_rvc.inc.c" + static void decode_opc(DisasContext *ctx) { /* check for compressed insn */ @@ -2007,11 +680,16 @@ static void decode_opc(DisasContext *ctx) gen_exception_illegal(ctx); } else { ctx->pc_succ_insn = ctx->base.pc_next + 2; - decode_RV32_64C(ctx); + if (!decode_insn16(ctx, ctx->opcode)) { + /* fall back to old decoder */ + decode_RV32_64C(ctx); + } } } else { ctx->pc_succ_insn = ctx->base.pc_next + 4; - decode_RV32_64G(ctx); + if (!decode_insn32(ctx, ctx->opcode)) { + gen_exception_illegal(ctx); + } } } @@ -2105,11 +783,11 @@ static const TranslatorOps riscv_tr_ops = { .disas_log = riscv_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { DisasContext ctx; - translator_loop(&riscv_tr_ops, &ctx.base, cs, tb); + translator_loop(&riscv_tr_ops, &ctx.base, cs, tb, max_insns); } void riscv_translate_init(void) diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 698dd9cb82..b58ef0a8ef 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -399,6 +399,13 @@ int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) return 0; } +void s390_set_max_pagesize(uint64_t pagesize, Error **errp) +{ + if (kvm_enabled()) { + kvm_s390_set_max_pagesize(pagesize, errp); + } +} + void s390_cmma_reset(void) { if (kvm_enabled()) { diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index cb6d77053a..7305cacc7b 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -734,6 +734,7 @@ static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg) /* cpu.c */ void s390_crypto_reset(void); int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit); +void s390_set_max_pagesize(uint64_t pagesize, Error **errp); void s390_cmma_reset(void); void s390_enable_css_support(S390CPU *cpu); int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id, @@ -753,7 +754,7 @@ static inline uint8_t s390_cpu_get_state(S390CPU *cpu) /* cpu_models.c */ -void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void s390_cpu_list(void); #define cpu_list s390_cpu_list void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga, const S390FeatInit feat_init); diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index eb125d4d0d..e5afa15512 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -18,6 +18,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "qemu/error-report.h" +#include "qemu/qemu-print.h" #include "qapi/qmp/qerror.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qmp/qdict.h" @@ -308,7 +309,6 @@ const S390CPUDef *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, static void s390_print_cpu_model_list_entry(gpointer data, gpointer user_data) { - CPUListState *s = user_data; const S390CPUClass *scc = S390_CPU_CLASS((ObjectClass *)data); char *name = g_strdup(object_class_get_name((ObjectClass *)data)); const char *details = ""; @@ -321,8 +321,7 @@ static void s390_print_cpu_model_list_entry(gpointer data, gpointer user_data) /* strip off the -s390x-cpu */ g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0; - (*s->cpu_fprintf)(s->file, "s390 %-15s %-35s %s\n", name, scc->desc, - details); + qemu_printf("s390 %-15s %-35s %s\n", name, scc->desc, details); g_free(name); } @@ -360,33 +359,29 @@ static gint s390_cpu_list_compare(gconstpointer a, gconstpointer b) return cc_a->is_static ? -1 : 1; } -void s390_cpu_list(FILE *f, fprintf_function print) +void s390_cpu_list(void) { - CPUListState s = { - .file = f, - .cpu_fprintf = print, - }; S390FeatGroup group; S390Feat feat; GSList *list; list = object_class_get_list(TYPE_S390_CPU, false); list = g_slist_sort(list, s390_cpu_list_compare); - g_slist_foreach(list, s390_print_cpu_model_list_entry, &s); + g_slist_foreach(list, s390_print_cpu_model_list_entry, NULL); g_slist_free(list); - (*print)(f, "\nRecognized feature flags:\n"); + qemu_printf("\nRecognized feature flags:\n"); for (feat = 0; feat < S390_FEAT_MAX; feat++) { const S390FeatDef *def = s390_feat_def(feat); - (*print)(f, "%-20s %-50s\n", def->name, def->desc); + qemu_printf("%-20s %-50s\n", def->name, def->desc); } - (*print)(f, "\nRecognized feature groups:\n"); + qemu_printf("\nRecognized feature groups:\n"); for (group = 0; group < S390_FEAT_GROUP_MAX; group++) { const S390FeatGroupDef *def = s390_feat_group_def(group); - (*print)(f, "%-20s %-50s\n", def->name, def->desc); + qemu_printf("%-20s %-50s\n", def->name, def->desc); } } diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 8e9573221c..f957a2c830 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -23,6 +23,7 @@ #include "internal.h" #include "exec/gdbstub.h" #include "qemu/timer.h" +#include "qemu/qemu-print.h" #include "hw/s390x/ioinst.h" #include "sysemu/hw_accel.h" #ifndef CONFIG_USER_ONLY @@ -313,65 +314,64 @@ int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len) } #endif /* CONFIG_USER_ONLY */ -void s390_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void s390_cpu_dump_state(CPUState *cs, FILE *f, int flags) { S390CPU *cpu = S390_CPU(cs); CPUS390XState *env = &cpu->env; int i; if (env->cc_op > 3) { - cpu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %15s\n", - env->psw.mask, env->psw.addr, cc_name(env->cc_op)); + qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %15s\n", + env->psw.mask, env->psw.addr, cc_name(env->cc_op)); } else { - cpu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %02x\n", - env->psw.mask, env->psw.addr, env->cc_op); + qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %02x\n", + env->psw.mask, env->psw.addr, env->cc_op); } for (i = 0; i < 16; i++) { - cpu_fprintf(f, "R%02d=%016" PRIx64, i, env->regs[i]); + qemu_fprintf(f, "R%02d=%016" PRIx64, i, env->regs[i]); if ((i % 4) == 3) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } else { - cpu_fprintf(f, " "); + qemu_fprintf(f, " "); } } if (flags & CPU_DUMP_FPU) { if (s390_has_feat(S390_FEAT_VECTOR)) { for (i = 0; i < 32; i++) { - cpu_fprintf(f, "V%02d=%016" PRIx64 "%016" PRIx64 "%c", - i, env->vregs[i][0].ll, env->vregs[i][1].ll, - i % 2 ? '\n' : ' '); + qemu_fprintf(f, "V%02d=%016" PRIx64 "%016" PRIx64 "%c", + i, env->vregs[i][0].ll, env->vregs[i][1].ll, + i % 2 ? '\n' : ' '); } } else { for (i = 0; i < 16; i++) { - cpu_fprintf(f, "F%02d=%016" PRIx64 "%c", - i, get_freg(env, i)->ll, - (i % 4) == 3 ? '\n' : ' '); + qemu_fprintf(f, "F%02d=%016" PRIx64 "%c", + i, get_freg(env, i)->ll, + (i % 4) == 3 ? '\n' : ' '); } } } #ifndef CONFIG_USER_ONLY for (i = 0; i < 16; i++) { - cpu_fprintf(f, "C%02d=%016" PRIx64, i, env->cregs[i]); + qemu_fprintf(f, "C%02d=%016" PRIx64, i, env->cregs[i]); if ((i % 4) == 3) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } else { - cpu_fprintf(f, " "); + qemu_fprintf(f, " "); } } #endif #ifdef DEBUG_INLINE_BRANCHES for (i = 0; i < CC_OP_MAX; i++) { - cpu_fprintf(f, " %15s = %10ld\t%10ld\n", cc_name(i), - inline_branch_miss[i], inline_branch_hit[i]); + qemu_fprintf(f, " %15s = %10ld\t%10ld\n", cc_name(i), + inline_branch_miss[i], inline_branch_hit[i]); } #endif - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } const char *cc_name(enum cc_op cc_op) diff --git a/target/s390x/internal.h b/target/s390x/internal.h index 3b4855c175..26575f2130 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -292,8 +292,7 @@ void s390_cpu_gdb_init(CPUState *cs); /* helper.c */ -void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, - int flags); +void s390_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr); uint64_t get_psw_mask(CPUS390XState *env); diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c index bf7795e47a..22b4514ca6 100644 --- a/target/s390x/kvm-stub.c +++ b/target/s390x/kvm-stub.c @@ -93,6 +93,10 @@ int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit) return 0; } +void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp) +{ +} + void kvm_s390_crypto_reset(void) { } diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 19530fb94e..7df7be4a1b 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -283,44 +283,37 @@ void kvm_s390_crypto_reset(void) } } -static int kvm_s390_configure_mempath_backing(KVMState *s) +void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp) { - size_t path_psize = qemu_getrampagesize(); - - if (path_psize == 4 * KiB) { - return 0; + if (pagesize == 4 * KiB) { + return; } if (!hpage_1m_allowed()) { - error_report("This QEMU machine does not support huge page " - "mappings"); - return -EINVAL; + error_setg(errp, "This QEMU machine does not support huge page " + "mappings"); + return; } - if (path_psize != 1 * MiB) { - error_report("Memory backing with 2G pages was specified, " - "but KVM does not support this memory backing"); - return -EINVAL; + if (pagesize != 1 * MiB) { + error_setg(errp, "Memory backing with 2G pages was specified, " + "but KVM does not support this memory backing"); + return; } - if (kvm_vm_enable_cap(s, KVM_CAP_S390_HPAGE_1M, 0)) { - error_report("Memory backing with 1M pages was specified, " - "but KVM does not support this memory backing"); - return -EINVAL; + if (kvm_vm_enable_cap(kvm_state, KVM_CAP_S390_HPAGE_1M, 0)) { + error_setg(errp, "Memory backing with 1M pages was specified, " + "but KVM does not support this memory backing"); + return; } cap_hpage_1m = 1; - return 0; } int kvm_arch_init(MachineState *ms, KVMState *s) { MachineClass *mc = MACHINE_GET_CLASS(ms); - if (kvm_s390_configure_mempath_backing(s)) { - return -EINVAL; - } - mc->default_cpu_type = S390_CPU_TYPE_NAME("host"); cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS); cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF); @@ -782,7 +775,7 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op); if (ret < 0) { - error_printf("KVM_S390_MEM_OP failed: %s\n", strerror(-ret)); + warn_report("KVM_S390_MEM_OP failed: %s", strerror(-ret)); } return ret; } diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h index 6e52287da3..caf985955b 100644 --- a/target/s390x/kvm_s390x.h +++ b/target/s390x/kvm_s390x.h @@ -36,6 +36,7 @@ int kvm_s390_cmma_active(void); void kvm_s390_cmma_reset(void); void kvm_s390_reset_vcpu(S390CPU *cpu); int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit); +void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp); void kvm_s390_crypto_reset(void); void kvm_s390_restart_interrupt(S390CPU *cpu); void kvm_s390_stop_interrupt(S390CPU *cpu); diff --git a/target/s390x/trace-events b/target/s390x/trace-events index e509b08799..fda1ee8220 100644 --- a/target/s390x/trace-events +++ b/target/s390x/trace-events @@ -1,25 +1,25 @@ # See docs/devel/tracing.txt for syntax documentation. -# target/s390x/mmu_helper.c +# mmu_helper.c get_skeys_nonzero(int rc) "SKEY: Call to get_skeys unexpectedly returned %d" set_skeys_nonzero(int rc) "SKEY: Call to set_skeys unexpectedly returned %d" -# target/s390x/ioinst.c +# ioinst.c ioinst(const char *insn) "IOINST: %s" ioinst_sch_id(const char *insn, int cssid, int ssid, int schid) "IOINST: %s (%x.%x.%04x)" ioinst_chp_id(const char *insn, int cssid, int chpid) "IOINST: %s (%x.%02x)" ioinst_chsc_cmd(uint16_t cmd, uint16_t len) "IOINST: chsc command 0x%04x, len 0x%04x" -# target/s390x/kvm.c +# kvm.c kvm_enable_cmma(int rc) "CMMA: enabling with result code %d" kvm_clear_cmma(int rc) "CMMA: clearing with result code %d" kvm_failed_cpu_state_set(int cpu_index, uint8_t state, const char *msg) "Warning: Unable to set cpu %d state %" PRIu8 " to KVM: %s" kvm_assign_subch_ioeventfd(int fd, uint32_t addr, bool assign, int datamatch) "fd: %d sch: @0x%x assign: %d vq: %d" -# target/s390x/cpu.c +# cpu.c cpu_set_state(int cpu_index, uint8_t state) "setting cpu %d state to %" PRIu8 cpu_halt(int cpu_index) "halting cpu %d" cpu_unhalt(int cpu_index) "unhalting cpu %d" -# target/s390x/sigp.c +# sigp.c sigp_finished(uint8_t order, int cpu_index, int dst_index, int cc) "SIGP: Finished order %u on cpu %d -> cpu %d with cc=%d" diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 0afa8f7ca5..d4951836ad 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -6552,11 +6552,11 @@ static const TranslatorOps s390x_tr_ops = { .disas_log = s390x_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { DisasContext dc; - translator_loop(&s390x_tr_ops, &dc.base, cs, tb); + translator_loop(&s390x_tr_ops, &dc.base, cs, tb, max_insns); } void restore_state_to_opc(CPUS390XState *env, TranslationBlock *tb, diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index b9f393b7c7..da2799082e 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/qemu-print.h" #include "cpu.h" #include "qemu-common.h" #include "migration/vmstate.h" @@ -79,30 +80,20 @@ static void superh_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) info->print_insn = print_insn_sh; } -typedef struct SuperHCPUListState { - fprintf_function cpu_fprintf; - FILE *file; -} SuperHCPUListState; - static void superh_cpu_list_entry(gpointer data, gpointer user_data) { - SuperHCPUListState *s = user_data; const char *typename = object_class_get_name(OBJECT_CLASS(data)); int len = strlen(typename) - strlen(SUPERH_CPU_TYPE_SUFFIX); - (*s->cpu_fprintf)(s->file, "%.*s\n", len, typename); + qemu_printf("%.*s\n", len, typename); } -void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void sh4_cpu_list(void) { - SuperHCPUListState s = { - .cpu_fprintf = cpu_fprintf, - .file = f, - }; GSList *list; list = object_class_get_list_sorted(TYPE_SUPERH_CPU, false); - g_slist_foreach(list, superh_cpu_list_entry, &s); + g_slist_foreach(list, superh_cpu_list_entry, NULL); g_slist_free(list); } diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 775b5743bf..84b08ff640 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -232,8 +232,7 @@ static inline SuperHCPU *sh_env_get_cpu(CPUSH4State *env) void superh_cpu_do_interrupt(CPUState *cpu); bool superh_cpu_exec_interrupt(CPUState *cpu, int int_req); -void superh_cpu_dump_state(CPUState *cpu, FILE *f, - fprintf_function cpu_fprintf, int flags); +void superh_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int superh_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); @@ -247,7 +246,7 @@ int cpu_sh4_signal_handler(int host_signum, void *pinfo, int superh_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, int rw, int mmu_idx); -void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void sh4_cpu_list(void); #if !defined(CONFIG_USER_ONLY) void cpu_sh4_invalidate_tlb(CPUSH4State *s); uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s, diff --git a/target/sh4/translate.c b/target/sh4/translate.c index ab254b0e8d..cdf0888490 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -30,6 +30,7 @@ #include "exec/translator.h" #include "trace-tcg.h" #include "exec/log.h" +#include "qemu/qemu-print.h" typedef struct DisasContext { @@ -156,32 +157,32 @@ void sh4_translate_init(void) fregnames[i]); } -void superh_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags) +void superh_cpu_dump_state(CPUState *cs, FILE *f, int flags) { SuperHCPU *cpu = SUPERH_CPU(cs); CPUSH4State *env = &cpu->env; int i; - cpu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x fpscr=0x%08x\n", - env->pc, cpu_read_sr(env), env->pr, env->fpscr); - cpu_fprintf(f, "spc=0x%08x ssr=0x%08x gbr=0x%08x vbr=0x%08x\n", - env->spc, env->ssr, env->gbr, env->vbr); - cpu_fprintf(f, "sgr=0x%08x dbr=0x%08x delayed_pc=0x%08x fpul=0x%08x\n", - env->sgr, env->dbr, env->delayed_pc, env->fpul); + + qemu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x fpscr=0x%08x\n", + env->pc, cpu_read_sr(env), env->pr, env->fpscr); + qemu_fprintf(f, "spc=0x%08x ssr=0x%08x gbr=0x%08x vbr=0x%08x\n", + env->spc, env->ssr, env->gbr, env->vbr); + qemu_fprintf(f, "sgr=0x%08x dbr=0x%08x delayed_pc=0x%08x fpul=0x%08x\n", + env->sgr, env->dbr, env->delayed_pc, env->fpul); for (i = 0; i < 24; i += 4) { - cpu_fprintf(f, "r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n", + qemu_printf("r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n", i, env->gregs[i], i + 1, env->gregs[i + 1], i + 2, env->gregs[i + 2], i + 3, env->gregs[i + 3]); } if (env->flags & DELAY_SLOT) { - cpu_fprintf(f, "in delay slot (delayed_pc=0x%08x)\n", + qemu_printf("in delay slot (delayed_pc=0x%08x)\n", env->delayed_pc); } else if (env->flags & DELAY_SLOT_CONDITIONAL) { - cpu_fprintf(f, "in conditional delay slot (delayed_pc=0x%08x)\n", + qemu_printf("in conditional delay slot (delayed_pc=0x%08x)\n", env->delayed_pc); } else if (env->flags & DELAY_SLOT_RTE) { - cpu_fprintf(f, "in rte delay slot (delayed_pc=0x%08x)\n", - env->delayed_pc); + qemu_fprintf(f, "in rte delay slot (delayed_pc=0x%08x)\n", + env->delayed_pc); } } @@ -2382,11 +2383,11 @@ static const TranslatorOps sh4_tr_ops = { .disas_log = sh4_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { DisasContext ctx; - translator_loop(&sh4_tr_ops, &ctx.base, cs, tb); + translator_loop(&sh4_tr_ops, &ctx.base, cs, tb, max_insns); } void restore_state_to_opc(CPUSH4State *env, TranslationBlock *tb, diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 4a4445bdf5..4654c2a6a0 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "cpu.h" -#include "qemu/error-report.h" +#include "qemu/qemu-print.h" #include "exec/exec-all.h" #include "hw/qdev-properties.h" #include "qapi/visitor.h" @@ -556,55 +556,51 @@ static const char * const feature_name[] = { "gl", }; -static void print_features(FILE *f, fprintf_function cpu_fprintf, - uint32_t features, const char *prefix) +static void print_features(uint32_t features, const char *prefix) { unsigned int i; for (i = 0; i < ARRAY_SIZE(feature_name); i++) { if (feature_name[i] && (features & (1 << i))) { if (prefix) { - (*cpu_fprintf)(f, "%s", prefix); + qemu_printf("%s", prefix); } - (*cpu_fprintf)(f, "%s ", feature_name[i]); + qemu_printf("%s ", feature_name[i]); } } } -void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void sparc_cpu_list(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) { - (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx - " FPU %08x MMU %08x NWINS %d ", - sparc_defs[i].name, - sparc_defs[i].iu_version, - sparc_defs[i].fpu_version, - sparc_defs[i].mmu_version, - sparc_defs[i].nwindows); - print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES & - ~sparc_defs[i].features, "-"); - print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES & - sparc_defs[i].features, "+"); - (*cpu_fprintf)(f, "\n"); + qemu_printf("Sparc %16s IU " TARGET_FMT_lx + " FPU %08x MMU %08x NWINS %d ", + sparc_defs[i].name, + sparc_defs[i].iu_version, + sparc_defs[i].fpu_version, + sparc_defs[i].mmu_version, + sparc_defs[i].nwindows); + print_features(CPU_DEFAULT_FEATURES & ~sparc_defs[i].features, "-"); + print_features(~CPU_DEFAULT_FEATURES & sparc_defs[i].features, "+"); + qemu_printf("\n"); } - (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): "); - print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL); - (*cpu_fprintf)(f, "\n"); - (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): "); - print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL); - (*cpu_fprintf)(f, "\n"); - (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version " - "fpu_version mmu_version nwindows\n"); + qemu_printf("Default CPU feature flags (use '-' to remove): "); + print_features(CPU_DEFAULT_FEATURES, NULL); + qemu_printf("\n"); + qemu_printf("Available CPU feature flags (use '+' to add): "); + print_features(~CPU_DEFAULT_FEATURES, NULL); + qemu_printf("\n"); + qemu_printf("Numerical features (use '=' to set): iu_version " + "fpu_version mmu_version nwindows\n"); } -static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf, - uint32_t cc) +static void cpu_print_cc(FILE *f, uint32_t cc) { - cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG ? 'N' : '-', - cc & PSR_ZERO ? 'Z' : '-', cc & PSR_OVF ? 'V' : '-', - cc & PSR_CARRY ? 'C' : '-'); + qemu_fprintf(f, "%c%c%c%c", cc & PSR_NEG ? 'N' : '-', + cc & PSR_ZERO ? 'Z' : '-', cc & PSR_OVF ? 'V' : '-', + cc & PSR_CARRY ? 'C' : '-'); } #ifdef TARGET_SPARC64 @@ -613,35 +609,34 @@ static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf, #define REGS_PER_LINE 8 #endif -void sparc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) +void sparc_cpu_dump_state(CPUState *cs, FILE *f, int flags) { SPARCCPU *cpu = SPARC_CPU(cs); CPUSPARCState *env = &cpu->env; int i, x; - cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, - env->npc); + qemu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, + env->npc); for (i = 0; i < 8; i++) { if (i % REGS_PER_LINE == 0) { - cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1); + qemu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1); } - cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]); + qemu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]); if (i % REGS_PER_LINE == REGS_PER_LINE - 1) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } for (x = 0; x < 3; x++) { for (i = 0; i < 8; i++) { if (i % REGS_PER_LINE == 0) { - cpu_fprintf(f, "%%%c%d-%d: ", - x == 0 ? 'o' : (x == 1 ? 'l' : 'i'), - i, i + REGS_PER_LINE - 1); + qemu_fprintf(f, "%%%c%d-%d: ", + x == 0 ? 'o' : (x == 1 ? 'l' : 'i'), + i, i + REGS_PER_LINE - 1); } - cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]); + qemu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]); if (i % REGS_PER_LINE == REGS_PER_LINE - 1) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } } @@ -649,42 +644,42 @@ void sparc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, if (flags & CPU_DUMP_FPU) { for (i = 0; i < TARGET_DPREGS; i++) { if ((i & 3) == 0) { - cpu_fprintf(f, "%%f%02d: ", i * 2); + qemu_fprintf(f, "%%f%02d: ", i * 2); } - cpu_fprintf(f, " %016" PRIx64, env->fpr[i].ll); + qemu_fprintf(f, " %016" PRIx64, env->fpr[i].ll); if ((i & 3) == 3) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } } } #ifdef TARGET_SPARC64 - cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate, - (unsigned)cpu_get_ccr(env)); - cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT); - cpu_fprintf(f, " xcc: "); - cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4)); - cpu_fprintf(f, ") asi: %02x tl: %d pil: %x gl: %d\n", env->asi, env->tl, - env->psrpil, env->gl); - cpu_fprintf(f, "tbr: " TARGET_FMT_lx " hpstate: " TARGET_FMT_lx " htba: " - TARGET_FMT_lx "\n", env->tbr, env->hpstate, env->htba); - cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d " - "cleanwin: %d cwp: %d\n", - env->cansave, env->canrestore, env->otherwin, env->wstate, - env->cleanwin, env->nwindows - 1 - env->cwp); - cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: " - TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs); + qemu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate, + (unsigned)cpu_get_ccr(env)); + cpu_print_cc(f, cpu_get_ccr(env) << PSR_CARRY_SHIFT); + qemu_fprintf(f, " xcc: "); + cpu_print_cc(f, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4)); + qemu_fprintf(f, ") asi: %02x tl: %d pil: %x gl: %d\n", env->asi, env->tl, + env->psrpil, env->gl); + qemu_fprintf(f, "tbr: " TARGET_FMT_lx " hpstate: " TARGET_FMT_lx " htba: " + TARGET_FMT_lx "\n", env->tbr, env->hpstate, env->htba); + qemu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d " + "cleanwin: %d cwp: %d\n", + env->cansave, env->canrestore, env->otherwin, env->wstate, + env->cleanwin, env->nwindows - 1 - env->cwp); + qemu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: " + TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs); #else - cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env)); - cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env)); - cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs ? 'S' : '-', - env->psrps ? 'P' : '-', env->psret ? 'E' : '-', - env->wim); - cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n", - env->fsr, env->y); + qemu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env)); + cpu_print_cc(f, cpu_get_psr(env)); + qemu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs ? 'S' : '-', + env->psrps ? 'P' : '-', env->psret ? 'E' : '-', + env->wim); + qemu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n", + env->fsr, env->y); #endif - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } static void sparc_cpu_set_pc(CPUState *cs, vaddr value) diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 4972ebcfd4..85b9665ccc 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -564,8 +564,7 @@ extern const struct VMStateDescription vmstate_sparc_cpu; #endif void sparc_cpu_do_interrupt(CPUState *cpu); -void sparc_cpu_dump_state(CPUState *cpu, FILE *f, - fprintf_function cpu_fprintf, int flags); +void sparc_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); @@ -578,12 +577,12 @@ void cpu_raise_exception_ra(CPUSPARCState *, int, uintptr_t) QEMU_NORETURN; #ifndef NO_CPU_IO_DEFS /* cpu_init.c */ void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu); -void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void sparc_cpu_list(void); /* mmu_helper.c */ int sparc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, int rw, int mmu_idx); target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev); -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env); +void dump_mmu(CPUSPARCState *env); #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) int sparc_cpu_memory_rw_debug(CPUState *cpu, vaddr addr, diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c index 5bc090213c..a7fcb84ac0 100644 --- a/target/sparc/ldst_helper.c +++ b/target/sparc/ldst_helper.c @@ -198,7 +198,7 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, replace_tlb_entry(&tlb[i], 0, 0, env1); #ifdef DEBUG_MMU DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i); - dump_mmu(stdout, fprintf, env1); + dump_mmu(env1); #endif } } @@ -260,7 +260,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); #ifdef DEBUG_MMU DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i); - dump_mmu(stdout, fprintf, env1); + dump_mmu(env1); #endif return; } @@ -279,7 +279,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, #ifdef DEBUG_MMU DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n", strmmu, (replace_used ? "used" : "unused"), i); - dump_mmu(stdout, fprintf, env1); + dump_mmu(env1); #endif return; } @@ -886,7 +886,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, break; } #ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); + dump_mmu(env); #endif } break; @@ -941,7 +941,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, reg, oldreg, env->mmuregs[reg]); } #ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); + dump_mmu(env); #endif } break; @@ -1634,7 +1634,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, PRIx64 "\n", reg, oldreg, env->immuregs[reg]); } #ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); + dump_mmu(env); #endif return; } @@ -1658,7 +1658,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, } #ifdef DEBUG_MMU DPRINTF_MMU("immu data access replaced entry [%i]\n", i); - dump_mmu(stdout, fprintf, env); + dump_mmu(env); #endif return; } @@ -1718,7 +1718,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); } #ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env); + dump_mmu(env); #endif return; } @@ -1740,7 +1740,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, } #ifdef DEBUG_MMU DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i); - dump_mmu(stdout, fprintf, env); + dump_mmu(env); #endif return; } diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c index 135a9c9d9b..afcc5b617d 100644 --- a/target/sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/exec-all.h" +#include "qemu/qemu-print.h" #include "trace.h" /* Sparc MMU emulation */ @@ -320,7 +321,7 @@ target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev) return 0; } -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env) +void dump_mmu(CPUSPARCState *env) { CPUState *cs = CPU(sparc_env_get_cpu(env)); target_ulong va, va1, va2; @@ -330,29 +331,29 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env) pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); pde = ldl_phys(cs->as, pde_ptr); - (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n", - (hwaddr)env->mmuregs[1] << 4, env->mmuregs[2]); + qemu_printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n", + (hwaddr)env->mmuregs[1] << 4, env->mmuregs[2]); for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { pde = mmu_probe(env, va, 2); if (pde) { pa = cpu_get_phys_page_debug(cs, va); - (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx - " PDE: " TARGET_FMT_lx "\n", va, pa, pde); + qemu_printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx + " PDE: " TARGET_FMT_lx "\n", va, pa, pde); for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { pde = mmu_probe(env, va1, 1); if (pde) { pa = cpu_get_phys_page_debug(cs, va1); - (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " - TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", - va1, pa, pde); + qemu_printf(" VA: " TARGET_FMT_lx ", PA: " + TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", + va1, pa, pde); for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { pde = mmu_probe(env, va2, 0); if (pde) { pa = cpu_get_phys_page_debug(cs, va2); - (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " - TARGET_FMT_plx " PTE: " - TARGET_FMT_lx "\n", - va2, pa, pde); + qemu_printf(" VA: " TARGET_FMT_lx ", PA: " + TARGET_FMT_plx " PTE: " + TARGET_FMT_lx "\n", + va2, pa, pde); } } } @@ -739,21 +740,21 @@ int sparc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, return 1; } -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env) +void dump_mmu(CPUSPARCState *env) { unsigned int i; const char *mask; - (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %" - PRId64 "\n", - env->dmmu.mmu_primary_context, - env->dmmu.mmu_secondary_context); - (*cpu_fprintf)(f, "DMMU Tag Access: %" PRIx64 ", TSB Tag Target: %" PRIx64 - "\n", env->dmmu.tag_access, env->dmmu.tsb_tag_target); + qemu_printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" + PRId64 "\n", + env->dmmu.mmu_primary_context, + env->dmmu.mmu_secondary_context); + qemu_printf("DMMU Tag Access: %" PRIx64 ", TSB Tag Target: %" PRIx64 + "\n", env->dmmu.tag_access, env->dmmu.tsb_tag_target); if ((env->lsu & DMMU_E) == 0) { - (*cpu_fprintf)(f, "DMMU disabled\n"); + qemu_printf("DMMU disabled\n"); } else { - (*cpu_fprintf)(f, "DMMU dump\n"); + qemu_printf("DMMU dump\n"); for (i = 0; i < 64; i++) { switch (TTE_PGSIZE(env->dtlb[i].tte)) { default: @@ -771,26 +772,26 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env) break; } if (TTE_IS_VALID(env->dtlb[i].tte)) { - (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" - ", %s, %s, %s, %s, ctx %" PRId64 " %s\n", - i, - env->dtlb[i].tag & (uint64_t)~0x1fffULL, - TTE_PA(env->dtlb[i].tte), - mask, - TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user", - TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO", - TTE_IS_LOCKED(env->dtlb[i].tte) ? - "locked" : "unlocked", - env->dtlb[i].tag & (uint64_t)0x1fffULL, - TTE_IS_GLOBAL(env->dtlb[i].tte) ? - "global" : "local"); + qemu_printf("[%02u] VA: %" PRIx64 ", PA: %llx" + ", %s, %s, %s, %s, ctx %" PRId64 " %s\n", + i, + env->dtlb[i].tag & (uint64_t)~0x1fffULL, + TTE_PA(env->dtlb[i].tte), + mask, + TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user", + TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO", + TTE_IS_LOCKED(env->dtlb[i].tte) ? + "locked" : "unlocked", + env->dtlb[i].tag & (uint64_t)0x1fffULL, + TTE_IS_GLOBAL(env->dtlb[i].tte) ? + "global" : "local"); } } } if ((env->lsu & IMMU_E) == 0) { - (*cpu_fprintf)(f, "IMMU disabled\n"); + qemu_printf("IMMU disabled\n"); } else { - (*cpu_fprintf)(f, "IMMU dump\n"); + qemu_printf("IMMU dump\n"); for (i = 0; i < 64; i++) { switch (TTE_PGSIZE(env->itlb[i].tte)) { default: @@ -808,18 +809,18 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env) break; } if (TTE_IS_VALID(env->itlb[i].tte)) { - (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" - ", %s, %s, %s, ctx %" PRId64 " %s\n", - i, - env->itlb[i].tag & (uint64_t)~0x1fffULL, - TTE_PA(env->itlb[i].tte), - mask, - TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user", - TTE_IS_LOCKED(env->itlb[i].tte) ? - "locked" : "unlocked", - env->itlb[i].tag & (uint64_t)0x1fffULL, - TTE_IS_GLOBAL(env->itlb[i].tte) ? - "global" : "local"); + qemu_printf("[%02u] VA: %" PRIx64 ", PA: %llx" + ", %s, %s, %s, ctx %" PRId64 " %s\n", + i, + env->itlb[i].tag & (uint64_t)~0x1fffULL, + TTE_PA(env->itlb[i].tte), + mask, + TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user", + TTE_IS_LOCKED(env->itlb[i].tte) ? + "locked" : "unlocked", + env->itlb[i].tag & (uint64_t)0x1fffULL, + TTE_IS_GLOBAL(env->itlb[i].tte) ? + "global" : "local"); } } } diff --git a/target/sparc/monitor.c b/target/sparc/monitor.c index f3ca524ae9..3ec3b51a3d 100644 --- a/target/sparc/monitor.c +++ b/target/sparc/monitor.c @@ -36,7 +36,7 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) monitor_printf(mon, "No CPU available\n"); return; } - dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1); + dump_mmu(env1); } #ifndef TARGET_SPARC64 diff --git a/target/sparc/trace-events b/target/sparc/trace-events index 764b1e5a02..6a064e2327 100644 --- a/target/sparc/trace-events +++ b/target/sparc/trace-events @@ -1,6 +1,6 @@ # See docs/devel/tracing.txt for syntax documentation. -# target/sparc/mmu_helper.c +# mmu_helper.c mmu_helper_dfault(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DFAULT at 0x%"PRIx64" context 0x%"PRIx64" mmu_idx=%d tl=%d" mmu_helper_dprot(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DPROT at 0x%"PRIx64" context 0x%"PRIx64" mmu_idx=%d tl=%d" mmu_helper_dmiss(uint64_t address, uint64_t context) "DMISS at 0x%"PRIx64" context 0x%"PRIx64 @@ -10,16 +10,16 @@ mmu_helper_get_phys_addr_code(uint32_t tl, int mmu_idx, uint64_t prim_context, u mmu_helper_get_phys_addr_data(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=0x%"PRIx64" secondary context=0x%"PRIx64" address=0x%"PRIx64 mmu_helper_mmu_fault(uint64_t address, uint64_t paddr, int mmu_idx, uint32_t tl, uint64_t prim_context, uint64_t sec_context) "Translate at 0x%"PRIx64" -> 0x%"PRIx64", mmu_idx=%d tl=%d primary context=0x%"PRIx64" secondary context=0x%"PRIx64 -# target/sparc/int64_helper.c +# int64_helper.c int_helper_set_softint(uint32_t softint) "new 0x%08x" int_helper_clear_softint(uint32_t softint) "new 0x%08x" int_helper_write_softint(uint32_t softint) "new 0x%08x" -# target/sparc/int32_helper.c +# int32_helper.c int_helper_icache_freeze(void) "Instruction cache: freeze" int_helper_dcache_freeze(void) "Data cache: freeze" -# target/sparc/win_helper.c +# win_helper.c win_helper_gregset_error(uint32_t pstate) "ERROR in get_gregset: active pstate bits=0x%x" win_helper_switch_pstate(uint32_t pstate_regs, uint32_t new_pstate_regs) "change_pstate: switching regs old=0x%x new=0x%x" win_helper_no_switch_pstate(uint32_t new_pstate_regs) "change_pstate: regs new=0x%x (unchanged)" diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 74315cdf09..091bab53af 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -5962,11 +5962,11 @@ static const TranslatorOps sparc_tr_ops = { .disas_log = sparc_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { DisasContext dc = {}; - translator_loop(&sparc_tr_ops, &dc.base, cs, tb); + translator_loop(&sparc_tr_ops, &dc.base, cs, tb, max_insns); } void sparc_tcg_init(void) diff --git a/target/tilegx/cpu.c b/target/tilegx/cpu.c index bfe9be59b5..b9d37105fa 100644 --- a/target/tilegx/cpu.c +++ b/target/tilegx/cpu.c @@ -24,9 +24,9 @@ #include "qemu-common.h" #include "hw/qdev-properties.h" #include "linux-user/syscall_defs.h" +#include "qemu/qemu-print.h" -static void tilegx_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags) +static void tilegx_cpu_dump_state(CPUState *cs, FILE *f, int flags) { static const char * const reg_names[TILEGX_R_COUNT] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", @@ -43,12 +43,12 @@ static void tilegx_cpu_dump_state(CPUState *cs, FILE *f, int i; for (i = 0; i < TILEGX_R_COUNT; i++) { - cpu_fprintf(f, "%-4s" TARGET_FMT_lx "%s", - reg_names[i], env->regs[i], - (i % 4) == 3 ? "\n" : " "); + qemu_fprintf(f, "%-4s" TARGET_FMT_lx "%s", + reg_names[i], env->regs[i], + (i % 4) == 3 ? "\n" : " "); } - cpu_fprintf(f, "PC " TARGET_FMT_lx " CEX " TARGET_FMT_lx "\n\n", - env->pc, env->spregs[TILEGX_SPR_CMPEXCH]); + qemu_fprintf(f, "PC " TARGET_FMT_lx " CEX " TARGET_FMT_lx "\n\n", + env->pc, env->spregs[TILEGX_SPR_CMPEXCH]); } static ObjectClass *tilegx_cpu_class_by_name(const char *cpu_model) diff --git a/target/tilegx/translate.c b/target/tilegx/translate.c index df1e4d0fef..c46a4ab151 100644 --- a/target/tilegx/translate.c +++ b/target/tilegx/translate.c @@ -2369,7 +2369,7 @@ static void translate_one_bundle(DisasContext *dc, uint64_t bundle) } } -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { CPUTLGState *env = cs->env_ptr; DisasContext ctx; @@ -2377,7 +2377,6 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) uint64_t pc_start = tb->pc; uint64_t page_start = pc_start & TARGET_PAGE_MASK; int num_insns = 0; - int max_insns = tb_cflags(tb) & CF_COUNT_MASK; dc->pc = pc_start; dc->mmuidx = 0; @@ -2392,15 +2391,6 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) qemu_log_lock(); qemu_log("IN: %s\n", lookup_symbol(pc_start)); } - if (!max_insns) { - max_insns = CF_COUNT_MASK; - } - if (cs->singlestep_enabled || singlestep) { - max_insns = 1; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } gen_tb_start(tb); while (1) { diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h index 00e69dc154..64d1a9c75e 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -224,8 +224,7 @@ static inline TriCoreCPU *tricore_env_get_cpu(CPUTriCoreState *env) #define ENV_OFFSET offsetof(TriCoreCPU, env) hwaddr tricore_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -void tricore_cpu_dump_state(CPUState *cpu, FILE *f, - fprintf_function cpu_fprintf, int flags); +void tricore_cpu_dump_state(CPUState *cpu, FILE *f, int flags); #define MASK_PCXI_PCPN 0xff000000 @@ -375,7 +374,7 @@ void fpu_set_state(CPUTriCoreState *env); #define MMU_USER_IDX 2 -void tricore_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void tricore_cpu_list(void); #define cpu_signal_handler cpu_tricore_signal_handler #define cpu_list tricore_cpu_list diff --git a/target/tricore/helper.c b/target/tricore/helper.c index 0769046993..78ee87c9ea 100644 --- a/target/tricore/helper.c +++ b/target/tricore/helper.c @@ -20,6 +20,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "fpu/softfloat.h" +#include "qemu/qemu-print.h" enum { TLBRET_DIRTY = -4, @@ -82,28 +83,22 @@ int cpu_tricore_handle_mmu_fault(CPUState *cs, target_ulong address, static void tricore_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - CPUListState *s = user_data; const char *typename; char *name; typename = object_class_get_name(oc); name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_TRICORE_CPU)); - (*s->cpu_fprintf)(s->file, " %s\n", - name); + qemu_printf(" %s\n", name); g_free(name); } -void tricore_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void tricore_cpu_list(void) { - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; GSList *list; list = object_class_get_list_sorted(TYPE_TRICORE_CPU, false); - (*cpu_fprintf)(f, "Available CPUs:\n"); - g_slist_foreach(list, tricore_cpu_list_entry, &s); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, tricore_cpu_list_entry, NULL); g_slist_free(list); } diff --git a/target/tricore/translate.c b/target/tricore/translate.c index b12c391be5..8f6416144e 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -24,6 +24,7 @@ #include "exec/exec-all.h" #include "tcg-op.h" #include "exec/cpu_ldst.h" +#include "qemu/qemu-print.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" @@ -88,8 +89,7 @@ enum { MODE_UU = 3, }; -void tricore_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags) +void tricore_cpu_dump_state(CPUState *cs, FILE *f, int flags) { TriCoreCPU *cpu = TRICORE_CPU(cs); CPUTriCoreState *env = &cpu->env; @@ -98,26 +98,26 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f, psw = psw_read(env); - cpu_fprintf(f, "PC: " TARGET_FMT_lx, env->PC); - cpu_fprintf(f, " PSW: " TARGET_FMT_lx, psw); - cpu_fprintf(f, " ICR: " TARGET_FMT_lx, env->ICR); - cpu_fprintf(f, "\nPCXI: " TARGET_FMT_lx, env->PCXI); - cpu_fprintf(f, " FCX: " TARGET_FMT_lx, env->FCX); - cpu_fprintf(f, " LCX: " TARGET_FMT_lx, env->LCX); + qemu_fprintf(f, "PC: " TARGET_FMT_lx, env->PC); + qemu_fprintf(f, " PSW: " TARGET_FMT_lx, psw); + qemu_fprintf(f, " ICR: " TARGET_FMT_lx, env->ICR); + qemu_fprintf(f, "\nPCXI: " TARGET_FMT_lx, env->PCXI); + qemu_fprintf(f, " FCX: " TARGET_FMT_lx, env->FCX); + qemu_fprintf(f, " LCX: " TARGET_FMT_lx, env->LCX); for (i = 0; i < 16; ++i) { if ((i & 3) == 0) { - cpu_fprintf(f, "\nGPR A%02d:", i); + qemu_fprintf(f, "\nGPR A%02d:", i); } - cpu_fprintf(f, " " TARGET_FMT_lx, env->gpr_a[i]); + qemu_fprintf(f, " " TARGET_FMT_lx, env->gpr_a[i]); } for (i = 0; i < 16; ++i) { if ((i & 3) == 0) { - cpu_fprintf(f, "\nGPR D%02d:", i); + qemu_fprintf(f, "\nGPR D%02d:", i); } - cpu_fprintf(f, " " TARGET_FMT_lx, env->gpr_d[i]); + qemu_fprintf(f, " " TARGET_FMT_lx, env->gpr_d[i]); } - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } /* @@ -8807,24 +8807,12 @@ static void decode_opc(CPUTriCoreState *env, DisasContext *ctx, int *is_branch) } } -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { CPUTriCoreState *env = cs->env_ptr; DisasContext ctx; target_ulong pc_start; - int num_insns, max_insns; - - num_insns = 0; - max_insns = tb_cflags(tb) & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (singlestep) { - max_insns = 1; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } + int num_insns = 0; pc_start = tb->pc; ctx.pc = pc_start; diff --git a/target/unicore32/cpu.h b/target/unicore32/cpu.h index 735d3ae9dc..24abe5e5c0 100644 --- a/target/unicore32/cpu.h +++ b/target/unicore32/cpu.h @@ -97,8 +97,7 @@ static inline UniCore32CPU *uc32_env_get_cpu(CPUUniCore32State *env) void uc32_cpu_do_interrupt(CPUState *cpu); bool uc32_cpu_exec_interrupt(CPUState *cpu, int int_req); -void uc32_cpu_dump_state(CPUState *cpu, FILE *f, - fprintf_function cpu_fprintf, int flags); +void uc32_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr uc32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); #define ASR_M (0x1f) diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c index 002569ff3b..89b02d1c3c 100644 --- a/target/unicore32/translate.c +++ b/target/unicore32/translate.c @@ -17,6 +17,7 @@ #include "qemu/log.h" #include "exec/cpu_ldst.h" #include "exec/translator.h" +#include "qemu/qemu-print.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" @@ -1870,14 +1871,13 @@ static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s) } /* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) { CPUUniCore32State *env = cs->env_ptr; DisasContext dc1, *dc = &dc1; target_ulong pc_start; uint32_t page_start; int num_insns; - int max_insns; /* generate intermediate code */ num_temps = 0; @@ -1896,13 +1896,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) cpu_F1d = tcg_temp_new_i64(); page_start = pc_start & TARGET_PAGE_MASK; num_insns = 0; - max_insns = tb_cflags(tb) & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } #ifndef CONFIG_USER_ONLY if ((env->uncached_asr & ASR_M) == ASR_MODE_USER) { @@ -2043,8 +2036,7 @@ static const char *cpu_mode_names[16] = { #undef UCF64_DUMP_STATE #ifdef UCF64_DUMP_STATE -static void cpu_dump_state_ucf64(CPUUniCore32State *env, FILE *f, - fprintf_function cpu_fprintf, int flags) +static void cpu_dump_state_ucf64(CPUUniCore32State *env, int flags) { int i; union { @@ -2064,20 +2056,19 @@ static void cpu_dump_state_ucf64(CPUUniCore32State *env, FILE *f, s0.i = d.l.lower; s1.i = d.l.upper; d0.f64 = d.d; - cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g)", - i * 2, (int)s0.i, s0.s, - i * 2 + 1, (int)s1.i, s1.s); - cpu_fprintf(f, " d%02d=%" PRIx64 "(%8g)\n", - i, (uint64_t)d0.f64, d0.d); + qemu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g)", + i * 2, (int)s0.i, s0.s, + i * 2 + 1, (int)s1.i, s1.s); + qemu_fprintf(f, " d%02d=%" PRIx64 "(%8g)\n", + i, (uint64_t)d0.f64, d0.d); } - cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]); + qemu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]); } #else #define cpu_dump_state_ucf64(env, file, pr, flags) do { } while (0) #endif -void uc32_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags) +void uc32_cpu_dump_state(CPUState *cs, FILE *f, int flags) { UniCore32CPU *cpu = UNICORE32_CPU(cs); CPUUniCore32State *env = &cpu->env; @@ -2085,21 +2076,21 @@ void uc32_cpu_dump_state(CPUState *cs, FILE *f, uint32_t psr; for (i = 0; i < 32; i++) { - cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); + qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]); if ((i % 4) == 3) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); } else { - cpu_fprintf(f, " "); + qemu_fprintf(f, " "); } } psr = cpu_asr_read(env); - cpu_fprintf(f, "PSR=%08x %c%c%c%c %s\n", - psr, - psr & (1 << 31) ? 'N' : '-', - psr & (1 << 30) ? 'Z' : '-', - psr & (1 << 29) ? 'C' : '-', - psr & (1 << 28) ? 'V' : '-', - cpu_mode_names[psr & 0xf]); + qemu_fprintf(f, "PSR=%08x %c%c%c%c %s\n", + psr, + psr & (1 << 31) ? 'N' : '-', + psr & (1 << 30) ? 'Z' : '-', + psr & (1 << 29) ? 'C' : '-', + psr & (1 << 28) ? 'V' : '-', + cpu_mode_names[psr & 0xf]); if (flags & CPU_DUMP_FPU) { cpu_dump_state_ucf64(env, f, cpu_fprintf, flags); diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 4d8152682f..5d23e1345b 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -560,8 +560,7 @@ void xtensa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, unsigned size, MMUAccessType access_type, int mmu_idx, MemTxAttrs attrs, MemTxResult response, uintptr_t retaddr); -void xtensa_cpu_dump_state(CPUState *cpu, FILE *f, - fprintf_function cpu_fprintf, int flags); +void xtensa_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); void xtensa_count_regs(const XtensaConfig *config, unsigned *n_regs, unsigned *n_core_regs); @@ -600,7 +599,7 @@ void xtensa_irq_init(CPUXtensaState *env); qemu_irq *xtensa_get_extints(CPUXtensaState *env); qemu_irq xtensa_get_runstall(CPUXtensaState *env); int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc); -void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void xtensa_cpu_list(void); void xtensa_sync_window_from_phys(CPUXtensaState *env); void xtensa_sync_phys_from_window(CPUXtensaState *env); void xtensa_rotate_window(CPUXtensaState *env, uint32_t delta); @@ -673,7 +672,7 @@ int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, uint32_t vaddr, int is_write, int mmu_idx, uint32_t *paddr, uint32_t *page_size, unsigned *access); void reset_mmu(CPUXtensaState *env); -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env); +void dump_mmu(CPUXtensaState *env); static inline MemoryRegion *xtensa_get_er_region(CPUXtensaState *env) { diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c index f4867a9b56..5f37f378a3 100644 --- a/target/xtensa/helper.c +++ b/target/xtensa/helper.c @@ -31,6 +31,7 @@ #include "exec/gdbstub.h" #include "exec/helper-proto.h" #include "qemu/error-report.h" +#include "qemu/qemu-print.h" #include "qemu/host-utils.h" static struct XtensaConfigList *xtensa_cores; @@ -228,12 +229,12 @@ void xtensa_breakpoint_handler(CPUState *cs) } } -void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf) +void xtensa_cpu_list(void) { XtensaConfigList *core = xtensa_cores; - cpu_fprintf(f, "Available CPUs:\n"); + qemu_printf("Available CPUs:\n"); for (; core; core = core->next) { - cpu_fprintf(f, " %s\n", core->config->name); + qemu_printf(" %s\n", core->config->name); } } diff --git a/target/xtensa/mmu_helper.c b/target/xtensa/mmu_helper.c index 2096fbbd9f..79a10da231 100644 --- a/target/xtensa/mmu_helper.c +++ b/target/xtensa/mmu_helper.c @@ -27,6 +27,7 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" +#include "qemu/qemu-print.h" #include "qemu/units.h" #include "cpu.h" #include "exec/helper-proto.h" @@ -740,8 +741,7 @@ int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, } } -static void dump_tlb(FILE *f, fprintf_function cpu_fprintf, - CPUXtensaState *env, bool dtlb) +static void dump_tlb(CPUXtensaState *env, bool dtlb) { unsigned wi, ei; const xtensa_tlb *conf = @@ -780,13 +780,11 @@ static void dump_tlb(FILE *f, fprintf_function cpu_fprintf, if (print_header) { print_header = false; - cpu_fprintf(f, "Way %u (%d %s)\n", wi, sz, sz_text); - cpu_fprintf(f, - "\tVaddr Paddr ASID Attr RWX Cache\n" + qemu_printf("Way %u (%d %s)\n", wi, sz, sz_text); + qemu_printf("\tVaddr Paddr ASID Attr RWX Cache\n" "\t---------- ---------- ---- ---- --- -------\n"); } - cpu_fprintf(f, - "\t0x%08x 0x%08x 0x%02x 0x%02x %c%c%c %-7s\n", + qemu_printf("\t0x%08x 0x%08x 0x%02x 0x%02x %c%c%c %-7s\n", entry->vaddr, entry->paddr, entry->asid, @@ -801,18 +799,18 @@ static void dump_tlb(FILE *f, fprintf_function cpu_fprintf, } } -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env) +void dump_mmu(CPUXtensaState *env) { if (xtensa_option_bits_enabled(env->config, XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION) | XTENSA_OPTION_BIT(XTENSA_OPTION_MMU))) { - cpu_fprintf(f, "ITLB:\n"); - dump_tlb(f, cpu_fprintf, env, false); - cpu_fprintf(f, "\nDTLB:\n"); - dump_tlb(f, cpu_fprintf, env, true); + qemu_printf("ITLB:\n"); + dump_tlb(env, false); + qemu_printf("\nDTLB:\n"); + dump_tlb(env, true); } else { - cpu_fprintf(f, "No TLB for this CPU core\n"); + qemu_printf("No TLB for this CPU core\n"); } } diff --git a/target/xtensa/monitor.c b/target/xtensa/monitor.c index 2ee2b5b23e..cf7957bb63 100644 --- a/target/xtensa/monitor.c +++ b/target/xtensa/monitor.c @@ -35,5 +35,5 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) monitor_printf(mon, "No CPU available\n"); return; } - dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1); + dump_mmu(env1); } diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 77bc04d6b0..301c8e3161 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -35,6 +35,7 @@ #include "disas/disas.h" #include "tcg-op.h" #include "qemu/log.h" +#include "qemu/qemu-print.h" #include "sysemu/sysemu.h" #include "exec/cpu_ldst.h" #include "exec/semihost.h" @@ -1041,7 +1042,6 @@ static bool break_dependency(struct slot_prop *a, copy[n].resource = b->in[j].resource; copy[n].arg = b->arg + index; ++n; - ++i; ++j; rv = true; } @@ -1635,66 +1635,67 @@ static const TranslatorOps xtensa_translator_ops = { .disas_log = xtensa_tr_disas_log, }; -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb) +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) { DisasContext dc = {}; - translator_loop(&xtensa_translator_ops, &dc.base, cpu, tb); + translator_loop(&xtensa_translator_ops, &dc.base, cpu, tb, max_insns); } -void xtensa_cpu_dump_state(CPUState *cs, FILE *f, - fprintf_function cpu_fprintf, int flags) +void xtensa_cpu_dump_state(CPUState *cs, FILE *f, int flags) { XtensaCPU *cpu = XTENSA_CPU(cs); CPUXtensaState *env = &cpu->env; int i, j; - cpu_fprintf(f, "PC=%08x\n\n", env->pc); + qemu_fprintf(f, "PC=%08x\n\n", env->pc); for (i = j = 0; i < 256; ++i) { if (xtensa_option_bits_enabled(env->config, sregnames[i].opt_bits)) { - cpu_fprintf(f, "%12s=%08x%c", sregnames[i].name, env->sregs[i], - (j++ % 4) == 3 ? '\n' : ' '); + qemu_fprintf(f, "%12s=%08x%c", + sregnames[i].name, env->sregs[i], + (j++ % 4) == 3 ? '\n' : ' '); } } - cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n"); + qemu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n"); for (i = j = 0; i < 256; ++i) { if (xtensa_option_bits_enabled(env->config, uregnames[i].opt_bits)) { - cpu_fprintf(f, "%s=%08x%c", uregnames[i].name, env->uregs[i], - (j++ % 4) == 3 ? '\n' : ' '); + qemu_fprintf(f, "%s=%08x%c", + uregnames[i].name, env->uregs[i], + (j++ % 4) == 3 ? '\n' : ' '); } } - cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n"); + qemu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n"); for (i = 0; i < 16; ++i) { - cpu_fprintf(f, " A%02d=%08x%c", i, env->regs[i], - (i % 4) == 3 ? '\n' : ' '); + qemu_fprintf(f, " A%02d=%08x%c", + i, env->regs[i], (i % 4) == 3 ? '\n' : ' '); } xtensa_sync_phys_from_window(env); - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); for (i = 0; i < env->config->nareg; ++i) { - cpu_fprintf(f, "AR%02d=%08x ", i, env->phys_regs[i]); + qemu_fprintf(f, "AR%02d=%08x ", i, env->phys_regs[i]); if (i % 4 == 3) { bool ws = (env->sregs[WINDOW_START] & (1 << (i / 4))) != 0; bool cw = env->sregs[WINDOW_BASE] == i / 4; - cpu_fprintf(f, "%c%c\n", ws ? '<' : ' ', cw ? '=' : ' '); + qemu_fprintf(f, "%c%c\n", ws ? '<' : ' ', cw ? '=' : ' '); } } if ((flags & CPU_DUMP_FPU) && xtensa_option_enabled(env->config, XTENSA_OPTION_FP_COPROCESSOR)) { - cpu_fprintf(f, "\n"); + qemu_fprintf(f, "\n"); for (i = 0; i < 16; ++i) { - cpu_fprintf(f, "F%02d=%08x (%+10.8e)%c", i, - float32_val(env->fregs[i].f32[FP_F32_LOW]), - *(float *)(env->fregs[i].f32 + FP_F32_LOW), - (i % 2) == 1 ? '\n' : ' '); + qemu_fprintf(f, "F%02d=%08x (%+10.8e)%c", i, + float32_val(env->fregs[i].f32[FP_F32_LOW]), + *(float *)(env->fregs[i].f32 + FP_F32_LOW), + (i % 2) == 1 ? '\n' : ' '); } } } diff --git a/target/xtensa/xtensa-semi.c b/target/xtensa/xtensa-semi.c index 2f76216276..5f5ce4f344 100644 --- a/target/xtensa/xtensa-semi.c +++ b/target/xtensa/xtensa-semi.c @@ -202,7 +202,6 @@ void HELPER(simcall)(CPUXtensaState *env) switch (regs[2]) { case TARGET_SYS_exit: - qemu_log("exit(%d) simcall\n", regs[3]); exit(regs[3]); break; |