uasm.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * A small micro-assembler. It is intentionally kept simple, does only
  7. * support a subset of instructions, and does not try to hide pipeline
  8. * effects like branch delay slots.
  9. *
  10. * Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer
  11. * Copyright (C) 2005, 2007 Maciej W. Rozycki
  12. * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
  13. * Copyright (C) 2012, 2013 MIPS Technologies, Inc. All rights reserved.
  14. */
  15. enum fields {
  16. RS = 0x001,
  17. RT = 0x002,
  18. RD = 0x004,
  19. RE = 0x008,
  20. SIMM = 0x010,
  21. UIMM = 0x020,
  22. BIMM = 0x040,
  23. JIMM = 0x080,
  24. FUNC = 0x100,
  25. SET = 0x200,
  26. SCIMM = 0x400
  27. };
  28. #define OP_MASK 0x3f
  29. #define OP_SH 26
  30. #define RD_MASK 0x1f
  31. #define RD_SH 11
  32. #define RE_MASK 0x1f
  33. #define RE_SH 6
  34. #define IMM_MASK 0xffff
  35. #define IMM_SH 0
  36. #define JIMM_MASK 0x3ffffff
  37. #define JIMM_SH 0
  38. #define FUNC_MASK 0x3f
  39. #define FUNC_SH 0
  40. #define SET_MASK 0x7
  41. #define SET_SH 0
  42. enum opcode {
  43. insn_invalid,
  44. insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1,
  45. insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
  46. insn_bne, insn_cache, insn_daddiu, insn_daddu, insn_dins, insn_dinsm,
  47. insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll,
  48. insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret,
  49. insn_ext, insn_ins, insn_j, insn_jal, insn_jr, insn_ld, insn_ldx,
  50. insn_ll, insn_lld, insn_lui, insn_lw, insn_lwx, insn_mfc0, insn_mtc0,
  51. insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sc, insn_scd,
  52. insn_sd, insn_sll, insn_sra, insn_srl, insn_subu, insn_sw,
  53. insn_syscall, insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor,
  54. insn_xori,
  55. };
  56. struct insn {
  57. enum opcode opcode;
  58. u32 match;
  59. enum fields fields;
  60. };
  61. static inline __uasminit u32 build_rs(u32 arg)
  62. {
  63. WARN(arg & ~RS_MASK, KERN_WARNING "Micro-assembler field overflow\n");
  64. return (arg & RS_MASK) << RS_SH;
  65. }
  66. static inline __uasminit u32 build_rt(u32 arg)
  67. {
  68. WARN(arg & ~RT_MASK, KERN_WARNING "Micro-assembler field overflow\n");
  69. return (arg & RT_MASK) << RT_SH;
  70. }
  71. static inline __uasminit u32 build_rd(u32 arg)
  72. {
  73. WARN(arg & ~RD_MASK, KERN_WARNING "Micro-assembler field overflow\n");
  74. return (arg & RD_MASK) << RD_SH;
  75. }
  76. static inline __uasminit u32 build_re(u32 arg)
  77. {
  78. WARN(arg & ~RE_MASK, KERN_WARNING "Micro-assembler field overflow\n");
  79. return (arg & RE_MASK) << RE_SH;
  80. }
  81. static inline __uasminit u32 build_simm(s32 arg)
  82. {
  83. WARN(arg > 0x7fff || arg < -0x8000,
  84. KERN_WARNING "Micro-assembler field overflow\n");
  85. return arg & 0xffff;
  86. }
  87. static inline __uasminit u32 build_uimm(u32 arg)
  88. {
  89. WARN(arg & ~IMM_MASK, KERN_WARNING "Micro-assembler field overflow\n");
  90. return arg & IMM_MASK;
  91. }
  92. static inline __uasminit u32 build_scimm(u32 arg)
  93. {
  94. WARN(arg & ~SCIMM_MASK,
  95. KERN_WARNING "Micro-assembler field overflow\n");
  96. return (arg & SCIMM_MASK) << SCIMM_SH;
  97. }
  98. static inline __uasminit u32 build_func(u32 arg)
  99. {
  100. WARN(arg & ~FUNC_MASK, KERN_WARNING "Micro-assembler field overflow\n");
  101. return arg & FUNC_MASK;
  102. }
  103. static inline __uasminit u32 build_set(u32 arg)
  104. {
  105. WARN(arg & ~SET_MASK, KERN_WARNING "Micro-assembler field overflow\n");
  106. return arg & SET_MASK;
  107. }
  108. static void __uasminit build_insn(u32 **buf, enum opcode opc, ...);
  109. #define I_u1u2u3(op) \
  110. Ip_u1u2u3(op) \
  111. { \
  112. build_insn(buf, insn##op, a, b, c); \
  113. } \
  114. UASM_EXPORT_SYMBOL(uasm_i##op);
  115. #define I_u2u1u3(op) \
  116. Ip_u2u1u3(op) \
  117. { \
  118. build_insn(buf, insn##op, b, a, c); \
  119. } \
  120. UASM_EXPORT_SYMBOL(uasm_i##op);
  121. #define I_u3u1u2(op) \
  122. Ip_u3u1u2(op) \
  123. { \
  124. build_insn(buf, insn##op, b, c, a); \
  125. } \
  126. UASM_EXPORT_SYMBOL(uasm_i##op);
  127. #define I_u1u2s3(op) \
  128. Ip_u1u2s3(op) \
  129. { \
  130. build_insn(buf, insn##op, a, b, c); \
  131. } \
  132. UASM_EXPORT_SYMBOL(uasm_i##op);
  133. #define I_u2s3u1(op) \
  134. Ip_u2s3u1(op) \
  135. { \
  136. build_insn(buf, insn##op, c, a, b); \
  137. } \
  138. UASM_EXPORT_SYMBOL(uasm_i##op);
  139. #define I_u2u1s3(op) \
  140. Ip_u2u1s3(op) \
  141. { \
  142. build_insn(buf, insn##op, b, a, c); \
  143. } \
  144. UASM_EXPORT_SYMBOL(uasm_i##op);
  145. #define I_u2u1msbu3(op) \
  146. Ip_u2u1msbu3(op) \
  147. { \
  148. build_insn(buf, insn##op, b, a, c+d-1, c); \
  149. } \
  150. UASM_EXPORT_SYMBOL(uasm_i##op);
  151. #define I_u2u1msb32u3(op) \
  152. Ip_u2u1msbu3(op) \
  153. { \
  154. build_insn(buf, insn##op, b, a, c+d-33, c); \
  155. } \
  156. UASM_EXPORT_SYMBOL(uasm_i##op);
  157. #define I_u2u1msbdu3(op) \
  158. Ip_u2u1msbu3(op) \
  159. { \
  160. build_insn(buf, insn##op, b, a, d-1, c); \
  161. } \
  162. UASM_EXPORT_SYMBOL(uasm_i##op);
  163. #define I_u1u2(op) \
  164. Ip_u1u2(op) \
  165. { \
  166. build_insn(buf, insn##op, a, b); \
  167. } \
  168. UASM_EXPORT_SYMBOL(uasm_i##op);
  169. #define I_u1s2(op) \
  170. Ip_u1s2(op) \
  171. { \
  172. build_insn(buf, insn##op, a, b); \
  173. } \
  174. UASM_EXPORT_SYMBOL(uasm_i##op);
  175. #define I_u1(op) \
  176. Ip_u1(op) \
  177. { \
  178. build_insn(buf, insn##op, a); \
  179. } \
  180. UASM_EXPORT_SYMBOL(uasm_i##op);
  181. #define I_0(op) \
  182. Ip_0(op) \
  183. { \
  184. build_insn(buf, insn##op); \
  185. } \
  186. UASM_EXPORT_SYMBOL(uasm_i##op);
  187. I_u2u1s3(_addiu)
  188. I_u3u1u2(_addu)
  189. I_u2u1u3(_andi)
  190. I_u3u1u2(_and)
  191. I_u1u2s3(_beq)
  192. I_u1u2s3(_beql)
  193. I_u1s2(_bgez)
  194. I_u1s2(_bgezl)
  195. I_u1s2(_bltz)
  196. I_u1s2(_bltzl)
  197. I_u1u2s3(_bne)
  198. I_u2s3u1(_cache)
  199. I_u1u2u3(_dmfc0)
  200. I_u1u2u3(_dmtc0)
  201. I_u2u1s3(_daddiu)
  202. I_u3u1u2(_daddu)
  203. I_u2u1u3(_dsll)
  204. I_u2u1u3(_dsll32)
  205. I_u2u1u3(_dsra)
  206. I_u2u1u3(_dsrl)
  207. I_u2u1u3(_dsrl32)
  208. I_u2u1u3(_drotr)
  209. I_u2u1u3(_drotr32)
  210. I_u3u1u2(_dsubu)
  211. I_0(_eret)
  212. I_u2u1msbdu3(_ext)
  213. I_u2u1msbu3(_ins)
  214. I_u1(_j)
  215. I_u1(_jal)
  216. I_u1(_jr)
  217. I_u2s3u1(_ld)
  218. I_u2s3u1(_ll)
  219. I_u2s3u1(_lld)
  220. I_u1s2(_lui)
  221. I_u2s3u1(_lw)
  222. I_u1u2u3(_mfc0)
  223. I_u1u2u3(_mtc0)
  224. I_u2u1u3(_ori)
  225. I_u3u1u2(_or)
  226. I_0(_rfe)
  227. I_u2s3u1(_sc)
  228. I_u2s3u1(_scd)
  229. I_u2s3u1(_sd)
  230. I_u2u1u3(_sll)
  231. I_u2u1u3(_sra)
  232. I_u2u1u3(_srl)
  233. I_u2u1u3(_rotr)
  234. I_u3u1u2(_subu)
  235. I_u2s3u1(_sw)
  236. I_0(_tlbp)
  237. I_0(_tlbr)
  238. I_0(_tlbwi)
  239. I_0(_tlbwr)
  240. I_u3u1u2(_xor)
  241. I_u2u1u3(_xori)
  242. I_u2u1msbu3(_dins);
  243. I_u2u1msb32u3(_dinsm);
  244. I_u1(_syscall);
  245. I_u1u2s3(_bbit0);
  246. I_u1u2s3(_bbit1);
  247. I_u3u1u2(_lwx)
  248. I_u3u1u2(_ldx)
  249. #ifdef CONFIG_CPU_CAVIUM_OCTEON
  250. #include <asm/octeon/octeon.h>
  251. void __uasminit ISAFUNC(uasm_i_pref)(u32 **buf, unsigned int a, signed int b,
  252. unsigned int c)
  253. {
  254. if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) && a <= 24 && a != 5)
  255. /*
  256. * As per erratum Core-14449, replace prefetches 0-4,
  257. * 6-24 with 'pref 28'.
  258. */
  259. build_insn(buf, insn_pref, c, 28, b);
  260. else
  261. build_insn(buf, insn_pref, c, a, b);
  262. }
  263. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_i_pref));
  264. #else
  265. I_u2s3u1(_pref)
  266. #endif
  267. /* Handle labels. */
  268. void __uasminit ISAFUNC(uasm_build_label)(struct uasm_label **lab, u32 *addr, int lid)
  269. {
  270. (*lab)->addr = addr;
  271. (*lab)->lab = lid;
  272. (*lab)++;
  273. }
  274. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_build_label));
  275. int __uasminit ISAFUNC(uasm_in_compat_space_p)(long addr)
  276. {
  277. /* Is this address in 32bit compat space? */
  278. #ifdef CONFIG_64BIT
  279. return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
  280. #else
  281. return 1;
  282. #endif
  283. }
  284. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_in_compat_space_p));
  285. static int __uasminit uasm_rel_highest(long val)
  286. {
  287. #ifdef CONFIG_64BIT
  288. return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
  289. #else
  290. return 0;
  291. #endif
  292. }
  293. static int __uasminit uasm_rel_higher(long val)
  294. {
  295. #ifdef CONFIG_64BIT
  296. return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
  297. #else
  298. return 0;
  299. #endif
  300. }
  301. int __uasminit ISAFUNC(uasm_rel_hi)(long val)
  302. {
  303. return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
  304. }
  305. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_rel_hi));
  306. int __uasminit ISAFUNC(uasm_rel_lo)(long val)
  307. {
  308. return ((val & 0xffff) ^ 0x8000) - 0x8000;
  309. }
  310. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_rel_lo));
  311. void __uasminit ISAFUNC(UASM_i_LA_mostly)(u32 **buf, unsigned int rs, long addr)
  312. {
  313. if (!ISAFUNC(uasm_in_compat_space_p)(addr)) {
  314. ISAFUNC(uasm_i_lui)(buf, rs, uasm_rel_highest(addr));
  315. if (uasm_rel_higher(addr))
  316. ISAFUNC(uasm_i_daddiu)(buf, rs, rs, uasm_rel_higher(addr));
  317. if (ISAFUNC(uasm_rel_hi(addr))) {
  318. ISAFUNC(uasm_i_dsll)(buf, rs, rs, 16);
  319. ISAFUNC(uasm_i_daddiu)(buf, rs, rs,
  320. ISAFUNC(uasm_rel_hi)(addr));
  321. ISAFUNC(uasm_i_dsll)(buf, rs, rs, 16);
  322. } else
  323. ISAFUNC(uasm_i_dsll32)(buf, rs, rs, 0);
  324. } else
  325. ISAFUNC(uasm_i_lui)(buf, rs, ISAFUNC(uasm_rel_hi(addr)));
  326. }
  327. UASM_EXPORT_SYMBOL(ISAFUNC(UASM_i_LA_mostly));
  328. void __uasminit ISAFUNC(UASM_i_LA)(u32 **buf, unsigned int rs, long addr)
  329. {
  330. ISAFUNC(UASM_i_LA_mostly)(buf, rs, addr);
  331. if (ISAFUNC(uasm_rel_lo(addr))) {
  332. if (!ISAFUNC(uasm_in_compat_space_p)(addr))
  333. ISAFUNC(uasm_i_daddiu)(buf, rs, rs,
  334. ISAFUNC(uasm_rel_lo(addr)));
  335. else
  336. ISAFUNC(uasm_i_addiu)(buf, rs, rs,
  337. ISAFUNC(uasm_rel_lo(addr)));
  338. }
  339. }
  340. UASM_EXPORT_SYMBOL(ISAFUNC(UASM_i_LA));
  341. /* Handle relocations. */
  342. void __uasminit
  343. ISAFUNC(uasm_r_mips_pc16)(struct uasm_reloc **rel, u32 *addr, int lid)
  344. {
  345. (*rel)->addr = addr;
  346. (*rel)->type = R_MIPS_PC16;
  347. (*rel)->lab = lid;
  348. (*rel)++;
  349. }
  350. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_r_mips_pc16));
  351. static inline void __uasminit
  352. __resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab);
  353. void __uasminit
  354. ISAFUNC(uasm_resolve_relocs)(struct uasm_reloc *rel, struct uasm_label *lab)
  355. {
  356. struct uasm_label *l;
  357. for (; rel->lab != UASM_LABEL_INVALID; rel++)
  358. for (l = lab; l->lab != UASM_LABEL_INVALID; l++)
  359. if (rel->lab == l->lab)
  360. __resolve_relocs(rel, l);
  361. }
  362. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_resolve_relocs));
  363. void __uasminit
  364. ISAFUNC(uasm_move_relocs)(struct uasm_reloc *rel, u32 *first, u32 *end, long off)
  365. {
  366. for (; rel->lab != UASM_LABEL_INVALID; rel++)
  367. if (rel->addr >= first && rel->addr < end)
  368. rel->addr += off;
  369. }
  370. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_relocs));
  371. void __uasminit
  372. ISAFUNC(uasm_move_labels)(struct uasm_label *lab, u32 *first, u32 *end, long off)
  373. {
  374. for (; lab->lab != UASM_LABEL_INVALID; lab++)
  375. if (lab->addr >= first && lab->addr < end)
  376. lab->addr += off;
  377. }
  378. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_labels));
  379. void __uasminit
  380. ISAFUNC(uasm_copy_handler)(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first,
  381. u32 *end, u32 *target)
  382. {
  383. long off = (long)(target - first);
  384. memcpy(target, first, (end - first) * sizeof(u32));
  385. ISAFUNC(uasm_move_relocs(rel, first, end, off));
  386. ISAFUNC(uasm_move_labels(lab, first, end, off));
  387. }
  388. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_copy_handler));
  389. int __uasminit ISAFUNC(uasm_insn_has_bdelay)(struct uasm_reloc *rel, u32 *addr)
  390. {
  391. for (; rel->lab != UASM_LABEL_INVALID; rel++) {
  392. if (rel->addr == addr
  393. && (rel->type == R_MIPS_PC16
  394. || rel->type == R_MIPS_26))
  395. return 1;
  396. }
  397. return 0;
  398. }
  399. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_insn_has_bdelay));
  400. /* Convenience functions for labeled branches. */
  401. void __uasminit
  402. ISAFUNC(uasm_il_bltz)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
  403. {
  404. uasm_r_mips_pc16(r, *p, lid);
  405. ISAFUNC(uasm_i_bltz)(p, reg, 0);
  406. }
  407. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bltz));
  408. void __uasminit
  409. ISAFUNC(uasm_il_b)(u32 **p, struct uasm_reloc **r, int lid)
  410. {
  411. uasm_r_mips_pc16(r, *p, lid);
  412. ISAFUNC(uasm_i_b)(p, 0);
  413. }
  414. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_b));
  415. void __uasminit
  416. ISAFUNC(uasm_il_beqz)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
  417. {
  418. uasm_r_mips_pc16(r, *p, lid);
  419. ISAFUNC(uasm_i_beqz)(p, reg, 0);
  420. }
  421. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqz));
  422. void __uasminit
  423. ISAFUNC(uasm_il_beqzl)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
  424. {
  425. uasm_r_mips_pc16(r, *p, lid);
  426. ISAFUNC(uasm_i_beqzl)(p, reg, 0);
  427. }
  428. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqzl));
  429. void __uasminit
  430. ISAFUNC(uasm_il_bne)(u32 **p, struct uasm_reloc **r, unsigned int reg1,
  431. unsigned int reg2, int lid)
  432. {
  433. uasm_r_mips_pc16(r, *p, lid);
  434. ISAFUNC(uasm_i_bne)(p, reg1, reg2, 0);
  435. }
  436. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bne));
  437. void __uasminit
  438. ISAFUNC(uasm_il_bnez)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
  439. {
  440. uasm_r_mips_pc16(r, *p, lid);
  441. ISAFUNC(uasm_i_bnez)(p, reg, 0);
  442. }
  443. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bnez));
  444. void __uasminit
  445. ISAFUNC(uasm_il_bgezl)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
  446. {
  447. uasm_r_mips_pc16(r, *p, lid);
  448. ISAFUNC(uasm_i_bgezl)(p, reg, 0);
  449. }
  450. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgezl));
  451. void __uasminit
  452. ISAFUNC(uasm_il_bgez)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
  453. {
  454. uasm_r_mips_pc16(r, *p, lid);
  455. ISAFUNC(uasm_i_bgez)(p, reg, 0);
  456. }
  457. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgez));
  458. void __uasminit
  459. ISAFUNC(uasm_il_bbit0)(u32 **p, struct uasm_reloc **r, unsigned int reg,
  460. unsigned int bit, int lid)
  461. {
  462. uasm_r_mips_pc16(r, *p, lid);
  463. ISAFUNC(uasm_i_bbit0)(p, reg, bit, 0);
  464. }
  465. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit0));
  466. void __uasminit
  467. ISAFUNC(uasm_il_bbit1)(u32 **p, struct uasm_reloc **r, unsigned int reg,
  468. unsigned int bit, int lid)
  469. {
  470. uasm_r_mips_pc16(r, *p, lid);
  471. ISAFUNC(uasm_i_bbit1)(p, reg, bit, 0);
  472. }
  473. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit1));