1/* 2 * RISC-V translation routines for the RVXI Base Integer Instruction Set. 3 * 4 * Copyright (c) 2020 Western Digital 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2 or later, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License along with 16 * this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19#ifndef CONFIG_USER_ONLY 20static void check_access(DisasContext *ctx) { 21 if (!ctx->hlsx) { 22 if (ctx->virt_enabled) { 23 generate_exception(ctx, RISCV_EXCP_VIRT_INSTRUCTION_FAULT); 24 } else { 25 generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST); 26 } 27 } 28} 29#endif 30 31static bool trans_hlv_b(DisasContext *ctx, arg_hlv_b *a) 32{ 33 REQUIRE_EXT(ctx, RVH); 34#ifndef CONFIG_USER_ONLY 35 TCGv t0 = tcg_temp_new(); 36 TCGv t1 = tcg_temp_new(); 37 38 check_access(ctx); 39 40 gen_get_gpr(t0, a->rs1); 41 42 tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_SB); 43 gen_set_gpr(a->rd, t1); 44 45 tcg_temp_free(t0); 46 tcg_temp_free(t1); 47 return true; 48#else 49 return false; 50#endif 51} 52 53static bool trans_hlv_h(DisasContext *ctx, arg_hlv_h *a) 54{ 55 REQUIRE_EXT(ctx, RVH); 56#ifndef CONFIG_USER_ONLY 57 TCGv t0 = tcg_temp_new(); 58 TCGv t1 = tcg_temp_new(); 59 60 check_access(ctx); 61 62 gen_get_gpr(t0, a->rs1); 63 64 tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESW); 65 gen_set_gpr(a->rd, t1); 66 67 tcg_temp_free(t0); 68 tcg_temp_free(t1); 69 return true; 70#else 71 return false; 72#endif 73} 74 75static bool trans_hlv_w(DisasContext *ctx, arg_hlv_w *a) 76{ 77 REQUIRE_EXT(ctx, RVH); 78#ifndef CONFIG_USER_ONLY 79 TCGv t0 = tcg_temp_new(); 80 TCGv t1 = tcg_temp_new(); 81 82 check_access(ctx); 83 84 gen_get_gpr(t0, a->rs1); 85 86 tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESL); 87 gen_set_gpr(a->rd, t1); 88 89 tcg_temp_free(t0); 90 tcg_temp_free(t1); 91 return true; 92#else 93 return false; 94#endif 95} 96 97static bool trans_hlv_bu(DisasContext *ctx, arg_hlv_bu *a) 98{ 99 REQUIRE_EXT(ctx, RVH); 100#ifndef CONFIG_USER_ONLY 101 TCGv t0 = tcg_temp_new(); 102 TCGv t1 = tcg_temp_new(); 103 104 check_access(ctx); 105 106 gen_get_gpr(t0, a->rs1); 107 108 tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_UB); 109 gen_set_gpr(a->rd, t1); 110 111 tcg_temp_free(t0); 112 tcg_temp_free(t1); 113 return true; 114#else 115 return false; 116#endif 117} 118 119static bool trans_hlv_hu(DisasContext *ctx, arg_hlv_hu *a) 120{ 121 REQUIRE_EXT(ctx, RVH); 122#ifndef CONFIG_USER_ONLY 123 TCGv t0 = tcg_temp_new(); 124 TCGv t1 = tcg_temp_new(); 125 126 check_access(ctx); 127 128 gen_get_gpr(t0, a->rs1); 129 tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEUW); 130 gen_set_gpr(a->rd, t1); 131 132 tcg_temp_free(t0); 133 tcg_temp_free(t1); 134 return true; 135#else 136 return false; 137#endif 138} 139 140static bool trans_hsv_b(DisasContext *ctx, arg_hsv_b *a) 141{ 142 REQUIRE_EXT(ctx, RVH); 143#ifndef CONFIG_USER_ONLY 144 TCGv t0 = tcg_temp_new(); 145 TCGv dat = tcg_temp_new(); 146 147 check_access(ctx); 148 149 gen_get_gpr(t0, a->rs1); 150 gen_get_gpr(dat, a->rs2); 151 152 tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_SB); 153 154 tcg_temp_free(t0); 155 tcg_temp_free(dat); 156 return true; 157#else 158 return false; 159#endif 160} 161 162static bool trans_hsv_h(DisasContext *ctx, arg_hsv_h *a) 163{ 164 REQUIRE_EXT(ctx, RVH); 165#ifndef CONFIG_USER_ONLY 166 TCGv t0 = tcg_temp_new(); 167 TCGv dat = tcg_temp_new(); 168 169 check_access(ctx); 170 171 gen_get_gpr(t0, a->rs1); 172 gen_get_gpr(dat, a->rs2); 173 174 tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESW); 175 176 tcg_temp_free(t0); 177 tcg_temp_free(dat); 178 return true; 179#else 180 return false; 181#endif 182} 183 184static bool trans_hsv_w(DisasContext *ctx, arg_hsv_w *a) 185{ 186 REQUIRE_EXT(ctx, RVH); 187#ifndef CONFIG_USER_ONLY 188 TCGv t0 = tcg_temp_new(); 189 TCGv dat = tcg_temp_new(); 190 191 check_access(ctx); 192 193 gen_get_gpr(t0, a->rs1); 194 gen_get_gpr(dat, a->rs2); 195 196 tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TESL); 197 198 tcg_temp_free(t0); 199 tcg_temp_free(dat); 200 return true; 201#else 202 return false; 203#endif 204} 205 206#ifdef TARGET_RISCV64 207static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a) 208{ 209 REQUIRE_EXT(ctx, RVH); 210#ifndef CONFIG_USER_ONLY 211 TCGv t0 = tcg_temp_new(); 212 TCGv t1 = tcg_temp_new(); 213 214 check_access(ctx); 215 216 gen_get_gpr(t0, a->rs1); 217 218 tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEUL); 219 gen_set_gpr(a->rd, t1); 220 221 tcg_temp_free(t0); 222 tcg_temp_free(t1); 223 return true; 224#else 225 return false; 226#endif 227} 228 229static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a) 230{ 231 REQUIRE_EXT(ctx, RVH); 232#ifndef CONFIG_USER_ONLY 233 TCGv t0 = tcg_temp_new(); 234 TCGv t1 = tcg_temp_new(); 235 236 check_access(ctx); 237 238 gen_get_gpr(t0, a->rs1); 239 240 tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEQ); 241 gen_set_gpr(a->rd, t1); 242 243 tcg_temp_free(t0); 244 tcg_temp_free(t1); 245 return true; 246#else 247 return false; 248#endif 249} 250 251static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a) 252{ 253 REQUIRE_EXT(ctx, RVH); 254#ifndef CONFIG_USER_ONLY 255 TCGv t0 = tcg_temp_new(); 256 TCGv dat = tcg_temp_new(); 257 258 check_access(ctx); 259 260 gen_get_gpr(t0, a->rs1); 261 gen_get_gpr(dat, a->rs2); 262 263 tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEQ); 264 265 tcg_temp_free(t0); 266 tcg_temp_free(dat); 267 return true; 268#else 269 return false; 270#endif 271} 272#endif 273 274static bool trans_hlvx_hu(DisasContext *ctx, arg_hlvx_hu *a) 275{ 276 REQUIRE_EXT(ctx, RVH); 277#ifndef CONFIG_USER_ONLY 278 TCGv t0 = tcg_temp_new(); 279 TCGv t1 = tcg_temp_new(); 280 TCGv mem_idx = tcg_temp_new(); 281 TCGv memop = tcg_temp_new(); 282 283 gen_get_gpr(t0, a->rs1); 284 tcg_gen_movi_tl(mem_idx, ctx->mem_idx); 285 tcg_gen_movi_tl(memop, MO_TEUW); 286 287 gen_helper_hyp_x_load(t1, cpu_env, t0, mem_idx, memop); 288 gen_set_gpr(a->rd, t1); 289 290 tcg_temp_free(t0); 291 tcg_temp_free(t1); 292 tcg_temp_free(mem_idx); 293 tcg_temp_free(memop); 294 return true; 295#else 296 return false; 297#endif 298} 299 300static bool trans_hlvx_wu(DisasContext *ctx, arg_hlvx_wu *a) 301{ 302 REQUIRE_EXT(ctx, RVH); 303#ifndef CONFIG_USER_ONLY 304 TCGv t0 = tcg_temp_new(); 305 TCGv t1 = tcg_temp_new(); 306 TCGv mem_idx = tcg_temp_new(); 307 TCGv memop = tcg_temp_new(); 308 309 gen_get_gpr(t0, a->rs1); 310 tcg_gen_movi_tl(mem_idx, ctx->mem_idx); 311 tcg_gen_movi_tl(memop, MO_TEUL); 312 313 gen_helper_hyp_x_load(t1, cpu_env, t0, mem_idx, memop); 314 gen_set_gpr(a->rd, t1); 315 316 tcg_temp_free(t0); 317 tcg_temp_free(t1); 318 tcg_temp_free(mem_idx); 319 tcg_temp_free(memop); 320 return true; 321#else 322 return false; 323#endif 324} 325 326static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) 327{ 328 REQUIRE_EXT(ctx, RVH); 329#ifndef CONFIG_USER_ONLY 330 gen_helper_hyp_gvma_tlb_flush(cpu_env); 331 return true; 332#endif 333 return false; 334} 335 336static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a) 337{ 338 REQUIRE_EXT(ctx, RVH); 339#ifndef CONFIG_USER_ONLY 340 gen_helper_hyp_tlb_flush(cpu_env); 341 return true; 342#endif 343 return false; 344} 345