uaccess.S 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /*
  2. * linux/arch/arm/lib/uaccess.S
  3. *
  4. * Copyright (C) 1995, 1996,1997,1998 Russell King
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * Routines to block copy data to/from user memory
  11. * These are highly optimised both for the 4k page size
  12. * and for various alignments.
  13. */
  14. #include <linux/linkage.h>
  15. #include <asm/assembler.h>
  16. #include <asm/errno.h>
  17. .text
  18. #define PAGE_SHIFT 12
  19. /* Prototype: int __copy_to_user(void *to, const char *from, size_t n)
  20. * Purpose : copy a block to user memory from kernel memory
  21. * Params : to - user memory
  22. * : from - kernel memory
  23. * : n - number of bytes to copy
  24. * Returns : Number of bytes NOT copied.
  25. */
  26. .Lc2u_dest_not_aligned:
  27. rsb ip, ip, #4
  28. cmp ip, #2
  29. ldrb r3, [r1], #1
  30. USER( strbt r3, [r0], #1) @ May fault
  31. ldrgeb r3, [r1], #1
  32. USER( strgebt r3, [r0], #1) @ May fault
  33. ldrgtb r3, [r1], #1
  34. USER( strgtbt r3, [r0], #1) @ May fault
  35. sub r2, r2, ip
  36. b .Lc2u_dest_aligned
  37. ENTRY(__copy_to_user)
  38. stmfd sp!, {r2, r4 - r7, lr}
  39. cmp r2, #4
  40. blt .Lc2u_not_enough
  41. ands ip, r0, #3
  42. bne .Lc2u_dest_not_aligned
  43. .Lc2u_dest_aligned:
  44. ands ip, r1, #3
  45. bne .Lc2u_src_not_aligned
  46. /*
  47. * Seeing as there has to be at least 8 bytes to copy, we can
  48. * copy one word, and force a user-mode page fault...
  49. */
  50. .Lc2u_0fupi: subs r2, r2, #4
  51. addmi ip, r2, #4
  52. bmi .Lc2u_0nowords
  53. ldr r3, [r1], #4
  54. USER( strt r3, [r0], #4) @ May fault
  55. mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
  56. rsb ip, ip, #0
  57. movs ip, ip, lsr #32 - PAGE_SHIFT
  58. beq .Lc2u_0fupi
  59. /*
  60. * ip = max no. of bytes to copy before needing another "strt" insn
  61. */
  62. cmp r2, ip
  63. movlt ip, r2
  64. sub r2, r2, ip
  65. subs ip, ip, #32
  66. blt .Lc2u_0rem8lp
  67. .Lc2u_0cpy8lp: ldmia r1!, {r3 - r6}
  68. stmia r0!, {r3 - r6} @ Shouldnt fault
  69. ldmia r1!, {r3 - r6}
  70. subs ip, ip, #32
  71. stmia r0!, {r3 - r6} @ Shouldnt fault
  72. bpl .Lc2u_0cpy8lp
  73. .Lc2u_0rem8lp: cmn ip, #16
  74. ldmgeia r1!, {r3 - r6}
  75. stmgeia r0!, {r3 - r6} @ Shouldnt fault
  76. tst ip, #8
  77. ldmneia r1!, {r3 - r4}
  78. stmneia r0!, {r3 - r4} @ Shouldnt fault
  79. tst ip, #4
  80. ldrne r3, [r1], #4
  81. strnet r3, [r0], #4 @ Shouldnt fault
  82. ands ip, ip, #3
  83. beq .Lc2u_0fupi
  84. .Lc2u_0nowords: teq ip, #0
  85. beq .Lc2u_finished
  86. .Lc2u_nowords: cmp ip, #2
  87. ldrb r3, [r1], #1
  88. USER( strbt r3, [r0], #1) @ May fault
  89. ldrgeb r3, [r1], #1
  90. USER( strgebt r3, [r0], #1) @ May fault
  91. ldrgtb r3, [r1], #1
  92. USER( strgtbt r3, [r0], #1) @ May fault
  93. b .Lc2u_finished
  94. .Lc2u_not_enough:
  95. movs ip, r2
  96. bne .Lc2u_nowords
  97. .Lc2u_finished: mov r0, #0
  98. ldmfd sp!, {r2, r4 - r7, pc}
  99. .Lc2u_src_not_aligned:
  100. bic r1, r1, #3
  101. ldr r7, [r1], #4
  102. cmp ip, #2
  103. bgt .Lc2u_3fupi
  104. beq .Lc2u_2fupi
  105. .Lc2u_1fupi: subs r2, r2, #4
  106. addmi ip, r2, #4
  107. bmi .Lc2u_1nowords
  108. mov r3, r7, pull #8
  109. ldr r7, [r1], #4
  110. orr r3, r3, r7, push #24
  111. USER( strt r3, [r0], #4) @ May fault
  112. mov ip, r0, lsl #32 - PAGE_SHIFT
  113. rsb ip, ip, #0
  114. movs ip, ip, lsr #32 - PAGE_SHIFT
  115. beq .Lc2u_1fupi
  116. cmp r2, ip
  117. movlt ip, r2
  118. sub r2, r2, ip
  119. subs ip, ip, #16
  120. blt .Lc2u_1rem8lp
  121. .Lc2u_1cpy8lp: mov r3, r7, pull #8
  122. ldmia r1!, {r4 - r7}
  123. subs ip, ip, #16
  124. orr r3, r3, r4, push #24
  125. mov r4, r4, pull #8
  126. orr r4, r4, r5, push #24
  127. mov r5, r5, pull #8
  128. orr r5, r5, r6, push #24
  129. mov r6, r6, pull #8
  130. orr r6, r6, r7, push #24
  131. stmia r0!, {r3 - r6} @ Shouldnt fault
  132. bpl .Lc2u_1cpy8lp
  133. .Lc2u_1rem8lp: tst ip, #8
  134. movne r3, r7, pull #8
  135. ldmneia r1!, {r4, r7}
  136. orrne r3, r3, r4, push #24
  137. movne r4, r4, pull #8
  138. orrne r4, r4, r7, push #24
  139. stmneia r0!, {r3 - r4} @ Shouldnt fault
  140. tst ip, #4
  141. movne r3, r7, pull #8
  142. ldrne r7, [r1], #4
  143. orrne r3, r3, r7, push #24
  144. strnet r3, [r0], #4 @ Shouldnt fault
  145. ands ip, ip, #3
  146. beq .Lc2u_1fupi
  147. .Lc2u_1nowords: mov r3, r7, get_byte_1
  148. teq ip, #0
  149. beq .Lc2u_finished
  150. cmp ip, #2
  151. USER( strbt r3, [r0], #1) @ May fault
  152. movge r3, r7, get_byte_2
  153. USER( strgebt r3, [r0], #1) @ May fault
  154. movgt r3, r7, get_byte_3
  155. USER( strgtbt r3, [r0], #1) @ May fault
  156. b .Lc2u_finished
  157. .Lc2u_2fupi: subs r2, r2, #4
  158. addmi ip, r2, #4
  159. bmi .Lc2u_2nowords
  160. mov r3, r7, pull #16
  161. ldr r7, [r1], #4
  162. orr r3, r3, r7, push #16
  163. USER( strt r3, [r0], #4) @ May fault
  164. mov ip, r0, lsl #32 - PAGE_SHIFT
  165. rsb ip, ip, #0
  166. movs ip, ip, lsr #32 - PAGE_SHIFT
  167. beq .Lc2u_2fupi
  168. cmp r2, ip
  169. movlt ip, r2
  170. sub r2, r2, ip
  171. subs ip, ip, #16
  172. blt .Lc2u_2rem8lp
  173. .Lc2u_2cpy8lp: mov r3, r7, pull #16
  174. ldmia r1!, {r4 - r7}
  175. subs ip, ip, #16
  176. orr r3, r3, r4, push #16
  177. mov r4, r4, pull #16
  178. orr r4, r4, r5, push #16
  179. mov r5, r5, pull #16
  180. orr r5, r5, r6, push #16
  181. mov r6, r6, pull #16
  182. orr r6, r6, r7, push #16
  183. stmia r0!, {r3 - r6} @ Shouldnt fault
  184. bpl .Lc2u_2cpy8lp
  185. .Lc2u_2rem8lp: tst ip, #8
  186. movne r3, r7, pull #16
  187. ldmneia r1!, {r4, r7}
  188. orrne r3, r3, r4, push #16
  189. movne r4, r4, pull #16
  190. orrne r4, r4, r7, push #16
  191. stmneia r0!, {r3 - r4} @ Shouldnt fault
  192. tst ip, #4
  193. movne r3, r7, pull #16
  194. ldrne r7, [r1], #4
  195. orrne r3, r3, r7, push #16
  196. strnet r3, [r0], #4 @ Shouldnt fault
  197. ands ip, ip, #3
  198. beq .Lc2u_2fupi
  199. .Lc2u_2nowords: mov r3, r7, get_byte_2
  200. teq ip, #0
  201. beq .Lc2u_finished
  202. cmp ip, #2
  203. USER( strbt r3, [r0], #1) @ May fault
  204. movge r3, r7, get_byte_3
  205. USER( strgebt r3, [r0], #1) @ May fault
  206. ldrgtb r3, [r1], #0
  207. USER( strgtbt r3, [r0], #1) @ May fault
  208. b .Lc2u_finished
  209. .Lc2u_3fupi: subs r2, r2, #4
  210. addmi ip, r2, #4
  211. bmi .Lc2u_3nowords
  212. mov r3, r7, pull #24
  213. ldr r7, [r1], #4
  214. orr r3, r3, r7, push #8
  215. USER( strt r3, [r0], #4) @ May fault
  216. mov ip, r0, lsl #32 - PAGE_SHIFT
  217. rsb ip, ip, #0
  218. movs ip, ip, lsr #32 - PAGE_SHIFT
  219. beq .Lc2u_3fupi
  220. cmp r2, ip
  221. movlt ip, r2
  222. sub r2, r2, ip
  223. subs ip, ip, #16
  224. blt .Lc2u_3rem8lp
  225. .Lc2u_3cpy8lp: mov r3, r7, pull #24
  226. ldmia r1!, {r4 - r7}
  227. subs ip, ip, #16
  228. orr r3, r3, r4, push #8
  229. mov r4, r4, pull #24
  230. orr r4, r4, r5, push #8
  231. mov r5, r5, pull #24
  232. orr r5, r5, r6, push #8
  233. mov r6, r6, pull #24
  234. orr r6, r6, r7, push #8
  235. stmia r0!, {r3 - r6} @ Shouldnt fault
  236. bpl .Lc2u_3cpy8lp
  237. .Lc2u_3rem8lp: tst ip, #8
  238. movne r3, r7, pull #24
  239. ldmneia r1!, {r4, r7}
  240. orrne r3, r3, r4, push #8
  241. movne r4, r4, pull #24
  242. orrne r4, r4, r7, push #8
  243. stmneia r0!, {r3 - r4} @ Shouldnt fault
  244. tst ip, #4
  245. movne r3, r7, pull #24
  246. ldrne r7, [r1], #4
  247. orrne r3, r3, r7, push #8
  248. strnet r3, [r0], #4 @ Shouldnt fault
  249. ands ip, ip, #3
  250. beq .Lc2u_3fupi
  251. .Lc2u_3nowords: mov r3, r7, get_byte_3
  252. teq ip, #0
  253. beq .Lc2u_finished
  254. cmp ip, #2
  255. USER( strbt r3, [r0], #1) @ May fault
  256. ldrgeb r3, [r1], #1
  257. USER( strgebt r3, [r0], #1) @ May fault
  258. ldrgtb r3, [r1], #0
  259. USER( strgtbt r3, [r0], #1) @ May fault
  260. b .Lc2u_finished
  261. ENDPROC(__copy_to_user)
  262. .section .fixup,"ax"
  263. .align 0
  264. 9001: ldmfd sp!, {r0, r4 - r7, pc}
  265. .previous
  266. /* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n);
  267. * Purpose : copy a block from user memory to kernel memory
  268. * Params : to - kernel memory
  269. * : from - user memory
  270. * : n - number of bytes to copy
  271. * Returns : Number of bytes NOT copied.
  272. */
  273. .Lcfu_dest_not_aligned:
  274. rsb ip, ip, #4
  275. cmp ip, #2
  276. USER( ldrbt r3, [r1], #1) @ May fault
  277. strb r3, [r0], #1
  278. USER( ldrgebt r3, [r1], #1) @ May fault
  279. strgeb r3, [r0], #1
  280. USER( ldrgtbt r3, [r1], #1) @ May fault
  281. strgtb r3, [r0], #1
  282. sub r2, r2, ip
  283. b .Lcfu_dest_aligned
  284. ENTRY(__copy_from_user)
  285. stmfd sp!, {r0, r2, r4 - r7, lr}
  286. cmp r2, #4
  287. blt .Lcfu_not_enough
  288. ands ip, r0, #3
  289. bne .Lcfu_dest_not_aligned
  290. .Lcfu_dest_aligned:
  291. ands ip, r1, #3
  292. bne .Lcfu_src_not_aligned
  293. /*
  294. * Seeing as there has to be at least 8 bytes to copy, we can
  295. * copy one word, and force a user-mode page fault...
  296. */
  297. .Lcfu_0fupi: subs r2, r2, #4
  298. addmi ip, r2, #4
  299. bmi .Lcfu_0nowords
  300. USER( ldrt r3, [r1], #4)
  301. str r3, [r0], #4
  302. mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
  303. rsb ip, ip, #0
  304. movs ip, ip, lsr #32 - PAGE_SHIFT
  305. beq .Lcfu_0fupi
  306. /*
  307. * ip = max no. of bytes to copy before needing another "strt" insn
  308. */
  309. cmp r2, ip
  310. movlt ip, r2
  311. sub r2, r2, ip
  312. subs ip, ip, #32
  313. blt .Lcfu_0rem8lp
  314. .Lcfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault
  315. stmia r0!, {r3 - r6}
  316. ldmia r1!, {r3 - r6} @ Shouldnt fault
  317. subs ip, ip, #32
  318. stmia r0!, {r3 - r6}
  319. bpl .Lcfu_0cpy8lp
  320. .Lcfu_0rem8lp: cmn ip, #16
  321. ldmgeia r1!, {r3 - r6} @ Shouldnt fault
  322. stmgeia r0!, {r3 - r6}
  323. tst ip, #8
  324. ldmneia r1!, {r3 - r4} @ Shouldnt fault
  325. stmneia r0!, {r3 - r4}
  326. tst ip, #4
  327. ldrnet r3, [r1], #4 @ Shouldnt fault
  328. strne r3, [r0], #4
  329. ands ip, ip, #3
  330. beq .Lcfu_0fupi
  331. .Lcfu_0nowords: teq ip, #0
  332. beq .Lcfu_finished
  333. .Lcfu_nowords: cmp ip, #2
  334. USER( ldrbt r3, [r1], #1) @ May fault
  335. strb r3, [r0], #1
  336. USER( ldrgebt r3, [r1], #1) @ May fault
  337. strgeb r3, [r0], #1
  338. USER( ldrgtbt r3, [r1], #1) @ May fault
  339. strgtb r3, [r0], #1
  340. b .Lcfu_finished
  341. .Lcfu_not_enough:
  342. movs ip, r2
  343. bne .Lcfu_nowords
  344. .Lcfu_finished: mov r0, #0
  345. add sp, sp, #8
  346. ldmfd sp!, {r4 - r7, pc}
  347. .Lcfu_src_not_aligned:
  348. bic r1, r1, #3
  349. USER( ldrt r7, [r1], #4) @ May fault
  350. cmp ip, #2
  351. bgt .Lcfu_3fupi
  352. beq .Lcfu_2fupi
  353. .Lcfu_1fupi: subs r2, r2, #4
  354. addmi ip, r2, #4
  355. bmi .Lcfu_1nowords
  356. mov r3, r7, pull #8
  357. USER( ldrt r7, [r1], #4) @ May fault
  358. orr r3, r3, r7, push #24
  359. str r3, [r0], #4
  360. mov ip, r1, lsl #32 - PAGE_SHIFT
  361. rsb ip, ip, #0
  362. movs ip, ip, lsr #32 - PAGE_SHIFT
  363. beq .Lcfu_1fupi
  364. cmp r2, ip
  365. movlt ip, r2
  366. sub r2, r2, ip
  367. subs ip, ip, #16
  368. blt .Lcfu_1rem8lp
  369. .Lcfu_1cpy8lp: mov r3, r7, pull #8
  370. ldmia r1!, {r4 - r7} @ Shouldnt fault
  371. subs ip, ip, #16
  372. orr r3, r3, r4, push #24
  373. mov r4, r4, pull #8
  374. orr r4, r4, r5, push #24
  375. mov r5, r5, pull #8
  376. orr r5, r5, r6, push #24
  377. mov r6, r6, pull #8
  378. orr r6, r6, r7, push #24
  379. stmia r0!, {r3 - r6}
  380. bpl .Lcfu_1cpy8lp
  381. .Lcfu_1rem8lp: tst ip, #8
  382. movne r3, r7, pull #8
  383. ldmneia r1!, {r4, r7} @ Shouldnt fault
  384. orrne r3, r3, r4, push #24
  385. movne r4, r4, pull #8
  386. orrne r4, r4, r7, push #24
  387. stmneia r0!, {r3 - r4}
  388. tst ip, #4
  389. movne r3, r7, pull #8
  390. USER( ldrnet r7, [r1], #4) @ May fault
  391. orrne r3, r3, r7, push #24
  392. strne r3, [r0], #4
  393. ands ip, ip, #3
  394. beq .Lcfu_1fupi
  395. .Lcfu_1nowords: mov r3, r7, get_byte_1
  396. teq ip, #0
  397. beq .Lcfu_finished
  398. cmp ip, #2
  399. strb r3, [r0], #1
  400. movge r3, r7, get_byte_2
  401. strgeb r3, [r0], #1
  402. movgt r3, r7, get_byte_3
  403. strgtb r3, [r0], #1
  404. b .Lcfu_finished
  405. .Lcfu_2fupi: subs r2, r2, #4
  406. addmi ip, r2, #4
  407. bmi .Lcfu_2nowords
  408. mov r3, r7, pull #16
  409. USER( ldrt r7, [r1], #4) @ May fault
  410. orr r3, r3, r7, push #16
  411. str r3, [r0], #4
  412. mov ip, r1, lsl #32 - PAGE_SHIFT
  413. rsb ip, ip, #0
  414. movs ip, ip, lsr #32 - PAGE_SHIFT
  415. beq .Lcfu_2fupi
  416. cmp r2, ip
  417. movlt ip, r2
  418. sub r2, r2, ip
  419. subs ip, ip, #16
  420. blt .Lcfu_2rem8lp
  421. .Lcfu_2cpy8lp: mov r3, r7, pull #16
  422. ldmia r1!, {r4 - r7} @ Shouldnt fault
  423. subs ip, ip, #16
  424. orr r3, r3, r4, push #16
  425. mov r4, r4, pull #16
  426. orr r4, r4, r5, push #16
  427. mov r5, r5, pull #16
  428. orr r5, r5, r6, push #16
  429. mov r6, r6, pull #16
  430. orr r6, r6, r7, push #16
  431. stmia r0!, {r3 - r6}
  432. bpl .Lcfu_2cpy8lp
  433. .Lcfu_2rem8lp: tst ip, #8
  434. movne r3, r7, pull #16
  435. ldmneia r1!, {r4, r7} @ Shouldnt fault
  436. orrne r3, r3, r4, push #16
  437. movne r4, r4, pull #16
  438. orrne r4, r4, r7, push #16
  439. stmneia r0!, {r3 - r4}
  440. tst ip, #4
  441. movne r3, r7, pull #16
  442. USER( ldrnet r7, [r1], #4) @ May fault
  443. orrne r3, r3, r7, push #16
  444. strne r3, [r0], #4
  445. ands ip, ip, #3
  446. beq .Lcfu_2fupi
  447. .Lcfu_2nowords: mov r3, r7, get_byte_2
  448. teq ip, #0
  449. beq .Lcfu_finished
  450. cmp ip, #2
  451. strb r3, [r0], #1
  452. movge r3, r7, get_byte_3
  453. strgeb r3, [r0], #1
  454. USER( ldrgtbt r3, [r1], #0) @ May fault
  455. strgtb r3, [r0], #1
  456. b .Lcfu_finished
  457. .Lcfu_3fupi: subs r2, r2, #4
  458. addmi ip, r2, #4
  459. bmi .Lcfu_3nowords
  460. mov r3, r7, pull #24
  461. USER( ldrt r7, [r1], #4) @ May fault
  462. orr r3, r3, r7, push #8
  463. str r3, [r0], #4
  464. mov ip, r1, lsl #32 - PAGE_SHIFT
  465. rsb ip, ip, #0
  466. movs ip, ip, lsr #32 - PAGE_SHIFT
  467. beq .Lcfu_3fupi
  468. cmp r2, ip
  469. movlt ip, r2
  470. sub r2, r2, ip
  471. subs ip, ip, #16
  472. blt .Lcfu_3rem8lp
  473. .Lcfu_3cpy8lp: mov r3, r7, pull #24
  474. ldmia r1!, {r4 - r7} @ Shouldnt fault
  475. orr r3, r3, r4, push #8
  476. mov r4, r4, pull #24
  477. orr r4, r4, r5, push #8
  478. mov r5, r5, pull #24
  479. orr r5, r5, r6, push #8
  480. mov r6, r6, pull #24
  481. orr r6, r6, r7, push #8
  482. stmia r0!, {r3 - r6}
  483. subs ip, ip, #16
  484. bpl .Lcfu_3cpy8lp
  485. .Lcfu_3rem8lp: tst ip, #8
  486. movne r3, r7, pull #24
  487. ldmneia r1!, {r4, r7} @ Shouldnt fault
  488. orrne r3, r3, r4, push #8
  489. movne r4, r4, pull #24
  490. orrne r4, r4, r7, push #8
  491. stmneia r0!, {r3 - r4}
  492. tst ip, #4
  493. movne r3, r7, pull #24
  494. USER( ldrnet r7, [r1], #4) @ May fault
  495. orrne r3, r3, r7, push #8
  496. strne r3, [r0], #4
  497. ands ip, ip, #3
  498. beq .Lcfu_3fupi
  499. .Lcfu_3nowords: mov r3, r7, get_byte_3
  500. teq ip, #0
  501. beq .Lcfu_finished
  502. cmp ip, #2
  503. strb r3, [r0], #1
  504. USER( ldrgebt r3, [r1], #1) @ May fault
  505. strgeb r3, [r0], #1
  506. USER( ldrgtbt r3, [r1], #1) @ May fault
  507. strgtb r3, [r0], #1
  508. b .Lcfu_finished
  509. ENDPROC(__copy_from_user)
  510. .section .fixup,"ax"
  511. .align 0
  512. /*
  513. * We took an exception. r0 contains a pointer to
  514. * the byte not copied.
  515. */
  516. 9001: ldr r2, [sp], #4 @ void *to
  517. sub r2, r0, r2 @ bytes copied
  518. ldr r1, [sp], #4 @ unsigned long count
  519. subs r4, r1, r2 @ bytes left to copy
  520. movne r1, r4
  521. blne __memzero
  522. mov r0, r4
  523. ldmfd sp!, {r4 - r7, pc}
  524. .previous