memcpy.S
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:12k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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.  * Unified implementation of memcpy, memmove and the __copy_user backend.
  7.  *
  8.  * Copyright (C) 1998, 99, 2000, 01, 2002 Ralf Baechle (ralf@gnu.org)
  9.  * Copyright (C) 1999, 2000, 01, 2002 Silicon Graphics, Inc.
  10.  * Copyright (C) 2002 Broadcom, Inc.
  11.  *   memcpy/copy_user author: Mark Vandevoorde
  12.  *
  13.  * Mnemonic names for arguments to memcpy/__copy_user
  14.  */
  15. #include <linux/config.h>
  16. #include <asm/asm.h>
  17. #include <asm/offset.h>
  18. #include <asm/regdef.h>
  19. #define dst a0
  20. #define src a1
  21. #define len a2
  22. /*
  23.  * Spec
  24.  *
  25.  * memcpy copies len bytes from src to dst and sets v0 to dst.
  26.  * It assumes that
  27.  *   - src and dst don't overlap
  28.  *   - src is readable
  29.  *   - dst is writable
  30.  * memcpy uses the standard calling convention
  31.  *
  32.  * __copy_user copies up to len bytes from src to dst and sets a2 (len) to
  33.  * the number of uncopied bytes due to an exception caused by a read or write.
  34.  * __copy_user assumes that src and dst don't overlap, and that the call is
  35.  * implementing one of the following:
  36.  *   copy_to_user
  37.  *     - src is readable  (no exceptions when reading src)
  38.  *   copy_from_user
  39.  *     - dst is writable  (no exceptions when writing dst)
  40.  * __copy_user uses a non-standard calling convention; see
  41.  * include/asm-mips/uaccess.h
  42.  *
  43.  * When an exception happens on a load, the handler must
  44.  # ensure that all of the destination buffer is overwritten to prevent
  45.  * leaking information to user mode programs.
  46.  */
  47. /*
  48.  * Implementation
  49.  */
  50. /*
  51.  * The exception handler for loads requires that:
  52.  *  1- AT contain the address of the byte just past the end of the source
  53.  *     of the copy,
  54.  *  2- src_entry <= src < AT, and
  55.  *  3- (dst - src) == (dst_entry - src_entry),
  56.  * The _entry suffix denotes values when __copy_user was called.
  57.  *
  58.  * (1) is set up up by uaccess.h and maintained by not writing AT in copy_user
  59.  * (2) is met by incrementing src by the number of bytes copied
  60.  * (3) is met by not doing loads between a pair of increments of dst and src
  61.  *
  62.  * The exception handlers for stores adjust len (if necessary) and return.
  63.  * These handlers do not need to overwrite any data.
  64.  *
  65.  * For __rmemcpy and memmove an exception is always a kernel bug, therefore
  66.  * they're not protected.
  67.  */
  68. #define EXC(inst_reg,addr,handler)
  69. 9: inst_reg, addr;
  70. .section __ex_table,"a";
  71. PTR 9b, handler;
  72. .previous
  73. /*
  74.  * In the mips (not mips64) tree, so we can't use doubles
  75.  */
  76. #undef USE_DOUBLE
  77. #if defined(USE_DOUBLE)
  78. #define LOAD   ld
  79. #define LOADL  ldl
  80. #define LOADR  ldr
  81. #define STOREL sdl
  82. #define STORER sdr
  83. #define STORE  sd
  84. #define ADD    daddu
  85. #define SUB    dsubu
  86. #define SRL    dsrl
  87. #define SRA    dsra
  88. #define SLL    dsll
  89. #define SLLV   dsllv
  90. #define SRLV   dsrlv
  91. #define NBYTES 8
  92. #define LOG_NBYTES 3
  93. #else
  94. #define LOAD   lw
  95. #define LOADL  lwl
  96. #define LOADR  lwr
  97. #define STOREL swl
  98. #define STORER swr
  99. #define STORE  sw
  100. #define ADD    addu
  101. #define SUB    subu
  102. #define SRL    srl
  103. #define SLL    sll
  104. #define SRA    sra
  105. #define SLLV   sllv
  106. #define SRLV   srlv
  107. #define NBYTES 4
  108. #define LOG_NBYTES 2
  109. #endif /* USE_DOUBLE */
  110. #ifdef CONFIG_CPU_LITTLE_ENDIAN
  111. #define LDFIRST LOADR
  112. #define LDREST  LOADL
  113. #define STFIRST STORER
  114. #define STREST  STOREL
  115. #define SHIFT_DISCARD SLLV
  116. #else
  117. #define LDFIRST LOADL
  118. #define LDREST  LOADR
  119. #define STFIRST STOREL
  120. #define STREST  STORER
  121. #define SHIFT_DISCARD SRLV
  122. #endif
  123. #define FIRST(unit) ((unit)*NBYTES)
  124. #define REST(unit)  (FIRST(unit)+NBYTES-1)
  125. #define UNIT(unit)  FIRST(unit)
  126. #define ADDRMASK (NBYTES-1)
  127. .text
  128. .set noreorder
  129. .set noat
  130. /*
  131.  * A combined memcpy/__copy_user
  132.  * __copy_user sets len to 0 for success; else to an upper bound of
  133.  * the number of uncopied bytes.
  134.  * memcpy sets v0 to dst.
  135.  */
  136. .align 5
  137. LEAF(memcpy) /* a0=dst a1=src a2=len */
  138. move v0, dst /* return value */
  139. __memcpy:
  140. FEXPORT(__copy_user)
  141. /*
  142.  * Note: dst & src may be unaligned, len may be 0
  143.  * Temps
  144.  */
  145. #define rem t8
  146. /*
  147.  * The "issue break"s below are very approximate.
  148.  * Issue delays for dcache fills will perturb the schedule, as will
  149.  * load queue full replay traps, etc.
  150.  *
  151.  * If len < NBYTES use byte operations.
  152.  */
  153. PREF( 0, 0(src) )
  154. PREF( 1, 0(dst) )
  155. sltu t2, len, NBYTES
  156. and t1, dst, ADDRMASK
  157. PREF( 0, 1*32(src) )
  158. PREF( 1, 1*32(dst) )
  159. bnez t2, copy_bytes_checklen
  160.  and t0, src, ADDRMASK
  161. PREF( 0, 2*32(src) )
  162. PREF( 1, 2*32(dst) )
  163. bnez t1, dst_unaligned
  164.  nop
  165. bnez t0, src_unaligned_dst_aligned
  166. /*
  167.  * use delay slot for fall-through
  168.  * src and dst are aligned; need to compute rem
  169.  */
  170. both_aligned:
  171.  SRL t0, len, LOG_NBYTES+3    # +3 for 8 units/iter
  172. beqz t0, cleanup_both_aligned # len < 8*NBYTES
  173.  and rem, len, (8*NBYTES-1)  # rem = len % (8*NBYTES)
  174. PREF( 0, 3*32(src) )
  175. PREF( 1, 3*32(dst) )
  176. .align 4
  177. 1:
  178. EXC( LOAD t0, UNIT(0)(src), l_exc)
  179. EXC( LOAD t1, UNIT(1)(src), l_exc_copy)
  180. EXC( LOAD t2, UNIT(2)(src), l_exc_copy)
  181. EXC( LOAD t3, UNIT(3)(src), l_exc_copy)
  182. SUB len, len, 8*NBYTES
  183. EXC( LOAD t4, UNIT(4)(src), l_exc_copy)
  184. EXC( LOAD t7, UNIT(5)(src), l_exc_copy)
  185. EXC( STORE t0, UNIT(0)(dst), s_exc_p8u)
  186. EXC( STORE t1, UNIT(1)(dst), s_exc_p7u)
  187. EXC( LOAD t0, UNIT(6)(src), l_exc_copy)
  188. EXC( LOAD t1, UNIT(7)(src), l_exc_copy)
  189. ADD src, src, 8*NBYTES
  190. ADD dst, dst, 8*NBYTES
  191. EXC( STORE t2, UNIT(-6)(dst), s_exc_p6u)
  192. EXC( STORE t3, UNIT(-5)(dst), s_exc_p5u)
  193. EXC( STORE t4, UNIT(-4)(dst), s_exc_p4u)
  194. EXC( STORE t7, UNIT(-3)(dst), s_exc_p3u)
  195. EXC( STORE t0, UNIT(-2)(dst), s_exc_p2u)
  196. EXC( STORE t1, UNIT(-1)(dst), s_exc_p1u)
  197. PREF( 0, 8*32(src) )
  198. PREF( 1, 8*32(dst) )
  199. bne len, rem, 1b
  200.  nop
  201. /*
  202.  * len == rem == the number of bytes left to copy < 8*NBYTES
  203.  */
  204. cleanup_both_aligned:
  205. beqz len, done
  206.  sltu t0, len, 4*NBYTES
  207. bnez t0, less_than_4units
  208.  and rem, len, (NBYTES-1) # rem = len % NBYTES
  209. /*
  210.  * len >= 4*NBYTES
  211.  */
  212. EXC( LOAD t0, UNIT(0)(src), l_exc)
  213. EXC( LOAD t1, UNIT(1)(src), l_exc_copy)
  214. EXC( LOAD t2, UNIT(2)(src), l_exc_copy)
  215. EXC( LOAD t3, UNIT(3)(src), l_exc_copy)
  216. SUB len, len, 4*NBYTES
  217. ADD src, src, 4*NBYTES
  218. EXC( STORE t0, UNIT(0)(dst), s_exc_p4u)
  219. EXC( STORE t1, UNIT(1)(dst), s_exc_p3u)
  220. EXC( STORE t2, UNIT(2)(dst), s_exc_p2u)
  221. EXC( STORE t3, UNIT(3)(dst), s_exc_p1u)
  222. beqz len, done
  223.  ADD dst, dst, 4*NBYTES
  224. less_than_4units:
  225. /*
  226.  * rem = len % NBYTES
  227.  */
  228. beq rem, len, copy_bytes
  229.  nop
  230. 1:
  231. EXC( LOAD  t0, 0(src), l_exc)
  232. ADD src, src, NBYTES
  233. SUB len, len, NBYTES
  234. EXC( STORE t0, 0(dst), s_exc_p1u)
  235. bne rem, len, 1b
  236.  ADD dst, dst, NBYTES
  237. /*
  238.  * src and dst are aligned, need to copy rem bytes (rem < NBYTES)
  239.  * A loop would do only a byte at a time with possible branch
  240.  * mispredicts.  Can't do an explicit LOAD dst,mask,or,STORE
  241.  * because can't assume read-access to dst.  Instead, use
  242.  * STREST dst, which doesn't require read access to dst.
  243.  *
  244.  * This code should perform better than a simple loop on modern,
  245.  * wide-issue mips processors because the code has fewer branches and
  246.  * more instruction-level parallelism.
  247.  */
  248. #define bits t2
  249. beqz len, done
  250.  ADD t1, dst, len # t1 is just past last byte of dst
  251. li bits, 8*NBYTES
  252. SLL rem, len, 3 # rem = number of bits to keep
  253. EXC( LOAD t0, 0(src), l_exc)
  254. SUB bits, bits, rem # bits = number of bits to discard
  255. SHIFT_DISCARD t0, t0, bits
  256. EXC( STREST t0, -1(t1), s_exc)
  257. jr ra
  258.  move len, zero
  259. dst_unaligned:
  260. /*
  261.  * dst is unaligned
  262.  * t0 = src & ADDRMASK
  263.  * t1 = dst & ADDRMASK; T1 > 0
  264.  * len >= NBYTES
  265.  *
  266.  * Copy enough bytes to align dst
  267.  * Set match = (src and dst have same alignment)
  268.  */
  269. #define match rem
  270. EXC( LDFIRST t3, FIRST(0)(src), l_exc)
  271. ADD t2, zero, NBYTES
  272. EXC( LDREST t3, REST(0)(src), l_exc_copy)
  273. SUB t2, t2, t1 # t2 = number of bytes copied
  274. xor match, t0, t1
  275. EXC( STFIRST t3, FIRST(0)(dst), s_exc)
  276. beq len, t2, done
  277.  SUB len, len, t2
  278. ADD dst, dst, t2
  279. beqz match, both_aligned
  280.  ADD src, src, t2
  281. src_unaligned_dst_aligned:
  282. SRL t0, len, LOG_NBYTES+2    # +2 for 4 units/iter
  283. PREF( 0, 3*32(src) )
  284. beqz t0, cleanup_src_unaligned
  285.  and rem, len, (4*NBYTES-1)   # rem = len % 4*NBYTES
  286. PREF( 1, 3*32(dst) )
  287. 1:
  288. /*
  289.  * Avoid consecutive LD*'s to the same register since some mips
  290.  * implementations can't issue them in the same cycle.
  291.  * It's OK to load FIRST(N+1) before REST(N) because the two addresses
  292.  * are to the same unit (unless src is aligned, but it's not).
  293.  */
  294. EXC( LDFIRST t0, FIRST(0)(src), l_exc)
  295. EXC( LDFIRST t1, FIRST(1)(src), l_exc_copy)
  296. SUB     len, len, 4*NBYTES
  297. EXC( LDREST t0, REST(0)(src), l_exc_copy)
  298. EXC( LDREST t1, REST(1)(src), l_exc_copy)
  299. EXC( LDFIRST t2, FIRST(2)(src), l_exc_copy)
  300. EXC( LDFIRST t3, FIRST(3)(src), l_exc_copy)
  301. EXC( LDREST t2, REST(2)(src), l_exc_copy)
  302. EXC( LDREST t3, REST(3)(src), l_exc_copy)
  303. PREF( 0, 9*32(src) )     # 0 is PREF_LOAD  (not streamed)
  304. ADD src, src, 4*NBYTES
  305. #ifdef CONFIG_CPU_SB1
  306. nop     # improves slotting
  307. #endif
  308. EXC( STORE t0, UNIT(0)(dst), s_exc_p4u)
  309. EXC( STORE t1, UNIT(1)(dst), s_exc_p3u)
  310. EXC( STORE t2, UNIT(2)(dst), s_exc_p2u)
  311. EXC( STORE t3, UNIT(3)(dst), s_exc_p1u)
  312. PREF( 1, 9*32(dst) )      # 1 is PREF_STORE (not streamed)
  313. bne len, rem, 1b
  314.  ADD dst, dst, 4*NBYTES
  315. cleanup_src_unaligned:
  316. beqz len, done
  317.  and rem, len, NBYTES-1  # rem = len % NBYTES
  318. beq rem, len, copy_bytes
  319. 1:
  320. EXC(  LDFIRST t0, FIRST(0)(src), l_exc)
  321. EXC( LDREST t0, REST(0)(src), l_exc_copy)
  322. ADD src, src, NBYTES
  323. SUB len, len, NBYTES
  324. EXC( STORE t0, 0(dst), s_exc_p1u)
  325. bne len, rem, 1b
  326.  ADD dst, dst, NBYTES
  327. copy_bytes_checklen:
  328. beqz len, done
  329.  nop
  330. copy_bytes:
  331. /* 0 < len < NBYTES  */
  332. #define COPY_BYTE(N)
  333. EXC( lb t0, N(src), l_exc);
  334. SUB len, len, 1;
  335. beqz len, done;
  336. EXC(  sb t0, N(dst), s_exc_p1)
  337. COPY_BYTE(0)
  338. COPY_BYTE(1)
  339. #ifdef USE_DOUBLE
  340. COPY_BYTE(2)
  341. COPY_BYTE(3)
  342. COPY_BYTE(4)
  343. COPY_BYTE(5)
  344. #endif
  345. EXC( lb t0, NBYTES-2(src), l_exc)
  346. SUB len, len, 1
  347. jr ra
  348. EXC(  sb t0, NBYTES-2(dst), s_exc_p1)
  349. done:
  350. jr ra
  351.  nop
  352. END(memcpy)
  353. l_exc_copy:
  354. /*
  355.  * Copy bytes from src until faulting load address (or until a
  356.  * lb faults)
  357.  *
  358.  * When reached by a faulting LDFIRST/LDREST, THREAD_BUADDR($28)
  359.  * may be more than a byte beyond the last address.
  360.  * Hence, the lb below may get an exception.
  361.  *
  362.  * Assumes src < THREAD_BUADDR($28)
  363.  */
  364. lw t0, THREAD_BUADDR($28)
  365. 1:
  366. EXC( lb t1, 0(src), l_exc)
  367. ADD src, src, 1
  368. sb t1, 0(dst) # can't fault -- we're copy_from_user
  369. bne src, t0, 1b
  370.  ADD dst, dst, 1
  371. l_exc:
  372. lw t0, THREAD_BUADDR($28) # t0 is just past last good address
  373.  nop
  374. subu len, AT, t0 # len number of uncopied bytes
  375. /*
  376.  * Here's where we rely on src and dst being incremented in tandem,
  377.  *   See (3) above.
  378.  * dst += (fault addr - src) to put dst at first byte to clear
  379.  */
  380. addu dst, t0 # compute start address in a1
  381. subu dst, src
  382. /*
  383.  * Clear len bytes starting at dst.  Can't call __bzero because it
  384.  * might modify len.  An inefficient loop for these rare times...
  385.  */
  386. beqz len, done
  387.  SUB src, len, 1
  388. 1: sb zero, 0(dst)
  389. ADD dst, dst, 1
  390. bnez src, 1b
  391.  SUB src, src, 1
  392. jr ra
  393.  nop
  394. #define SEXC(n)
  395. s_exc_p ## n ## u:
  396. jr ra;
  397.  ADD len, len, n*NBYTES
  398. SEXC(8)
  399. SEXC(7)
  400. SEXC(6)
  401. SEXC(5)
  402. SEXC(4)
  403. SEXC(3)
  404. SEXC(2)
  405. SEXC(1)
  406. s_exc_p1:
  407. jr ra
  408.  ADD len, len, 1
  409. s_exc:
  410. jr ra
  411.  nop
  412. .align 5
  413. LEAF(memmove)
  414. addu t0, a0, a2
  415. addu t1, a1, a2
  416. sltu t0, a1, t0 # dst + len <= src -> memcpy
  417. sltu t1, a0, t1 # dst >= src + len -> memcpy
  418. and t0, t1
  419. beqz t0, __memcpy
  420.  move v0, a0 /* return value */
  421. beqz a2, r_out
  422. END(memmove)
  423. /* fall through to __rmemcpy */
  424. LEAF(__rmemcpy) /* a0=dst a1=src a2=len */
  425.  sltu t0, a1, a0
  426. beqz t0, r_end_bytes_up # src >= dst
  427.  nop
  428. addu a0, a2 # dst = dst + len
  429. addu a1, a2 # src = src + len
  430. r_end_bytes:
  431. lb t0, -1(a1)
  432. subu a2, a2, 0x1
  433. sb t0, -1(a0)
  434. subu a1, a1, 0x1
  435. bnez a2, r_end_bytes
  436.  subu a0, a0, 0x1
  437. r_out:
  438. jr ra
  439.  move a2, zero
  440. r_end_bytes_up:
  441. lb t0, (a1)
  442. subu a2, a2, 0x1
  443. sb t0, (a0)
  444. addu a1, a1, 0x1
  445. bnez a2, r_end_bytes_up
  446.  addu a0, a0, 0x1
  447. jr ra
  448.  move a2, zero
  449. END(__rmemcpy)