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