/* * Power ISA decode for Storage Control instructions * * Copyright (c) 2022 Instituto de Pesquisas Eldorado (eldorado.org.br) * * 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.1 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 . */ /* * Store Control Instructions */ #include "mmu-book3s-v3.h" static bool trans_SLBIE(DisasContext *ctx, arg_SLBIE *a) { REQUIRE_64BIT(ctx); REQUIRE_INSNS_FLAGS(ctx, SLBI); REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) gen_helper_SLBIE(tcg_env, cpu_gpr[a->rb]); #else qemu_build_not_reached(); #endif return true; } static bool trans_SLBIEG(DisasContext *ctx, arg_SLBIEG *a) { REQUIRE_64BIT(ctx); REQUIRE_INSNS_FLAGS2(ctx, ISA300); REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) gen_helper_SLBIEG(tcg_env, cpu_gpr[a->rb]); #else qemu_build_not_reached(); #endif return true; } static bool trans_SLBIA(DisasContext *ctx, arg_SLBIA *a) { REQUIRE_64BIT(ctx); REQUIRE_INSNS_FLAGS(ctx, SLBI); REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) gen_helper_SLBIA(tcg_env, tcg_constant_i32(a->ih)); #else qemu_build_not_reached(); #endif return true; } static bool trans_SLBIAG(DisasContext *ctx, arg_SLBIAG *a) { REQUIRE_64BIT(ctx); REQUIRE_INSNS_FLAGS2(ctx, ISA300); REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) gen_helper_SLBIAG(tcg_env, cpu_gpr[a->rs], tcg_constant_i32(a->l)); #else qemu_build_not_reached(); #endif return true; } static bool trans_SLBMTE(DisasContext *ctx, arg_SLBMTE *a) { REQUIRE_64BIT(ctx); REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) gen_helper_SLBMTE(tcg_env, cpu_gpr[a->rb], cpu_gpr[a->rt]); #else qemu_build_not_reached(); #endif return true; } static bool trans_SLBMFEV(DisasContext *ctx, arg_SLBMFEV *a) { REQUIRE_64BIT(ctx); REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) gen_helper_SLBMFEV(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]); #else qemu_build_not_reached(); #endif return true; } static bool trans_SLBMFEE(DisasContext *ctx, arg_SLBMFEE *a) { REQUIRE_64BIT(ctx); REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) gen_helper_SLBMFEE(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]); #else qemu_build_not_reached(); #endif return true; } static bool trans_SLBFEE(DisasContext *ctx, arg_SLBFEE *a) { REQUIRE_64BIT(ctx); REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); #else #if defined(TARGET_PPC64) TCGLabel *l1, *l2; if (unlikely(ctx->pr)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return true; } gen_helper_SLBFEE(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]); l1 = gen_new_label(); l2 = gen_new_label(); tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[a->rt], -1, l1); tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ); tcg_gen_br(l2); gen_set_label(l1); tcg_gen_movi_tl(cpu_gpr[a->rt], 0); gen_set_label(l2); #else qemu_build_not_reached(); #endif #endif return true; } static bool trans_SLBSYNC(DisasContext *ctx, arg_SLBSYNC *a) { REQUIRE_64BIT(ctx); REQUIRE_INSNS_FLAGS2(ctx, ISA300); REQUIRE_SV(ctx); #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) gen_check_tlb_flush(ctx, true); #else qemu_build_not_reached(); #endif return true; } static bool do_tlbie(DisasContext *ctx, arg_X_tlbie *a, bool local) { #if defined(CONFIG_USER_ONLY) gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); return true; #else TCGv_i32 t1; int rb; rb = a->rb; if ((ctx->insns_flags2 & PPC2_ISA300) == 0) { /* * Before Power ISA 3.0, the corresponding bits of RIC, PRS, and R * (and RS for tlbiel) were reserved fields and should be ignored. */ a->ric = 0; a->prs = false; a->r = false; if (local) { a->rs = 0; } } if (ctx->pr) { /* tlbie[l] is privileged... */ gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); return true; } else if (!ctx->hv) { if ((!a->prs && ctx->hr) || (!local && !ctx->gtse)) { /* * ... except when PRS=0 and HR=1, or when GTSE=0 for tlbie, * making it hypervisor privileged. */ gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); return true; } } if (!local && NARROW_MODE(ctx)) { TCGv t0 = tcg_temp_new(); tcg_gen_ext32u_tl(t0, cpu_gpr[rb]); gen_helper_tlbie(tcg_env, t0); #if defined(TARGET_PPC64) /* * ISA 3.1B says that MSR SF must be 1 when this instruction is executed; * otherwise the results are undefined. */ } else if (a->r) { gen_helper_tlbie_isa300(tcg_env, cpu_gpr[rb], cpu_gpr[a->rs], tcg_constant_i32(a->ric << TLBIE_F_RIC_SHIFT | a->prs << TLBIE_F_PRS_SHIFT | a->r << TLBIE_F_R_SHIFT | local << TLBIE_F_LOCAL_SHIFT)); return true; #endif } else { gen_helper_tlbie(tcg_env, cpu_gpr[rb]); } if (local) { return true; } t1 = tcg_temp_new_i32(); tcg_gen_ld_i32(t1, tcg_env, offsetof(CPUPPCState, tlb_need_flush)); tcg_gen_ori_i32(t1, t1, TLB_NEED_GLOBAL_FLUSH); tcg_gen_st_i32(t1, tcg_env, offsetof(CPUPPCState, tlb_need_flush)); return true; #endif } TRANS_FLAGS(MEM_TLBIE, TLBIE, do_tlbie, false) TRANS_FLAGS(MEM_TLBIE, TLBIEL, do_tlbie, true)