From 64603d1efffc8fa0883656c371e6471f6269be92 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 2 Sep 2020 22:46:49 -0700 Subject: [PATCH 01/18] target/microblaze: Renumber D_FLAG ESS[DS] is bit 19 in the manual, but the manual uses big-endian bit numbering. This corresponds to bit 12 in little-endian numbering. Let the comment about matching the ESR be true by renumbering it. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index a25a2b427f..32811f773d 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -264,10 +264,10 @@ struct CPUMBState { /* MSR_UM (1 << 11) */ /* MSR_VM (1 << 13) */ /* ESR_ESS_MASK [11:5] -- unwind into iflags for unaligned excp */ +#define D_FLAG (1 << 12) /* Bit in ESR. */ #define DRTI_FLAG (1 << 16) #define DRTE_FLAG (1 << 17) #define DRTB_FLAG (1 << 18) -#define D_FLAG (1 << 19) /* Bit in ESR. */ /* TB dependent CPUMBState. */ #define IFLAGS_TB_MASK (D_FLAG | BIMM_FLAG | IMM_FLAG | \ From a9f614587bdfdfce7a5e41c1a092eb7c0c10705a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 2 Sep 2020 23:11:00 -0700 Subject: [PATCH 02/18] target/microblaze: Cleanup mb_cpu_do_interrupt Reindent; remove dead/commented code. Use D_FLAG to set ESS[DS]. Sink MSR adjustment for kernel entry, iflags and res_addr clear. Improve CPU_LOG_INT formatting; report pc and msr before and after. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.c | 209 ++++++++++++++++--------------------- 1 file changed, 91 insertions(+), 118 deletions(-) diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 00090526da..27a24bb99a 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -111,6 +111,7 @@ void mb_cpu_do_interrupt(CPUState *cs) MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; uint32_t t, msr = mb_cpu_read_msr(env); + bool set_esr; /* IMM flag cannot propagate across a branch and into the dslot. */ assert((env->iflags & (D_FLAG | IMM_FLAG)) != (D_FLAG | IMM_FLAG)); @@ -118,142 +119,114 @@ void mb_cpu_do_interrupt(CPUState *cs) assert((env->iflags & (D_FLAG | BIMM_FLAG)) != BIMM_FLAG); /* RTI flags are private to translate. */ assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG))); - env->res_addr = RES_ADDR_NONE; + switch (cs->exception_index) { - case EXCP_HW_EXCP: - if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) { - qemu_log_mask(LOG_GUEST_ERROR, "Exception raised on system without exceptions!\n"); - return; - } + case EXCP_HW_EXCP: + if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Exception raised on system without exceptions!\n"); + return; + } - env->regs[17] = env->pc + 4; - env->esr &= ~(1 << 12); + qemu_log_mask(CPU_LOG_INT, + "INT: HWE at pc=%08x msr=%08x iflags=%x\n", + env->pc, msr, env->iflags); - /* Exception breaks branch + dslot sequence? */ - if (env->iflags & D_FLAG) { - env->esr |= 1 << 12 ; - env->btr = env->btarget; - } + /* Exception breaks branch + dslot sequence? */ + set_esr = true; + env->esr &= ~D_FLAG; + if (env->iflags & D_FLAG) { + env->esr |= D_FLAG; + env->btr = env->btarget; + } - /* Disable the MMU. */ - t = (msr & (MSR_VM | MSR_UM)) << 1; - msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); - msr |= t; - /* Exception in progress. */ - msr |= MSR_EIP; - mb_cpu_write_msr(env, msr); + /* Exception in progress. */ + msr |= MSR_EIP; + env->regs[17] = env->pc + 4; + env->pc = cpu->cfg.base_vectors + 0x20; + break; - qemu_log_mask(CPU_LOG_INT, - "hw exception at pc=%x ear=%" PRIx64 " " - "esr=%x iflags=%x\n", - env->pc, env->ear, - env->esr, env->iflags); - log_cpu_state_mask(CPU_LOG_INT, cs, 0); - env->iflags = 0; - env->pc = cpu->cfg.base_vectors + 0x20; - break; + case EXCP_MMU: + qemu_log_mask(CPU_LOG_INT, + "INT: MMU at pc=%08x msr=%08x " + "ear=%" PRIx64 " iflags=%x\n", + env->pc, msr, env->ear, env->iflags); - case EXCP_MMU: + /* Exception breaks branch + dslot sequence? */ + set_esr = true; + env->esr &= ~D_FLAG; + if (env->iflags & D_FLAG) { + env->esr |= D_FLAG; + env->btr = env->btarget; + /* Reexecute the branch. */ + env->regs[17] = env->pc - (env->iflags & BIMM_FLAG ? 8 : 4); + } else if (env->iflags & IMM_FLAG) { + /* Reexecute the imm. */ + env->regs[17] = env->pc - 4; + } else { env->regs[17] = env->pc; + } - qemu_log_mask(CPU_LOG_INT, - "MMU exception at pc=%x iflags=%x ear=%" PRIx64 "\n", - env->pc, env->iflags, env->ear); + /* Exception in progress. */ + msr |= MSR_EIP; + env->pc = cpu->cfg.base_vectors + 0x20; + break; - env->esr &= ~(1 << 12); - /* Exception breaks branch + dslot sequence? */ - if (env->iflags & D_FLAG) { - env->esr |= 1 << 12 ; - env->btr = env->btarget; + case EXCP_IRQ: + assert(!(msr & (MSR_EIP | MSR_BIP))); + assert(msr & MSR_IE); + assert(!(env->iflags & (D_FLAG | IMM_FLAG))); - /* Reexecute the branch. */ - env->regs[17] -= 4; - /* was the branch immprefixed?. */ - if (env->iflags & BIMM_FLAG) { - env->regs[17] -= 4; - log_cpu_state_mask(CPU_LOG_INT, cs, 0); - } - } else if (env->iflags & IMM_FLAG) { - env->regs[17] -= 4; - } + qemu_log_mask(CPU_LOG_INT, + "INT: DEV at pc=%08x msr=%08x iflags=%x\n", + env->pc, msr, env->iflags); + set_esr = false; - /* Disable the MMU. */ - t = (msr & (MSR_VM | MSR_UM)) << 1; - msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); - msr |= t; - /* Exception in progress. */ - msr |= MSR_EIP; - mb_cpu_write_msr(env, msr); + /* Disable interrupts. */ + msr &= ~MSR_IE; + env->regs[14] = env->pc; + env->pc = cpu->cfg.base_vectors + 0x10; + break; - qemu_log_mask(CPU_LOG_INT, - "exception at pc=%x ear=%" PRIx64 " iflags=%x\n", - env->pc, env->ear, env->iflags); - log_cpu_state_mask(CPU_LOG_INT, cs, 0); - env->iflags = 0; - env->pc = cpu->cfg.base_vectors + 0x20; - break; + case EXCP_HW_BREAK: + assert(!(env->iflags & (D_FLAG | IMM_FLAG))); - case EXCP_IRQ: - assert(!(msr & (MSR_EIP | MSR_BIP))); - assert(msr & MSR_IE); - assert(!(env->iflags & (D_FLAG | IMM_FLAG))); + qemu_log_mask(CPU_LOG_INT, + "INT: BRK at pc=%08x msr=%08x iflags=%x\n", + env->pc, msr, env->iflags); + set_esr = false; - t = (msr & (MSR_VM | MSR_UM)) << 1; + /* Break in progress. */ + msr |= MSR_BIP; + env->regs[16] = env->pc; + env->pc = cpu->cfg.base_vectors + 0x18; + break; -#if 0 -#include "disas/disas.h" + default: + cpu_abort(cs, "unhandled exception type=%d\n", cs->exception_index); + /* not reached */ + } -/* Useful instrumentation when debugging interrupt issues in either - the models or in sw. */ - { - const char *sym; + /* Save previous mode, disable mmu, disable user-mode. */ + t = (msr & (MSR_VM | MSR_UM)) << 1; + msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); + msr |= t; + mb_cpu_write_msr(env, msr); - sym = lookup_symbol(env->pc); - if (sym - && (!strcmp("netif_rx", sym) - || !strcmp("process_backlog", sym))) { + env->res_addr = RES_ADDR_NONE; + env->iflags = 0; - qemu_log("interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n", - env->pc, msr, t, env->iflags, sym); - - log_cpu_state(cs, 0); - } - } -#endif - qemu_log_mask(CPU_LOG_INT, - "interrupt at pc=%x msr=%x %x iflags=%x\n", - env->pc, msr, t, env->iflags); - - msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM | MSR_IE); - msr |= t; - mb_cpu_write_msr(env, msr); - - env->regs[14] = env->pc; - env->iflags = 0; - env->pc = cpu->cfg.base_vectors + 0x10; - //log_cpu_state_mask(CPU_LOG_INT, cs, 0); - break; - - case EXCP_HW_BREAK: - assert(!(env->iflags & (D_FLAG | IMM_FLAG))); - - t = (msr & (MSR_VM | MSR_UM)) << 1; - qemu_log_mask(CPU_LOG_INT, - "break at pc=%x msr=%x %x iflags=%x\n", - env->pc, msr, t, env->iflags); - log_cpu_state_mask(CPU_LOG_INT, cs, 0); - msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); - msr |= t; - msr |= MSR_BIP; - env->regs[16] = env->pc; - env->iflags = 0; - env->pc = cpu->cfg.base_vectors + 0x18; - mb_cpu_write_msr(env, msr); - break; - default: - cpu_abort(cs, "unhandled exception type=%d\n", - cs->exception_index); - break; + if (!set_esr) { + qemu_log_mask(CPU_LOG_INT, + " to pc=%08x msr=%08x\n", env->pc, msr); + } else if (env->esr & D_FLAG) { + qemu_log_mask(CPU_LOG_INT, + " to pc=%08x msr=%08x esr=%04x btr=%08x\n", + env->pc, msr, env->esr, env->btr); + } else { + qemu_log_mask(CPU_LOG_INT, + " to pc=%08x msr=%08x esr=%04x\n", + env->pc, msr, env->esr); } } From 8ce97bc188ecebd5030059411b6e29f2cec64dc1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 2 Sep 2020 23:18:35 -0700 Subject: [PATCH 03/18] target/microblaze: Rename mmu structs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce typedefs and follow CODING_STYLE for naming. Rename struct microblaze_mmu to MicroBlazeMMU. Rename struct microblaze_mmu_lookup to MicroBlazeMMULookup. Tested-by: Edgar E. Iglesias Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 2 +- target/microblaze/helper.c | 4 ++-- target/microblaze/mmu.c | 11 +++++------ target/microblaze/mmu.h | 15 ++++++--------- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 32811f773d..20c2979396 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -278,7 +278,7 @@ struct CPUMBState { #if !defined(CONFIG_USER_ONLY) /* Unified MMU. */ - struct microblaze_mmu mmu; + MicroBlazeMMU mmu; #endif /* Fields up to this point are cleared by a CPU reset */ diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 27a24bb99a..3c2fd388fb 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -52,7 +52,7 @@ bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size, { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; - struct microblaze_mmu_lookup lu; + MicroBlazeMMULookup lu; unsigned int hit; int prot; @@ -235,7 +235,7 @@ hwaddr mb_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; target_ulong vaddr, paddr = 0; - struct microblaze_mmu_lookup lu; + MicroBlazeMMULookup lu; int mmu_idx = cpu_mmu_index(env, false); unsigned int hit; diff --git a/target/microblaze/mmu.c b/target/microblaze/mmu.c index 6e583d78d9..0546cfd0bc 100644 --- a/target/microblaze/mmu.c +++ b/target/microblaze/mmu.c @@ -35,7 +35,7 @@ static unsigned int tlb_decode_size(unsigned int f) static void mmu_flush_idx(CPUMBState *env, unsigned int idx) { CPUState *cs = env_cpu(env); - struct microblaze_mmu *mmu = &env->mmu; + MicroBlazeMMU *mmu = &env->mmu; unsigned int tlb_size; uint32_t tlb_tag, end, t; @@ -55,7 +55,7 @@ static void mmu_flush_idx(CPUMBState *env, unsigned int idx) static void mmu_change_pid(CPUMBState *env, unsigned int newpid) { - struct microblaze_mmu *mmu = &env->mmu; + MicroBlazeMMU *mmu = &env->mmu; unsigned int i; uint32_t t; @@ -73,8 +73,7 @@ static void mmu_change_pid(CPUMBState *env, unsigned int newpid) } /* rw - 0 = read, 1 = write, 2 = fetch. */ -unsigned int mmu_translate(struct microblaze_mmu *mmu, - struct microblaze_mmu_lookup *lu, +unsigned int mmu_translate(MicroBlazeMMU *mmu, MicroBlazeMMULookup *lu, target_ulong vaddr, int rw, int mmu_idx) { unsigned int i, hit = 0; @@ -290,7 +289,7 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v) break; case MMU_R_TLBSX: { - struct microblaze_mmu_lookup lu; + MicroBlazeMMULookup lu; int hit; if (env->mmu.c_mmu_tlb_access <= 1) { @@ -314,7 +313,7 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v) } } -void mmu_init(struct microblaze_mmu *mmu) +void mmu_init(MicroBlazeMMU *mmu) { int i; for (i = 0; i < ARRAY_SIZE(mmu->regs); i++) { diff --git a/target/microblaze/mmu.h b/target/microblaze/mmu.h index 75e5301c79..c1feb811b9 100644 --- a/target/microblaze/mmu.h +++ b/target/microblaze/mmu.h @@ -63,8 +63,7 @@ #define TLB_ENTRIES 64 -struct microblaze_mmu -{ +typedef struct { /* Data and tag brams. */ uint64_t rams[2][TLB_ENTRIES]; /* We keep a separate ram for the tids to avoid the 48 bit tag width. */ @@ -76,10 +75,9 @@ struct microblaze_mmu int c_mmu_tlb_access; int c_mmu_zones; uint64_t c_addr_mask; /* Mask to apply to physical addresses. */ -}; +} MicroBlazeMMU; -struct microblaze_mmu_lookup -{ +typedef struct { uint32_t paddr; uint32_t vaddr; unsigned int size; @@ -88,13 +86,12 @@ struct microblaze_mmu_lookup enum { ERR_PROT, ERR_MISS, ERR_HIT } err; -}; +} MicroBlazeMMULookup; -unsigned int mmu_translate(struct microblaze_mmu *mmu, - struct microblaze_mmu_lookup *lu, +unsigned int mmu_translate(MicroBlazeMMU *mmu, MicroBlazeMMULookup *lu, target_ulong vaddr, int rw, int mmu_idx); uint32_t mmu_read(CPUMBState *env, bool ea, uint32_t rn); void mmu_write(CPUMBState *env, bool ea, uint32_t rn, uint32_t v); -void mmu_init(struct microblaze_mmu *mmu); +void mmu_init(MicroBlazeMMU *mmu); #endif From 17e777965257e19b17dfbf7c08c495f05303a860 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 31 Aug 2020 09:28:33 -0700 Subject: [PATCH 04/18] target/microblaze: Rename DISAS_UPDATE to DISAS_EXIT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name "update" suggests that something needs updating, but this is not the case. Use "exit" to emphasize that nothing needs doing except to exit. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index a8a3249185..8ceb04f4f0 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -37,7 +37,7 @@ /* is_jmp field values */ #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ -#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ +#define DISAS_EXIT DISAS_TARGET_1 /* all cpu state modified dynamically */ static TCGv_i32 cpu_R[32]; static TCGv_i32 cpu_pc; @@ -1161,7 +1161,7 @@ static bool trans_brk(DisasContext *dc, arg_typea_br *arg) tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP); tcg_gen_movi_tl(cpu_res_addr, -1); - dc->base.is_jmp = DISAS_UPDATE; + dc->base.is_jmp = DISAS_EXIT; return true; } @@ -1202,7 +1202,7 @@ static bool trans_brki(DisasContext *dc, arg_typeb_br *arg) ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM)); } tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set); - dc->base.is_jmp = DISAS_UPDATE; + dc->base.is_jmp = DISAS_EXIT; #endif return true; @@ -1712,7 +1712,7 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) /* Force an exit if the per-tb cpu state has changed. */ if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { - dc->base.is_jmp = DISAS_UPDATE; + dc->base.is_jmp = DISAS_EXIT; tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); } } @@ -1733,7 +1733,7 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) gen_goto_tb(dc, 0, dc->base.pc_next); return; - case DISAS_UPDATE: + case DISAS_EXIT: if (unlikely(cs->singlestep_enabled)) { gen_raise_exception(dc, EXCP_DEBUG); } else { From f6278ca9699dfd5df21a3f844945ec1e3122c44c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 31 Aug 2020 09:34:01 -0700 Subject: [PATCH 05/18] target/microblaze: Introduce DISAS_EXIT_NEXT, DISAS_EXIT_JUMP Like DISAS_EXIT, except we need to update cpu_pc, either to pc_next or to btarget respectively. Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 8ceb04f4f0..2abef328a3 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -39,6 +39,11 @@ #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ #define DISAS_EXIT DISAS_TARGET_1 /* all cpu state modified dynamically */ +/* cpu state besides pc was modified dynamically; update pc to next */ +#define DISAS_EXIT_NEXT DISAS_TARGET_2 +/* cpu state besides pc was modified dynamically; update pc to btarget */ +#define DISAS_EXIT_JUMP DISAS_TARGET_3 + static TCGv_i32 cpu_R[32]; static TCGv_i32 cpu_pc; static TCGv_i32 cpu_msr; @@ -1712,8 +1717,7 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) /* Force an exit if the per-tb cpu state has changed. */ if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { - dc->base.is_jmp = DISAS_EXIT; - tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); + dc->base.is_jmp = DISAS_EXIT_NEXT; } } @@ -1734,12 +1738,14 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) return; case DISAS_EXIT: - if (unlikely(cs->singlestep_enabled)) { - gen_raise_exception(dc, EXCP_DEBUG); - } else { - tcg_gen_exit_tb(NULL, 0); - } - return; + break; + case DISAS_EXIT_NEXT: + tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); + break; + case DISAS_EXIT_JUMP: + tcg_gen_mov_i32(cpu_pc, cpu_btarget); + tcg_gen_discard_i32(cpu_btarget); + break; case DISAS_JUMP: if (dc->jmp_dest != -1 && !cs->singlestep_enabled) { @@ -1781,6 +1787,13 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) default: g_assert_not_reached(); } + + /* Finish DISAS_EXIT_* */ + if (unlikely(cs->singlestep_enabled)) { + gen_raise_exception(dc, EXCP_DEBUG); + } else { + tcg_gen_exit_tb(NULL, 0); + } } static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) From 43b341346662099850f4b4a3353dc25fb00cc400 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 31 Aug 2020 09:38:45 -0700 Subject: [PATCH 06/18] target/microblaze: Replace cpustate_changed with DISAS_EXIT_NEXT Rather than look for the combination of DISAS_NEXT with a separate variable, go ahead and set is_jmp to the desired state. Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 2abef328a3..6bf299a826 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -70,7 +70,6 @@ typedef struct DisasContext { /* Decoder. */ uint32_t ext_imm; - unsigned int cpustate_changed; unsigned int tb_flags; unsigned int tb_flags_to_set; int mem_index; @@ -1255,7 +1254,7 @@ static bool trans_mbar(DisasContext *dc, arg_mbar *arg) * * Therefore, choose to end the TB always. */ - dc->cpustate_changed = 1; + dc->base.is_jmp = DISAS_EXIT_NEXT; return true; } @@ -1307,19 +1306,6 @@ static void msr_read(DisasContext *dc, TCGv_i32 d) tcg_temp_free_i32(t); } -#ifndef CONFIG_USER_ONLY -static void msr_write(DisasContext *dc, TCGv_i32 v) -{ - dc->cpustate_changed = 1; - - /* Install MSR_C. */ - tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); - - /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ - tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); -} -#endif - static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set) { uint32_t imm = arg->imm; @@ -1352,7 +1338,7 @@ static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set) } else { tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm); } - dc->cpustate_changed = 1; + dc->base.is_jmp = DISAS_EXIT_NEXT; } return true; } @@ -1385,7 +1371,13 @@ static bool trans_mts(DisasContext *dc, arg_mts *arg) TCGv_i32 src = reg_for_read(dc, arg->ra); switch (arg->rs) { case SR_MSR: - msr_write(dc, src); + /* Install MSR_C. */ + tcg_gen_extract_i32(cpu_msr_c, src, 2, 1); + /* + * Clear MSR_C and MSR_CC; + * MSR_PVR is not writable, and is always clear. + */ + tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR)); break; case SR_FSR: tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr)); @@ -1417,7 +1409,7 @@ static bool trans_mts(DisasContext *dc, arg_mts *arg) qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs); return true; } - dc->cpustate_changed = 1; + dc->base.is_jmp = DISAS_EXIT_NEXT; return true; #endif } @@ -1629,7 +1621,6 @@ static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) dc->cpu = cpu; dc->tb_flags = dc->base.tb->flags; - dc->cpustate_changed = 0; dc->ext_imm = dc->base.tb->cs_base; dc->r0 = NULL; dc->r0_set = false; @@ -1714,11 +1705,6 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) } dc->base.is_jmp = DISAS_JUMP; } - - /* Force an exit if the per-tb cpu state has changed. */ - if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { - dc->base.is_jmp = DISAS_EXIT_NEXT; - } } static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) From 3d35bcc2135faefa7565f1023ce3e7df9032aedc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 31 Aug 2020 10:08:20 -0700 Subject: [PATCH 07/18] target/microblaze: Handle DISAS_EXIT_NEXT in delay slot It is legal to put an mts instruction into a delay slot. We should continue to return to the main loop in that case so that we recognize any pending interrupts. Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 6bf299a826..608d413c83 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1696,6 +1696,10 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) dc->base.pc_next += 4; if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) { + /* + * Finish any return-from branch. + * TODO: Diagnose rtXd in delay slot of rtYd earlier. + */ if (dc->tb_flags & DRTI_FLAG) { do_rti(dc); } else if (dc->tb_flags & DRTB_FLAG) { @@ -1703,7 +1707,35 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) } else if (dc->tb_flags & DRTE_FLAG) { do_rte(dc); } - dc->base.is_jmp = DISAS_JUMP; + + /* Complete the branch, ending the TB. */ + switch (dc->base.is_jmp) { + case DISAS_NORETURN: + /* + * E.g. illegal insn in a delay slot. We've already exited + * and will handle D_FLAG in mb_cpu_do_interrupt. + */ + break; + case DISAS_EXIT: + /* + * TODO: diagnose brk/brki in delay slot earlier. + * This would then fold into the illegal insn case above. + */ + break; + case DISAS_NEXT: + /* Normal insn a delay slot. */ + dc->base.is_jmp = DISAS_JUMP; + break; + case DISAS_EXIT_NEXT: + /* + * E.g. mts insn in a delay slot. Continue with btarget, + * but still return to the main loop. + */ + dc->base.is_jmp = DISAS_EXIT_JUMP; + break; + default: + g_assert_not_reached(); + } } } From 3c745866ed8169638accecd81e61dcfafa3cb3fb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 31 Aug 2020 10:35:15 -0700 Subject: [PATCH 08/18] target/microblaze: Force rtid, rted, rtbd to exit These return-from-exception type instructions have modified MSR to re-enable various forms of interrupt. Force a return to the main loop. Consolidate the cleanup of tb_flags into mb_tr_translate_insn. Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 608d413c83..da84fdb20b 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1518,7 +1518,6 @@ static void do_rti(DisasContext *dc) tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); tcg_temp_free_i32(tmp); - dc->tb_flags &= ~DRTI_FLAG; } static void do_rtb(DisasContext *dc) @@ -1531,7 +1530,6 @@ static void do_rtb(DisasContext *dc) tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); tcg_temp_free_i32(tmp); - dc->tb_flags &= ~DRTB_FLAG; } static void do_rte(DisasContext *dc) @@ -1545,7 +1543,6 @@ static void do_rte(DisasContext *dc) tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); tcg_temp_free_i32(tmp); - dc->tb_flags &= ~DRTE_FLAG; } /* Insns connected to FSL or AXI stream attached devices. */ @@ -1700,12 +1697,16 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) * Finish any return-from branch. * TODO: Diagnose rtXd in delay slot of rtYd earlier. */ - if (dc->tb_flags & DRTI_FLAG) { - do_rti(dc); - } else if (dc->tb_flags & DRTB_FLAG) { - do_rtb(dc); - } else if (dc->tb_flags & DRTE_FLAG) { - do_rte(dc); + uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG); + if (unlikely(rt_ibe != 0)) { + dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG); + if (rt_ibe & DRTI_FLAG) { + do_rti(dc); + } else if (rt_ibe & DRTB_FLAG) { + do_rtb(dc); + } else { + do_rte(dc); + } } /* Complete the branch, ending the TB. */ @@ -1723,8 +1724,12 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) */ break; case DISAS_NEXT: - /* Normal insn a delay slot. */ - dc->base.is_jmp = DISAS_JUMP; + /* + * Normal insn a delay slot. + * However, the return-from-exception type insns should + * return to the main loop, as they have adjusted MSR. + */ + dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP); break; case DISAS_EXIT_NEXT: /* From 4059bd90eb29fb837636db278d6907f4df0f6158 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 31 Aug 2020 10:42:04 -0700 Subject: [PATCH 09/18] target/microblaze: Use tcg_gen_lookup_and_goto_ptr Normal indirect jumps, or page-crossing direct jumps, can use tcg_gen_lookup_and_goto_ptr to avoid returning to the main loop simply to find an existing TB for the next pc. Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index da84fdb20b..d98572fab9 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -147,7 +147,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) tcg_gen_exit_tb(dc->base.tb, n); } else { tcg_gen_movi_i32(cpu_pc, dest); - tcg_gen_exit_tb(NULL, 0); + tcg_gen_lookup_and_goto_ptr(); } dc->base.is_jmp = DISAS_NORETURN; } @@ -1803,7 +1803,7 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) if (unlikely(cs->singlestep_enabled)) { gen_raise_exception(dc, EXCP_DEBUG); } else { - tcg_gen_exit_tb(NULL, 0); + tcg_gen_lookup_and_goto_ptr(); } return; From 2a7567a2f3a2f2d1580f104efd7ddc67e598b071 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 1 Sep 2020 11:42:08 -0700 Subject: [PATCH 10/18] target/microblaze: Diagnose invalid insns in delay slots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These cases result in undefined and undocumented behaviour but the behaviour is deterministic, i.e cores will not lock-up or expose security issues. However, RTL will not raise exceptions either. Therefore, log a GUEST_ERROR and treat these cases as nops, to avoid corner cases which could put qemu into an invalid state. Tested-by: Edgar E. Iglesias Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 48 ++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index d98572fab9..ff0cb7dbb6 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -179,6 +179,21 @@ static bool trap_userspace(DisasContext *dc, bool cond) return cond_user; } +/* + * Return true, and log an error, if the current insn is + * within a delay slot. + */ +static bool invalid_delay_slot(DisasContext *dc, const char *insn_type) +{ + if (dc->tb_flags & D_FLAG) { + qemu_log_mask(LOG_GUEST_ERROR, + "Invalid insn in delay slot: %s at %08x\n", + insn_type, (uint32_t)dc->base.pc_next); + return true; + } + return false; +} + static TCGv_i32 reg_for_read(DisasContext *dc, int reg) { if (likely(reg != 0)) { @@ -500,6 +515,9 @@ DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) static bool trans_imm(DisasContext *dc, arg_imm *arg) { + if (invalid_delay_slot(dc, "imm")) { + return true; + } dc->ext_imm = arg->imm << 16; tcg_gen_movi_i32(cpu_imm, dc->ext_imm); dc->tb_flags_to_set = IMM_FLAG; @@ -1067,6 +1085,9 @@ static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm, { uint32_t add_pc; + if (invalid_delay_slot(dc, "branch")) { + return true; + } if (delay) { setup_dslot(dc, dest_rb < 0); } @@ -1106,6 +1127,9 @@ static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm, { TCGv_i32 zero, next; + if (invalid_delay_slot(dc, "bcc")) { + return true; + } if (delay) { setup_dslot(dc, dest_rb < 0); } @@ -1158,6 +1182,10 @@ static bool trans_brk(DisasContext *dc, arg_typea_br *arg) if (trap_userspace(dc, true)) { return true; } + if (invalid_delay_slot(dc, "brk")) { + return true; + } + tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb)); if (arg->rd) { tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); @@ -1176,6 +1204,10 @@ static bool trans_brki(DisasContext *dc, arg_typeb_br *arg) if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) { return true; } + if (invalid_delay_slot(dc, "brki")) { + return true; + } + tcg_gen_movi_i32(cpu_pc, imm); if (arg->rd) { tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); @@ -1216,6 +1248,11 @@ static bool trans_mbar(DisasContext *dc, arg_mbar *arg) { int mbar_imm = arg->imm; + /* Note that mbar is a specialized branch instruction. */ + if (invalid_delay_slot(dc, "mbar")) { + return true; + } + /* Data access memory barrier. */ if ((mbar_imm & 2) == 0) { tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); @@ -1263,6 +1300,10 @@ static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set) if (trap_userspace(dc, to_set)) { return true; } + if (invalid_delay_slot(dc, "rts")) { + return true; + } + dc->tb_flags_to_set |= to_set; setup_dslot(dc, true); @@ -1695,7 +1736,6 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) { /* * Finish any return-from branch. - * TODO: Diagnose rtXd in delay slot of rtYd earlier. */ uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG); if (unlikely(rt_ibe != 0)) { @@ -1717,12 +1757,6 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) * and will handle D_FLAG in mb_cpu_do_interrupt. */ break; - case DISAS_EXIT: - /* - * TODO: diagnose brk/brki in delay slot earlier. - * This would then fold into the illegal insn case above. - */ - break; case DISAS_NEXT: /* * Normal insn a delay slot. From 84bf3249a3701d04c453ce6c77481d78c2606bfe Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Sep 2020 10:49:22 -0700 Subject: [PATCH 11/18] target/microblaze: Split out MicroBlazeCPUConfig This struct was previously unnamed, and defined in MicroBlazeCPU. Pull it out to its own typedef so that we can reuse it. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 55 ++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 20c2979396..59d2a079c4 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -291,6 +291,34 @@ struct CPUMBState { } pvr; }; +/* + * Microblaze Configuration Settings + */ +typedef struct { + bool stackprot; + uint32_t base_vectors; + uint8_t addr_size; + uint8_t use_fpu; + uint8_t use_hw_mul; + bool use_barrel; + bool use_div; + bool use_msr_instr; + bool use_pcmp_instr; + bool use_mmu; + bool dcache_writeback; + bool endi; + bool dopb_bus_exception; + bool iopb_bus_exception; + bool illegal_opcode_exception; + bool opcode_0_illegal; + bool div_zero_exception; + bool unaligned_exceptions; + uint8_t pvr_user1; + uint32_t pvr_user2; + char *version; + uint8_t pvr; +} MicroBlazeCPUConfig; + /** * MicroBlazeCPU: * @env: #CPUMBState @@ -305,32 +333,7 @@ struct MicroBlazeCPU { CPUNegativeOffsetState neg; CPUMBState env; - - /* Microblaze Configuration Settings */ - struct { - bool stackprot; - uint32_t base_vectors; - uint8_t addr_size; - uint8_t use_fpu; - uint8_t use_hw_mul; - bool use_barrel; - bool use_div; - bool use_msr_instr; - bool use_pcmp_instr; - bool use_mmu; - bool dcache_writeback; - bool endi; - bool dopb_bus_exception; - bool iopb_bus_exception; - bool illegal_opcode_exception; - bool opcode_0_illegal; - bool div_zero_exception; - bool unaligned_exceptions; - uint8_t pvr_user1; - uint32_t pvr_user2; - char *version; - uint8_t pvr; - } cfg; + MicroBlazeCPUConfig cfg; }; From a0b2d16a09374464450c47f280fc10df70a5de72 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Sep 2020 10:53:03 -0700 Subject: [PATCH 12/18] target/microblaze: Reorg MicroBlazeCPUConfig to minimize holes Sort the elements by type and size, removing a number of holes and reducing the size of the entire struct. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 59d2a079c4..4d53345f23 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -293,13 +293,22 @@ struct CPUMBState { /* * Microblaze Configuration Settings + * + * Note that the structure is sorted by type and size to minimize holes. */ typedef struct { - bool stackprot; + char *version; + uint32_t base_vectors; + uint32_t pvr_user2; + uint8_t addr_size; uint8_t use_fpu; uint8_t use_hw_mul; + uint8_t pvr_user1; + uint8_t pvr; + + bool stackprot; bool use_barrel; bool use_div; bool use_msr_instr; @@ -313,10 +322,6 @@ typedef struct { bool opcode_0_illegal; bool div_zero_exception; bool unaligned_exceptions; - uint8_t pvr_user1; - uint32_t pvr_user2; - char *version; - uint8_t pvr; } MicroBlazeCPUConfig; /** From a4bcfc3380c7fab42613dc5747d4b48f0bae29df Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Sep 2020 11:11:28 -0700 Subject: [PATCH 13/18] target/microblaze: Move pvr regs to MicroBlazeCPUConfig These values are constant, and are derived from the other configuration knobs. Move them into MicroBlazeCPUConfig to emphasize that they are not variable. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- hw/microblaze/petalogix_ml605_mmu.c | 6 +- target/microblaze/cpu.c | 92 ++++++++++++++--------------- target/microblaze/cpu.h | 5 +- target/microblaze/gdbstub.c | 4 +- target/microblaze/helper.c | 2 +- target/microblaze/op_helper.c | 2 +- target/microblaze/translate.c | 3 +- 7 files changed, 54 insertions(+), 60 deletions(-) diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index e49fc86eb8..159db6cbe2 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -200,9 +200,9 @@ petalogix_ml605_init(MachineState *machine) } /* setup PVR to match kernel settings */ - cpu->env.pvr.regs[4] = 0xc56b8000; - cpu->env.pvr.regs[5] = 0xc56be000; - cpu->env.pvr.regs[10] = 0x0e000000; /* virtex 6 */ + cpu->cfg.pvr_regs[4] = 0xc56b8000; + cpu->cfg.pvr_regs[5] = 0xc56be000; + cpu->cfg.pvr_regs[10] = 0x0e000000; /* virtex 6 */ microblaze_load_kernel(cpu, MEMORY_BASEADDR, ram_size, machine->initrd_filename, diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 6392524135..b9bb7f0cc7 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -153,7 +153,6 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) CPUState *cs = CPU(dev); MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(dev); MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); - CPUMBState *env = &cpu->env; uint8_t version_code = 0; const char *version; int i = 0; @@ -173,16 +172,6 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) qemu_init_vcpu(cs); - env->pvr.regs[0] = PVR0_USE_EXC_MASK - | PVR0_USE_ICACHE_MASK - | PVR0_USE_DCACHE_MASK; - env->pvr.regs[2] = PVR2_D_OPB_MASK - | PVR2_D_LMB_MASK - | PVR2_I_OPB_MASK - | PVR2_I_LMB_MASK - | PVR2_FPU_EXC_MASK - | 0; - version = cpu->cfg.version ? cpu->cfg.version : DEFAULT_CPU_VERSION; for (i = 0; mb_cpu_lookup[i].name && version; i++) { if (strcmp(mb_cpu_lookup[i].name, version) == 0) { @@ -195,46 +184,53 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) qemu_log("Invalid MicroBlaze version number: %s\n", cpu->cfg.version); } - env->pvr.regs[0] |= (cpu->cfg.stackprot ? PVR0_SPROT_MASK : 0) | - (cpu->cfg.use_fpu ? PVR0_USE_FPU_MASK : 0) | - (cpu->cfg.use_hw_mul ? PVR0_USE_HW_MUL_MASK : 0) | - (cpu->cfg.use_barrel ? PVR0_USE_BARREL_MASK : 0) | - (cpu->cfg.use_div ? PVR0_USE_DIV_MASK : 0) | - (cpu->cfg.use_mmu ? PVR0_USE_MMU_MASK : 0) | - (cpu->cfg.endi ? PVR0_ENDI_MASK : 0) | - (version_code << PVR0_VERSION_SHIFT) | - (cpu->cfg.pvr == C_PVR_FULL ? PVR0_PVR_FULL_MASK : 0) | - cpu->cfg.pvr_user1; + cpu->cfg.pvr_regs[0] = + (PVR0_USE_EXC_MASK | + PVR0_USE_ICACHE_MASK | + PVR0_USE_DCACHE_MASK | + (cpu->cfg.stackprot ? PVR0_SPROT_MASK : 0) | + (cpu->cfg.use_fpu ? PVR0_USE_FPU_MASK : 0) | + (cpu->cfg.use_hw_mul ? PVR0_USE_HW_MUL_MASK : 0) | + (cpu->cfg.use_barrel ? PVR0_USE_BARREL_MASK : 0) | + (cpu->cfg.use_div ? PVR0_USE_DIV_MASK : 0) | + (cpu->cfg.use_mmu ? PVR0_USE_MMU_MASK : 0) | + (cpu->cfg.endi ? PVR0_ENDI_MASK : 0) | + (version_code << PVR0_VERSION_SHIFT) | + (cpu->cfg.pvr == C_PVR_FULL ? PVR0_PVR_FULL_MASK : 0) | + cpu->cfg.pvr_user1); - env->pvr.regs[1] = cpu->cfg.pvr_user2; - env->pvr.regs[2] |= (cpu->cfg.use_fpu ? PVR2_USE_FPU_MASK : 0) | - (cpu->cfg.use_fpu > 1 ? PVR2_USE_FPU2_MASK : 0) | - (cpu->cfg.use_hw_mul ? PVR2_USE_HW_MUL_MASK : 0) | - (cpu->cfg.use_hw_mul > 1 ? PVR2_USE_MUL64_MASK : 0) | - (cpu->cfg.use_barrel ? PVR2_USE_BARREL_MASK : 0) | - (cpu->cfg.use_div ? PVR2_USE_DIV_MASK : 0) | - (cpu->cfg.use_msr_instr ? PVR2_USE_MSR_INSTR : 0) | - (cpu->cfg.use_pcmp_instr ? PVR2_USE_PCMP_INSTR : 0) | - (cpu->cfg.dopb_bus_exception ? - PVR2_DOPB_BUS_EXC_MASK : 0) | - (cpu->cfg.iopb_bus_exception ? - PVR2_IOPB_BUS_EXC_MASK : 0) | - (cpu->cfg.div_zero_exception ? - PVR2_DIV_ZERO_EXC_MASK : 0) | - (cpu->cfg.illegal_opcode_exception ? - PVR2_ILL_OPCODE_EXC_MASK : 0) | - (cpu->cfg.unaligned_exceptions ? - PVR2_UNALIGNED_EXC_MASK : 0) | - (cpu->cfg.opcode_0_illegal ? - PVR2_OPCODE_0x0_ILL_MASK : 0); + cpu->cfg.pvr_regs[1] = cpu->cfg.pvr_user2; - env->pvr.regs[5] |= cpu->cfg.dcache_writeback ? - PVR5_DCACHE_WRITEBACK_MASK : 0; + cpu->cfg.pvr_regs[2] = + (PVR2_D_OPB_MASK | + PVR2_D_LMB_MASK | + PVR2_I_OPB_MASK | + PVR2_I_LMB_MASK | + PVR2_FPU_EXC_MASK | + (cpu->cfg.use_fpu ? PVR2_USE_FPU_MASK : 0) | + (cpu->cfg.use_fpu > 1 ? PVR2_USE_FPU2_MASK : 0) | + (cpu->cfg.use_hw_mul ? PVR2_USE_HW_MUL_MASK : 0) | + (cpu->cfg.use_hw_mul > 1 ? PVR2_USE_MUL64_MASK : 0) | + (cpu->cfg.use_barrel ? PVR2_USE_BARREL_MASK : 0) | + (cpu->cfg.use_div ? PVR2_USE_DIV_MASK : 0) | + (cpu->cfg.use_msr_instr ? PVR2_USE_MSR_INSTR : 0) | + (cpu->cfg.use_pcmp_instr ? PVR2_USE_PCMP_INSTR : 0) | + (cpu->cfg.dopb_bus_exception ? PVR2_DOPB_BUS_EXC_MASK : 0) | + (cpu->cfg.iopb_bus_exception ? PVR2_IOPB_BUS_EXC_MASK : 0) | + (cpu->cfg.div_zero_exception ? PVR2_DIV_ZERO_EXC_MASK : 0) | + (cpu->cfg.illegal_opcode_exception ? PVR2_ILL_OPCODE_EXC_MASK : 0) | + (cpu->cfg.unaligned_exceptions ? PVR2_UNALIGNED_EXC_MASK : 0) | + (cpu->cfg.opcode_0_illegal ? PVR2_OPCODE_0x0_ILL_MASK : 0)); - env->pvr.regs[10] = 0x0c000000 | /* Default to spartan 3a dsp family. */ - (cpu->cfg.addr_size - 32) << PVR10_ASIZE_SHIFT; - env->pvr.regs[11] = (cpu->cfg.use_mmu ? PVR11_USE_MMU : 0) | - 16 << 17; + cpu->cfg.pvr_regs[5] |= + cpu->cfg.dcache_writeback ? PVR5_DCACHE_WRITEBACK_MASK : 0; + + cpu->cfg.pvr_regs[10] = + (0x0c000000 | /* Default to spartan 3a dsp family. */ + (cpu->cfg.addr_size - 32) << PVR10_ASIZE_SHIFT); + + cpu->cfg.pvr_regs[11] = ((cpu->cfg.use_mmu ? PVR11_USE_MMU : 0) | + 16 << 17); mcc->parent_realize(dev, errp); } diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 4d53345f23..ef96f2fe02 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -285,10 +285,6 @@ struct CPUMBState { struct {} end_reset_fields; /* These fields are preserved on reset. */ - - struct { - uint32_t regs[13]; - } pvr; }; /* @@ -301,6 +297,7 @@ typedef struct { uint32_t base_vectors; uint32_t pvr_user2; + uint32_t pvr_regs[13]; uint8_t addr_size; uint8_t use_fpu; diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index 08d6a0e807..9e3b9ac824 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -78,7 +78,7 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) break; case GDB_PVR0 ... GDB_PVR11: /* PVR12 is intentionally skipped */ - val = env->pvr.regs[n - GDB_PVR0]; + val = cpu->cfg.pvr_regs[n - GDB_PVR0]; break; case GDB_EDR: val = env->edr; @@ -134,7 +134,7 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) break; case GDB_PVR0 ... GDB_PVR11: /* PVR12 is intentionally skipped */ - env->pvr.regs[n - GDB_PVR0] = tmp; + cpu->cfg.pvr_regs[n - GDB_PVR0] = tmp; break; case GDB_EDR: env->edr = tmp; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 3c2fd388fb..c9f236c897 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -122,7 +122,7 @@ void mb_cpu_do_interrupt(CPUState *cs) switch (cs->exception_index) { case EXCP_HW_EXCP: - if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) { + if (!(cpu->cfg.pvr_regs[0] & PVR0_USE_EXC_MASK)) { qemu_log_mask(LOG_GUEST_ERROR, "Exception raised on system without exceptions!\n"); return; diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 4614e99db3..757f3ff04b 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -134,7 +134,7 @@ static void update_fpu_flags(CPUMBState *env, int flags, uintptr_t ra) raise = 1; } if (raise - && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK) + && (env_archcpu(env)->cfg.pvr_regs[2] & PVR2_FPU_EXC_MASK) && (env->msr & MSR_EE)) { raise_fpu_exception(env, ra); } diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index ff0cb7dbb6..9e4551d99b 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1539,7 +1539,8 @@ static bool trans_mfs(DisasContext *dc, arg_mfs *arg) case 0x2000 ... 0x200c: tcg_gen_ld_i32(dest, cpu_env, - offsetof(CPUMBState, pvr.regs[arg->rs - 0x2000])); + offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000]) + - offsetof(MicroBlazeCPU, env)); break; default: qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs); From 5ad7cc07e5eb4c716b70a8a70f87264ecd1346f9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Sep 2020 11:12:49 -0700 Subject: [PATCH 14/18] target/microblaze: Treat pvr_regs as constant Do not allow gdb to set the values, and don't bother dumping unchanging values with -d cpu. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/gdbstub.c | 4 ---- target/microblaze/translate.c | 5 ----- 2 files changed, 9 deletions(-) diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c index 9e3b9ac824..be39fd4540 100644 --- a/target/microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c @@ -132,10 +132,6 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) case GDB_BTR: env->btr = tmp; break; - case GDB_PVR0 ... GDB_PVR11: - /* PVR12 is intentionally skipped */ - cpu->cfg.pvr_regs[n - GDB_PVR0] = tmp; - break; case GDB_EDR: env->edr = tmp; break; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 9e4551d99b..eca422b3db 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1919,11 +1919,6 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) env->esr, env->fsr, env->btr, env->edr, env->ear, env->slr, env->shr); - for (i = 0; i < 12; i++) { - qemu_fprintf(f, "rpvr%-2d=%08x%c", - i, env->pvr.regs[i], i % 4 == 3 ? '\n' : ' '); - } - for (i = 0; i < 32; i++) { qemu_fprintf(f, "r%2.2d=%08x%c", i, env->regs[i], i % 4 == 3 ? '\n' : ' '); From de73ee1abe95d37fa1b9c3129cb8a778eea43159 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Sep 2020 11:31:57 -0700 Subject: [PATCH 15/18] target/microblaze: Move mmu parameters to MicroBlazeCPUConfig The final 4 fields in MicroBlazeMMU are configuration constants. Move them into MicroBlazeCPUConfig where they belong. Remove the leading "c_" from the member names, as that presumably implied "config", and that should not be explicit in the location. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.c | 9 +++++---- target/microblaze/cpu.h | 5 +++++ target/microblaze/helper.c | 4 ++-- target/microblaze/mmu.c | 30 +++++++++++++++++------------- target/microblaze/mmu.h | 7 +------ 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index b9bb7f0cc7..fde646a7ad 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -135,10 +135,6 @@ static void mb_cpu_reset(DeviceState *dev) #else mb_cpu_write_msr(env, 0); mmu_init(&env->mmu); - env->mmu.c_mmu = 3; - env->mmu.c_mmu_tlb_access = 3; - env->mmu.c_mmu_zones = 16; - env->mmu.c_addr_mask = MAKE_64BIT_MASK(0, cpu->cfg.addr_size); #endif } @@ -232,6 +228,11 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) cpu->cfg.pvr_regs[11] = ((cpu->cfg.use_mmu ? PVR11_USE_MMU : 0) | 16 << 17); + cpu->cfg.mmu = 3; + cpu->cfg.mmu_tlb_access = 3; + cpu->cfg.mmu_zones = 16; + cpu->cfg.addr_mask = MAKE_64BIT_MASK(0, cpu->cfg.addr_size); + mcc->parent_realize(dev, errp); } diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index ef96f2fe02..b54f99da61 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -295,6 +295,8 @@ struct CPUMBState { typedef struct { char *version; + uint64_t addr_mask; + uint32_t base_vectors; uint32_t pvr_user2; uint32_t pvr_regs[13]; @@ -304,6 +306,9 @@ typedef struct { uint8_t use_hw_mul; uint8_t pvr_user1; uint8_t pvr; + uint8_t mmu; + uint8_t mmu_tlb_access; + uint8_t mmu_zones; bool stackprot; bool use_barrel; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index c9f236c897..3d6ce1b31b 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -64,7 +64,7 @@ bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size, return true; } - hit = mmu_translate(&env->mmu, &lu, address, access_type, mmu_idx); + hit = mmu_translate(cpu, &lu, address, access_type, mmu_idx); if (likely(hit)) { uint32_t vaddr = address & TARGET_PAGE_MASK; uint32_t paddr = lu.paddr + vaddr - lu.vaddr; @@ -240,7 +240,7 @@ hwaddr mb_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) unsigned int hit; if (mmu_idx != MMU_NOMMU_IDX) { - hit = mmu_translate(&env->mmu, &lu, addr, 0, 0); + hit = mmu_translate(cpu, &lu, addr, 0, 0); if (hit) { vaddr = addr & TARGET_PAGE_MASK; paddr = lu.paddr + vaddr - lu.vaddr; diff --git a/target/microblaze/mmu.c b/target/microblaze/mmu.c index 0546cfd0bc..1dbbb271c4 100644 --- a/target/microblaze/mmu.c +++ b/target/microblaze/mmu.c @@ -73,9 +73,10 @@ static void mmu_change_pid(CPUMBState *env, unsigned int newpid) } /* rw - 0 = read, 1 = write, 2 = fetch. */ -unsigned int mmu_translate(MicroBlazeMMU *mmu, MicroBlazeMMULookup *lu, +unsigned int mmu_translate(MicroBlazeCPU *cpu, MicroBlazeMMULookup *lu, target_ulong vaddr, int rw, int mmu_idx) { + MicroBlazeMMU *mmu = &cpu->env.mmu; unsigned int i, hit = 0; unsigned int tlb_ex = 0, tlb_wr = 0, tlb_zsel; uint64_t tlb_tag, tlb_rpn, mask; @@ -114,13 +115,13 @@ unsigned int mmu_translate(MicroBlazeMMU *mmu, MicroBlazeMMULookup *lu, t0 = mmu->regs[MMU_R_ZPR] >> (30 - (tlb_zsel * 2)); t0 &= 0x3; - if (tlb_zsel > mmu->c_mmu_zones) { + if (tlb_zsel > cpu->cfg.mmu_zones) { qemu_log_mask(LOG_GUEST_ERROR, "tlb zone select out of range! %d\n", tlb_zsel); t0 = 1; /* Ignore. */ } - if (mmu->c_mmu == 1) { + if (cpu->cfg.mmu == 1) { t0 = 1; /* Zones are disabled. */ } @@ -157,7 +158,7 @@ unsigned int mmu_translate(MicroBlazeMMU *mmu, MicroBlazeMMULookup *lu, tlb_rpn = d & TLB_RPN_MASK; lu->vaddr = tlb_tag; - lu->paddr = tlb_rpn & mmu->c_addr_mask; + lu->paddr = tlb_rpn & cpu->cfg.addr_mask; lu->size = tlb_size; lu->err = ERR_HIT; lu->idx = i; @@ -175,10 +176,11 @@ done: /* Writes/reads to the MMU's special regs end up here. */ uint32_t mmu_read(CPUMBState *env, bool ext, uint32_t rn) { + MicroBlazeCPU *cpu = env_archcpu(env); unsigned int i; uint32_t r = 0; - if (env->mmu.c_mmu < 2 || !env->mmu.c_mmu_tlb_access) { + if (cpu->cfg.mmu < 2 || !cpu->cfg.mmu_tlb_access) { qemu_log_mask(LOG_GUEST_ERROR, "MMU access on MMU-less system\n"); return 0; } @@ -191,7 +193,7 @@ uint32_t mmu_read(CPUMBState *env, bool ext, uint32_t rn) /* Reads to HI/LO trig reads from the mmu rams. */ case MMU_R_TLBLO: case MMU_R_TLBHI: - if (!(env->mmu.c_mmu_tlb_access & 1)) { + if (!(cpu->cfg.mmu_tlb_access & 1)) { qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn); return 0; @@ -204,7 +206,7 @@ uint32_t mmu_read(CPUMBState *env, bool ext, uint32_t rn) break; case MMU_R_PID: case MMU_R_ZPR: - if (!(env->mmu.c_mmu_tlb_access & 1)) { + if (!(cpu->cfg.mmu_tlb_access & 1)) { qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn); return 0; @@ -227,12 +229,14 @@ uint32_t mmu_read(CPUMBState *env, bool ext, uint32_t rn) void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v) { + MicroBlazeCPU *cpu = env_archcpu(env); uint64_t tmp64; unsigned int i; + qemu_log_mask(CPU_LOG_MMU, "%s rn=%d=%x old=%x\n", __func__, rn, v, env->mmu.regs[rn]); - if (env->mmu.c_mmu < 2 || !env->mmu.c_mmu_tlb_access) { + if (cpu->cfg.mmu < 2 || !cpu->cfg.mmu_tlb_access) { qemu_log_mask(LOG_GUEST_ERROR, "MMU access on MMU-less system\n"); return; } @@ -258,7 +262,7 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v) env->mmu.rams[rn & 1][i] = deposit64(tmp64, ext * 32, 32, v); break; case MMU_R_ZPR: - if (env->mmu.c_mmu_tlb_access <= 1) { + if (cpu->cfg.mmu_tlb_access <= 1) { qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn); return; @@ -272,7 +276,7 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v) env->mmu.regs[rn] = v; break; case MMU_R_PID: - if (env->mmu.c_mmu_tlb_access <= 1) { + if (cpu->cfg.mmu_tlb_access <= 1) { qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn); return; @@ -292,14 +296,14 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v) MicroBlazeMMULookup lu; int hit; - if (env->mmu.c_mmu_tlb_access <= 1) { + if (cpu->cfg.mmu_tlb_access <= 1) { qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn); return; } - hit = mmu_translate(&env->mmu, &lu, - v & TLB_EPN_MASK, 0, cpu_mmu_index(env, false)); + hit = mmu_translate(cpu, &lu, v & TLB_EPN_MASK, + 0, cpu_mmu_index(env, false)); if (hit) { env->mmu.regs[MMU_R_TLBX] = lu.idx; } else { diff --git a/target/microblaze/mmu.h b/target/microblaze/mmu.h index c1feb811b9..7d0fbb8341 100644 --- a/target/microblaze/mmu.h +++ b/target/microblaze/mmu.h @@ -70,11 +70,6 @@ typedef struct { uint8_t tids[TLB_ENTRIES]; /* Control flops. */ uint32_t regs[3]; - - int c_mmu; - int c_mmu_tlb_access; - int c_mmu_zones; - uint64_t c_addr_mask; /* Mask to apply to physical addresses. */ } MicroBlazeMMU; typedef struct { @@ -88,7 +83,7 @@ typedef struct { } err; } MicroBlazeMMULookup; -unsigned int mmu_translate(MicroBlazeMMU *mmu, MicroBlazeMMULookup *lu, +unsigned int mmu_translate(MicroBlazeCPU *cpu, MicroBlazeMMULookup *lu, target_ulong vaddr, int rw, int mmu_idx); uint32_t mmu_read(CPUMBState *env, bool ea, uint32_t rn); void mmu_write(CPUMBState *env, bool ea, uint32_t rn, uint32_t v); From 77f63e1dadb38bd0d4540c8bbf53156ecffa59a7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 2 Sep 2020 21:41:00 -0700 Subject: [PATCH 16/18] target/microblaze: Fill in VMStateDescription for cpu Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.c | 8 +-- target/microblaze/cpu.h | 4 ++ target/microblaze/machine.c | 106 ++++++++++++++++++++++++++++++++++ target/microblaze/meson.build | 5 +- 4 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 target/microblaze/machine.c diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index fde646a7ad..9b2482159d 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -26,7 +26,6 @@ #include "cpu.h" #include "qemu/module.h" #include "hw/qdev-properties.h" -#include "migration/vmstate.h" #include "exec/exec-all.h" #include "fpu/softfloat-helpers.h" @@ -251,11 +250,6 @@ static void mb_cpu_initfn(Object *obj) #endif } -static const VMStateDescription vmstate_mb_cpu = { - .name = "cpu", - .unmigratable = 1, -}; - static Property mb_properties[] = { DEFINE_PROP_UINT32("base-vectors", MicroBlazeCPU, cfg.base_vectors, 0), DEFINE_PROP_BOOL("use-stack-protection", MicroBlazeCPU, cfg.stackprot, @@ -335,8 +329,8 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) #ifndef CONFIG_USER_ONLY cc->do_transaction_failed = mb_cpu_transaction_failed; cc->get_phys_page_debug = mb_cpu_get_phys_page_debug; -#endif dc->vmsd = &vmstate_mb_cpu; +#endif device_class_set_props(dc, mb_properties); cc->gdb_num_core_regs = 32 + 27; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index b54f99da61..297b36879a 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -429,4 +429,8 @@ static inline int cpu_mmu_index(CPUMBState *env, bool ifetch) return MMU_KERNEL_IDX; } +#ifndef CONFIG_USER_ONLY +extern const VMStateDescription vmstate_mb_cpu; +#endif + #endif diff --git a/target/microblaze/machine.c b/target/microblaze/machine.c new file mode 100644 index 0000000000..acdb8d0474 --- /dev/null +++ b/target/microblaze/machine.c @@ -0,0 +1,106 @@ +/* + * Microblaze VMState for qemu. + * + * Copyright (c) 2020 Linaro, Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "migration/cpu.h" + + +static VMStateField vmstate_mmu_fields[] = { + VMSTATE_UINT64_2DARRAY(rams, MicroBlazeMMU, 2, TLB_ENTRIES), + VMSTATE_UINT8_ARRAY(tids, MicroBlazeMMU, TLB_ENTRIES), + VMSTATE_UINT32_ARRAY(regs, MicroBlazeMMU, 3), + VMSTATE_END_OF_LIST() +}; + +static const VMStateDescription vmstate_mmu = { + .name = "mmu", + .version_id = 0, + .minimum_version_id = 0, + .fields = vmstate_mmu_fields, +}; + +static int get_msr(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field) +{ + CPUMBState *env = container_of(opaque, CPUMBState, msr); + + mb_cpu_write_msr(env, qemu_get_be32(f)); + return 0; +} + +static int put_msr(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field, QJSON *vmdesc) +{ + CPUMBState *env = container_of(opaque, CPUMBState, msr); + + qemu_put_be32(f, mb_cpu_read_msr(env)); + return 0; +} + +static const VMStateInfo vmstate_msr = { + .name = "msr", + .get = get_msr, + .put = put_msr, +}; + +static VMStateField vmstate_env_fields[] = { + VMSTATE_UINT32_ARRAY(regs, CPUMBState, 32), + + VMSTATE_UINT32(pc, CPUMBState), + VMSTATE_SINGLE(msr, CPUMBState, 0, vmstate_msr, uint32_t), + VMSTATE_UINT32(esr, CPUMBState), + VMSTATE_UINT32(fsr, CPUMBState), + VMSTATE_UINT32(btr, CPUMBState), + VMSTATE_UINT32(edr, CPUMBState), + VMSTATE_UINT32(slr, CPUMBState), + VMSTATE_UINT32(shr, CPUMBState), + VMSTATE_UINT64(ear, CPUMBState), + + VMSTATE_UINT32(btarget, CPUMBState), + VMSTATE_UINT32(imm, CPUMBState), + VMSTATE_UINT32(iflags, CPUMBState), + + VMSTATE_UINT32(res_val, CPUMBState), + VMSTATE_UINTTL(res_addr, CPUMBState), + + VMSTATE_STRUCT(mmu, CPUMBState, 0, vmstate_mmu, MicroBlazeMMU), + + VMSTATE_END_OF_LIST() +}; + +static const VMStateDescription vmstate_env = { + .name = "env", + .version_id = 0, + .minimum_version_id = 0, + .fields = vmstate_env_fields, +}; + +static VMStateField vmstate_cpu_fields[] = { + VMSTATE_CPU(), + VMSTATE_STRUCT(env, MicroBlazeCPU, 1, vmstate_env, CPUMBState), + VMSTATE_END_OF_LIST() +}; + +const VMStateDescription vmstate_mb_cpu = { + .name = "cpu", + .version_id = 0, + .minimum_version_id = 0, + .fields = vmstate_cpu_fields, +}; diff --git a/target/microblaze/meson.build b/target/microblaze/meson.build index 639c3f73a8..05ee0ec163 100644 --- a/target/microblaze/meson.build +++ b/target/microblaze/meson.build @@ -11,7 +11,10 @@ microblaze_ss.add(files( )) microblaze_softmmu_ss = ss.source_set() -microblaze_softmmu_ss.add(files('mmu.c')) +microblaze_softmmu_ss.add(files( + 'mmu.c', + 'machine.c', +)) target_arch += {'microblaze': microblaze_ss} target_softmmu_arch += {'microblaze': microblaze_softmmu_ss} From 4b8936310b70056a8702f3b6b2b30f5aa72f887d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Sep 2020 11:49:13 -0700 Subject: [PATCH 17/18] target/microblaze: Put MicroBlazeCPUConfig into DisasContext The bulk of the translator should not have access to the complete cpu state, to avoid the temptation to examine bits that are in run time, but not translation time context. We do need access to the constant cpu configuration, and that is sufficient, so put that into DisasContext. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index eca422b3db..abfcc7e6c8 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -60,7 +60,7 @@ static TCGv_i32 cpu_res_val; /* This is the state at translation time. */ typedef struct DisasContext { DisasContextBase base; - MicroBlazeCPU *cpu; + const MicroBlazeCPUConfig *cfg; /* TCG op of the current insn_start. */ TCGOp *insn_start; @@ -159,7 +159,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) static bool trap_illegal(DisasContext *dc, bool cond) { if (cond && (dc->tb_flags & MSR_EE) - && dc->cpu->cfg.illegal_opcode_exception) { + && dc->cfg->illegal_opcode_exception) { gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); } return cond; @@ -291,7 +291,7 @@ static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ - { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); } + { return dc->cfg->CFG && do_typea(dc, a, SE, FN); } #define DO_TYPEA0(NAME, SE, FN) \ static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ @@ -299,7 +299,7 @@ static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ - { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); } + { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); } #define DO_TYPEBI(NAME, SE, FNI) \ static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ @@ -307,7 +307,7 @@ static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ - { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); } + { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); } #define DO_TYPEBV(NAME, SE, FN) \ static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ @@ -683,7 +683,7 @@ static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) tcg_gen_movi_tl(ret, 0); } - if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) { + if ((ra == 1 || rb == 1) && dc->cfg->stackprot) { gen_helper_stackprot(cpu_env, ret); } return ret; @@ -703,7 +703,7 @@ static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) tcg_gen_movi_tl(ret, (uint32_t)imm); } - if (ra == 1 && dc->cpu->cfg.stackprot) { + if (ra == 1 && dc->cfg->stackprot) { gen_helper_stackprot(cpu_env, ret); } return ret; @@ -712,7 +712,7 @@ static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) #ifndef CONFIG_USER_ONLY static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) { - int addr_size = dc->cpu->cfg.addr_size; + int addr_size = dc->cfg->addr_size; TCGv ret = tcg_temp_new(); if (addr_size == 32 || ra == 0) { @@ -772,7 +772,7 @@ static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, if (size > MO_8 && (dc->tb_flags & MSR_EE) && - dc->cpu->cfg.unaligned_exceptions) { + dc->cfg->unaligned_exceptions) { record_unaligned_ess(dc, rd, size, false); mop |= MO_ALIGN; } @@ -918,7 +918,7 @@ static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, if (size > MO_8 && (dc->tb_flags & MSR_EE) && - dc->cpu->cfg.unaligned_exceptions) { + dc->cfg->unaligned_exceptions) { record_unaligned_ess(dc, rd, size, true); mop |= MO_ALIGN; } @@ -1325,7 +1325,7 @@ DO_RTS(rtsd, 0) static bool trans_zero(DisasContext *dc, arg_zero *arg) { /* If opcode_0_illegal, trap. */ - if (dc->cpu->cfg.opcode_0_illegal) { + if (dc->cfg->opcode_0_illegal) { trap_illegal(dc, true); return true; } @@ -1658,7 +1658,7 @@ static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); int bound; - dc->cpu = cpu; + dc->cfg = &cpu->cfg; dc->tb_flags = dc->base.tb->flags; dc->ext_imm = dc->base.tb->cs_base; dc->r0 = NULL; From 7df61837df419740963f020d7ee7b852f6401301 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Sep 2020 11:38:40 -0700 Subject: [PATCH 18/18] configure: Do not set TARGET_ABI32 for microblaze In 19f27b6c2493 TARGET_ABI_LONG was reduced to 32 bits for CONFIG_USER_ONLY. There is no need to set this by hand; it will now be set automatically by include/exec/user/abitypes.h. Tested-by: Edgar E. Iglesias Reviewed-by: Edgar E. Iglesias Reported-by: Peter Maydell Signed-off-by: Richard Henderson --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index 166193cef9..f460aa6799 100755 --- a/configure +++ b/configure @@ -7752,7 +7752,6 @@ case "$target_name" in TARGET_SYSTBL_ABI=common mttcg="yes" bflt="yes" - echo "TARGET_ABI32=y" >> $config_target_mak ;; mips|mipsel) mttcg="yes"