unaligned.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Handle unaligned accesses by emulation.
  4. *
  5. * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
  6. *
  7. * Derived from MIPS:
  8. * Copyright (C) 1996, 1998, 1999, 2002 by Ralf Baechle
  9. * Copyright (C) 1999 Silicon Graphics, Inc.
  10. * Copyright (C) 2014 Imagination Technologies Ltd.
  11. */
  12. #include <linux/mm.h>
  13. #include <linux/sched.h>
  14. #include <linux/signal.h>
  15. #include <linux/debugfs.h>
  16. #include <linux/perf_event.h>
  17. #include <asm/asm.h>
  18. #include <asm/branch.h>
  19. #include <asm/fpu.h>
  20. #include <asm/inst.h>
  21. #include "access-helper.h"
  22. #ifdef CONFIG_DEBUG_FS
  23. static u32 unaligned_instructions_user;
  24. static u32 unaligned_instructions_kernel;
  25. #endif
  26. static inline unsigned long read_fpr(unsigned int idx)
  27. {
  28. #define READ_FPR(idx, __value) \
  29. __asm__ __volatile__("movfr2gr.d %0, $f"#idx"\n\t" : "=r"(__value));
  30. unsigned long __value;
  31. switch (idx) {
  32. case 0:
  33. READ_FPR(0, __value);
  34. break;
  35. case 1:
  36. READ_FPR(1, __value);
  37. break;
  38. case 2:
  39. READ_FPR(2, __value);
  40. break;
  41. case 3:
  42. READ_FPR(3, __value);
  43. break;
  44. case 4:
  45. READ_FPR(4, __value);
  46. break;
  47. case 5:
  48. READ_FPR(5, __value);
  49. break;
  50. case 6:
  51. READ_FPR(6, __value);
  52. break;
  53. case 7:
  54. READ_FPR(7, __value);
  55. break;
  56. case 8:
  57. READ_FPR(8, __value);
  58. break;
  59. case 9:
  60. READ_FPR(9, __value);
  61. break;
  62. case 10:
  63. READ_FPR(10, __value);
  64. break;
  65. case 11:
  66. READ_FPR(11, __value);
  67. break;
  68. case 12:
  69. READ_FPR(12, __value);
  70. break;
  71. case 13:
  72. READ_FPR(13, __value);
  73. break;
  74. case 14:
  75. READ_FPR(14, __value);
  76. break;
  77. case 15:
  78. READ_FPR(15, __value);
  79. break;
  80. case 16:
  81. READ_FPR(16, __value);
  82. break;
  83. case 17:
  84. READ_FPR(17, __value);
  85. break;
  86. case 18:
  87. READ_FPR(18, __value);
  88. break;
  89. case 19:
  90. READ_FPR(19, __value);
  91. break;
  92. case 20:
  93. READ_FPR(20, __value);
  94. break;
  95. case 21:
  96. READ_FPR(21, __value);
  97. break;
  98. case 22:
  99. READ_FPR(22, __value);
  100. break;
  101. case 23:
  102. READ_FPR(23, __value);
  103. break;
  104. case 24:
  105. READ_FPR(24, __value);
  106. break;
  107. case 25:
  108. READ_FPR(25, __value);
  109. break;
  110. case 26:
  111. READ_FPR(26, __value);
  112. break;
  113. case 27:
  114. READ_FPR(27, __value);
  115. break;
  116. case 28:
  117. READ_FPR(28, __value);
  118. break;
  119. case 29:
  120. READ_FPR(29, __value);
  121. break;
  122. case 30:
  123. READ_FPR(30, __value);
  124. break;
  125. case 31:
  126. READ_FPR(31, __value);
  127. break;
  128. default:
  129. panic("unexpected idx '%d'", idx);
  130. }
  131. #undef READ_FPR
  132. return __value;
  133. }
  134. static inline void write_fpr(unsigned int idx, unsigned long value)
  135. {
  136. #define WRITE_FPR(idx, value) \
  137. __asm__ __volatile__("movgr2fr.d $f"#idx", %0\n\t" :: "r"(value));
  138. switch (idx) {
  139. case 0:
  140. WRITE_FPR(0, value);
  141. break;
  142. case 1:
  143. WRITE_FPR(1, value);
  144. break;
  145. case 2:
  146. WRITE_FPR(2, value);
  147. break;
  148. case 3:
  149. WRITE_FPR(3, value);
  150. break;
  151. case 4:
  152. WRITE_FPR(4, value);
  153. break;
  154. case 5:
  155. WRITE_FPR(5, value);
  156. break;
  157. case 6:
  158. WRITE_FPR(6, value);
  159. break;
  160. case 7:
  161. WRITE_FPR(7, value);
  162. break;
  163. case 8:
  164. WRITE_FPR(8, value);
  165. break;
  166. case 9:
  167. WRITE_FPR(9, value);
  168. break;
  169. case 10:
  170. WRITE_FPR(10, value);
  171. break;
  172. case 11:
  173. WRITE_FPR(11, value);
  174. break;
  175. case 12:
  176. WRITE_FPR(12, value);
  177. break;
  178. case 13:
  179. WRITE_FPR(13, value);
  180. break;
  181. case 14:
  182. WRITE_FPR(14, value);
  183. break;
  184. case 15:
  185. WRITE_FPR(15, value);
  186. break;
  187. case 16:
  188. WRITE_FPR(16, value);
  189. break;
  190. case 17:
  191. WRITE_FPR(17, value);
  192. break;
  193. case 18:
  194. WRITE_FPR(18, value);
  195. break;
  196. case 19:
  197. WRITE_FPR(19, value);
  198. break;
  199. case 20:
  200. WRITE_FPR(20, value);
  201. break;
  202. case 21:
  203. WRITE_FPR(21, value);
  204. break;
  205. case 22:
  206. WRITE_FPR(22, value);
  207. break;
  208. case 23:
  209. WRITE_FPR(23, value);
  210. break;
  211. case 24:
  212. WRITE_FPR(24, value);
  213. break;
  214. case 25:
  215. WRITE_FPR(25, value);
  216. break;
  217. case 26:
  218. WRITE_FPR(26, value);
  219. break;
  220. case 27:
  221. WRITE_FPR(27, value);
  222. break;
  223. case 28:
  224. WRITE_FPR(28, value);
  225. break;
  226. case 29:
  227. WRITE_FPR(29, value);
  228. break;
  229. case 30:
  230. WRITE_FPR(30, value);
  231. break;
  232. case 31:
  233. WRITE_FPR(31, value);
  234. break;
  235. default:
  236. panic("unexpected idx '%d'", idx);
  237. }
  238. #undef WRITE_FPR
  239. }
  240. void emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned int *pc)
  241. {
  242. bool fp = false;
  243. bool sign, write;
  244. bool user = user_mode(regs);
  245. unsigned int res, size = 0;
  246. unsigned long value = 0;
  247. union loongarch_instruction insn;
  248. perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
  249. __get_inst(&insn.word, pc, user);
  250. switch (insn.reg2i12_format.opcode) {
  251. case ldh_op:
  252. size = 2;
  253. sign = true;
  254. write = false;
  255. break;
  256. case ldhu_op:
  257. size = 2;
  258. sign = false;
  259. write = false;
  260. break;
  261. case sth_op:
  262. size = 2;
  263. sign = true;
  264. write = true;
  265. break;
  266. case ldw_op:
  267. size = 4;
  268. sign = true;
  269. write = false;
  270. break;
  271. case ldwu_op:
  272. size = 4;
  273. sign = false;
  274. write = false;
  275. break;
  276. case stw_op:
  277. size = 4;
  278. sign = true;
  279. write = true;
  280. break;
  281. case ldd_op:
  282. size = 8;
  283. sign = true;
  284. write = false;
  285. break;
  286. case std_op:
  287. size = 8;
  288. sign = true;
  289. write = true;
  290. break;
  291. case flds_op:
  292. size = 4;
  293. fp = true;
  294. sign = true;
  295. write = false;
  296. break;
  297. case fsts_op:
  298. size = 4;
  299. fp = true;
  300. sign = true;
  301. write = true;
  302. break;
  303. case fldd_op:
  304. size = 8;
  305. fp = true;
  306. sign = true;
  307. write = false;
  308. break;
  309. case fstd_op:
  310. size = 8;
  311. fp = true;
  312. sign = true;
  313. write = true;
  314. break;
  315. }
  316. switch (insn.reg2i14_format.opcode) {
  317. case ldptrw_op:
  318. size = 4;
  319. sign = true;
  320. write = false;
  321. break;
  322. case stptrw_op:
  323. size = 4;
  324. sign = true;
  325. write = true;
  326. break;
  327. case ldptrd_op:
  328. size = 8;
  329. sign = true;
  330. write = false;
  331. break;
  332. case stptrd_op:
  333. size = 8;
  334. sign = true;
  335. write = true;
  336. break;
  337. }
  338. switch (insn.reg3_format.opcode) {
  339. case ldxh_op:
  340. size = 2;
  341. sign = true;
  342. write = false;
  343. break;
  344. case ldxhu_op:
  345. size = 2;
  346. sign = false;
  347. write = false;
  348. break;
  349. case stxh_op:
  350. size = 2;
  351. sign = true;
  352. write = true;
  353. break;
  354. case ldxw_op:
  355. size = 4;
  356. sign = true;
  357. write = false;
  358. break;
  359. case ldxwu_op:
  360. size = 4;
  361. sign = false;
  362. write = false;
  363. break;
  364. case stxw_op:
  365. size = 4;
  366. sign = true;
  367. write = true;
  368. break;
  369. case ldxd_op:
  370. size = 8;
  371. sign = true;
  372. write = false;
  373. break;
  374. case stxd_op:
  375. size = 8;
  376. sign = true;
  377. write = true;
  378. break;
  379. case fldxs_op:
  380. size = 4;
  381. fp = true;
  382. sign = true;
  383. write = false;
  384. break;
  385. case fstxs_op:
  386. size = 4;
  387. fp = true;
  388. sign = true;
  389. write = true;
  390. break;
  391. case fldxd_op:
  392. size = 8;
  393. fp = true;
  394. sign = true;
  395. write = false;
  396. break;
  397. case fstxd_op:
  398. size = 8;
  399. fp = true;
  400. sign = true;
  401. write = true;
  402. break;
  403. }
  404. if (!size)
  405. goto sigbus;
  406. if (user && !access_ok(addr, size))
  407. goto sigbus;
  408. if (!write) {
  409. res = unaligned_read(addr, &value, size, sign);
  410. if (res)
  411. goto fault;
  412. /* Rd is the same field in any formats */
  413. if (!fp)
  414. regs->regs[insn.reg3_format.rd] = value;
  415. else {
  416. if (is_fpu_owner())
  417. write_fpr(insn.reg3_format.rd, value);
  418. else
  419. set_fpr64(&current->thread.fpu.fpr[insn.reg3_format.rd], 0, value);
  420. }
  421. } else {
  422. /* Rd is the same field in any formats */
  423. if (!fp)
  424. value = regs->regs[insn.reg3_format.rd];
  425. else {
  426. if (is_fpu_owner())
  427. value = read_fpr(insn.reg3_format.rd);
  428. else
  429. value = get_fpr64(&current->thread.fpu.fpr[insn.reg3_format.rd], 0);
  430. }
  431. res = unaligned_write(addr, value, size);
  432. if (res)
  433. goto fault;
  434. }
  435. #ifdef CONFIG_DEBUG_FS
  436. if (user)
  437. unaligned_instructions_user++;
  438. else
  439. unaligned_instructions_kernel++;
  440. #endif
  441. compute_return_era(regs);
  442. return;
  443. fault:
  444. /* Did we have an exception handler installed? */
  445. if (fixup_exception(regs))
  446. return;
  447. die_if_kernel("Unhandled kernel unaligned access", regs);
  448. force_sig(SIGSEGV);
  449. return;
  450. sigbus:
  451. die_if_kernel("Unhandled kernel unaligned access", regs);
  452. force_sig(SIGBUS);
  453. return;
  454. }
  455. #ifdef CONFIG_DEBUG_FS
  456. static int __init debugfs_unaligned(void)
  457. {
  458. struct dentry *d;
  459. d = debugfs_create_dir("loongarch", NULL);
  460. debugfs_create_u32("unaligned_instructions_user",
  461. S_IRUGO, d, &unaligned_instructions_user);
  462. debugfs_create_u32("unaligned_instructions_kernel",
  463. S_IRUGO, d, &unaligned_instructions_kernel);
  464. return 0;
  465. }
  466. arch_initcall(debugfs_unaligned);
  467. #endif