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