~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm64/lib/insn.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2013 Huawei Ltd.
  4  * Author: Jiang Liu <liuj97@gmail.com>
  5  *
  6  * Copyright (C) 2014-2016 Zi Shen Lim <zlim.lnx@gmail.com>
  7  */
  8 #include <linux/bitops.h>
  9 #include <linux/bug.h>
 10 #include <linux/printk.h>
 11 #include <linux/sizes.h>
 12 #include <linux/types.h>
 13 
 14 #include <asm/debug-monitors.h>
 15 #include <asm/errno.h>
 16 #include <asm/insn.h>
 17 #include <asm/kprobes.h>
 18 
 19 #define AARCH64_INSN_SF_BIT     BIT(31)
 20 #define AARCH64_INSN_N_BIT      BIT(22)
 21 #define AARCH64_INSN_LSL_12     BIT(22)
 22 
 23 static int __kprobes aarch64_get_imm_shift_mask(enum aarch64_insn_imm_type type,
 24                                                 u32 *maskp, int *shiftp)
 25 {
 26         u32 mask;
 27         int shift;
 28 
 29         switch (type) {
 30         case AARCH64_INSN_IMM_26:
 31                 mask = BIT(26) - 1;
 32                 shift = 0;
 33                 break;
 34         case AARCH64_INSN_IMM_19:
 35                 mask = BIT(19) - 1;
 36                 shift = 5;
 37                 break;
 38         case AARCH64_INSN_IMM_16:
 39                 mask = BIT(16) - 1;
 40                 shift = 5;
 41                 break;
 42         case AARCH64_INSN_IMM_14:
 43                 mask = BIT(14) - 1;
 44                 shift = 5;
 45                 break;
 46         case AARCH64_INSN_IMM_12:
 47                 mask = BIT(12) - 1;
 48                 shift = 10;
 49                 break;
 50         case AARCH64_INSN_IMM_9:
 51                 mask = BIT(9) - 1;
 52                 shift = 12;
 53                 break;
 54         case AARCH64_INSN_IMM_7:
 55                 mask = BIT(7) - 1;
 56                 shift = 15;
 57                 break;
 58         case AARCH64_INSN_IMM_6:
 59         case AARCH64_INSN_IMM_S:
 60                 mask = BIT(6) - 1;
 61                 shift = 10;
 62                 break;
 63         case AARCH64_INSN_IMM_R:
 64                 mask = BIT(6) - 1;
 65                 shift = 16;
 66                 break;
 67         case AARCH64_INSN_IMM_N:
 68                 mask = 1;
 69                 shift = 22;
 70                 break;
 71         default:
 72                 return -EINVAL;
 73         }
 74 
 75         *maskp = mask;
 76         *shiftp = shift;
 77 
 78         return 0;
 79 }
 80 
 81 #define ADR_IMM_HILOSPLIT       2
 82 #define ADR_IMM_SIZE            SZ_2M
 83 #define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
 84 #define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
 85 #define ADR_IMM_LOSHIFT         29
 86 #define ADR_IMM_HISHIFT         5
 87 
 88 u64 aarch64_insn_decode_immediate(enum aarch64_insn_imm_type type, u32 insn)
 89 {
 90         u32 immlo, immhi, mask;
 91         int shift;
 92 
 93         switch (type) {
 94         case AARCH64_INSN_IMM_ADR:
 95                 shift = 0;
 96                 immlo = (insn >> ADR_IMM_LOSHIFT) & ADR_IMM_LOMASK;
 97                 immhi = (insn >> ADR_IMM_HISHIFT) & ADR_IMM_HIMASK;
 98                 insn = (immhi << ADR_IMM_HILOSPLIT) | immlo;
 99                 mask = ADR_IMM_SIZE - 1;
100                 break;
101         default:
102                 if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) {
103                         pr_err("%s: unknown immediate encoding %d\n", __func__,
104                                type);
105                         return 0;
106                 }
107         }
108 
109         return (insn >> shift) & mask;
110 }
111 
112 u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
113                                   u32 insn, u64 imm)
114 {
115         u32 immlo, immhi, mask;
116         int shift;
117 
118         if (insn == AARCH64_BREAK_FAULT)
119                 return AARCH64_BREAK_FAULT;
120 
121         switch (type) {
122         case AARCH64_INSN_IMM_ADR:
123                 shift = 0;
124                 immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
125                 imm >>= ADR_IMM_HILOSPLIT;
126                 immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
127                 imm = immlo | immhi;
128                 mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
129                         (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));
130                 break;
131         default:
132                 if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) {
133                         pr_err("%s: unknown immediate encoding %d\n", __func__,
134                                type);
135                         return AARCH64_BREAK_FAULT;
136                 }
137         }
138 
139         /* Update the immediate field. */
140         insn &= ~(mask << shift);
141         insn |= (imm & mask) << shift;
142 
143         return insn;
144 }
145 
146 u32 aarch64_insn_decode_register(enum aarch64_insn_register_type type,
147                                         u32 insn)
148 {
149         int shift;
150 
151         switch (type) {
152         case AARCH64_INSN_REGTYPE_RT:
153         case AARCH64_INSN_REGTYPE_RD:
154                 shift = 0;
155                 break;
156         case AARCH64_INSN_REGTYPE_RN:
157                 shift = 5;
158                 break;
159         case AARCH64_INSN_REGTYPE_RT2:
160         case AARCH64_INSN_REGTYPE_RA:
161                 shift = 10;
162                 break;
163         case AARCH64_INSN_REGTYPE_RM:
164                 shift = 16;
165                 break;
166         default:
167                 pr_err("%s: unknown register type encoding %d\n", __func__,
168                        type);
169                 return 0;
170         }
171 
172         return (insn >> shift) & GENMASK(4, 0);
173 }
174 
175 static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
176                                         u32 insn,
177                                         enum aarch64_insn_register reg)
178 {
179         int shift;
180 
181         if (insn == AARCH64_BREAK_FAULT)
182                 return AARCH64_BREAK_FAULT;
183 
184         if (reg < AARCH64_INSN_REG_0 || reg > AARCH64_INSN_REG_SP) {
185                 pr_err("%s: unknown register encoding %d\n", __func__, reg);
186                 return AARCH64_BREAK_FAULT;
187         }
188 
189         switch (type) {
190         case AARCH64_INSN_REGTYPE_RT:
191         case AARCH64_INSN_REGTYPE_RD:
192                 shift = 0;
193                 break;
194         case AARCH64_INSN_REGTYPE_RN:
195                 shift = 5;
196                 break;
197         case AARCH64_INSN_REGTYPE_RT2:
198         case AARCH64_INSN_REGTYPE_RA:
199                 shift = 10;
200                 break;
201         case AARCH64_INSN_REGTYPE_RM:
202         case AARCH64_INSN_REGTYPE_RS:
203                 shift = 16;
204                 break;
205         default:
206                 pr_err("%s: unknown register type encoding %d\n", __func__,
207                        type);
208                 return AARCH64_BREAK_FAULT;
209         }
210 
211         insn &= ~(GENMASK(4, 0) << shift);
212         insn |= reg << shift;
213 
214         return insn;
215 }
216 
217 static const u32 aarch64_insn_ldst_size[] = {
218         [AARCH64_INSN_SIZE_8] = 0,
219         [AARCH64_INSN_SIZE_16] = 1,
220         [AARCH64_INSN_SIZE_32] = 2,
221         [AARCH64_INSN_SIZE_64] = 3,
222 };
223 
224 static u32 aarch64_insn_encode_ldst_size(enum aarch64_insn_size_type type,
225                                          u32 insn)
226 {
227         u32 size;
228 
229         if (type < AARCH64_INSN_SIZE_8 || type > AARCH64_INSN_SIZE_64) {
230                 pr_err("%s: unknown size encoding %d\n", __func__, type);
231                 return AARCH64_BREAK_FAULT;
232         }
233 
234         size = aarch64_insn_ldst_size[type];
235         insn &= ~GENMASK(31, 30);
236         insn |= size << 30;
237 
238         return insn;
239 }
240 
241 static inline long label_imm_common(unsigned long pc, unsigned long addr,
242                                      long range)
243 {
244         long offset;
245 
246         if ((pc & 0x3) || (addr & 0x3)) {
247                 pr_err("%s: A64 instructions must be word aligned\n", __func__);
248                 return range;
249         }
250 
251         offset = ((long)addr - (long)pc);
252 
253         if (offset < -range || offset >= range) {
254                 pr_err("%s: offset out of range\n", __func__);
255                 return range;
256         }
257 
258         return offset;
259 }
260 
261 u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
262                                           enum aarch64_insn_branch_type type)
263 {
264         u32 insn;
265         long offset;
266 
267         /*
268          * B/BL support [-128M, 128M) offset
269          * ARM64 virtual address arrangement guarantees all kernel and module
270          * texts are within +/-128M.
271          */
272         offset = label_imm_common(pc, addr, SZ_128M);
273         if (offset >= SZ_128M)
274                 return AARCH64_BREAK_FAULT;
275 
276         switch (type) {
277         case AARCH64_INSN_BRANCH_LINK:
278                 insn = aarch64_insn_get_bl_value();
279                 break;
280         case AARCH64_INSN_BRANCH_NOLINK:
281                 insn = aarch64_insn_get_b_value();
282                 break;
283         default:
284                 pr_err("%s: unknown branch encoding %d\n", __func__, type);
285                 return AARCH64_BREAK_FAULT;
286         }
287 
288         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_26, insn,
289                                              offset >> 2);
290 }
291 
292 u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
293                                      enum aarch64_insn_register reg,
294                                      enum aarch64_insn_variant variant,
295                                      enum aarch64_insn_branch_type type)
296 {
297         u32 insn;
298         long offset;
299 
300         offset = label_imm_common(pc, addr, SZ_1M);
301         if (offset >= SZ_1M)
302                 return AARCH64_BREAK_FAULT;
303 
304         switch (type) {
305         case AARCH64_INSN_BRANCH_COMP_ZERO:
306                 insn = aarch64_insn_get_cbz_value();
307                 break;
308         case AARCH64_INSN_BRANCH_COMP_NONZERO:
309                 insn = aarch64_insn_get_cbnz_value();
310                 break;
311         default:
312                 pr_err("%s: unknown branch encoding %d\n", __func__, type);
313                 return AARCH64_BREAK_FAULT;
314         }
315 
316         switch (variant) {
317         case AARCH64_INSN_VARIANT_32BIT:
318                 break;
319         case AARCH64_INSN_VARIANT_64BIT:
320                 insn |= AARCH64_INSN_SF_BIT;
321                 break;
322         default:
323                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
324                 return AARCH64_BREAK_FAULT;
325         }
326 
327         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, reg);
328 
329         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn,
330                                              offset >> 2);
331 }
332 
333 u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr,
334                                      enum aarch64_insn_condition cond)
335 {
336         u32 insn;
337         long offset;
338 
339         offset = label_imm_common(pc, addr, SZ_1M);
340 
341         insn = aarch64_insn_get_bcond_value();
342 
343         if (cond < AARCH64_INSN_COND_EQ || cond > AARCH64_INSN_COND_AL) {
344                 pr_err("%s: unknown condition encoding %d\n", __func__, cond);
345                 return AARCH64_BREAK_FAULT;
346         }
347         insn |= cond;
348 
349         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn,
350                                              offset >> 2);
351 }
352 
353 u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg,
354                                 enum aarch64_insn_branch_type type)
355 {
356         u32 insn;
357 
358         switch (type) {
359         case AARCH64_INSN_BRANCH_NOLINK:
360                 insn = aarch64_insn_get_br_value();
361                 break;
362         case AARCH64_INSN_BRANCH_LINK:
363                 insn = aarch64_insn_get_blr_value();
364                 break;
365         case AARCH64_INSN_BRANCH_RETURN:
366                 insn = aarch64_insn_get_ret_value();
367                 break;
368         default:
369                 pr_err("%s: unknown branch encoding %d\n", __func__, type);
370                 return AARCH64_BREAK_FAULT;
371         }
372 
373         return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, reg);
374 }
375 
376 u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
377                                     enum aarch64_insn_register base,
378                                     enum aarch64_insn_register offset,
379                                     enum aarch64_insn_size_type size,
380                                     enum aarch64_insn_ldst_type type)
381 {
382         u32 insn;
383 
384         switch (type) {
385         case AARCH64_INSN_LDST_LOAD_REG_OFFSET:
386                 insn = aarch64_insn_get_ldr_reg_value();
387                 break;
388         case AARCH64_INSN_LDST_SIGNED_LOAD_REG_OFFSET:
389                 insn = aarch64_insn_get_signed_ldr_reg_value();
390                 break;
391         case AARCH64_INSN_LDST_STORE_REG_OFFSET:
392                 insn = aarch64_insn_get_str_reg_value();
393                 break;
394         default:
395                 pr_err("%s: unknown load/store encoding %d\n", __func__, type);
396                 return AARCH64_BREAK_FAULT;
397         }
398 
399         insn = aarch64_insn_encode_ldst_size(size, insn);
400 
401         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, reg);
402 
403         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
404                                             base);
405 
406         return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn,
407                                             offset);
408 }
409 
410 u32 aarch64_insn_gen_load_store_imm(enum aarch64_insn_register reg,
411                                     enum aarch64_insn_register base,
412                                     unsigned int imm,
413                                     enum aarch64_insn_size_type size,
414                                     enum aarch64_insn_ldst_type type)
415 {
416         u32 insn;
417         u32 shift;
418 
419         if (size < AARCH64_INSN_SIZE_8 || size > AARCH64_INSN_SIZE_64) {
420                 pr_err("%s: unknown size encoding %d\n", __func__, type);
421                 return AARCH64_BREAK_FAULT;
422         }
423 
424         shift = aarch64_insn_ldst_size[size];
425         if (imm & ~(BIT(12 + shift) - BIT(shift))) {
426                 pr_err("%s: invalid imm: %d\n", __func__, imm);
427                 return AARCH64_BREAK_FAULT;
428         }
429 
430         imm >>= shift;
431 
432         switch (type) {
433         case AARCH64_INSN_LDST_LOAD_IMM_OFFSET:
434                 insn = aarch64_insn_get_ldr_imm_value();
435                 break;
436         case AARCH64_INSN_LDST_SIGNED_LOAD_IMM_OFFSET:
437                 insn = aarch64_insn_get_signed_load_imm_value();
438                 break;
439         case AARCH64_INSN_LDST_STORE_IMM_OFFSET:
440                 insn = aarch64_insn_get_str_imm_value();
441                 break;
442         default:
443                 pr_err("%s: unknown load/store encoding %d\n", __func__, type);
444                 return AARCH64_BREAK_FAULT;
445         }
446 
447         insn = aarch64_insn_encode_ldst_size(size, insn);
448 
449         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, reg);
450 
451         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
452                                             base);
453 
454         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_12, insn, imm);
455 }
456 
457 u32 aarch64_insn_gen_load_literal(unsigned long pc, unsigned long addr,
458                                   enum aarch64_insn_register reg,
459                                   bool is64bit)
460 {
461         u32 insn;
462         long offset;
463 
464         offset = label_imm_common(pc, addr, SZ_1M);
465         if (offset >= SZ_1M)
466                 return AARCH64_BREAK_FAULT;
467 
468         insn = aarch64_insn_get_ldr_lit_value();
469 
470         if (is64bit)
471                 insn |= BIT(30);
472 
473         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, reg);
474 
475         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn,
476                                              offset >> 2);
477 }
478 
479 u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
480                                      enum aarch64_insn_register reg2,
481                                      enum aarch64_insn_register base,
482                                      int offset,
483                                      enum aarch64_insn_variant variant,
484                                      enum aarch64_insn_ldst_type type)
485 {
486         u32 insn;
487         int shift;
488 
489         switch (type) {
490         case AARCH64_INSN_LDST_LOAD_PAIR_PRE_INDEX:
491                 insn = aarch64_insn_get_ldp_pre_value();
492                 break;
493         case AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX:
494                 insn = aarch64_insn_get_stp_pre_value();
495                 break;
496         case AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX:
497                 insn = aarch64_insn_get_ldp_post_value();
498                 break;
499         case AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX:
500                 insn = aarch64_insn_get_stp_post_value();
501                 break;
502         default:
503                 pr_err("%s: unknown load/store encoding %d\n", __func__, type);
504                 return AARCH64_BREAK_FAULT;
505         }
506 
507         switch (variant) {
508         case AARCH64_INSN_VARIANT_32BIT:
509                 if ((offset & 0x3) || (offset < -256) || (offset > 252)) {
510                         pr_err("%s: offset must be multiples of 4 in the range of [-256, 252] %d\n",
511                                __func__, offset);
512                         return AARCH64_BREAK_FAULT;
513                 }
514                 shift = 2;
515                 break;
516         case AARCH64_INSN_VARIANT_64BIT:
517                 if ((offset & 0x7) || (offset < -512) || (offset > 504)) {
518                         pr_err("%s: offset must be multiples of 8 in the range of [-512, 504] %d\n",
519                                __func__, offset);
520                         return AARCH64_BREAK_FAULT;
521                 }
522                 shift = 3;
523                 insn |= AARCH64_INSN_SF_BIT;
524                 break;
525         default:
526                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
527                 return AARCH64_BREAK_FAULT;
528         }
529 
530         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn,
531                                             reg1);
532 
533         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT2, insn,
534                                             reg2);
535 
536         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
537                                             base);
538 
539         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_7, insn,
540                                              offset >> shift);
541 }
542 
543 u32 aarch64_insn_gen_load_store_ex(enum aarch64_insn_register reg,
544                                    enum aarch64_insn_register base,
545                                    enum aarch64_insn_register state,
546                                    enum aarch64_insn_size_type size,
547                                    enum aarch64_insn_ldst_type type)
548 {
549         u32 insn;
550 
551         switch (type) {
552         case AARCH64_INSN_LDST_LOAD_EX:
553         case AARCH64_INSN_LDST_LOAD_ACQ_EX:
554                 insn = aarch64_insn_get_load_ex_value();
555                 if (type == AARCH64_INSN_LDST_LOAD_ACQ_EX)
556                         insn |= BIT(15);
557                 break;
558         case AARCH64_INSN_LDST_STORE_EX:
559         case AARCH64_INSN_LDST_STORE_REL_EX:
560                 insn = aarch64_insn_get_store_ex_value();
561                 if (type == AARCH64_INSN_LDST_STORE_REL_EX)
562                         insn |= BIT(15);
563                 break;
564         default:
565                 pr_err("%s: unknown load/store exclusive encoding %d\n", __func__, type);
566                 return AARCH64_BREAK_FAULT;
567         }
568 
569         insn = aarch64_insn_encode_ldst_size(size, insn);
570 
571         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn,
572                                             reg);
573 
574         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
575                                             base);
576 
577         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT2, insn,
578                                             AARCH64_INSN_REG_ZR);
579 
580         return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RS, insn,
581                                             state);
582 }
583 
584 #ifdef CONFIG_ARM64_LSE_ATOMICS
585 static u32 aarch64_insn_encode_ldst_order(enum aarch64_insn_mem_order_type type,
586                                           u32 insn)
587 {
588         u32 order;
589 
590         switch (type) {
591         case AARCH64_INSN_MEM_ORDER_NONE:
592                 order = 0;
593                 break;
594         case AARCH64_INSN_MEM_ORDER_ACQ:
595                 order = 2;
596                 break;
597         case AARCH64_INSN_MEM_ORDER_REL:
598                 order = 1;
599                 break;
600         case AARCH64_INSN_MEM_ORDER_ACQREL:
601                 order = 3;
602                 break;
603         default:
604                 pr_err("%s: unknown mem order %d\n", __func__, type);
605                 return AARCH64_BREAK_FAULT;
606         }
607 
608         insn &= ~GENMASK(23, 22);
609         insn |= order << 22;
610 
611         return insn;
612 }
613 
614 u32 aarch64_insn_gen_atomic_ld_op(enum aarch64_insn_register result,
615                                   enum aarch64_insn_register address,
616                                   enum aarch64_insn_register value,
617                                   enum aarch64_insn_size_type size,
618                                   enum aarch64_insn_mem_atomic_op op,
619                                   enum aarch64_insn_mem_order_type order)
620 {
621         u32 insn;
622 
623         switch (op) {
624         case AARCH64_INSN_MEM_ATOMIC_ADD:
625                 insn = aarch64_insn_get_ldadd_value();
626                 break;
627         case AARCH64_INSN_MEM_ATOMIC_CLR:
628                 insn = aarch64_insn_get_ldclr_value();
629                 break;
630         case AARCH64_INSN_MEM_ATOMIC_EOR:
631                 insn = aarch64_insn_get_ldeor_value();
632                 break;
633         case AARCH64_INSN_MEM_ATOMIC_SET:
634                 insn = aarch64_insn_get_ldset_value();
635                 break;
636         case AARCH64_INSN_MEM_ATOMIC_SWP:
637                 insn = aarch64_insn_get_swp_value();
638                 break;
639         default:
640                 pr_err("%s: unimplemented mem atomic op %d\n", __func__, op);
641                 return AARCH64_BREAK_FAULT;
642         }
643 
644         switch (size) {
645         case AARCH64_INSN_SIZE_32:
646         case AARCH64_INSN_SIZE_64:
647                 break;
648         default:
649                 pr_err("%s: unimplemented size encoding %d\n", __func__, size);
650                 return AARCH64_BREAK_FAULT;
651         }
652 
653         insn = aarch64_insn_encode_ldst_size(size, insn);
654 
655         insn = aarch64_insn_encode_ldst_order(order, insn);
656 
657         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn,
658                                             result);
659 
660         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
661                                             address);
662 
663         return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RS, insn,
664                                             value);
665 }
666 
667 static u32 aarch64_insn_encode_cas_order(enum aarch64_insn_mem_order_type type,
668                                          u32 insn)
669 {
670         u32 order;
671 
672         switch (type) {
673         case AARCH64_INSN_MEM_ORDER_NONE:
674                 order = 0;
675                 break;
676         case AARCH64_INSN_MEM_ORDER_ACQ:
677                 order = BIT(22);
678                 break;
679         case AARCH64_INSN_MEM_ORDER_REL:
680                 order = BIT(15);
681                 break;
682         case AARCH64_INSN_MEM_ORDER_ACQREL:
683                 order = BIT(15) | BIT(22);
684                 break;
685         default:
686                 pr_err("%s: unknown mem order %d\n", __func__, type);
687                 return AARCH64_BREAK_FAULT;
688         }
689 
690         insn &= ~(BIT(15) | BIT(22));
691         insn |= order;
692 
693         return insn;
694 }
695 
696 u32 aarch64_insn_gen_cas(enum aarch64_insn_register result,
697                          enum aarch64_insn_register address,
698                          enum aarch64_insn_register value,
699                          enum aarch64_insn_size_type size,
700                          enum aarch64_insn_mem_order_type order)
701 {
702         u32 insn;
703 
704         switch (size) {
705         case AARCH64_INSN_SIZE_32:
706         case AARCH64_INSN_SIZE_64:
707                 break;
708         default:
709                 pr_err("%s: unimplemented size encoding %d\n", __func__, size);
710                 return AARCH64_BREAK_FAULT;
711         }
712 
713         insn = aarch64_insn_get_cas_value();
714 
715         insn = aarch64_insn_encode_ldst_size(size, insn);
716 
717         insn = aarch64_insn_encode_cas_order(order, insn);
718 
719         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn,
720                                             result);
721 
722         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
723                                             address);
724 
725         return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RS, insn,
726                                             value);
727 }
728 #endif
729 
730 u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
731                                  enum aarch64_insn_register src,
732                                  int imm, enum aarch64_insn_variant variant,
733                                  enum aarch64_insn_adsb_type type)
734 {
735         u32 insn;
736 
737         switch (type) {
738         case AARCH64_INSN_ADSB_ADD:
739                 insn = aarch64_insn_get_add_imm_value();
740                 break;
741         case AARCH64_INSN_ADSB_SUB:
742                 insn = aarch64_insn_get_sub_imm_value();
743                 break;
744         case AARCH64_INSN_ADSB_ADD_SETFLAGS:
745                 insn = aarch64_insn_get_adds_imm_value();
746                 break;
747         case AARCH64_INSN_ADSB_SUB_SETFLAGS:
748                 insn = aarch64_insn_get_subs_imm_value();
749                 break;
750         default:
751                 pr_err("%s: unknown add/sub encoding %d\n", __func__, type);
752                 return AARCH64_BREAK_FAULT;
753         }
754 
755         switch (variant) {
756         case AARCH64_INSN_VARIANT_32BIT:
757                 break;
758         case AARCH64_INSN_VARIANT_64BIT:
759                 insn |= AARCH64_INSN_SF_BIT;
760                 break;
761         default:
762                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
763                 return AARCH64_BREAK_FAULT;
764         }
765 
766         /* We can't encode more than a 24bit value (12bit + 12bit shift) */
767         if (imm & ~(BIT(24) - 1))
768                 goto out;
769 
770         /* If we have something in the top 12 bits... */
771         if (imm & ~(SZ_4K - 1)) {
772                 /* ... and in the low 12 bits -> error */
773                 if (imm & (SZ_4K - 1))
774                         goto out;
775 
776                 imm >>= 12;
777                 insn |= AARCH64_INSN_LSL_12;
778         }
779 
780         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
781 
782         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src);
783 
784         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_12, insn, imm);
785 
786 out:
787         pr_err("%s: invalid immediate encoding %d\n", __func__, imm);
788         return AARCH64_BREAK_FAULT;
789 }
790 
791 u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst,
792                               enum aarch64_insn_register src,
793                               int immr, int imms,
794                               enum aarch64_insn_variant variant,
795                               enum aarch64_insn_bitfield_type type)
796 {
797         u32 insn;
798         u32 mask;
799 
800         switch (type) {
801         case AARCH64_INSN_BITFIELD_MOVE:
802                 insn = aarch64_insn_get_bfm_value();
803                 break;
804         case AARCH64_INSN_BITFIELD_MOVE_UNSIGNED:
805                 insn = aarch64_insn_get_ubfm_value();
806                 break;
807         case AARCH64_INSN_BITFIELD_MOVE_SIGNED:
808                 insn = aarch64_insn_get_sbfm_value();
809                 break;
810         default:
811                 pr_err("%s: unknown bitfield encoding %d\n", __func__, type);
812                 return AARCH64_BREAK_FAULT;
813         }
814 
815         switch (variant) {
816         case AARCH64_INSN_VARIANT_32BIT:
817                 mask = GENMASK(4, 0);
818                 break;
819         case AARCH64_INSN_VARIANT_64BIT:
820                 insn |= AARCH64_INSN_SF_BIT | AARCH64_INSN_N_BIT;
821                 mask = GENMASK(5, 0);
822                 break;
823         default:
824                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
825                 return AARCH64_BREAK_FAULT;
826         }
827 
828         if (immr & ~mask) {
829                 pr_err("%s: invalid immr encoding %d\n", __func__, immr);
830                 return AARCH64_BREAK_FAULT;
831         }
832         if (imms & ~mask) {
833                 pr_err("%s: invalid imms encoding %d\n", __func__, imms);
834                 return AARCH64_BREAK_FAULT;
835         }
836 
837         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
838 
839         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src);
840 
841         insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_R, insn, immr);
842 
843         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_S, insn, imms);
844 }
845 
846 u32 aarch64_insn_gen_movewide(enum aarch64_insn_register dst,
847                               int imm, int shift,
848                               enum aarch64_insn_variant variant,
849                               enum aarch64_insn_movewide_type type)
850 {
851         u32 insn;
852 
853         switch (type) {
854         case AARCH64_INSN_MOVEWIDE_ZERO:
855                 insn = aarch64_insn_get_movz_value();
856                 break;
857         case AARCH64_INSN_MOVEWIDE_KEEP:
858                 insn = aarch64_insn_get_movk_value();
859                 break;
860         case AARCH64_INSN_MOVEWIDE_INVERSE:
861                 insn = aarch64_insn_get_movn_value();
862                 break;
863         default:
864                 pr_err("%s: unknown movewide encoding %d\n", __func__, type);
865                 return AARCH64_BREAK_FAULT;
866         }
867 
868         if (imm & ~(SZ_64K - 1)) {
869                 pr_err("%s: invalid immediate encoding %d\n", __func__, imm);
870                 return AARCH64_BREAK_FAULT;
871         }
872 
873         switch (variant) {
874         case AARCH64_INSN_VARIANT_32BIT:
875                 if (shift != 0 && shift != 16) {
876                         pr_err("%s: invalid shift encoding %d\n", __func__,
877                                shift);
878                         return AARCH64_BREAK_FAULT;
879                 }
880                 break;
881         case AARCH64_INSN_VARIANT_64BIT:
882                 insn |= AARCH64_INSN_SF_BIT;
883                 if (shift != 0 && shift != 16 && shift != 32 && shift != 48) {
884                         pr_err("%s: invalid shift encoding %d\n", __func__,
885                                shift);
886                         return AARCH64_BREAK_FAULT;
887                 }
888                 break;
889         default:
890                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
891                 return AARCH64_BREAK_FAULT;
892         }
893 
894         insn |= (shift >> 4) << 21;
895 
896         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
897 
898         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm);
899 }
900 
901 u32 aarch64_insn_gen_add_sub_shifted_reg(enum aarch64_insn_register dst,
902                                          enum aarch64_insn_register src,
903                                          enum aarch64_insn_register reg,
904                                          int shift,
905                                          enum aarch64_insn_variant variant,
906                                          enum aarch64_insn_adsb_type type)
907 {
908         u32 insn;
909 
910         switch (type) {
911         case AARCH64_INSN_ADSB_ADD:
912                 insn = aarch64_insn_get_add_value();
913                 break;
914         case AARCH64_INSN_ADSB_SUB:
915                 insn = aarch64_insn_get_sub_value();
916                 break;
917         case AARCH64_INSN_ADSB_ADD_SETFLAGS:
918                 insn = aarch64_insn_get_adds_value();
919                 break;
920         case AARCH64_INSN_ADSB_SUB_SETFLAGS:
921                 insn = aarch64_insn_get_subs_value();
922                 break;
923         default:
924                 pr_err("%s: unknown add/sub encoding %d\n", __func__, type);
925                 return AARCH64_BREAK_FAULT;
926         }
927 
928         switch (variant) {
929         case AARCH64_INSN_VARIANT_32BIT:
930                 if (shift & ~(SZ_32 - 1)) {
931                         pr_err("%s: invalid shift encoding %d\n", __func__,
932                                shift);
933                         return AARCH64_BREAK_FAULT;
934                 }
935                 break;
936         case AARCH64_INSN_VARIANT_64BIT:
937                 insn |= AARCH64_INSN_SF_BIT;
938                 if (shift & ~(SZ_64 - 1)) {
939                         pr_err("%s: invalid shift encoding %d\n", __func__,
940                                shift);
941                         return AARCH64_BREAK_FAULT;
942                 }
943                 break;
944         default:
945                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
946                 return AARCH64_BREAK_FAULT;
947         }
948 
949 
950         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
951 
952         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src);
953 
954         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, reg);
955 
956         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_6, insn, shift);
957 }
958 
959 u32 aarch64_insn_gen_data1(enum aarch64_insn_register dst,
960                            enum aarch64_insn_register src,
961                            enum aarch64_insn_variant variant,
962                            enum aarch64_insn_data1_type type)
963 {
964         u32 insn;
965 
966         switch (type) {
967         case AARCH64_INSN_DATA1_REVERSE_16:
968                 insn = aarch64_insn_get_rev16_value();
969                 break;
970         case AARCH64_INSN_DATA1_REVERSE_32:
971                 insn = aarch64_insn_get_rev32_value();
972                 break;
973         case AARCH64_INSN_DATA1_REVERSE_64:
974                 if (variant != AARCH64_INSN_VARIANT_64BIT) {
975                         pr_err("%s: invalid variant for reverse64 %d\n",
976                                __func__, variant);
977                         return AARCH64_BREAK_FAULT;
978                 }
979                 insn = aarch64_insn_get_rev64_value();
980                 break;
981         default:
982                 pr_err("%s: unknown data1 encoding %d\n", __func__, type);
983                 return AARCH64_BREAK_FAULT;
984         }
985 
986         switch (variant) {
987         case AARCH64_INSN_VARIANT_32BIT:
988                 break;
989         case AARCH64_INSN_VARIANT_64BIT:
990                 insn |= AARCH64_INSN_SF_BIT;
991                 break;
992         default:
993                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
994                 return AARCH64_BREAK_FAULT;
995         }
996 
997         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
998 
999         return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src);
1000 }
1001 
1002 u32 aarch64_insn_gen_data2(enum aarch64_insn_register dst,
1003                            enum aarch64_insn_register src,
1004                            enum aarch64_insn_register reg,
1005                            enum aarch64_insn_variant variant,
1006                            enum aarch64_insn_data2_type type)
1007 {
1008         u32 insn;
1009 
1010         switch (type) {
1011         case AARCH64_INSN_DATA2_UDIV:
1012                 insn = aarch64_insn_get_udiv_value();
1013                 break;
1014         case AARCH64_INSN_DATA2_SDIV:
1015                 insn = aarch64_insn_get_sdiv_value();
1016                 break;
1017         case AARCH64_INSN_DATA2_LSLV:
1018                 insn = aarch64_insn_get_lslv_value();
1019                 break;
1020         case AARCH64_INSN_DATA2_LSRV:
1021                 insn = aarch64_insn_get_lsrv_value();
1022                 break;
1023         case AARCH64_INSN_DATA2_ASRV:
1024                 insn = aarch64_insn_get_asrv_value();
1025                 break;
1026         case AARCH64_INSN_DATA2_RORV:
1027                 insn = aarch64_insn_get_rorv_value();
1028                 break;
1029         default:
1030                 pr_err("%s: unknown data2 encoding %d\n", __func__, type);
1031                 return AARCH64_BREAK_FAULT;
1032         }
1033 
1034         switch (variant) {
1035         case AARCH64_INSN_VARIANT_32BIT:
1036                 break;
1037         case AARCH64_INSN_VARIANT_64BIT:
1038                 insn |= AARCH64_INSN_SF_BIT;
1039                 break;
1040         default:
1041                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
1042                 return AARCH64_BREAK_FAULT;
1043         }
1044 
1045         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
1046 
1047         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src);
1048 
1049         return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, reg);
1050 }
1051 
1052 u32 aarch64_insn_gen_data3(enum aarch64_insn_register dst,
1053                            enum aarch64_insn_register src,
1054                            enum aarch64_insn_register reg1,
1055                            enum aarch64_insn_register reg2,
1056                            enum aarch64_insn_variant variant,
1057                            enum aarch64_insn_data3_type type)
1058 {
1059         u32 insn;
1060 
1061         switch (type) {
1062         case AARCH64_INSN_DATA3_MADD:
1063                 insn = aarch64_insn_get_madd_value();
1064                 break;
1065         case AARCH64_INSN_DATA3_MSUB:
1066                 insn = aarch64_insn_get_msub_value();
1067                 break;
1068         default:
1069                 pr_err("%s: unknown data3 encoding %d\n", __func__, type);
1070                 return AARCH64_BREAK_FAULT;
1071         }
1072 
1073         switch (variant) {
1074         case AARCH64_INSN_VARIANT_32BIT:
1075                 break;
1076         case AARCH64_INSN_VARIANT_64BIT:
1077                 insn |= AARCH64_INSN_SF_BIT;
1078                 break;
1079         default:
1080                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
1081                 return AARCH64_BREAK_FAULT;
1082         }
1083 
1084         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
1085 
1086         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RA, insn, src);
1087 
1088         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
1089                                             reg1);
1090 
1091         return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn,
1092                                             reg2);
1093 }
1094 
1095 u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst,
1096                                          enum aarch64_insn_register src,
1097                                          enum aarch64_insn_register reg,
1098                                          int shift,
1099                                          enum aarch64_insn_variant variant,
1100                                          enum aarch64_insn_logic_type type)
1101 {
1102         u32 insn;
1103 
1104         switch (type) {
1105         case AARCH64_INSN_LOGIC_AND:
1106                 insn = aarch64_insn_get_and_value();
1107                 break;
1108         case AARCH64_INSN_LOGIC_BIC:
1109                 insn = aarch64_insn_get_bic_value();
1110                 break;
1111         case AARCH64_INSN_LOGIC_ORR:
1112                 insn = aarch64_insn_get_orr_value();
1113                 break;
1114         case AARCH64_INSN_LOGIC_ORN:
1115                 insn = aarch64_insn_get_orn_value();
1116                 break;
1117         case AARCH64_INSN_LOGIC_EOR:
1118                 insn = aarch64_insn_get_eor_value();
1119                 break;
1120         case AARCH64_INSN_LOGIC_EON:
1121                 insn = aarch64_insn_get_eon_value();
1122                 break;
1123         case AARCH64_INSN_LOGIC_AND_SETFLAGS:
1124                 insn = aarch64_insn_get_ands_value();
1125                 break;
1126         case AARCH64_INSN_LOGIC_BIC_SETFLAGS:
1127                 insn = aarch64_insn_get_bics_value();
1128                 break;
1129         default:
1130                 pr_err("%s: unknown logical encoding %d\n", __func__, type);
1131                 return AARCH64_BREAK_FAULT;
1132         }
1133 
1134         switch (variant) {
1135         case AARCH64_INSN_VARIANT_32BIT:
1136                 if (shift & ~(SZ_32 - 1)) {
1137                         pr_err("%s: invalid shift encoding %d\n", __func__,
1138                                shift);
1139                         return AARCH64_BREAK_FAULT;
1140                 }
1141                 break;
1142         case AARCH64_INSN_VARIANT_64BIT:
1143                 insn |= AARCH64_INSN_SF_BIT;
1144                 if (shift & ~(SZ_64 - 1)) {
1145                         pr_err("%s: invalid shift encoding %d\n", __func__,
1146                                shift);
1147                         return AARCH64_BREAK_FAULT;
1148                 }
1149                 break;
1150         default:
1151                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
1152                 return AARCH64_BREAK_FAULT;
1153         }
1154 
1155 
1156         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
1157 
1158         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src);
1159 
1160         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, reg);
1161 
1162         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_6, insn, shift);
1163 }
1164 
1165 /*
1166  * MOV (register) is architecturally an alias of ORR (shifted register) where
1167  * MOV <*d>, <*m> is equivalent to ORR <*d>, <*ZR>, <*m>
1168  */
1169 u32 aarch64_insn_gen_move_reg(enum aarch64_insn_register dst,
1170                               enum aarch64_insn_register src,
1171                               enum aarch64_insn_variant variant)
1172 {
1173         return aarch64_insn_gen_logical_shifted_reg(dst, AARCH64_INSN_REG_ZR,
1174                                                     src, 0, variant,
1175                                                     AARCH64_INSN_LOGIC_ORR);
1176 }
1177 
1178 u32 aarch64_insn_gen_adr(unsigned long pc, unsigned long addr,
1179                          enum aarch64_insn_register reg,
1180                          enum aarch64_insn_adr_type type)
1181 {
1182         u32 insn;
1183         s32 offset;
1184 
1185         switch (type) {
1186         case AARCH64_INSN_ADR_TYPE_ADR:
1187                 insn = aarch64_insn_get_adr_value();
1188                 offset = addr - pc;
1189                 break;
1190         case AARCH64_INSN_ADR_TYPE_ADRP:
1191                 insn = aarch64_insn_get_adrp_value();
1192                 offset = (addr - ALIGN_DOWN(pc, SZ_4K)) >> 12;
1193                 break;
1194         default:
1195                 pr_err("%s: unknown adr encoding %d\n", __func__, type);
1196                 return AARCH64_BREAK_FAULT;
1197         }
1198 
1199         if (offset < -SZ_1M || offset >= SZ_1M)
1200                 return AARCH64_BREAK_FAULT;
1201 
1202         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, reg);
1203 
1204         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_ADR, insn, offset);
1205 }
1206 
1207 /*
1208  * Decode the imm field of a branch, and return the byte offset as a
1209  * signed value (so it can be used when computing a new branch
1210  * target).
1211  */
1212 s32 aarch64_get_branch_offset(u32 insn)
1213 {
1214         s32 imm;
1215 
1216         if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn)) {
1217                 imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_26, insn);
1218                 return (imm << 6) >> 4;
1219         }
1220 
1221         if (aarch64_insn_is_cbz(insn) || aarch64_insn_is_cbnz(insn) ||
1222             aarch64_insn_is_bcond(insn)) {
1223                 imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_19, insn);
1224                 return (imm << 13) >> 11;
1225         }
1226 
1227         if (aarch64_insn_is_tbz(insn) || aarch64_insn_is_tbnz(insn)) {
1228                 imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_14, insn);
1229                 return (imm << 18) >> 16;
1230         }
1231 
1232         /* Unhandled instruction */
1233         BUG();
1234 }
1235 
1236 /*
1237  * Encode the displacement of a branch in the imm field and return the
1238  * updated instruction.
1239  */
1240 u32 aarch64_set_branch_offset(u32 insn, s32 offset)
1241 {
1242         if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn))
1243                 return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_26, insn,
1244                                                      offset >> 2);
1245 
1246         if (aarch64_insn_is_cbz(insn) || aarch64_insn_is_cbnz(insn) ||
1247             aarch64_insn_is_bcond(insn))
1248                 return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn,
1249                                                      offset >> 2);
1250 
1251         if (aarch64_insn_is_tbz(insn) || aarch64_insn_is_tbnz(insn))
1252                 return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_14, insn,
1253                                                      offset >> 2);
1254 
1255         /* Unhandled instruction */
1256         BUG();
1257 }
1258 
1259 s32 aarch64_insn_adrp_get_offset(u32 insn)
1260 {
1261         BUG_ON(!aarch64_insn_is_adrp(insn));
1262         return aarch64_insn_decode_immediate(AARCH64_INSN_IMM_ADR, insn) << 12;
1263 }
1264 
1265 u32 aarch64_insn_adrp_set_offset(u32 insn, s32 offset)
1266 {
1267         BUG_ON(!aarch64_insn_is_adrp(insn));
1268         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_ADR, insn,
1269                                                 offset >> 12);
1270 }
1271 
1272 /*
1273  * Extract the Op/CR data from a msr/mrs instruction.
1274  */
1275 u32 aarch64_insn_extract_system_reg(u32 insn)
1276 {
1277         return (insn & 0x1FFFE0) >> 5;
1278 }
1279 
1280 bool aarch32_insn_is_wide(u32 insn)
1281 {
1282         return insn >= 0xe800;
1283 }
1284 
1285 /*
1286  * Macros/defines for extracting register numbers from instruction.
1287  */
1288 u32 aarch32_insn_extract_reg_num(u32 insn, int offset)
1289 {
1290         return (insn & (0xf << offset)) >> offset;
1291 }
1292 
1293 #define OPC2_MASK       0x7
1294 #define OPC2_OFFSET     5
1295 u32 aarch32_insn_mcr_extract_opc2(u32 insn)
1296 {
1297         return (insn & (OPC2_MASK << OPC2_OFFSET)) >> OPC2_OFFSET;
1298 }
1299 
1300 #define CRM_MASK        0xf
1301 u32 aarch32_insn_mcr_extract_crm(u32 insn)
1302 {
1303         return insn & CRM_MASK;
1304 }
1305 
1306 static bool range_of_ones(u64 val)
1307 {
1308         /* Doesn't handle full ones or full zeroes */
1309         u64 sval = val >> __ffs64(val);
1310 
1311         /* One of Sean Eron Anderson's bithack tricks */
1312         return ((sval + 1) & (sval)) == 0;
1313 }
1314 
1315 static u32 aarch64_encode_immediate(u64 imm,
1316                                     enum aarch64_insn_variant variant,
1317                                     u32 insn)
1318 {
1319         unsigned int immr, imms, n, ones, ror, esz, tmp;
1320         u64 mask;
1321 
1322         switch (variant) {
1323         case AARCH64_INSN_VARIANT_32BIT:
1324                 esz = 32;
1325                 break;
1326         case AARCH64_INSN_VARIANT_64BIT:
1327                 insn |= AARCH64_INSN_SF_BIT;
1328                 esz = 64;
1329                 break;
1330         default:
1331                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
1332                 return AARCH64_BREAK_FAULT;
1333         }
1334 
1335         mask = GENMASK(esz - 1, 0);
1336 
1337         /* Can't encode full zeroes, full ones, or value wider than the mask */
1338         if (!imm || imm == mask || imm & ~mask)
1339                 return AARCH64_BREAK_FAULT;
1340 
1341         /*
1342          * Inverse of Replicate(). Try to spot a repeating pattern
1343          * with a pow2 stride.
1344          */
1345         for (tmp = esz / 2; tmp >= 2; tmp /= 2) {
1346                 u64 emask = BIT(tmp) - 1;
1347 
1348                 if ((imm & emask) != ((imm >> tmp) & emask))
1349                         break;
1350 
1351                 esz = tmp;
1352                 mask = emask;
1353         }
1354 
1355         /* N is only set if we're encoding a 64bit value */
1356         n = esz == 64;
1357 
1358         /* Trim imm to the element size */
1359         imm &= mask;
1360 
1361         /* That's how many ones we need to encode */
1362         ones = hweight64(imm);
1363 
1364         /*
1365          * imms is set to (ones - 1), prefixed with a string of ones
1366          * and a zero if they fit. Cap it to 6 bits.
1367          */
1368         imms  = ones - 1;
1369         imms |= 0xf << ffs(esz);
1370         imms &= BIT(6) - 1;
1371 
1372         /* Compute the rotation */
1373         if (range_of_ones(imm)) {
1374                 /*
1375                  * Pattern: 0..01..10..0
1376                  *
1377                  * Compute how many rotate we need to align it right
1378                  */
1379                 ror = __ffs64(imm);
1380         } else {
1381                 /*
1382                  * Pattern: 0..01..10..01..1
1383                  *
1384                  * Fill the unused top bits with ones, and check if
1385                  * the result is a valid immediate (all ones with a
1386                  * contiguous ranges of zeroes).
1387                  */
1388                 imm |= ~mask;
1389                 if (!range_of_ones(~imm))
1390                         return AARCH64_BREAK_FAULT;
1391 
1392                 /*
1393                  * Compute the rotation to get a continuous set of
1394                  * ones, with the first bit set at position 0
1395                  */
1396                 ror = fls64(~imm);
1397         }
1398 
1399         /*
1400          * immr is the number of bits we need to rotate back to the
1401          * original set of ones. Note that this is relative to the
1402          * element size...
1403          */
1404         immr = (esz - ror) % esz;
1405 
1406         insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_N, insn, n);
1407         insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_R, insn, immr);
1408         return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_S, insn, imms);
1409 }
1410 
1411 u32 aarch64_insn_gen_logical_immediate(enum aarch64_insn_logic_type type,
1412                                        enum aarch64_insn_variant variant,
1413                                        enum aarch64_insn_register Rn,
1414                                        enum aarch64_insn_register Rd,
1415                                        u64 imm)
1416 {
1417         u32 insn;
1418 
1419         switch (type) {
1420         case AARCH64_INSN_LOGIC_AND:
1421                 insn = aarch64_insn_get_and_imm_value();
1422                 break;
1423         case AARCH64_INSN_LOGIC_ORR:
1424                 insn = aarch64_insn_get_orr_imm_value();
1425                 break;
1426         case AARCH64_INSN_LOGIC_EOR:
1427                 insn = aarch64_insn_get_eor_imm_value();
1428                 break;
1429         case AARCH64_INSN_LOGIC_AND_SETFLAGS:
1430                 insn = aarch64_insn_get_ands_imm_value();
1431                 break;
1432         default:
1433                 pr_err("%s: unknown logical encoding %d\n", __func__, type);
1434                 return AARCH64_BREAK_FAULT;
1435         }
1436 
1437         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, Rd);
1438         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, Rn);
1439         return aarch64_encode_immediate(imm, variant, insn);
1440 }
1441 
1442 u32 aarch64_insn_gen_extr(enum aarch64_insn_variant variant,
1443                           enum aarch64_insn_register Rm,
1444                           enum aarch64_insn_register Rn,
1445                           enum aarch64_insn_register Rd,
1446                           u8 lsb)
1447 {
1448         u32 insn;
1449 
1450         insn = aarch64_insn_get_extr_value();
1451 
1452         switch (variant) {
1453         case AARCH64_INSN_VARIANT_32BIT:
1454                 if (lsb > 31)
1455                         return AARCH64_BREAK_FAULT;
1456                 break;
1457         case AARCH64_INSN_VARIANT_64BIT:
1458                 if (lsb > 63)
1459                         return AARCH64_BREAK_FAULT;
1460                 insn |= AARCH64_INSN_SF_BIT;
1461                 insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_N, insn, 1);
1462                 break;
1463         default:
1464                 pr_err("%s: unknown variant encoding %d\n", __func__, variant);
1465                 return AARCH64_BREAK_FAULT;
1466         }
1467 
1468         insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_S, insn, lsb);
1469         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, Rd);
1470         insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, Rn);
1471         return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, Rm);
1472 }
1473 
1474 u32 aarch64_insn_gen_dmb(enum aarch64_insn_mb_type type)
1475 {
1476         u32 opt;
1477         u32 insn;
1478 
1479         switch (type) {
1480         case AARCH64_INSN_MB_SY:
1481                 opt = 0xf;
1482                 break;
1483         case AARCH64_INSN_MB_ST:
1484                 opt = 0xe;
1485                 break;
1486         case AARCH64_INSN_MB_LD:
1487                 opt = 0xd;
1488                 break;
1489         case AARCH64_INSN_MB_ISH:
1490                 opt = 0xb;
1491                 break;
1492         case AARCH64_INSN_MB_ISHST:
1493                 opt = 0xa;
1494                 break;
1495         case AARCH64_INSN_MB_ISHLD:
1496                 opt = 0x9;
1497                 break;
1498         case AARCH64_INSN_MB_NSH:
1499                 opt = 0x7;
1500                 break;
1501         case AARCH64_INSN_MB_NSHST:
1502                 opt = 0x6;
1503                 break;
1504         case AARCH64_INSN_MB_NSHLD:
1505                 opt = 0x5;
1506                 break;
1507         default:
1508                 pr_err("%s: unknown dmb type %d\n", __func__, type);
1509                 return AARCH64_BREAK_FAULT;
1510         }
1511 
1512         insn = aarch64_insn_get_dmb_value();
1513         insn &= ~GENMASK(11, 8);
1514         insn |= (opt << 8);
1515 
1516         return insn;
1517 }
1518 
1519 u32 aarch64_insn_gen_mrs(enum aarch64_insn_register result,
1520                          enum aarch64_insn_system_register sysreg)
1521 {
1522         u32 insn = aarch64_insn_get_mrs_value();
1523 
1524         insn &= ~GENMASK(19, 0);
1525         insn |= sysreg << 5;
1526         return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT,
1527                                             insn, result);
1528 }
1529 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php