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 206static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a) 207{ 208 REQUIRE_64BIT(ctx); 209 REQUIRE_EXT(ctx, RVH); 210 211#ifndef CONFIG_USER_ONLY 212 TCGv t0 = tcg_temp_new(); 213 TCGv t1 = tcg_temp_new(); 214 215 check_access(ctx); 216 217 gen_get_gpr(t0, a->rs1); 218 219 tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEUL); 220 gen_set_gpr(a->rd, t1); 221 222 tcg_temp_free(t0); 223 tcg_temp_free(t1); 224 return true; 225#else 226 return false; 227#endif 228} 229 230static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a) 231{ 232 REQUIRE_64BIT(ctx); 233 REQUIRE_EXT(ctx, RVH); 234 235#ifndef CONFIG_USER_ONLY 236 TCGv t0 = tcg_temp_new(); 237 TCGv t1 = tcg_temp_new(); 238 239 check_access(ctx); 240 241 gen_get_gpr(t0, a->rs1); 242 243 tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEQ); 244 gen_set_gpr(a->rd, t1); 245 246 tcg_temp_free(t0); 247 tcg_temp_free(t1); 248 return true; 249#else 250 return false; 251#endif 252} 253 254static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a) 255{ 256 REQUIRE_64BIT(ctx); 257 REQUIRE_EXT(ctx, RVH); 258 259#ifndef CONFIG_USER_ONLY 260 TCGv t0 = tcg_temp_new(); 261 TCGv dat = tcg_temp_new(); 262 263 check_access(ctx); 264 265 gen_get_gpr(t0, a->rs1); 266 gen_get_gpr(dat, a->rs2); 267 268 tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK, MO_TEQ); 269 270 tcg_temp_free(t0); 271 tcg_temp_free(dat); 272 return true; 273#else 274 return false; 275#endif 276} 277 278static bool trans_hlvx_hu(DisasContext *ctx, arg_hlvx_hu *a) 279{ 280 REQUIRE_EXT(ctx, RVH); 281#ifndef CONFIG_USER_ONLY 282 TCGv t0 = tcg_temp_new(); 283 TCGv t1 = tcg_temp_new(); 284 285 check_access(ctx); 286 287 gen_get_gpr(t0, a->rs1); 288 289 gen_helper_hyp_hlvx_hu(t1, cpu_env, t0); 290 gen_set_gpr(a->rd, t1); 291 292 tcg_temp_free(t0); 293 tcg_temp_free(t1); 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 307 check_access(ctx); 308 309 gen_get_gpr(t0, a->rs1); 310 311 gen_helper_hyp_hlvx_wu(t1, cpu_env, t0); 312 gen_set_gpr(a->rd, t1); 313 314 tcg_temp_free(t0); 315 tcg_temp_free(t1); 316 return true; 317#else 318 return false; 319#endif 320} 321 322static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) 323{ 324 REQUIRE_EXT(ctx, RVH); 325#ifndef CONFIG_USER_ONLY 326 gen_helper_hyp_gvma_tlb_flush(cpu_env); 327 return true; 328#endif 329 return false; 330} 331 332static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a) 333{ 334 REQUIRE_EXT(ctx, RVH); 335#ifndef CONFIG_USER_ONLY 336 gen_helper_hyp_tlb_flush(cpu_env); 337 return true; 338#endif 339 return false; 340} 341