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 bool check_access(DisasContext *ctx) 21{ 22 if (!ctx->hlsx) { 23 tcg_gen_st_i32(tcg_constant_i32(ctx->opcode), cpu_env, 24 offsetof(CPURISCVState, bins)); 25 if (ctx->virt_enabled) { 26 generate_exception(ctx, RISCV_EXCP_VIRT_INSTRUCTION_FAULT); 27 } else { 28 generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST); 29 } 30 return false; 31 } 32 return true; 33} 34#endif 35 36static bool do_hlv(DisasContext *ctx, arg_r2 *a, MemOp mop) 37{ 38#ifdef CONFIG_USER_ONLY 39 return false; 40#else 41 decode_save_opc(ctx); 42 if (check_access(ctx)) { 43 TCGv dest = dest_gpr(ctx, a->rd); 44 TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE); 45 int mem_idx = ctx->mem_idx | MMU_HYP_ACCESS_BIT; 46 tcg_gen_qemu_ld_tl(dest, addr, mem_idx, mop); 47 gen_set_gpr(ctx, a->rd, dest); 48 } 49 return true; 50#endif 51} 52 53static bool trans_hlv_b(DisasContext *ctx, arg_hlv_b *a) 54{ 55 REQUIRE_EXT(ctx, RVH); 56 return do_hlv(ctx, a, MO_SB); 57} 58 59static bool trans_hlv_h(DisasContext *ctx, arg_hlv_h *a) 60{ 61 REQUIRE_EXT(ctx, RVH); 62 return do_hlv(ctx, a, MO_TESW); 63} 64 65static bool trans_hlv_w(DisasContext *ctx, arg_hlv_w *a) 66{ 67 REQUIRE_EXT(ctx, RVH); 68 return do_hlv(ctx, a, MO_TESL); 69} 70 71static bool trans_hlv_bu(DisasContext *ctx, arg_hlv_bu *a) 72{ 73 REQUIRE_EXT(ctx, RVH); 74 return do_hlv(ctx, a, MO_UB); 75} 76 77static bool trans_hlv_hu(DisasContext *ctx, arg_hlv_hu *a) 78{ 79 REQUIRE_EXT(ctx, RVH); 80 return do_hlv(ctx, a, MO_TEUW); 81} 82 83static bool do_hsv(DisasContext *ctx, arg_r2_s *a, MemOp mop) 84{ 85#ifdef CONFIG_USER_ONLY 86 return false; 87#else 88 decode_save_opc(ctx); 89 if (check_access(ctx)) { 90 TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE); 91 TCGv data = get_gpr(ctx, a->rs2, EXT_NONE); 92 int mem_idx = ctx->mem_idx | MMU_HYP_ACCESS_BIT; 93 tcg_gen_qemu_st_tl(data, addr, mem_idx, mop); 94 } 95 return true; 96#endif 97} 98 99static bool trans_hsv_b(DisasContext *ctx, arg_hsv_b *a) 100{ 101 REQUIRE_EXT(ctx, RVH); 102 return do_hsv(ctx, a, MO_SB); 103} 104 105static bool trans_hsv_h(DisasContext *ctx, arg_hsv_h *a) 106{ 107 REQUIRE_EXT(ctx, RVH); 108 return do_hsv(ctx, a, MO_TESW); 109} 110 111static bool trans_hsv_w(DisasContext *ctx, arg_hsv_w *a) 112{ 113 REQUIRE_EXT(ctx, RVH); 114 return do_hsv(ctx, a, MO_TESL); 115} 116 117static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a) 118{ 119 REQUIRE_64BIT(ctx); 120 REQUIRE_EXT(ctx, RVH); 121 return do_hlv(ctx, a, MO_TEUL); 122} 123 124static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a) 125{ 126 REQUIRE_64BIT(ctx); 127 REQUIRE_EXT(ctx, RVH); 128 return do_hlv(ctx, a, MO_TEUQ); 129} 130 131static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a) 132{ 133 REQUIRE_64BIT(ctx); 134 REQUIRE_EXT(ctx, RVH); 135 return do_hsv(ctx, a, MO_TEUQ); 136} 137 138#ifndef CONFIG_USER_ONLY 139static bool do_hlvx(DisasContext *ctx, arg_r2 *a, 140 void (*func)(TCGv, TCGv_env, TCGv)) 141{ 142 decode_save_opc(ctx); 143 if (check_access(ctx)) { 144 TCGv dest = dest_gpr(ctx, a->rd); 145 TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE); 146 func(dest, cpu_env, addr); 147 gen_set_gpr(ctx, a->rd, dest); 148 } 149 return true; 150} 151#endif 152 153static bool trans_hlvx_hu(DisasContext *ctx, arg_hlvx_hu *a) 154{ 155 REQUIRE_EXT(ctx, RVH); 156#ifndef CONFIG_USER_ONLY 157 return do_hlvx(ctx, a, gen_helper_hyp_hlvx_hu); 158#else 159 return false; 160#endif 161} 162 163static bool trans_hlvx_wu(DisasContext *ctx, arg_hlvx_wu *a) 164{ 165 REQUIRE_EXT(ctx, RVH); 166#ifndef CONFIG_USER_ONLY 167 return do_hlvx(ctx, a, gen_helper_hyp_hlvx_wu); 168#else 169 return false; 170#endif 171} 172 173static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) 174{ 175 REQUIRE_EXT(ctx, RVH); 176#ifndef CONFIG_USER_ONLY 177 decode_save_opc(ctx); 178 gen_helper_hyp_gvma_tlb_flush(cpu_env); 179 return true; 180#endif 181 return false; 182} 183 184static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a) 185{ 186 REQUIRE_EXT(ctx, RVH); 187#ifndef CONFIG_USER_ONLY 188 decode_save_opc(ctx); 189 gen_helper_hyp_tlb_flush(cpu_env); 190 return true; 191#endif 192 return false; 193} 194