master
inc 371 lines 10.2 KB
Raw
1 /*
2 * Power ISA decode for Storage Control instructions
3 *
4 * Copyright (c) 2022 Instituto de Pesquisas Eldorado (eldorado.org.br)
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21 * Store Control Instructions
22 */
23
24 #include "mmu-book3s-v3.h"
25
26 static bool trans_SLBIE(DisasContext *ctx, arg_SLBIE *a)
27 {
28 REQUIRE_64BIT(ctx);
29 REQUIRE_INSNS_FLAGS(ctx, SLBI);
30 REQUIRE_SV(ctx);
31
32 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
33 gen_helper_SLBIE(tcg_env, cpu_gpr[a->rb]);
34 #else
35 qemu_build_not_reached();
36 #endif
37 return true;
38 }
39
40 static bool trans_SLBIEG(DisasContext *ctx, arg_SLBIEG *a)
41 {
42 REQUIRE_64BIT(ctx);
43 REQUIRE_INSNS_FLAGS2(ctx, ISA300);
44 REQUIRE_SV(ctx);
45
46 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
47 gen_helper_SLBIEG(tcg_env, cpu_gpr[a->rb]);
48 #else
49 qemu_build_not_reached();
50 #endif
51 return true;
52 }
53
54 static bool trans_SLBIA(DisasContext *ctx, arg_SLBIA *a)
55 {
56 REQUIRE_64BIT(ctx);
57 REQUIRE_INSNS_FLAGS(ctx, SLBI);
58 REQUIRE_SV(ctx);
59
60 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
61 gen_helper_SLBIA(tcg_env, tcg_constant_i32(a->ih));
62 #else
63 qemu_build_not_reached();
64 #endif
65 return true;
66 }
67
68 static bool trans_SLBIAG(DisasContext *ctx, arg_SLBIAG *a)
69 {
70 REQUIRE_64BIT(ctx);
71 REQUIRE_INSNS_FLAGS2(ctx, ISA300);
72 REQUIRE_SV(ctx);
73
74 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
75 gen_helper_SLBIAG(tcg_env, cpu_gpr[a->rs], tcg_constant_i32(a->l));
76 #else
77 qemu_build_not_reached();
78 #endif
79 return true;
80 }
81
82 static bool trans_SLBMTE(DisasContext *ctx, arg_SLBMTE *a)
83 {
84 REQUIRE_64BIT(ctx);
85 REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B);
86 REQUIRE_SV(ctx);
87
88 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
89 gen_helper_SLBMTE(tcg_env, cpu_gpr[a->rb], cpu_gpr[a->rt]);
90 #else
91 qemu_build_not_reached();
92 #endif
93 return true;
94 }
95
96 static bool trans_SLBMFEV(DisasContext *ctx, arg_SLBMFEV *a)
97 {
98 REQUIRE_64BIT(ctx);
99 REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B);
100 REQUIRE_SV(ctx);
101
102 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
103 gen_helper_SLBMFEV(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]);
104 #else
105 qemu_build_not_reached();
106 #endif
107 return true;
108 }
109
110 static bool trans_SLBMFEE(DisasContext *ctx, arg_SLBMFEE *a)
111 {
112 REQUIRE_64BIT(ctx);
113 REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B);
114 REQUIRE_SV(ctx);
115
116 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
117 gen_helper_SLBMFEE(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]);
118 #else
119 qemu_build_not_reached();
120 #endif
121 return true;
122 }
123
124 static bool trans_SLBFEE(DisasContext *ctx, arg_SLBFEE *a)
125 {
126 REQUIRE_64BIT(ctx);
127 REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B);
128
129 #if defined(CONFIG_USER_ONLY)
130 gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
131 #else
132
133 #if defined(TARGET_PPC64)
134 TCGLabel *l1, *l2;
135
136 if (unlikely(ctx->pr)) {
137 gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
138 return true;
139 }
140 gen_helper_SLBFEE(cpu_gpr[a->rt], tcg_env,
141 cpu_gpr[a->rb]);
142 l1 = gen_new_label();
143 l2 = gen_new_label();
144 tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
145 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[a->rt], -1, l1);
146 tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ);
147 tcg_gen_br(l2);
148 gen_set_label(l1);
149 tcg_gen_movi_tl(cpu_gpr[a->rt], 0);
150 gen_set_label(l2);
151 #else
152 qemu_build_not_reached();
153 #endif
154 #endif
155 return true;
156 }
157
158 static bool trans_ISYNC(DisasContext *ctx, arg_ISYNC *a)
159 {
160 REQUIRE_INSNS_FLAGS(ctx, MEM);
161
162 /*
163 * We need to check for a pending TLB flush. This can only happen in
164 * kernel mode however so check MSR_PR
165 */
166 if (!ctx->pr) {
167 gen_check_tlb_flush(ctx, false);
168 }
169 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
170 ctx->base.is_jmp = DISAS_EXIT_UPDATE;
171
172 return true;
173 }
174
175 static bool trans_SLBSYNC(DisasContext *ctx, arg_SLBSYNC *a)
176 {
177 REQUIRE_64BIT(ctx);
178 REQUIRE_INSNS_FLAGS2(ctx, ISA300);
179 REQUIRE_SV(ctx);
180
181 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
182 gen_check_tlb_flush(ctx, true);
183 #else
184 qemu_build_not_reached();
185 #endif
186 return true;
187 }
188
189 static bool do_tlbie(DisasContext *ctx, arg_X_tlbie *a, bool local)
190 {
191 #if defined(CONFIG_USER_ONLY)
192 gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
193 return true;
194 #else
195 TCGv_i32 t1;
196 int rb;
197
198 rb = a->rb;
199
200 if ((ctx->insns_flags2 & PPC2_ISA300) == 0) {
201 /*
202 * Before Power ISA 3.0, the corresponding bits of RIC, PRS, and R
203 * (and RS for tlbiel) were reserved fields and should be ignored.
204 */
205 a->ric = 0;
206 a->prs = false;
207 a->r = false;
208 if (local) {
209 a->rs = 0;
210 }
211 }
212
213 if (ctx->pr) {
214 /* tlbie[l] is privileged... */
215 gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
216 return true;
217 } else if (!ctx->hv) {
218 if ((!a->prs && ctx->hr) || (!local && !ctx->gtse)) {
219 /*
220 * ... except when PRS=0 and HR=1, or when GTSE=0 for tlbie,
221 * making it hypervisor privileged.
222 */
223 gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
224 return true;
225 }
226 }
227
228 if (!local && NARROW_MODE(ctx)) {
229 TCGv t0 = tcg_temp_new();
230 tcg_gen_ext32u_tl(t0, cpu_gpr[rb]);
231 gen_helper_tlbie(tcg_env, t0);
232
233 #if defined(TARGET_PPC64)
234 /*
235 * ISA 3.1B says that MSR SF must be 1 when this instruction is executed;
236 * otherwise the results are undefined.
237 */
238 } else if (a->r) {
239 gen_helper_tlbie_isa300(tcg_env, cpu_gpr[rb], cpu_gpr[a->rs],
240 tcg_constant_i32(a->ric << TLBIE_F_RIC_SHIFT |
241 a->prs << TLBIE_F_PRS_SHIFT |
242 a->r << TLBIE_F_R_SHIFT |
243 local << TLBIE_F_LOCAL_SHIFT));
244 if (!local) {
245 /*
246 * Global TLB flush uses async-work which must run before the
247 * next instruction, so this must be the last in the TB.
248 */
249 ctx->base.is_jmp = DISAS_EXIT_UPDATE;
250 }
251 return true;
252 #endif
253
254 } else {
255 gen_helper_tlbie(tcg_env, cpu_gpr[rb]);
256 }
257
258 if (local) {
259 return true;
260 }
261
262 t1 = tcg_temp_new_i32();
263 tcg_gen_ld_i32(t1, tcg_env, offsetof(CPUPPCState, tlb_need_flush));
264 tcg_gen_ori_i32(t1, t1, TLB_NEED_GLOBAL_FLUSH);
265 tcg_gen_st_i32(t1, tcg_env, offsetof(CPUPPCState, tlb_need_flush));
266
267 return true;
268 #endif
269 }
270
271 TRANS_FLAGS(MEM_TLBIE, TLBIE, do_tlbie, false)
272 TRANS_FLAGS(MEM_TLBIE, TLBIEL, do_tlbie, true)
273
274 /*
275 * Decodetree populates a->wc and a->pl based on ISA v3.1, however they may
276 * or may not be used based on the ISA:
277 * For ISA < 2.06 - both wc and pl are ignored
278 * For ISA == 2.06, 2.07, 3.0 - wc is used and pl is ignored
279 * For ISA 3.1 - both wc and pl are used
280 */
281 static bool do_wait(DisasContext *ctx, arg_X_wait *a)
282 {
283 uint32_t wc;
284
285 if (ctx->insns_flags & PPC_WAIT) {
286 /* v2.03-v2.07 define an older incompatible 'wait' encoding. */
287
288 if (ctx->insns_flags2 & PPC2_PM_ISA206) {
289 /* v2.06 introduced the WC field. WC > 0 may be treated as no-op. */
290 wc = a->wc;
291 } else {
292 wc = 0;
293 }
294
295 } else if (ctx->insns_flags2 & PPC2_ISA300) {
296 /* v3.0 defines a new 'wait' encoding. */
297 wc = a->wc;
298 if (ctx->insns_flags2 & PPC2_ISA310) {
299 uint32_t pl = a->pl;
300
301 /* WC 1,2 may be treated as no-op. WC 3 is reserved. */
302 if (wc == 3) {
303 gen_invalid(ctx);
304 return true;
305 }
306
307 /* PL 1-3 are reserved. If WC=2 then the insn is treated as noop. */
308 if (pl > 0 && wc != 2) {
309 gen_invalid(ctx);
310 return true;
311 }
312
313 } else { /* ISA300 */
314 /* WC 1-3 are reserved */
315 if (wc > 0) {
316 gen_invalid(ctx);
317 return true;
318 }
319 }
320
321 } else {
322 warn_report("wait instruction decoded with wrong ISA flags.");
323 gen_invalid(ctx);
324 return true;
325 }
326
327 /*
328 * wait without WC field or with WC=0 waits for an exception / interrupt
329 * to occur.
330 */
331 if (wc == 0) {
332 TCGv_i32 t0 = tcg_constant_i32(1);
333 tcg_gen_st_i32(t0, tcg_env,
334 -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted));
335 /* Stop translation, as the CPU is supposed to sleep from now */
336 gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next);
337 }
338
339 /*
340 * Other wait types must not just wait until an exception occurs because
341 * ignoring their other wake-up conditions could cause a hang.
342 *
343 * For v2.06 and 2.07, wc=1,2,3 are architected but may be implemented as
344 * no-ops.
345 *
346 * wc=1 and wc=3 explicitly allow the instruction to be treated as a no-op.
347 *
348 * wc=2 waits for an implementation-specific condition, such could be
349 * always true, so it can be implemented as a no-op.
350 *
351 * For v3.1, wc=1,2 are architected but may be implemented as no-ops.
352 *
353 * wc=1 (waitrsv) waits for an exception or a reservation to be lost.
354 * Reservation-loss may have implementation-specific conditions, so it
355 * can be implemented as a no-op.
356 *
357 * wc=2 waits for an exception or an amount of time to pass. This
358 * amount is implementation-specific so it can be implemented as a
359 * no-op.
360 *
361 * ISA v3.1 allows for execution to resume "in the rare case of
362 * an implementation-dependent event", so in any case software must
363 * not depend on the architected resumption condition to become
364 * true, so no-op implementations should be architecturally correct
365 * (if suboptimal).
366 */
367 return true;
368 }
369
370 TRANS_FLAGS(WAIT, WAIT_ISA_2_X, do_wait)
371 TRANS_FLAGS2(ISA300, WAIT, do_wait)