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 281 check_access(ctx); 282 283 gen_get_gpr(t0, a->rs1); 284 285 gen_helper_hyp_hlvx_hu(t1, cpu_env, t0); 286 gen_set_gpr(a->rd, t1); 287 288 tcg_temp_free(t0); 289 tcg_temp_free(t1); 290 return true; 291#else 292 return false; 293#endif 294} 295 296static bool trans_hlvx_wu(DisasContext *ctx, arg_hlvx_wu *a) 297{ 298 REQUIRE_EXT(ctx, RVH); 299#ifndef CONFIG_USER_ONLY 300 TCGv t0 = tcg_temp_new(); 301 TCGv t1 = tcg_temp_new(); 302 303 check_access(ctx); 304 305 gen_get_gpr(t0, a->rs1); 306 307 gen_helper_hyp_hlvx_wu(t1, cpu_env, t0); 308 gen_set_gpr(a->rd, t1); 309 310 tcg_temp_free(t0); 311 tcg_temp_free(t1); 312 return true; 313#else 314 return false; 315#endif 316} 317 318static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) 319{ 320 REQUIRE_EXT(ctx, RVH); 321#ifndef CONFIG_USER_ONLY 322 gen_helper_hyp_gvma_tlb_flush(cpu_env); 323 return true; 324#endif 325 return false; 326} 327 328static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a) 329{ 330 REQUIRE_EXT(ctx, RVH); 331#ifndef CONFIG_USER_ONLY 332 gen_helper_hyp_tlb_flush(cpu_env); 333 return true; 334#endif 335 return false; 336} 337