align.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /* align.c - handle alignment exceptions for the Power PC.
  2. *
  3. * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
  4. * Copyright (c) 1998-1999 TiVo, Inc.
  5. * PowerPC 403GCX modifications.
  6. * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  7. * PowerPC 403GCX/405GP modifications.
  8. * Copyright (c) 2001-2002 PPC64 team, IBM Corp
  9. * 64-bit and Power4 support
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License
  13. * as published by the Free Software Foundation; either version
  14. * 2 of the License, or (at your option) any later version.
  15. */
  16. #include <linux/kernel.h>
  17. #include <linux/mm.h>
  18. #include <asm/processor.h>
  19. #include <asm/uaccess.h>
  20. #include <asm/system.h>
  21. #include <asm/cache.h>
  22. #include <asm/cputable.h>
  23. struct aligninfo {
  24. unsigned char len;
  25. unsigned char flags;
  26. };
  27. #define IS_XFORM(inst) (((inst) >> 26) == 31)
  28. #define IS_DSFORM(inst) (((inst) >> 26) >= 56)
  29. #define INVALID { 0, 0 }
  30. #define LD 1 /* load */
  31. #define ST 2 /* store */
  32. #define SE 4 /* sign-extend value */
  33. #define F 8 /* to/from fp regs */
  34. #define U 0x10 /* update index register */
  35. #define M 0x20 /* multiple load/store */
  36. #define SW 0x40 /* byte swap */
  37. #define DCBZ 0x5f /* 8xx/82xx dcbz faults when cache not enabled */
  38. /*
  39. * The PowerPC stores certain bits of the instruction that caused the
  40. * alignment exception in the DSISR register. This array maps those
  41. * bits to information about the operand length and what the
  42. * instruction would do.
  43. */
  44. static struct aligninfo aligninfo[128] = {
  45. { 4, LD }, /* 00 0 0000: lwz / lwarx */
  46. INVALID, /* 00 0 0001 */
  47. { 4, ST }, /* 00 0 0010: stw */
  48. INVALID, /* 00 0 0011 */
  49. { 2, LD }, /* 00 0 0100: lhz */
  50. { 2, LD+SE }, /* 00 0 0101: lha */
  51. { 2, ST }, /* 00 0 0110: sth */
  52. { 4, LD+M }, /* 00 0 0111: lmw */
  53. { 4, LD+F }, /* 00 0 1000: lfs */
  54. { 8, LD+F }, /* 00 0 1001: lfd */
  55. { 4, ST+F }, /* 00 0 1010: stfs */
  56. { 8, ST+F }, /* 00 0 1011: stfd */
  57. INVALID, /* 00 0 1100 */
  58. { 8, LD }, /* 00 0 1101: ld */
  59. INVALID, /* 00 0 1110 */
  60. { 8, ST }, /* 00 0 1111: std */
  61. { 4, LD+U }, /* 00 1 0000: lwzu */
  62. INVALID, /* 00 1 0001 */
  63. { 4, ST+U }, /* 00 1 0010: stwu */
  64. INVALID, /* 00 1 0011 */
  65. { 2, LD+U }, /* 00 1 0100: lhzu */
  66. { 2, LD+SE+U }, /* 00 1 0101: lhau */
  67. { 2, ST+U }, /* 00 1 0110: sthu */
  68. { 4, ST+M }, /* 00 1 0111: stmw */
  69. { 4, LD+F+U }, /* 00 1 1000: lfsu */
  70. { 8, LD+F+U }, /* 00 1 1001: lfdu */
  71. { 4, ST+F+U }, /* 00 1 1010: stfsu */
  72. { 8, ST+F+U }, /* 00 1 1011: stfdu */
  73. INVALID, /* 00 1 1100 */
  74. INVALID, /* 00 1 1101 */
  75. INVALID, /* 00 1 1110 */
  76. INVALID, /* 00 1 1111 */
  77. { 8, LD }, /* 01 0 0000: ldx */
  78. INVALID, /* 01 0 0001 */
  79. { 8, ST }, /* 01 0 0010: stdx */
  80. INVALID, /* 01 0 0011 */
  81. INVALID, /* 01 0 0100 */
  82. { 4, LD+SE }, /* 01 0 0101: lwax */
  83. INVALID, /* 01 0 0110 */
  84. INVALID, /* 01 0 0111 */
  85. { 0, LD }, /* 01 0 1000: lswx */
  86. { 0, LD }, /* 01 0 1001: lswi */
  87. { 0, ST }, /* 01 0 1010: stswx */
  88. { 0, ST }, /* 01 0 1011: stswi */
  89. INVALID, /* 01 0 1100 */
  90. { 8, LD+U }, /* 01 0 1101: ldu */
  91. INVALID, /* 01 0 1110 */
  92. { 8, ST+U }, /* 01 0 1111: stdu */
  93. { 8, LD+U }, /* 01 1 0000: ldux */
  94. INVALID, /* 01 1 0001 */
  95. { 8, ST+U }, /* 01 1 0010: stdux */
  96. INVALID, /* 01 1 0011 */
  97. INVALID, /* 01 1 0100 */
  98. { 4, LD+SE+U }, /* 01 1 0101: lwaux */
  99. INVALID, /* 01 1 0110 */
  100. INVALID, /* 01 1 0111 */
  101. INVALID, /* 01 1 1000 */
  102. INVALID, /* 01 1 1001 */
  103. INVALID, /* 01 1 1010 */
  104. INVALID, /* 01 1 1011 */
  105. INVALID, /* 01 1 1100 */
  106. INVALID, /* 01 1 1101 */
  107. INVALID, /* 01 1 1110 */
  108. INVALID, /* 01 1 1111 */
  109. INVALID, /* 10 0 0000 */
  110. INVALID, /* 10 0 0001 */
  111. { 0, ST }, /* 10 0 0010: stwcx. */
  112. INVALID, /* 10 0 0011 */
  113. INVALID, /* 10 0 0100 */
  114. INVALID, /* 10 0 0101 */
  115. INVALID, /* 10 0 0110 */
  116. INVALID, /* 10 0 0111 */
  117. { 4, LD+SW }, /* 10 0 1000: lwbrx */
  118. INVALID, /* 10 0 1001 */
  119. { 4, ST+SW }, /* 10 0 1010: stwbrx */
  120. INVALID, /* 10 0 1011 */
  121. { 2, LD+SW }, /* 10 0 1100: lhbrx */
  122. { 4, LD+SE }, /* 10 0 1101 lwa */
  123. { 2, ST+SW }, /* 10 0 1110: sthbrx */
  124. INVALID, /* 10 0 1111 */
  125. INVALID, /* 10 1 0000 */
  126. INVALID, /* 10 1 0001 */
  127. INVALID, /* 10 1 0010 */
  128. INVALID, /* 10 1 0011 */
  129. INVALID, /* 10 1 0100 */
  130. INVALID, /* 10 1 0101 */
  131. INVALID, /* 10 1 0110 */
  132. INVALID, /* 10 1 0111 */
  133. INVALID, /* 10 1 1000 */
  134. INVALID, /* 10 1 1001 */
  135. INVALID, /* 10 1 1010 */
  136. INVALID, /* 10 1 1011 */
  137. INVALID, /* 10 1 1100 */
  138. INVALID, /* 10 1 1101 */
  139. INVALID, /* 10 1 1110 */
  140. { L1_CACHE_BYTES, ST }, /* 10 1 1111: dcbz */
  141. { 4, LD }, /* 11 0 0000: lwzx */
  142. INVALID, /* 11 0 0001 */
  143. { 4, ST }, /* 11 0 0010: stwx */
  144. INVALID, /* 11 0 0011 */
  145. { 2, LD }, /* 11 0 0100: lhzx */
  146. { 2, LD+SE }, /* 11 0 0101: lhax */
  147. { 2, ST }, /* 11 0 0110: sthx */
  148. INVALID, /* 11 0 0111 */
  149. { 4, LD+F }, /* 11 0 1000: lfsx */
  150. { 8, LD+F }, /* 11 0 1001: lfdx */
  151. { 4, ST+F }, /* 11 0 1010: stfsx */
  152. { 8, ST+F }, /* 11 0 1011: stfdx */
  153. INVALID, /* 11 0 1100 */
  154. { 8, LD+M }, /* 11 0 1101: lmd */
  155. INVALID, /* 11 0 1110 */
  156. { 8, ST+M }, /* 11 0 1111: stmd */
  157. { 4, LD+U }, /* 11 1 0000: lwzux */
  158. INVALID, /* 11 1 0001 */
  159. { 4, ST+U }, /* 11 1 0010: stwux */
  160. INVALID, /* 11 1 0011 */
  161. { 2, LD+U }, /* 11 1 0100: lhzux */
  162. { 2, LD+SE+U }, /* 11 1 0101: lhaux */
  163. { 2, ST+U }, /* 11 1 0110: sthux */
  164. INVALID, /* 11 1 0111 */
  165. { 4, LD+F+U }, /* 11 1 1000: lfsux */
  166. { 8, LD+F+U }, /* 11 1 1001: lfdux */
  167. { 4, ST+F+U }, /* 11 1 1010: stfsux */
  168. { 8, ST+F+U }, /* 11 1 1011: stfdux */
  169. INVALID, /* 11 1 1100 */
  170. INVALID, /* 11 1 1101 */
  171. INVALID, /* 11 1 1110 */
  172. INVALID, /* 11 1 1111 */
  173. };
  174. #define SWAP(a, b) (t = (a), (a) = (b), (b) = t)
  175. static inline unsigned make_dsisr(unsigned instr)
  176. {
  177. unsigned dsisr;
  178. /* create a DSISR value from the instruction */
  179. dsisr = (instr & 0x03ff0000) >> 16; /* bits 6:15 --> 22:31 */
  180. if ( IS_XFORM(instr) ) {
  181. dsisr |= (instr & 0x00000006) << 14; /* bits 29:30 --> 15:16 */
  182. dsisr |= (instr & 0x00000040) << 8; /* bit 25 --> 17 */
  183. dsisr |= (instr & 0x00000780) << 3; /* bits 21:24 --> 18:21 */
  184. }
  185. else {
  186. dsisr |= (instr & 0x04000000) >> 12; /* bit 5 --> 17 */
  187. dsisr |= (instr & 0x78000000) >> 17; /* bits 1: 4 --> 18:21 */
  188. if ( IS_DSFORM(instr) ) {
  189. dsisr |= (instr & 0x00000003) << 18; /* bits 30:31 --> 12:13 */
  190. }
  191. }
  192. return dsisr;
  193. }
  194. int
  195. fix_alignment(struct pt_regs *regs)
  196. {
  197. unsigned int instr, nb, flags;
  198. int t;
  199. unsigned long reg, areg;
  200. unsigned long i;
  201. int ret;
  202. unsigned dsisr;
  203. unsigned char __user *addr;
  204. unsigned char __user *p;
  205. unsigned long __user *lp;
  206. union {
  207. long ll;
  208. double dd;
  209. unsigned char v[8];
  210. struct {
  211. unsigned hi32;
  212. int low32;
  213. } x32;
  214. struct {
  215. unsigned char hi48[6];
  216. short low16;
  217. } x16;
  218. } data;
  219. /*
  220. * Return 1 on success
  221. * Return 0 if unable to handle the interrupt
  222. * Return -EFAULT if data address is bad
  223. */
  224. dsisr = regs->dsisr;
  225. if (cpu_has_feature(CPU_FTR_NODSISRALIGN)) {
  226. unsigned int real_instr;
  227. if (__get_user(real_instr, (unsigned int __user *)regs->nip))
  228. return 0;
  229. dsisr = make_dsisr(real_instr);
  230. }
  231. /* extract the operation and registers from the dsisr */
  232. reg = (dsisr >> 5) & 0x1f; /* source/dest register */
  233. areg = dsisr & 0x1f; /* register to update */
  234. instr = (dsisr >> 10) & 0x7f;
  235. instr |= (dsisr >> 13) & 0x60;
  236. /* Lookup the operation in our table */
  237. nb = aligninfo[instr].len;
  238. flags = aligninfo[instr].flags;
  239. /* DAR has the operand effective address */
  240. addr = (unsigned char __user *)regs->dar;
  241. /* A size of 0 indicates an instruction we don't support */
  242. /* we also don't support the multiples (lmw, stmw, lmd, stmd) */
  243. if ((nb == 0) || (flags & M))
  244. return 0; /* too hard or invalid instruction */
  245. /*
  246. * Special handling for dcbz
  247. * dcbz may give an alignment exception for accesses to caching inhibited
  248. * storage
  249. */
  250. if (instr == DCBZ)
  251. addr = (unsigned char __user *) ((unsigned long)addr & -L1_CACHE_BYTES);
  252. /* Verify the address of the operand */
  253. if (user_mode(regs)) {
  254. if (!access_ok((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
  255. return -EFAULT; /* bad address */
  256. }
  257. /* Force the fprs into the save area so we can reference them */
  258. if (flags & F) {
  259. if (!user_mode(regs))
  260. return 0;
  261. flush_fp_to_thread(current);
  262. }
  263. /* If we are loading, get the data from user space */
  264. if (flags & LD) {
  265. data.ll = 0;
  266. ret = 0;
  267. p = addr;
  268. switch (nb) {
  269. case 8:
  270. ret |= __get_user(data.v[0], p++);
  271. ret |= __get_user(data.v[1], p++);
  272. ret |= __get_user(data.v[2], p++);
  273. ret |= __get_user(data.v[3], p++);
  274. case 4:
  275. ret |= __get_user(data.v[4], p++);
  276. ret |= __get_user(data.v[5], p++);
  277. case 2:
  278. ret |= __get_user(data.v[6], p++);
  279. ret |= __get_user(data.v[7], p++);
  280. if (ret)
  281. return -EFAULT;
  282. }
  283. }
  284. /* If we are storing, get the data from the saved gpr or fpr */
  285. if (flags & ST) {
  286. if (flags & F) {
  287. if (nb == 4) {
  288. /* Doing stfs, have to convert to single */
  289. preempt_disable();
  290. enable_kernel_fp();
  291. cvt_df(&current->thread.fpr[reg], (float *)&data.v[4], &current->thread.fpscr);
  292. disable_kernel_fp();
  293. preempt_enable();
  294. }
  295. else
  296. data.dd = current->thread.fpr[reg];
  297. }
  298. else
  299. data.ll = regs->gpr[reg];
  300. }
  301. /* Swap bytes as needed */
  302. if (flags & SW) {
  303. if (nb == 2)
  304. SWAP(data.v[6], data.v[7]);
  305. else { /* nb must be 4 */
  306. SWAP(data.v[4], data.v[7]);
  307. SWAP(data.v[5], data.v[6]);
  308. }
  309. }
  310. /* Sign extend as needed */
  311. if (flags & SE) {
  312. if ( nb == 2 )
  313. data.ll = data.x16.low16;
  314. else /* nb must be 4 */
  315. data.ll = data.x32.low32;
  316. }
  317. /* If we are loading, move the data to the gpr or fpr */
  318. if (flags & LD) {
  319. if (flags & F) {
  320. if (nb == 4) {
  321. /* Doing lfs, have to convert to double */
  322. preempt_disable();
  323. enable_kernel_fp();
  324. cvt_fd((float *)&data.v[4], &current->thread.fpr[reg], &current->thread.fpscr);
  325. disable_kernel_fp();
  326. preempt_enable();
  327. }
  328. else
  329. current->thread.fpr[reg] = data.dd;
  330. }
  331. else
  332. regs->gpr[reg] = data.ll;
  333. }
  334. /* If we are storing, copy the data to the user */
  335. if (flags & ST) {
  336. ret = 0;
  337. p = addr;
  338. switch (nb) {
  339. case 128: /* Special case - must be dcbz */
  340. lp = (unsigned long __user *)p;
  341. for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i)
  342. ret |= __put_user(0, lp++);
  343. break;
  344. case 8:
  345. ret |= __put_user(data.v[0], p++);
  346. ret |= __put_user(data.v[1], p++);
  347. ret |= __put_user(data.v[2], p++);
  348. ret |= __put_user(data.v[3], p++);
  349. case 4:
  350. ret |= __put_user(data.v[4], p++);
  351. ret |= __put_user(data.v[5], p++);
  352. case 2:
  353. ret |= __put_user(data.v[6], p++);
  354. ret |= __put_user(data.v[7], p++);
  355. }
  356. if (ret)
  357. return -EFAULT;
  358. }
  359. /* Update RA as needed */
  360. if (flags & U) {
  361. regs->gpr[areg] = regs->dar;
  362. }
  363. return 1;
  364. }