alignment.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (C) 2005-2017 Andes Technology Corporation
  3. #include <linux/proc_fs.h>
  4. #include <linux/uaccess.h>
  5. #include <linux/sysctl.h>
  6. #include <asm/unaligned.h>
  7. #define DEBUG(enable, tagged, ...) \
  8. do{ \
  9. if (enable) { \
  10. if (tagged) \
  11. pr_warn("[ %30s() ] ", __func__); \
  12. pr_warn(__VA_ARGS__); \
  13. } \
  14. } while (0)
  15. #define RT(inst) (((inst) >> 20) & 0x1FUL)
  16. #define RA(inst) (((inst) >> 15) & 0x1FUL)
  17. #define RB(inst) (((inst) >> 10) & 0x1FUL)
  18. #define SV(inst) (((inst) >> 8) & 0x3UL)
  19. #define IMM(inst) (((inst) >> 0) & 0x7FFFUL)
  20. #define RA3(inst) (((inst) >> 3) & 0x7UL)
  21. #define RT3(inst) (((inst) >> 6) & 0x7UL)
  22. #define IMM3U(inst) (((inst) >> 0) & 0x7UL)
  23. #define RA5(inst) (((inst) >> 0) & 0x1FUL)
  24. #define RT4(inst) (((inst) >> 5) & 0xFUL)
  25. #define GET_IMMSVAL(imm_value) \
  26. (((imm_value >> 14) & 0x1) ? (imm_value - 0x8000) : imm_value)
  27. #define __get8_data(val,addr,err) \
  28. __asm__( \
  29. "1: lbi.bi %1, [%2], #1\n" \
  30. "2:\n" \
  31. " .pushsection .text.fixup,\"ax\"\n" \
  32. " .align 2\n" \
  33. "3: movi %0, #1\n" \
  34. " j 2b\n" \
  35. " .popsection\n" \
  36. " .pushsection __ex_table,\"a\"\n" \
  37. " .align 3\n" \
  38. " .long 1b, 3b\n" \
  39. " .popsection\n" \
  40. : "=r" (err), "=&r" (val), "=r" (addr) \
  41. : "0" (err), "2" (addr))
  42. #define get16_data(addr, val_ptr) \
  43. do { \
  44. unsigned int err = 0, v, a = addr; \
  45. __get8_data(v,a,err); \
  46. *val_ptr = v << 0; \
  47. __get8_data(v,a,err); \
  48. *val_ptr |= v << 8; \
  49. if (err) \
  50. goto fault; \
  51. *val_ptr = le16_to_cpu(*val_ptr); \
  52. } while(0)
  53. #define get32_data(addr, val_ptr) \
  54. do { \
  55. unsigned int err = 0, v, a = addr; \
  56. __get8_data(v,a,err); \
  57. *val_ptr = v << 0; \
  58. __get8_data(v,a,err); \
  59. *val_ptr |= v << 8; \
  60. __get8_data(v,a,err); \
  61. *val_ptr |= v << 16; \
  62. __get8_data(v,a,err); \
  63. *val_ptr |= v << 24; \
  64. if (err) \
  65. goto fault; \
  66. *val_ptr = le32_to_cpu(*val_ptr); \
  67. } while(0)
  68. #define get_data(addr, val_ptr, len) \
  69. if (len == 2) \
  70. get16_data(addr, val_ptr); \
  71. else \
  72. get32_data(addr, val_ptr);
  73. #define set16_data(addr, val) \
  74. do { \
  75. unsigned int err = 0, *ptr = addr ; \
  76. val = le32_to_cpu(val); \
  77. __asm__( \
  78. "1: sbi.bi %2, [%1], #1\n" \
  79. " srli %2, %2, #8\n" \
  80. "2: sbi %2, [%1]\n" \
  81. "3:\n" \
  82. " .pushsection .text.fixup,\"ax\"\n" \
  83. " .align 2\n" \
  84. "4: movi %0, #1\n" \
  85. " j 3b\n" \
  86. " .popsection\n" \
  87. " .pushsection __ex_table,\"a\"\n" \
  88. " .align 3\n" \
  89. " .long 1b, 4b\n" \
  90. " .long 2b, 4b\n" \
  91. " .popsection\n" \
  92. : "=r" (err), "+r" (ptr), "+r" (val) \
  93. : "0" (err) \
  94. ); \
  95. if (err) \
  96. goto fault; \
  97. } while(0)
  98. #define set32_data(addr, val) \
  99. do { \
  100. unsigned int err = 0, *ptr = addr ; \
  101. val = le32_to_cpu(val); \
  102. __asm__( \
  103. "1: sbi.bi %2, [%1], #1\n" \
  104. " srli %2, %2, #8\n" \
  105. "2: sbi.bi %2, [%1], #1\n" \
  106. " srli %2, %2, #8\n" \
  107. "3: sbi.bi %2, [%1], #1\n" \
  108. " srli %2, %2, #8\n" \
  109. "4: sbi %2, [%1]\n" \
  110. "5:\n" \
  111. " .pushsection .text.fixup,\"ax\"\n" \
  112. " .align 2\n" \
  113. "6: movi %0, #1\n" \
  114. " j 5b\n" \
  115. " .popsection\n" \
  116. " .pushsection __ex_table,\"a\"\n" \
  117. " .align 3\n" \
  118. " .long 1b, 6b\n" \
  119. " .long 2b, 6b\n" \
  120. " .long 3b, 6b\n" \
  121. " .long 4b, 6b\n" \
  122. " .popsection\n" \
  123. : "=r" (err), "+r" (ptr), "+r" (val) \
  124. : "0" (err) \
  125. ); \
  126. if (err) \
  127. goto fault; \
  128. } while(0)
  129. #define set_data(addr, val, len) \
  130. if (len == 2) \
  131. set16_data(addr, val); \
  132. else \
  133. set32_data(addr, val);
  134. #define NDS32_16BIT_INSTRUCTION 0x80000000
  135. extern pte_t va_present(struct mm_struct *mm, unsigned long addr);
  136. extern pte_t va_kernel_present(unsigned long addr);
  137. extern int va_readable(struct pt_regs *regs, unsigned long addr);
  138. extern int va_writable(struct pt_regs *regs, unsigned long addr);
  139. int unalign_access_mode = 0, unalign_access_debug = 0;
  140. static inline unsigned long *idx_to_addr(struct pt_regs *regs, int idx)
  141. {
  142. /* this should be consistent with ptrace.h */
  143. if (idx >= 0 && idx <= 25) /* R0-R25 */
  144. return &regs->uregs[0] + idx;
  145. else if (idx >= 28 && idx <= 30) /* FP, GP, LP */
  146. return &regs->fp + (idx - 28);
  147. else if (idx == 31) /* SP */
  148. return &regs->sp;
  149. else
  150. return NULL; /* cause a segfault */
  151. }
  152. static inline unsigned long get_inst(unsigned long addr)
  153. {
  154. return be32_to_cpu(get_unaligned((u32 *) addr));
  155. }
  156. static inline unsigned long sign_extend(unsigned long val, int len)
  157. {
  158. unsigned long ret = 0;
  159. unsigned char *s, *t;
  160. int i = 0;
  161. val = cpu_to_le32(val);
  162. s = (void *)&val;
  163. t = (void *)&ret;
  164. while (i++ < len)
  165. *t++ = *s++;
  166. if (((*(t - 1)) & 0x80) && (i < 4)) {
  167. while (i++ <= 4)
  168. *t++ = 0xff;
  169. }
  170. return le32_to_cpu(ret);
  171. }
  172. static inline int do_16(unsigned long inst, struct pt_regs *regs)
  173. {
  174. int imm, regular, load, len, addr_mode, idx_mode;
  175. unsigned long unaligned_addr, target_val, source_idx, target_idx,
  176. shift = 0;
  177. switch ((inst >> 9) & 0x3F) {
  178. case 0x12: /* LHI333 */
  179. imm = 1;
  180. regular = 1;
  181. load = 1;
  182. len = 2;
  183. addr_mode = 3;
  184. idx_mode = 3;
  185. break;
  186. case 0x10: /* LWI333 */
  187. imm = 1;
  188. regular = 1;
  189. load = 1;
  190. len = 4;
  191. addr_mode = 3;
  192. idx_mode = 3;
  193. break;
  194. case 0x11: /* LWI333.bi */
  195. imm = 1;
  196. regular = 0;
  197. load = 1;
  198. len = 4;
  199. addr_mode = 3;
  200. idx_mode = 3;
  201. break;
  202. case 0x1A: /* LWI450 */
  203. imm = 0;
  204. regular = 1;
  205. load = 1;
  206. len = 4;
  207. addr_mode = 5;
  208. idx_mode = 4;
  209. break;
  210. case 0x16: /* SHI333 */
  211. imm = 1;
  212. regular = 1;
  213. load = 0;
  214. len = 2;
  215. addr_mode = 3;
  216. idx_mode = 3;
  217. break;
  218. case 0x14: /* SWI333 */
  219. imm = 1;
  220. regular = 1;
  221. load = 0;
  222. len = 4;
  223. addr_mode = 3;
  224. idx_mode = 3;
  225. break;
  226. case 0x15: /* SWI333.bi */
  227. imm = 1;
  228. regular = 0;
  229. load = 0;
  230. len = 4;
  231. addr_mode = 3;
  232. idx_mode = 3;
  233. break;
  234. case 0x1B: /* SWI450 */
  235. imm = 0;
  236. regular = 1;
  237. load = 0;
  238. len = 4;
  239. addr_mode = 5;
  240. idx_mode = 4;
  241. break;
  242. default:
  243. return -EFAULT;
  244. }
  245. if (addr_mode == 3) {
  246. unaligned_addr = *idx_to_addr(regs, RA3(inst));
  247. source_idx = RA3(inst);
  248. } else {
  249. unaligned_addr = *idx_to_addr(regs, RA5(inst));
  250. source_idx = RA5(inst);
  251. }
  252. if (idx_mode == 3)
  253. target_idx = RT3(inst);
  254. else
  255. target_idx = RT4(inst);
  256. if (imm)
  257. shift = IMM3U(inst) * len;
  258. if (regular)
  259. unaligned_addr += shift;
  260. if (load) {
  261. if (!access_ok(VERIFY_READ, (void *)unaligned_addr, len))
  262. return -EACCES;
  263. get_data(unaligned_addr, &target_val, len);
  264. *idx_to_addr(regs, target_idx) = target_val;
  265. } else {
  266. if (!access_ok(VERIFY_WRITE, (void *)unaligned_addr, len))
  267. return -EACCES;
  268. target_val = *idx_to_addr(regs, target_idx);
  269. set_data((void *)unaligned_addr, target_val, len);
  270. }
  271. if (!regular)
  272. *idx_to_addr(regs, source_idx) = unaligned_addr + shift;
  273. regs->ipc += 2;
  274. return 0;
  275. fault:
  276. return -EACCES;
  277. }
  278. static inline int do_32(unsigned long inst, struct pt_regs *regs)
  279. {
  280. int imm, regular, load, len, sign_ext;
  281. unsigned long unaligned_addr, target_val, shift;
  282. unaligned_addr = *idx_to_addr(regs, RA(inst));
  283. switch ((inst >> 25) << 1) {
  284. case 0x02: /* LHI */
  285. imm = 1;
  286. regular = 1;
  287. load = 1;
  288. len = 2;
  289. sign_ext = 0;
  290. break;
  291. case 0x0A: /* LHI.bi */
  292. imm = 1;
  293. regular = 0;
  294. load = 1;
  295. len = 2;
  296. sign_ext = 0;
  297. break;
  298. case 0x22: /* LHSI */
  299. imm = 1;
  300. regular = 1;
  301. load = 1;
  302. len = 2;
  303. sign_ext = 1;
  304. break;
  305. case 0x2A: /* LHSI.bi */
  306. imm = 1;
  307. regular = 0;
  308. load = 1;
  309. len = 2;
  310. sign_ext = 1;
  311. break;
  312. case 0x04: /* LWI */
  313. imm = 1;
  314. regular = 1;
  315. load = 1;
  316. len = 4;
  317. sign_ext = 0;
  318. break;
  319. case 0x0C: /* LWI.bi */
  320. imm = 1;
  321. regular = 0;
  322. load = 1;
  323. len = 4;
  324. sign_ext = 0;
  325. break;
  326. case 0x12: /* SHI */
  327. imm = 1;
  328. regular = 1;
  329. load = 0;
  330. len = 2;
  331. sign_ext = 0;
  332. break;
  333. case 0x1A: /* SHI.bi */
  334. imm = 1;
  335. regular = 0;
  336. load = 0;
  337. len = 2;
  338. sign_ext = 0;
  339. break;
  340. case 0x14: /* SWI */
  341. imm = 1;
  342. regular = 1;
  343. load = 0;
  344. len = 4;
  345. sign_ext = 0;
  346. break;
  347. case 0x1C: /* SWI.bi */
  348. imm = 1;
  349. regular = 0;
  350. load = 0;
  351. len = 4;
  352. sign_ext = 0;
  353. break;
  354. default:
  355. switch (inst & 0xff) {
  356. case 0x01: /* LH */
  357. imm = 0;
  358. regular = 1;
  359. load = 1;
  360. len = 2;
  361. sign_ext = 0;
  362. break;
  363. case 0x05: /* LH.bi */
  364. imm = 0;
  365. regular = 0;
  366. load = 1;
  367. len = 2;
  368. sign_ext = 0;
  369. break;
  370. case 0x11: /* LHS */
  371. imm = 0;
  372. regular = 1;
  373. load = 1;
  374. len = 2;
  375. sign_ext = 1;
  376. break;
  377. case 0x15: /* LHS.bi */
  378. imm = 0;
  379. regular = 0;
  380. load = 1;
  381. len = 2;
  382. sign_ext = 1;
  383. break;
  384. case 0x02: /* LW */
  385. imm = 0;
  386. regular = 1;
  387. load = 1;
  388. len = 4;
  389. sign_ext = 0;
  390. break;
  391. case 0x06: /* LW.bi */
  392. imm = 0;
  393. regular = 0;
  394. load = 1;
  395. len = 4;
  396. sign_ext = 0;
  397. break;
  398. case 0x09: /* SH */
  399. imm = 0;
  400. regular = 1;
  401. load = 0;
  402. len = 2;
  403. sign_ext = 0;
  404. break;
  405. case 0x0D: /* SH.bi */
  406. imm = 0;
  407. regular = 0;
  408. load = 0;
  409. len = 2;
  410. sign_ext = 0;
  411. break;
  412. case 0x0A: /* SW */
  413. imm = 0;
  414. regular = 1;
  415. load = 0;
  416. len = 4;
  417. sign_ext = 0;
  418. break;
  419. case 0x0E: /* SW.bi */
  420. imm = 0;
  421. regular = 0;
  422. load = 0;
  423. len = 4;
  424. sign_ext = 0;
  425. break;
  426. default:
  427. return -EFAULT;
  428. }
  429. }
  430. if (imm)
  431. shift = GET_IMMSVAL(IMM(inst)) * len;
  432. else
  433. shift = *idx_to_addr(regs, RB(inst)) << SV(inst);
  434. if (regular)
  435. unaligned_addr += shift;
  436. if (load) {
  437. if (!access_ok(VERIFY_READ, (void *)unaligned_addr, len))
  438. return -EACCES;
  439. get_data(unaligned_addr, &target_val, len);
  440. if (sign_ext)
  441. *idx_to_addr(regs, RT(inst)) =
  442. sign_extend(target_val, len);
  443. else
  444. *idx_to_addr(regs, RT(inst)) = target_val;
  445. } else {
  446. if (!access_ok(VERIFY_WRITE, (void *)unaligned_addr, len))
  447. return -EACCES;
  448. target_val = *idx_to_addr(regs, RT(inst));
  449. set_data((void *)unaligned_addr, target_val, len);
  450. }
  451. if (!regular)
  452. *idx_to_addr(regs, RA(inst)) = unaligned_addr + shift;
  453. regs->ipc += 4;
  454. return 0;
  455. fault:
  456. return -EACCES;
  457. }
  458. int do_unaligned_access(unsigned long addr, struct pt_regs *regs)
  459. {
  460. unsigned long inst;
  461. int ret = -EFAULT;
  462. mm_segment_t seg = get_fs();
  463. inst = get_inst(regs->ipc);
  464. DEBUG((unalign_access_debug > 0), 1,
  465. "Faulting addr: 0x%08lx, pc: 0x%08lx [inst: 0x%08lx ]\n", addr,
  466. regs->ipc, inst);
  467. set_fs(USER_DS);
  468. if (inst & NDS32_16BIT_INSTRUCTION)
  469. ret = do_16((inst >> 16) & 0xffff, regs);
  470. else
  471. ret = do_32(inst, regs);
  472. set_fs(seg);
  473. return ret;
  474. }
  475. #ifdef CONFIG_PROC_FS
  476. static struct ctl_table alignment_tbl[3] = {
  477. {
  478. .procname = "enable",
  479. .data = &unalign_access_mode,
  480. .maxlen = sizeof(unalign_access_mode),
  481. .mode = 0666,
  482. .proc_handler = &proc_dointvec
  483. }
  484. ,
  485. {
  486. .procname = "debug_info",
  487. .data = &unalign_access_debug,
  488. .maxlen = sizeof(unalign_access_debug),
  489. .mode = 0644,
  490. .proc_handler = &proc_dointvec
  491. }
  492. ,
  493. {}
  494. };
  495. static struct ctl_table nds32_sysctl_table[2] = {
  496. {
  497. .procname = "unaligned_access",
  498. .mode = 0555,
  499. .child = alignment_tbl},
  500. {}
  501. };
  502. static struct ctl_path nds32_path[2] = {
  503. {.procname = "nds32"},
  504. {}
  505. };
  506. /*
  507. * Initialize nds32 alignment-correction interface
  508. */
  509. static int __init nds32_sysctl_init(void)
  510. {
  511. register_sysctl_paths(nds32_path, nds32_sysctl_table);
  512. return 0;
  513. }
  514. __initcall(nds32_sysctl_init);
  515. #endif /* CONFIG_PROC_FS */