uaccess.S 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  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. .section .fixup,"ax"
  262. .align 0
  263. 9001: ldmfd sp!, {r0, r4 - r7, pc}
  264. .previous
  265. /* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n);
  266. * Purpose : copy a block from user memory to kernel memory
  267. * Params : to - kernel memory
  268. * : from - user memory
  269. * : n - number of bytes to copy
  270. * Returns : Number of bytes NOT copied.
  271. */
  272. .Lcfu_dest_not_aligned:
  273. rsb ip, ip, #4
  274. cmp ip, #2
  275. USER( ldrbt r3, [r1], #1) @ May fault
  276. strb r3, [r0], #1
  277. USER( ldrgebt r3, [r1], #1) @ May fault
  278. strgeb r3, [r0], #1
  279. USER( ldrgtbt r3, [r1], #1) @ May fault
  280. strgtb r3, [r0], #1
  281. sub r2, r2, ip
  282. b .Lcfu_dest_aligned
  283. ENTRY(__copy_from_user)
  284. stmfd sp!, {r0, r2, r4 - r7, lr}
  285. cmp r2, #4
  286. blt .Lcfu_not_enough
  287. ands ip, r0, #3
  288. bne .Lcfu_dest_not_aligned
  289. .Lcfu_dest_aligned:
  290. ands ip, r1, #3
  291. bne .Lcfu_src_not_aligned
  292. /*
  293. * Seeing as there has to be at least 8 bytes to copy, we can
  294. * copy one word, and force a user-mode page fault...
  295. */
  296. .Lcfu_0fupi: subs r2, r2, #4
  297. addmi ip, r2, #4
  298. bmi .Lcfu_0nowords
  299. USER( ldrt r3, [r1], #4)
  300. str r3, [r0], #4
  301. mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
  302. rsb ip, ip, #0
  303. movs ip, ip, lsr #32 - PAGE_SHIFT
  304. beq .Lcfu_0fupi
  305. /*
  306. * ip = max no. of bytes to copy before needing another "strt" insn
  307. */
  308. cmp r2, ip
  309. movlt ip, r2
  310. sub r2, r2, ip
  311. subs ip, ip, #32
  312. blt .Lcfu_0rem8lp
  313. .Lcfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault
  314. stmia r0!, {r3 - r6}
  315. ldmia r1!, {r3 - r6} @ Shouldnt fault
  316. subs ip, ip, #32
  317. stmia r0!, {r3 - r6}
  318. bpl .Lcfu_0cpy8lp
  319. .Lcfu_0rem8lp: cmn ip, #16
  320. ldmgeia r1!, {r3 - r6} @ Shouldnt fault
  321. stmgeia r0!, {r3 - r6}
  322. tst ip, #8
  323. ldmneia r1!, {r3 - r4} @ Shouldnt fault
  324. stmneia r0!, {r3 - r4}
  325. tst ip, #4
  326. ldrnet r3, [r1], #4 @ Shouldnt fault
  327. strne r3, [r0], #4
  328. ands ip, ip, #3
  329. beq .Lcfu_0fupi
  330. .Lcfu_0nowords: teq ip, #0
  331. beq .Lcfu_finished
  332. .Lcfu_nowords: cmp ip, #2
  333. USER( ldrbt r3, [r1], #1) @ May fault
  334. strb r3, [r0], #1
  335. USER( ldrgebt r3, [r1], #1) @ May fault
  336. strgeb r3, [r0], #1
  337. USER( ldrgtbt r3, [r1], #1) @ May fault
  338. strgtb r3, [r0], #1
  339. b .Lcfu_finished
  340. .Lcfu_not_enough:
  341. movs ip, r2
  342. bne .Lcfu_nowords
  343. .Lcfu_finished: mov r0, #0
  344. add sp, sp, #8
  345. ldmfd sp!, {r4 - r7, pc}
  346. .Lcfu_src_not_aligned:
  347. bic r1, r1, #3
  348. USER( ldrt r7, [r1], #4) @ May fault
  349. cmp ip, #2
  350. bgt .Lcfu_3fupi
  351. beq .Lcfu_2fupi
  352. .Lcfu_1fupi: subs r2, r2, #4
  353. addmi ip, r2, #4
  354. bmi .Lcfu_1nowords
  355. mov r3, r7, pull #8
  356. USER( ldrt r7, [r1], #4) @ May fault
  357. orr r3, r3, r7, push #24
  358. str r3, [r0], #4
  359. mov ip, r1, lsl #32 - PAGE_SHIFT
  360. rsb ip, ip, #0
  361. movs ip, ip, lsr #32 - PAGE_SHIFT
  362. beq .Lcfu_1fupi
  363. cmp r2, ip
  364. movlt ip, r2
  365. sub r2, r2, ip
  366. subs ip, ip, #16
  367. blt .Lcfu_1rem8lp
  368. .Lcfu_1cpy8lp: mov r3, r7, pull #8
  369. ldmia r1!, {r4 - r7} @ Shouldnt fault
  370. subs ip, ip, #16
  371. orr r3, r3, r4, push #24
  372. mov r4, r4, pull #8
  373. orr r4, r4, r5, push #24
  374. mov r5, r5, pull #8
  375. orr r5, r5, r6, push #24
  376. mov r6, r6, pull #8
  377. orr r6, r6, r7, push #24
  378. stmia r0!, {r3 - r6}
  379. bpl .Lcfu_1cpy8lp
  380. .Lcfu_1rem8lp: tst ip, #8
  381. movne r3, r7, pull #8
  382. ldmneia r1!, {r4, r7} @ Shouldnt fault
  383. orrne r3, r3, r4, push #24
  384. movne r4, r4, pull #8
  385. orrne r4, r4, r7, push #24
  386. stmneia r0!, {r3 - r4}
  387. tst ip, #4
  388. movne r3, r7, pull #8
  389. USER( ldrnet r7, [r1], #4) @ May fault
  390. orrne r3, r3, r7, push #24
  391. strne r3, [r0], #4
  392. ands ip, ip, #3
  393. beq .Lcfu_1fupi
  394. .Lcfu_1nowords: mov r3, r7, get_byte_1
  395. teq ip, #0
  396. beq .Lcfu_finished
  397. cmp ip, #2
  398. strb r3, [r0], #1
  399. movge r3, r7, get_byte_2
  400. strgeb r3, [r0], #1
  401. movgt r3, r7, get_byte_3
  402. strgtb r3, [r0], #1
  403. b .Lcfu_finished
  404. .Lcfu_2fupi: subs r2, r2, #4
  405. addmi ip, r2, #4
  406. bmi .Lcfu_2nowords
  407. mov r3, r7, pull #16
  408. USER( ldrt r7, [r1], #4) @ May fault
  409. orr r3, r3, r7, push #16
  410. str r3, [r0], #4
  411. mov ip, r1, lsl #32 - PAGE_SHIFT
  412. rsb ip, ip, #0
  413. movs ip, ip, lsr #32 - PAGE_SHIFT
  414. beq .Lcfu_2fupi
  415. cmp r2, ip
  416. movlt ip, r2
  417. sub r2, r2, ip
  418. subs ip, ip, #16
  419. blt .Lcfu_2rem8lp
  420. .Lcfu_2cpy8lp: mov r3, r7, pull #16
  421. ldmia r1!, {r4 - r7} @ Shouldnt fault
  422. subs ip, ip, #16
  423. orr r3, r3, r4, push #16
  424. mov r4, r4, pull #16
  425. orr r4, r4, r5, push #16
  426. mov r5, r5, pull #16
  427. orr r5, r5, r6, push #16
  428. mov r6, r6, pull #16
  429. orr r6, r6, r7, push #16
  430. stmia r0!, {r3 - r6}
  431. bpl .Lcfu_2cpy8lp
  432. .Lcfu_2rem8lp: tst ip, #8
  433. movne r3, r7, pull #16
  434. ldmneia r1!, {r4, r7} @ Shouldnt fault
  435. orrne r3, r3, r4, push #16
  436. movne r4, r4, pull #16
  437. orrne r4, r4, r7, push #16
  438. stmneia r0!, {r3 - r4}
  439. tst ip, #4
  440. movne r3, r7, pull #16
  441. USER( ldrnet r7, [r1], #4) @ May fault
  442. orrne r3, r3, r7, push #16
  443. strne r3, [r0], #4
  444. ands ip, ip, #3
  445. beq .Lcfu_2fupi
  446. .Lcfu_2nowords: mov r3, r7, get_byte_2
  447. teq ip, #0
  448. beq .Lcfu_finished
  449. cmp ip, #2
  450. strb r3, [r0], #1
  451. movge r3, r7, get_byte_3
  452. strgeb r3, [r0], #1
  453. USER( ldrgtbt r3, [r1], #0) @ May fault
  454. strgtb r3, [r0], #1
  455. b .Lcfu_finished
  456. .Lcfu_3fupi: subs r2, r2, #4
  457. addmi ip, r2, #4
  458. bmi .Lcfu_3nowords
  459. mov r3, r7, pull #24
  460. USER( ldrt r7, [r1], #4) @ May fault
  461. orr r3, r3, r7, push #8
  462. str r3, [r0], #4
  463. mov ip, r1, lsl #32 - PAGE_SHIFT
  464. rsb ip, ip, #0
  465. movs ip, ip, lsr #32 - PAGE_SHIFT
  466. beq .Lcfu_3fupi
  467. cmp r2, ip
  468. movlt ip, r2
  469. sub r2, r2, ip
  470. subs ip, ip, #16
  471. blt .Lcfu_3rem8lp
  472. .Lcfu_3cpy8lp: mov r3, r7, pull #24
  473. ldmia r1!, {r4 - r7} @ Shouldnt fault
  474. orr r3, r3, r4, push #8
  475. mov r4, r4, pull #24
  476. orr r4, r4, r5, push #8
  477. mov r5, r5, pull #24
  478. orr r5, r5, r6, push #8
  479. mov r6, r6, pull #24
  480. orr r6, r6, r7, push #8
  481. stmia r0!, {r3 - r6}
  482. subs ip, ip, #16
  483. bpl .Lcfu_3cpy8lp
  484. .Lcfu_3rem8lp: tst ip, #8
  485. movne r3, r7, pull #24
  486. ldmneia r1!, {r4, r7} @ Shouldnt fault
  487. orrne r3, r3, r4, push #8
  488. movne r4, r4, pull #24
  489. orrne r4, r4, r7, push #8
  490. stmneia r0!, {r3 - r4}
  491. tst ip, #4
  492. movne r3, r7, pull #24
  493. USER( ldrnet r7, [r1], #4) @ May fault
  494. orrne r3, r3, r7, push #8
  495. strne r3, [r0], #4
  496. ands ip, ip, #3
  497. beq .Lcfu_3fupi
  498. .Lcfu_3nowords: mov r3, r7, get_byte_3
  499. teq ip, #0
  500. beq .Lcfu_finished
  501. cmp ip, #2
  502. strb r3, [r0], #1
  503. USER( ldrgebt r3, [r1], #1) @ May fault
  504. strgeb r3, [r0], #1
  505. USER( ldrgtbt r3, [r1], #1) @ May fault
  506. strgtb r3, [r0], #1
  507. b .Lcfu_finished
  508. .section .fixup,"ax"
  509. .align 0
  510. /*
  511. * We took an exception. r0 contains a pointer to
  512. * the byte not copied.
  513. */
  514. 9001: ldr r2, [sp], #4 @ void *to
  515. sub r2, r0, r2 @ bytes copied
  516. ldr r1, [sp], #4 @ unsigned long count
  517. subs r4, r1, r2 @ bytes left to copy
  518. movne r1, r4
  519. blne __memzero
  520. mov r0, r4
  521. ldmfd sp!, {r4 - r7, pc}
  522. .previous