uasm.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 ISAFUNC(uasm_rel_lo)(long val)
  307. {
  308. return ((val & 0xffff) ^ 0x8000) - 0x8000;
  309. }
  310. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_rel_lo));
  311. void 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 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 ISAFUNC(uasm_r_mips_pc16)(struct uasm_reloc **rel, u32 *addr, int lid)
  343. {
  344. (*rel)->addr = addr;
  345. (*rel)->type = R_MIPS_PC16;
  346. (*rel)->lab = lid;
  347. (*rel)++;
  348. }
  349. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_r_mips_pc16));
  350. static inline void __resolve_relocs(struct uasm_reloc *rel,
  351. struct uasm_label *lab);
  352. void ISAFUNC(uasm_resolve_relocs)(struct uasm_reloc *rel,
  353. struct uasm_label *lab)
  354. {
  355. struct uasm_label *l;
  356. for (; rel->lab != UASM_LABEL_INVALID; rel++)
  357. for (l = lab; l->lab != UASM_LABEL_INVALID; l++)
  358. if (rel->lab == l->lab)
  359. __resolve_relocs(rel, l);
  360. }
  361. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_resolve_relocs));
  362. void ISAFUNC(uasm_move_relocs)(struct uasm_reloc *rel, u32 *first, u32 *end,
  363. long off)
  364. {
  365. for (; rel->lab != UASM_LABEL_INVALID; rel++)
  366. if (rel->addr >= first && rel->addr < end)
  367. rel->addr += off;
  368. }
  369. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_relocs));
  370. void ISAFUNC(uasm_move_labels)(struct uasm_label *lab, u32 *first, u32 *end,
  371. long off)
  372. {
  373. for (; lab->lab != UASM_LABEL_INVALID; lab++)
  374. if (lab->addr >= first && lab->addr < end)
  375. lab->addr += off;
  376. }
  377. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_labels));
  378. void ISAFUNC(uasm_copy_handler)(struct uasm_reloc *rel, struct uasm_label *lab,
  379. u32 *first, u32 *end, u32 *target)
  380. {
  381. long off = (long)(target - first);
  382. memcpy(target, first, (end - first) * sizeof(u32));
  383. ISAFUNC(uasm_move_relocs(rel, first, end, off));
  384. ISAFUNC(uasm_move_labels(lab, first, end, off));
  385. }
  386. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_copy_handler));
  387. int ISAFUNC(uasm_insn_has_bdelay)(struct uasm_reloc *rel, u32 *addr)
  388. {
  389. for (; rel->lab != UASM_LABEL_INVALID; rel++) {
  390. if (rel->addr == addr
  391. && (rel->type == R_MIPS_PC16
  392. || rel->type == R_MIPS_26))
  393. return 1;
  394. }
  395. return 0;
  396. }
  397. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_insn_has_bdelay));
  398. /* Convenience functions for labeled branches. */
  399. void ISAFUNC(uasm_il_bltz)(u32 **p, struct uasm_reloc **r, unsigned int reg,
  400. int lid)
  401. {
  402. uasm_r_mips_pc16(r, *p, lid);
  403. ISAFUNC(uasm_i_bltz)(p, reg, 0);
  404. }
  405. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bltz));
  406. void ISAFUNC(uasm_il_b)(u32 **p, struct uasm_reloc **r, int lid)
  407. {
  408. uasm_r_mips_pc16(r, *p, lid);
  409. ISAFUNC(uasm_i_b)(p, 0);
  410. }
  411. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_b));
  412. void ISAFUNC(uasm_il_beqz)(u32 **p, struct uasm_reloc **r, unsigned int reg,
  413. int lid)
  414. {
  415. uasm_r_mips_pc16(r, *p, lid);
  416. ISAFUNC(uasm_i_beqz)(p, reg, 0);
  417. }
  418. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqz));
  419. void ISAFUNC(uasm_il_beqzl)(u32 **p, struct uasm_reloc **r, unsigned int reg,
  420. int lid)
  421. {
  422. uasm_r_mips_pc16(r, *p, lid);
  423. ISAFUNC(uasm_i_beqzl)(p, reg, 0);
  424. }
  425. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqzl));
  426. void ISAFUNC(uasm_il_bne)(u32 **p, struct uasm_reloc **r, unsigned int reg1,
  427. unsigned int reg2, int lid)
  428. {
  429. uasm_r_mips_pc16(r, *p, lid);
  430. ISAFUNC(uasm_i_bne)(p, reg1, reg2, 0);
  431. }
  432. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bne));
  433. void ISAFUNC(uasm_il_bnez)(u32 **p, struct uasm_reloc **r, unsigned int reg,
  434. int lid)
  435. {
  436. uasm_r_mips_pc16(r, *p, lid);
  437. ISAFUNC(uasm_i_bnez)(p, reg, 0);
  438. }
  439. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bnez));
  440. void ISAFUNC(uasm_il_bgezl)(u32 **p, struct uasm_reloc **r, unsigned int reg,
  441. int lid)
  442. {
  443. uasm_r_mips_pc16(r, *p, lid);
  444. ISAFUNC(uasm_i_bgezl)(p, reg, 0);
  445. }
  446. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgezl));
  447. void ISAFUNC(uasm_il_bgez)(u32 **p, struct uasm_reloc **r, unsigned int reg,
  448. int lid)
  449. {
  450. uasm_r_mips_pc16(r, *p, lid);
  451. ISAFUNC(uasm_i_bgez)(p, reg, 0);
  452. }
  453. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgez));
  454. void ISAFUNC(uasm_il_bbit0)(u32 **p, struct uasm_reloc **r, unsigned int reg,
  455. unsigned int bit, int lid)
  456. {
  457. uasm_r_mips_pc16(r, *p, lid);
  458. ISAFUNC(uasm_i_bbit0)(p, reg, bit, 0);
  459. }
  460. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit0));
  461. void ISAFUNC(uasm_il_bbit1)(u32 **p, struct uasm_reloc **r, unsigned int reg,
  462. unsigned int bit, int lid)
  463. {
  464. uasm_r_mips_pc16(r, *p, lid);
  465. ISAFUNC(uasm_i_bbit1)(p, reg, bit, 0);
  466. }
  467. UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit1));