1/* 2 * linux/arch/arm/lib/memset.S 3 * 4 * Copyright (C) 1995-2000 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 * ASM optimised string functions 11 */ 12#include <linux/linkage.h> 13#include <asm/assembler.h> 14#include <asm/unwind.h> 15#include <asm/export.h> 16 17 .text 18 .align 5 19 20ENTRY(mmioset) 21ENTRY(memset) 22UNWIND( .fnstart ) 23 ands r3, r0, #3 @ 1 unaligned? 24 mov ip, r0 @ preserve r0 as return value 25 bne 6f @ 1 26/* 27 * we know that the pointer in ip is aligned to a word boundary. 28 */ 291: orr r1, r1, r1, lsl #8 30 orr r1, r1, r1, lsl #16 31 mov r3, r1 32 cmp r2, #16 33 blt 4f 34 35#if ! CALGN(1)+0 36 37/* 38 * We need 2 extra registers for this loop - use r8 and the LR 39 */ 40 stmfd sp!, {r8, lr} 41UNWIND( .fnend ) 42UNWIND( .fnstart ) 43UNWIND( .save {r8, lr} ) 44 mov r8, r1 45 mov lr, r1 46 472: subs r2, r2, #64 48 stmgeia ip!, {r1, r3, r8, lr} @ 64 bytes at a time. 49 stmgeia ip!, {r1, r3, r8, lr} 50 stmgeia ip!, {r1, r3, r8, lr} 51 stmgeia ip!, {r1, r3, r8, lr} 52 bgt 2b 53 ldmeqfd sp!, {r8, pc} @ Now <64 bytes to go. 54/* 55 * No need to correct the count; we're only testing bits from now on 56 */ 57 tst r2, #32 58 stmneia ip!, {r1, r3, r8, lr} 59 stmneia ip!, {r1, r3, r8, lr} 60 tst r2, #16 61 stmneia ip!, {r1, r3, r8, lr} 62 ldmfd sp!, {r8, lr} 63UNWIND( .fnend ) 64 65#else 66 67/* 68 * This version aligns the destination pointer in order to write 69 * whole cache lines at once. 70 */ 71 72 stmfd sp!, {r4-r8, lr} 73UNWIND( .fnend ) 74UNWIND( .fnstart ) 75UNWIND( .save {r4-r8, lr} ) 76 mov r4, r1 77 mov r5, r1 78 mov r6, r1 79 mov r7, r1 80 mov r8, r1 81 mov lr, r1 82 83 cmp r2, #96 84 tstgt ip, #31 85 ble 3f 86 87 and r8, ip, #31 88 rsb r8, r8, #32 89 sub r2, r2, r8 90 movs r8, r8, lsl #(32 - 4) 91 stmcsia ip!, {r4, r5, r6, r7} 92 stmmiia ip!, {r4, r5} 93 tst r8, #(1 << 30) 94 mov r8, r1 95 strne r1, [ip], #4 96 973: subs r2, r2, #64 98 stmgeia ip!, {r1, r3-r8, lr} 99 stmgeia ip!, {r1, r3-r8, lr} 100 bgt 3b 101 ldmeqfd sp!, {r4-r8, pc} 102 103 tst r2, #32 104 stmneia ip!, {r1, r3-r8, lr} 105 tst r2, #16 106 stmneia ip!, {r4-r7} 107 ldmfd sp!, {r4-r8, lr} 108UNWIND( .fnend ) 109 110#endif 111 112UNWIND( .fnstart ) 1134: tst r2, #8 114 stmneia ip!, {r1, r3} 115 tst r2, #4 116 strne r1, [ip], #4 117/* 118 * When we get here, we've got less than 4 bytes to zero. We 119 * may have an unaligned pointer as well. 120 */ 1215: tst r2, #2 122 strneb r1, [ip], #1 123 strneb r1, [ip], #1 124 tst r2, #1 125 strneb r1, [ip], #1 126 ret lr 127 1286: subs r2, r2, #4 @ 1 do we have enough 129 blt 5b @ 1 bytes to align with? 130 cmp r3, #2 @ 1 131 strltb r1, [ip], #1 @ 1 132 strleb r1, [ip], #1 @ 1 133 strb r1, [ip], #1 @ 1 134 add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3)) 135 b 1b 136UNWIND( .fnend ) 137ENDPROC(memset) 138ENDPROC(mmioset) 139EXPORT_SYMBOL(memset) 140EXPORT_SYMBOL(mmioset) 141