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