1/* 2 * Power ISA decode for Storage Control instructions 3 * 4 * Copyright (c) 2022 Instituto de Pesquisas Eldorado (eldorado.org.br) 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20/* 21 * Store Control Instructions 22 */ 23 24#include "mmu-book3s-v3.h" 25 26static bool trans_SLBIE(DisasContext *ctx, arg_SLBIE *a) 27{ 28 REQUIRE_64BIT(ctx); 29 REQUIRE_INSNS_FLAGS(ctx, SLBI); 30 REQUIRE_SV(ctx); 31 32#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) 33 gen_helper_SLBIE(tcg_env, cpu_gpr[a->rb]); 34#else 35 qemu_build_not_reached(); 36#endif 37 return true; 38} 39 40static bool trans_SLBIEG(DisasContext *ctx, arg_SLBIEG *a) 41{ 42 REQUIRE_64BIT(ctx); 43 REQUIRE_INSNS_FLAGS2(ctx, ISA300); 44 REQUIRE_SV(ctx); 45 46#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) 47 gen_helper_SLBIEG(tcg_env, cpu_gpr[a->rb]); 48#else 49 qemu_build_not_reached(); 50#endif 51 return true; 52} 53 54static bool trans_SLBIA(DisasContext *ctx, arg_SLBIA *a) 55{ 56 REQUIRE_64BIT(ctx); 57 REQUIRE_INSNS_FLAGS(ctx, SLBI); 58 REQUIRE_SV(ctx); 59 60#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) 61 gen_helper_SLBIA(tcg_env, tcg_constant_i32(a->ih)); 62#else 63 qemu_build_not_reached(); 64#endif 65 return true; 66} 67 68static bool trans_SLBIAG(DisasContext *ctx, arg_SLBIAG *a) 69{ 70 REQUIRE_64BIT(ctx); 71 REQUIRE_INSNS_FLAGS2(ctx, ISA300); 72 REQUIRE_SV(ctx); 73 74#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) 75 gen_helper_SLBIAG(tcg_env, cpu_gpr[a->rs], tcg_constant_i32(a->l)); 76#else 77 qemu_build_not_reached(); 78#endif 79 return true; 80} 81 82static bool trans_SLBMTE(DisasContext *ctx, arg_SLBMTE *a) 83{ 84 REQUIRE_64BIT(ctx); 85 REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); 86 REQUIRE_SV(ctx); 87 88#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) 89 gen_helper_SLBMTE(tcg_env, cpu_gpr[a->rb], cpu_gpr[a->rt]); 90#else 91 qemu_build_not_reached(); 92#endif 93 return true; 94} 95 96static bool trans_SLBMFEV(DisasContext *ctx, arg_SLBMFEV *a) 97{ 98 REQUIRE_64BIT(ctx); 99 REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); 100 REQUIRE_SV(ctx); 101 102#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) 103 gen_helper_SLBMFEV(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]); 104#else 105 qemu_build_not_reached(); 106#endif 107 return true; 108} 109 110static bool trans_SLBMFEE(DisasContext *ctx, arg_SLBMFEE *a) 111{ 112 REQUIRE_64BIT(ctx); 113 REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); 114 REQUIRE_SV(ctx); 115 116#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) 117 gen_helper_SLBMFEE(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]); 118#else 119 qemu_build_not_reached(); 120#endif 121 return true; 122} 123 124static bool trans_SLBFEE(DisasContext *ctx, arg_SLBFEE *a) 125{ 126 REQUIRE_64BIT(ctx); 127 REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); 128 129#if defined(CONFIG_USER_ONLY) 130 gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); 131#else 132 133#if defined(TARGET_PPC64) 134 TCGLabel *l1, *l2; 135 136 if (unlikely(ctx->pr)) { 137 gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); 138 return true; 139 } 140 gen_helper_SLBFEE(cpu_gpr[a->rt], tcg_env, 141 cpu_gpr[a->rb]); 142 l1 = gen_new_label(); 143 l2 = gen_new_label(); 144 tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); 145 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[a->rt], -1, l1); 146 tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ); 147 tcg_gen_br(l2); 148 gen_set_label(l1); 149 tcg_gen_movi_tl(cpu_gpr[a->rt], 0); 150 gen_set_label(l2); 151#else 152 qemu_build_not_reached(); 153#endif 154#endif 155 return true; 156} 157 158static bool trans_SLBSYNC(DisasContext *ctx, arg_SLBSYNC *a) 159{ 160 REQUIRE_64BIT(ctx); 161 REQUIRE_INSNS_FLAGS2(ctx, ISA300); 162 REQUIRE_SV(ctx); 163 164#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) 165 gen_check_tlb_flush(ctx, true); 166#else 167 qemu_build_not_reached(); 168#endif 169 return true; 170} 171 172static bool do_tlbie(DisasContext *ctx, arg_X_tlbie *a, bool local) 173{ 174#if defined(CONFIG_USER_ONLY) 175 gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); 176 return true; 177#else 178 TCGv_i32 t1; 179 int rb; 180 181 rb = a->rb; 182 183 if ((ctx->insns_flags2 & PPC2_ISA300) == 0) { 184 /* 185 * Before Power ISA 3.0, the corresponding bits of RIC, PRS, and R 186 * (and RS for tlbiel) were reserved fields and should be ignored. 187 */ 188 a->ric = 0; 189 a->prs = false; 190 a->r = false; 191 if (local) { 192 a->rs = 0; 193 } 194 } 195 196 if (ctx->pr) { 197 /* tlbie[l] is privileged... */ 198 gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); 199 return true; 200 } else if (!ctx->hv) { 201 if ((!a->prs && ctx->hr) || (!local && !ctx->gtse)) { 202 /* 203 * ... except when PRS=0 and HR=1, or when GTSE=0 for tlbie, 204 * making it hypervisor privileged. 205 */ 206 gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); 207 return true; 208 } 209 } 210 211 if (!local && NARROW_MODE(ctx)) { 212 TCGv t0 = tcg_temp_new(); 213 tcg_gen_ext32u_tl(t0, cpu_gpr[rb]); 214 gen_helper_tlbie(tcg_env, t0); 215 216#if defined(TARGET_PPC64) 217 /* 218 * ISA 3.1B says that MSR SF must be 1 when this instruction is executed; 219 * otherwise the results are undefined. 220 */ 221 } else if (a->r) { 222 gen_helper_tlbie_isa300(tcg_env, cpu_gpr[rb], cpu_gpr[a->rs], 223 tcg_constant_i32(a->ric << TLBIE_F_RIC_SHIFT | 224 a->prs << TLBIE_F_PRS_SHIFT | 225 a->r << TLBIE_F_R_SHIFT | 226 local << TLBIE_F_LOCAL_SHIFT)); 227 if (!local) { 228 /* 229 * Global TLB flush uses async-work which must run before the 230 * next instruction, so this must be the last in the TB. 231 */ 232 ctx->base.is_jmp = DISAS_EXIT_UPDATE; 233 } 234 return true; 235#endif 236 237 } else { 238 gen_helper_tlbie(tcg_env, cpu_gpr[rb]); 239 } 240 241 if (local) { 242 return true; 243 } 244 245 t1 = tcg_temp_new_i32(); 246 tcg_gen_ld_i32(t1, tcg_env, offsetof(CPUPPCState, tlb_need_flush)); 247 tcg_gen_ori_i32(t1, t1, TLB_NEED_GLOBAL_FLUSH); 248 tcg_gen_st_i32(t1, tcg_env, offsetof(CPUPPCState, tlb_need_flush)); 249 250 return true; 251#endif 252} 253 254TRANS_FLAGS(MEM_TLBIE, TLBIE, do_tlbie, false) 255TRANS_FLAGS(MEM_TLBIE, TLBIEL, do_tlbie, true) 256