copy_user.S
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* copy_user.S: Sparc optimized copy_from_user and copy_to_user code.
  2.  *
  3.  *  Copyright(C) 1995 Linus Torvalds
  4.  *  Copyright(C) 1996 David S. Miller
  5.  *  Copyright(C) 1996 Eddie C. Dost
  6.  *  Copyright(C) 1996,1998 Jakub Jelinek
  7.  *
  8.  * derived from:
  9.  * e-mail between David and Eddie.
  10.  *
  11.  * Returns 0 if successful, otherwise count of bytes not copied yet
  12.  */
  13. #include <asm/cprefix.h>
  14. #include <asm/ptrace.h>
  15. #include <asm/asmmacro.h>
  16. #include <asm/page.h>
  17. #define EX(x,y,a,b,z) 
  18. 98:  x,y;
  19. .section .fixup,z##alloc,z##execinstr;
  20. .align 4;
  21. 99: ba fixupretl;
  22.  a, b, %g3;
  23. .section __ex_table,z##alloc;
  24. .align 4;
  25. .word 98b, 99b;
  26. .text;
  27. .align 4
  28. #define EX2(x,y,c,d,e,a,b,z) 
  29. 98:  x,y;
  30. .section .fixup,z##alloc,z##execinstr;
  31. .align 4;
  32. 99: c, d, e;
  33. ba fixupretl;
  34.  a, b, %g3;
  35. .section __ex_table,z##alloc;
  36. .align 4;
  37. .word 98b, 99b;
  38. .text;
  39. .align 4
  40. #define EXO2(x,y,z) 
  41. 98:  x,##y;
  42. .section __ex_table,z##alloc;
  43. .align 4;
  44. .word 98b, 97f;
  45. .text;
  46. .align 4
  47. #define EXT(start,end,handler,z) 
  48. .section __ex_table,z##alloc;
  49. .align 4;
  50. .word start, 0, end, handler;
  51. .text;
  52. .align 4
  53. /* Please do not change following macros unless you change logic used
  54.  * in .fixup at the end of this file as well
  55.  */
  56. /* Both these macros have to start with exactly the same insn */
  57. #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) 
  58. ldd [%src + offset + 0x00], %t0; 
  59. ldd [%src + offset + 0x08], %t2; 
  60. ldd [%src + offset + 0x10], %t4; 
  61. ldd [%src + offset + 0x18], %t6; 
  62. st %t0, [%dst + offset + 0x00]; 
  63. st %t1, [%dst + offset + 0x04]; 
  64. st %t2, [%dst + offset + 0x08]; 
  65. st %t3, [%dst + offset + 0x0c]; 
  66. st %t4, [%dst + offset + 0x10]; 
  67. st %t5, [%dst + offset + 0x14]; 
  68. st %t6, [%dst + offset + 0x18]; 
  69. st %t7, [%dst + offset + 0x1c];
  70. #define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) 
  71. ldd [%src + offset + 0x00], %t0; 
  72. ldd [%src + offset + 0x08], %t2; 
  73. ldd [%src + offset + 0x10], %t4; 
  74. ldd [%src + offset + 0x18], %t6; 
  75. std %t0, [%dst + offset + 0x00]; 
  76. std %t2, [%dst + offset + 0x08]; 
  77. std %t4, [%dst + offset + 0x10]; 
  78. std %t6, [%dst + offset + 0x18];
  79. #define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) 
  80. ldd [%src - offset - 0x10], %t0; 
  81. ldd [%src - offset - 0x08], %t2; 
  82. st %t0, [%dst - offset - 0x10]; 
  83. st %t1, [%dst - offset - 0x0c]; 
  84. st %t2, [%dst - offset - 0x08]; 
  85. st %t3, [%dst - offset - 0x04];
  86. #define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) 
  87. lduh [%src + offset + 0x00], %t0; 
  88. lduh [%src + offset + 0x02], %t1; 
  89. lduh [%src + offset + 0x04], %t2; 
  90. lduh [%src + offset + 0x06], %t3; 
  91. sth %t0, [%dst + offset + 0x00]; 
  92. sth %t1, [%dst + offset + 0x02]; 
  93. sth %t2, [%dst + offset + 0x04]; 
  94. sth %t3, [%dst + offset + 0x06];
  95. #define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) 
  96. ldub [%src - offset - 0x02], %t0; 
  97. ldub [%src - offset - 0x01], %t1; 
  98. stb %t0, [%dst - offset - 0x02]; 
  99. stb %t1, [%dst - offset - 0x01];
  100. .text
  101. .align 4
  102. .globl  __copy_user_begin
  103. __copy_user_begin:
  104. .globl C_LABEL(__copy_user)
  105. dword_align:
  106. andcc %o1, 1, %g0
  107. be 4f
  108.  andcc %o1, 2, %g0
  109. EXO2(ldub [%o1], %g2,#)
  110. add %o1, 1, %o1
  111. EXO2(stb %g2, [%o0],#)
  112. sub %o2, 1, %o2
  113. bne 3f
  114.  add %o0, 1, %o0
  115. EXO2(lduh [%o1], %g2,#)
  116. add %o1, 2, %o1
  117. EXO2(sth %g2, [%o0],#)
  118. sub %o2, 2, %o2
  119. b 3f
  120.  add %o0, 2, %o0
  121. 4:
  122. EXO2(lduh [%o1], %g2,#)
  123. add %o1, 2, %o1
  124. EXO2(sth %g2, [%o0],#)
  125. sub %o2, 2, %o2
  126. b 3f
  127.  add %o0, 2, %o0
  128. C_LABEL(__copy_user): /* %o0=dst %o1=src %o2=len */
  129. xor %o0, %o1, %o4
  130. 1:
  131. andcc %o4, 3, %o5
  132. 2:
  133. bne cannot_optimize
  134.  cmp %o2, 15
  135. bleu short_aligned_end
  136.  andcc %o1, 3, %g0
  137. bne dword_align
  138. 3:
  139.  andcc %o1, 4, %g0
  140. be 2f
  141.  mov %o2, %g1
  142. EXO2(ld [%o1], %o4,#)
  143. sub %g1, 4, %g1
  144. EXO2(st %o4, [%o0],#)
  145. add %o1, 4, %o1
  146. add %o0, 4, %o0
  147. 2:
  148. andcc %g1, 0xffffff80, %g7
  149. be 3f
  150.  andcc %o0, 4, %g0
  151. be ldd_std + 4
  152. 5:
  153. MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
  154. MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
  155. MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
  156. MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
  157. 80:
  158. EXT(5b, 80b, 50f,#)
  159. subcc %g7, 128, %g7
  160. add %o1, 128, %o1
  161. bne 5b
  162.  add %o0, 128, %o0
  163. 3:
  164. andcc %g1, 0x70, %g7
  165. be copy_user_table_end
  166.  andcc %g1, 8, %g0
  167. sethi %hi(copy_user_table_end), %o5
  168. srl %g7, 1, %o4
  169. add %g7, %o4, %o4
  170. add %o1, %g7, %o1
  171. sub %o5, %o4, %o5
  172. jmpl %o5 + %lo(copy_user_table_end), %g0
  173.  add %o0, %g7, %o0
  174. copy_user_table:
  175. MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
  176. MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
  177. MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
  178. MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
  179. MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
  180. MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
  181. MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
  182. copy_user_table_end:
  183. EXT(copy_user_table, copy_user_table_end, 51f,#)
  184. be copy_user_last7
  185.  andcc %g1, 4, %g0
  186. EX(ldd [%o1], %g2, and %g1, 0xf,#)
  187. add %o0, 8, %o0
  188. add %o1, 8, %o1
  189. EX(st %g2, [%o0 - 0x08], and %g1, 0xf,#)
  190. EX2(st %g3, [%o0 - 0x04], and %g1, 0xf, %g1, sub %g1, 4,#)
  191. copy_user_last7:
  192. be 1f
  193.  andcc %g1, 2, %g0
  194. EX(ld [%o1], %g2, and %g1, 7,#)
  195. add %o1, 4, %o1
  196. EX(st %g2, [%o0], and %g1, 7,#)
  197. add %o0, 4, %o0
  198. 1:
  199. be 1f
  200.  andcc %g1, 1, %g0
  201. EX(lduh [%o1], %g2, and %g1, 3,#)
  202. add %o1, 2, %o1
  203. EX(sth %g2, [%o0], and %g1, 3,#)
  204. add %o0, 2, %o0
  205. 1:
  206. be 1f
  207.  nop
  208. EX(ldub [%o1], %g2, add %g0, 1,#)
  209. EX(stb %g2, [%o0], add %g0, 1,#)
  210. 1:
  211. retl
  212.    clr %o0
  213. ldd_std:
  214. MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
  215. MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
  216. MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
  217. MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
  218. 81:
  219. EXT(ldd_std, 81b, 52f,#)
  220. subcc %g7, 128, %g7
  221. add %o1, 128, %o1
  222. bne ldd_std
  223.  add %o0, 128, %o0
  224. andcc %g1, 0x70, %g7
  225. be copy_user_table_end
  226.  andcc %g1, 8, %g0
  227. sethi %hi(copy_user_table_end), %o5
  228. srl %g7, 1, %o4
  229. add %g7, %o4, %o4
  230. add %o1, %g7, %o1
  231. sub %o5, %o4, %o5
  232. jmpl %o5 + %lo(copy_user_table_end), %g0
  233.  add %o0, %g7, %o0
  234. cannot_optimize:
  235. bleu short_end
  236.  cmp %o5, 2
  237. bne byte_chunk
  238.  and %o2, 0xfffffff0, %o3
  239.  
  240. andcc %o1, 1, %g0
  241. be 10f
  242.  nop
  243. EXO2(ldub [%o1], %g2,#)
  244. add %o1, 1, %o1
  245. EXO2(stb %g2, [%o0],#)
  246. sub %o2, 1, %o2
  247. andcc %o2, 0xfffffff0, %o3
  248. be short_end
  249.  add %o0, 1, %o0
  250. 10:
  251. MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
  252. MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5)
  253. 82:
  254. EXT(10b, 82b, 53f,#)
  255. subcc %o3, 0x10, %o3
  256. add %o1, 0x10, %o1
  257. bne 10b
  258.  add %o0, 0x10, %o0
  259. b 2f
  260.  and %o2, 0xe, %o3
  261. byte_chunk:
  262. MOVE_SHORTCHUNK(o1, o0, -0x02, g2, g3)
  263. MOVE_SHORTCHUNK(o1, o0, -0x04, g2, g3)
  264. MOVE_SHORTCHUNK(o1, o0, -0x06, g2, g3)
  265. MOVE_SHORTCHUNK(o1, o0, -0x08, g2, g3)
  266. MOVE_SHORTCHUNK(o1, o0, -0x0a, g2, g3)
  267. MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3)
  268. MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3)
  269. MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3)
  270. 83:
  271. EXT(byte_chunk, 83b, 54f,#)
  272. subcc %o3, 0x10, %o3
  273. add %o1, 0x10, %o1
  274. bne byte_chunk
  275.  add %o0, 0x10, %o0
  276. short_end:
  277. and %o2, 0xe, %o3
  278. 2:
  279. sethi %hi(short_table_end), %o5
  280. sll %o3, 3, %o4
  281. add %o0, %o3, %o0
  282. sub %o5, %o4, %o5
  283. add %o1, %o3, %o1
  284. jmpl %o5 + %lo(short_table_end), %g0
  285.  andcc %o2, 1, %g0
  286. 84:
  287. MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
  288. MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
  289. MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
  290. MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
  291. MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
  292. MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
  293. MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
  294. short_table_end:
  295. EXT(84b, short_table_end, 55f,#)
  296. be 1f
  297.  nop
  298. EX(ldub [%o1], %g2, add %g0, 1,#)
  299. EX(stb %g2, [%o0], add %g0, 1,#)
  300. 1:
  301. retl
  302.    clr %o0
  303. short_aligned_end:
  304. bne short_end
  305.  andcc %o2, 8, %g0
  306. be 1f
  307.  andcc %o2, 4, %g0
  308. EXO2(ld [%o1 + 0x00], %g2,#)
  309. EXO2(ld [%o1 + 0x04], %g3,#)
  310. add %o1, 8, %o1
  311. EXO2(st %g2, [%o0 + 0x00],#)
  312. EX(st %g3, [%o0 + 0x04], sub %o2, 4,#)
  313. add %o0, 8, %o0
  314. 1:
  315. b copy_user_last7
  316.  mov %o2, %g1
  317. .section .fixup,#alloc,#execinstr
  318. .align 4
  319. 97:
  320. mov %o2, %g3
  321. fixupretl:
  322. sethi   %hi(PAGE_OFFSET), %g1
  323. cmp %o0, %g1
  324. blu 1f
  325.  cmp %o1, %g1
  326. bgeu 1f
  327.  nop
  328. save %sp, -64, %sp
  329. mov %i0, %o0
  330. call __bzero
  331.  mov %g3, %o1
  332. restore
  333. 1: retl
  334.  mov %g3, %o0
  335. /* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
  336. 50:
  337. /* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK
  338.  * happens. This is derived from the amount ldd reads, st stores, etc.
  339.  * x = g2 % 12;
  340.  * g3 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? 0 : (x - 4) * 4);
  341.  * o0 += (g2 / 12) * 32;
  342.  */
  343. cmp %g2, 12
  344. add %o0, %g7, %o0
  345. bcs 1f
  346.  cmp %g2, 24
  347. bcs 2f
  348.  cmp %g2, 36
  349. bcs 3f
  350.  nop
  351. sub %g2, 12, %g2
  352. sub %g7, 32, %g7
  353. 3: sub %g2, 12, %g2
  354. sub %g7, 32, %g7
  355. 2: sub %g2, 12, %g2
  356. sub %g7, 32, %g7
  357. 1: cmp %g2, 4
  358. bcs,a 60f
  359.  clr %g2
  360. sub %g2, 4, %g2
  361. sll %g2, 2, %g2
  362. 60: and %g1, 0x7f, %g3
  363. sub %o0, %g7, %o0
  364. add %g3, %g7, %g3
  365. ba fixupretl
  366.  sub %g3, %g2, %g3
  367. 51:
  368. /* i = 41 - g2; j = i % 6;
  369.  * g3 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : 16;
  370.  * o0 -= (i / 6) * 16 + 16;
  371.  */
  372. neg %g2
  373. and %g1, 0xf, %g1
  374. add %g2, 41, %g2
  375. add %o0, %g1, %o0
  376. 1: cmp %g2, 6
  377. bcs,a 2f
  378.  cmp %g2, 4
  379. add %g1, 16, %g1
  380. b 1b
  381.  sub %g2, 6, %g2
  382. 2: bcc,a 2f
  383.  mov 16, %g2
  384. inc %g2
  385. sll %g2, 2, %g2
  386. 2: add %g1, %g2, %g3
  387. ba fixupretl
  388.  sub %o0, %g3, %o0
  389. 52:
  390. /* g3 = g1 + g7 - (g2 / 8) * 32 + (g2 & 4) ? (g2 & 3) * 8 : 0;
  391.    o0 += (g2 / 8) * 32 */
  392. andn %g2, 7, %g4
  393. add %o0, %g7, %o0
  394. andcc %g2, 4, %g0
  395. and %g2, 3, %g2
  396. sll %g4, 2, %g4
  397. sll %g2, 3, %g2
  398. bne 60b
  399.  sub %g7, %g4, %g7
  400. ba 60b
  401.  clr %g2
  402. 53:
  403. /* g3 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 4) ? (g2 & 3) * 2 : 0;
  404.    o0 += (g2 & 8) */
  405. and %g2, 3, %g4
  406. andcc %g2, 4, %g0
  407. and %g2, 8, %g2
  408. sll %g4, 1, %g4
  409. be 1f
  410.  add %o0, %g2, %o0
  411. add %g2, %g4, %g2
  412. 1: and %o2, 0xf, %g3
  413. add %g3, %o3, %g3
  414. ba fixupretl
  415.  sub %g3, %g2, %g3
  416. 54:
  417. /* g3 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 2) ? (g2 & 1) : 0;
  418.    o0 += (g2 / 4) * 2 */
  419. srl %g2, 2, %o4
  420. and %g2, 1, %o5
  421. srl %g2, 1, %g2
  422. add %o4, %o4, %o4
  423. and %o5, %g2, %o5
  424. and %o2, 0xf, %o2
  425. add %o0, %o4, %o0
  426. sub %o3, %o5, %o3
  427. sub %o2, %o4, %o2
  428. ba fixupretl
  429.  add %o2, %o3, %g3
  430. 55:
  431. /* i = 27 - g2;
  432.    g3 = (o2 & 1) + i / 4 * 2 + !(i & 3);
  433.    o0 -= i / 4 * 2 + 1 */
  434. neg %g2
  435. and %o2, 1, %o2
  436. add %g2, 27, %g2
  437. srl %g2, 2, %o5
  438. andcc %g2, 3, %g0
  439. mov 1, %g2
  440. add %o5, %o5, %o5
  441. be,a 1f
  442.  clr %g2
  443. 1: add %g2, %o5, %g3
  444. sub %o0, %g3, %o0
  445. ba fixupretl
  446.  add %g3, %o2, %g3
  447. .globl  __copy_user_end
  448. __copy_user_end: