master
inc 213 lines 6.22 KB
Raw
1 /*
2 * Power ISA decode for branch instructions
3 *
4 * Copyright IBM Corp. 2021
5 *
6 * Authors:
7 * Daniel Henrique Barboza <danielhb413@gmail.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
11 */
12
13 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
14
15 static bool trans_RFEBB(DisasContext *ctx, arg_XL_s *arg)
16 {
17 REQUIRE_INSNS_FLAGS2(ctx, ISA207);
18
19 translator_io_start(&ctx->base);
20 gen_update_branch_history(ctx, ctx->cia, NULL, BHRB_TYPE_NORECORD);
21 gen_helper_rfebb(tcg_env, cpu_gpr[arg->s]);
22
23 ctx->base.is_jmp = DISAS_CHAIN;
24
25 return true;
26 }
27 #else
28 static bool trans_RFEBB(DisasContext *ctx, arg_XL_s *arg)
29 {
30 gen_invalid(ctx);
31 return true;
32 }
33 #endif
34
35 static bool trans_B(DisasContext *ctx, arg_I_b *a)
36 {
37 target_ulong target, li;
38
39 /* sign extend LI */
40 li = (a->li ^ 0x02000000) - 0x02000000;
41
42 if (likely(a->aa == 0)) {
43 target = ctx->cia + li;
44 } else {
45 target = li;
46 }
47 if (a->lk) {
48 gen_setlr(ctx, ctx->base.pc_next);
49 gen_update_branch_history(ctx, ctx->cia, NULL, BHRB_TYPE_CALL);
50 } else {
51 gen_update_branch_history(ctx, ctx->cia, NULL, BHRB_TYPE_OTHER);
52 }
53 gen_goto_tb(ctx, 0, target);
54 ctx->base.is_jmp = DISAS_NORETURN;
55
56 return true;
57 }
58
59 #define BCOND_IM 0
60 #define BCOND_LR 1
61 #define BCOND_CTR 2
62 #define BCOND_TAR 3
63
64 static bool bcond_helper(DisasContext *ctx, int type, uint32_t bo, int bi,
65 int bd, int bh, bool aa, bool lk)
66 {
67 TCGLabel *l1;
68 TCGv target;
69 target_long bhrb_type = BHRB_TYPE_OTHER;
70
71 if (type == BCOND_IM && bh != -1) {
72 /* BCOND_IM should never use bh */
73 return false;
74 } else if (type != BCOND_IM && (bd != -1 || aa != 0)) {
75 /* Other BCOND types should never use bd or aa */
76 return false;
77 }
78
79 if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) {
80 target = tcg_temp_new();
81 if (type == BCOND_CTR) {
82 tcg_gen_mov_tl(target, cpu_ctr);
83 } else if (type == BCOND_TAR) {
84 gen_load_spr(target, SPR_TAR);
85 } else {
86 tcg_gen_mov_tl(target, cpu_lr);
87 }
88 if (!lk) {
89 bhrb_type |= BHRB_TYPE_INDIRECT;
90 }
91 bhrb_type |= BHRB_TYPE_XL_FORM;
92 } else {
93 target = NULL;
94 }
95 if (lk) {
96 gen_setlr(ctx, ctx->base.pc_next);
97 bhrb_type |= BHRB_TYPE_CALL;
98 }
99 l1 = gen_new_label();
100 if ((bo & 0x4) == 0) {
101 /* Decrement and test CTR */
102 TCGv temp = tcg_temp_new();
103
104 if (type == BCOND_CTR) {
105 /*
106 * All ISAs up to v3 describe this form of bcctr as invalid but
107 * some processors, ie. 64-bit server processors compliant with
108 * arch 2.x, do implement a "test and decrement" logic instead,
109 * as described in their respective UMs. This logic involves CTR
110 * to act as both the branch target and a counter, which makes
111 * it basically useless and thus never used in real code.
112 *
113 * This form was hence chosen to trigger extra micro-architectural
114 * side-effect on real HW needed for the Spectre v2 workaround.
115 * It is up to guests that implement such workaround, ie. linux, to
116 * use this form in a way it just triggers the side-effect without
117 * doing anything else harmful.
118 */
119 if (unlikely(!is_book3s_arch2x(ctx))) {
120 gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
121 return true;
122 }
123
124 if (NARROW_MODE(ctx)) {
125 tcg_gen_ext32u_tl(temp, cpu_ctr);
126 } else {
127 tcg_gen_mov_tl(temp, cpu_ctr);
128 }
129 if (bo & 0x2) {
130 tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1);
131 } else {
132 tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1);
133 }
134 tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
135 } else {
136 tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
137 if (NARROW_MODE(ctx)) {
138 tcg_gen_ext32u_tl(temp, cpu_ctr);
139 } else {
140 tcg_gen_mov_tl(temp, cpu_ctr);
141 }
142 if (bo & 0x2) {
143 tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1);
144 } else {
145 tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1);
146 }
147 }
148 bhrb_type |= BHRB_TYPE_COND;
149 }
150 if ((bo & 0x10) == 0) {
151 /* Test CR */
152 uint32_t mask = 0x08 >> (bi & 0x03);
153 TCGv_i32 temp = tcg_temp_new_i32();
154
155 if (bo & 0x8) {
156 tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
157 tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l1);
158 } else {
159 tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
160 tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l1);
161 }
162 bhrb_type |= BHRB_TYPE_COND;
163 }
164
165 gen_update_branch_history(ctx, ctx->cia, target, bhrb_type);
166
167 if (type == BCOND_IM) {
168 target_ulong li = (target_long)((int16_t)(bd));
169 if (likely(aa == 0)) {
170 gen_goto_tb(ctx, 0, ctx->cia + li);
171 } else {
172 gen_goto_tb(ctx, 0, li);
173 }
174 } else {
175 if (NARROW_MODE(ctx)) {
176 tcg_gen_andi_tl(cpu_nip, target, (uint32_t)~3);
177 } else {
178 tcg_gen_andi_tl(cpu_nip, target, ~3);
179 }
180 gen_lookup_and_goto_ptr(ctx);
181 }
182 if ((bo & 0x14) != 0x14) {
183 /* fallthrough case */
184 gen_set_label(l1);
185 gen_goto_tb(ctx, 1, ctx->base.pc_next);
186 }
187 ctx->base.is_jmp = DISAS_NORETURN;
188
189 return true;
190 }
191
192 static bool trans_BC(DisasContext *ctx, arg_bcond *a)
193 {
194 /*
195 * bh is not used for bc variants hence we pass -1
196 */
197 return bcond_helper(ctx, BCOND_IM, a->bo, a->bi, a->bd, -1, a->aa, a->lk);
198 }
199
200 /*
201 * This helper is shared by bclr, bcctr and bctar.
202 */
203 static bool bclr_helper(DisasContext *ctx, arg_bclr *a, int type)
204 {
205 /*
206 * bd and aa is not used for bc variants hence we pass -1 and 0 respectively
207 */
208 return bcond_helper(ctx, type, a->bo, a->bi, -1, a->bh, 0, a->lk);
209 }
210
211 TRANS(BCLR, bclr_helper, BCOND_LR)
212 TRANS(BCCTR, bclr_helper, BCOND_CTR)
213 TRANS_FLAGS2(ISA207, BCTAR, bclr_helper, BCOND_TAR)