diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
| commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
| tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/lib | |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/arm/lib')
49 files changed, 5136 insertions, 0 deletions
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile new file mode 100644 index 000000000000..c0e65833ffc4 --- /dev/null +++ b/arch/arm/lib/Makefile | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | # | ||
| 2 | # linux/arch/arm/lib/Makefile | ||
| 3 | # | ||
| 4 | # Copyright (C) 1995-2000 Russell King | ||
| 5 | # | ||
| 6 | |||
| 7 | lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ | ||
| 8 | csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ | ||
| 9 | copy_page.o delay.o findbit.o memchr.o memcpy.o \ | ||
| 10 | memset.o memzero.o setbit.o strncpy_from_user.o \ | ||
| 11 | strnlen_user.o strchr.o strrchr.o testchangebit.o \ | ||
| 12 | testclearbit.o testsetbit.o uaccess.o getuser.o \ | ||
| 13 | putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ | ||
| 14 | ucmpdi2.o udivdi3.o lib1funcs.o div64.o \ | ||
| 15 | io-readsb.o io-writesb.o io-readsl.o io-writesl.o | ||
| 16 | |||
| 17 | ifeq ($(CONFIG_CPU_32v3),y) | ||
| 18 | lib-y += io-readsw-armv3.o io-writesw-armv3.o | ||
| 19 | else | ||
| 20 | lib-y += io-readsw-armv4.o io-writesw-armv4.o | ||
| 21 | endif | ||
| 22 | |||
| 23 | lib-$(CONFIG_ARCH_RPC) += ecard.o io-acorn.o floppydma.o | ||
| 24 | lib-$(CONFIG_ARCH_CLPS7500) += io-acorn.o | ||
| 25 | lib-$(CONFIG_ARCH_L7200) += io-acorn.o | ||
| 26 | lib-$(CONFIG_ARCH_SHARK) += io-shark.o | ||
| 27 | |||
| 28 | $(obj)/csumpartialcopy.o: $(obj)/csumpartialcopygeneric.S | ||
| 29 | $(obj)/csumpartialcopyuser.o: $(obj)/csumpartialcopygeneric.S | ||
diff --git a/arch/arm/lib/ashldi3.c b/arch/arm/lib/ashldi3.c new file mode 100644 index 000000000000..130f5a839669 --- /dev/null +++ b/arch/arm/lib/ashldi3.c | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | /* More subroutines needed by GCC output code on some machines. */ | ||
| 2 | /* Compile this one with gcc. */ | ||
| 3 | /* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU CC. | ||
| 6 | |||
| 7 | GNU CC is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation; either version 2, or (at your option) | ||
| 10 | any later version. | ||
| 11 | |||
| 12 | GNU CC is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU CC; see the file COPYING. If not, write to | ||
| 19 | the Free Software Foundation, 59 Temple Place - Suite 330, | ||
| 20 | Boston, MA 02111-1307, USA. */ | ||
| 21 | |||
| 22 | /* As a special exception, if you link this library with other files, | ||
| 23 | some of which are compiled with GCC, to produce an executable, | ||
| 24 | this library does not by itself cause the resulting executable | ||
| 25 | to be covered by the GNU General Public License. | ||
| 26 | This exception does not however invalidate any other reasons why | ||
| 27 | the executable file might be covered by the GNU General Public License. | ||
| 28 | */ | ||
| 29 | /* support functions required by the kernel. based on code from gcc-2.95.3 */ | ||
| 30 | /* I Molton 29/07/01 */ | ||
| 31 | |||
| 32 | #include "gcclib.h" | ||
| 33 | |||
| 34 | DItype | ||
| 35 | __ashldi3 (DItype u, word_type b) | ||
| 36 | { | ||
| 37 | DIunion w; | ||
| 38 | word_type bm; | ||
| 39 | DIunion uu; | ||
| 40 | |||
| 41 | if (b == 0) | ||
| 42 | return u; | ||
| 43 | |||
| 44 | uu.ll = u; | ||
| 45 | |||
| 46 | bm = (sizeof (SItype) * BITS_PER_UNIT) - b; | ||
| 47 | if (bm <= 0) | ||
| 48 | { | ||
| 49 | w.s.low = 0; | ||
| 50 | w.s.high = (USItype)uu.s.low << -bm; | ||
| 51 | } | ||
| 52 | else | ||
| 53 | { | ||
| 54 | USItype carries = (USItype)uu.s.low >> bm; | ||
| 55 | w.s.low = (USItype)uu.s.low << b; | ||
| 56 | w.s.high = ((USItype)uu.s.high << b) | carries; | ||
| 57 | } | ||
| 58 | |||
| 59 | return w.ll; | ||
| 60 | } | ||
| 61 | |||
diff --git a/arch/arm/lib/ashrdi3.c b/arch/arm/lib/ashrdi3.c new file mode 100644 index 000000000000..71625d218f8d --- /dev/null +++ b/arch/arm/lib/ashrdi3.c | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | /* More subroutines needed by GCC output code on some machines. */ | ||
| 2 | /* Compile this one with gcc. */ | ||
| 3 | /* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU CC. | ||
| 6 | |||
| 7 | GNU CC is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation; either version 2, or (at your option) | ||
| 10 | any later version. | ||
| 11 | |||
| 12 | GNU CC is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU CC; see the file COPYING. If not, write to | ||
| 19 | the Free Software Foundation, 59 Temple Place - Suite 330, | ||
| 20 | Boston, MA 02111-1307, USA. */ | ||
| 21 | |||
| 22 | /* As a special exception, if you link this library with other files, | ||
| 23 | some of which are compiled with GCC, to produce an executable, | ||
| 24 | this library does not by itself cause the resulting executable | ||
| 25 | to be covered by the GNU General Public License. | ||
| 26 | This exception does not however invalidate any other reasons why | ||
| 27 | the executable file might be covered by the GNU General Public License. | ||
| 28 | */ | ||
| 29 | /* support functions required by the kernel. based on code from gcc-2.95.3 */ | ||
| 30 | /* I Molton 29/07/01 */ | ||
| 31 | |||
| 32 | #include "gcclib.h" | ||
| 33 | |||
| 34 | DItype | ||
| 35 | __ashrdi3 (DItype u, word_type b) | ||
| 36 | { | ||
| 37 | DIunion w; | ||
| 38 | word_type bm; | ||
| 39 | DIunion uu; | ||
| 40 | |||
| 41 | if (b == 0) | ||
| 42 | return u; | ||
| 43 | |||
| 44 | uu.ll = u; | ||
| 45 | |||
| 46 | bm = (sizeof (SItype) * BITS_PER_UNIT) - b; | ||
| 47 | if (bm <= 0) | ||
| 48 | { | ||
| 49 | /* w.s.high = 1..1 or 0..0 */ | ||
| 50 | w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1); | ||
| 51 | w.s.low = uu.s.high >> -bm; | ||
| 52 | } | ||
| 53 | else | ||
| 54 | { | ||
| 55 | USItype carries = (USItype)uu.s.high << bm; | ||
| 56 | w.s.high = uu.s.high >> b; | ||
| 57 | w.s.low = ((USItype)uu.s.low >> b) | carries; | ||
| 58 | } | ||
| 59 | |||
| 60 | return w.ll; | ||
| 61 | } | ||
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S new file mode 100644 index 000000000000..68a21c0f3f52 --- /dev/null +++ b/arch/arm/lib/backtrace.S | |||
| @@ -0,0 +1,157 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/backtrace.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995, 1996 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 | * 27/03/03 Ian Molton Clean up CONFIG_CPU | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | #include <linux/config.h> | ||
| 14 | #include <linux/linkage.h> | ||
| 15 | #include <asm/assembler.h> | ||
| 16 | .text | ||
| 17 | |||
| 18 | @ fp is 0 or stack frame | ||
| 19 | |||
| 20 | #define frame r4 | ||
| 21 | #define next r5 | ||
| 22 | #define save r6 | ||
| 23 | #define mask r7 | ||
| 24 | #define offset r8 | ||
| 25 | |||
| 26 | ENTRY(__backtrace) | ||
| 27 | mov r1, #0x10 | ||
| 28 | mov r0, fp | ||
| 29 | |||
| 30 | ENTRY(c_backtrace) | ||
| 31 | |||
| 32 | #ifndef CONFIG_FRAME_POINTER | ||
| 33 | mov pc, lr | ||
| 34 | #else | ||
| 35 | |||
| 36 | stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... | ||
| 37 | tst r1, #0x10 @ 26 or 32-bit? | ||
| 38 | moveq mask, #0xfc000003 | ||
| 39 | movne mask, #0 | ||
| 40 | tst mask, r0 | ||
| 41 | movne r0, #0 | ||
| 42 | movs frame, r0 | ||
| 43 | 1: moveq r0, #-2 | ||
| 44 | LOADREGS(eqfd, sp!, {r4 - r8, pc}) | ||
| 45 | |||
| 46 | 2: stmfd sp!, {pc} @ calculate offset of PC in STMIA instruction | ||
| 47 | ldr r0, [sp], #4 | ||
| 48 | adr r1, 2b - 4 | ||
| 49 | sub offset, r0, r1 | ||
| 50 | |||
| 51 | 3: tst frame, mask @ Check for address exceptions... | ||
| 52 | bne 1b | ||
| 53 | |||
| 54 | 1001: ldr next, [frame, #-12] @ get fp | ||
| 55 | 1002: ldr r2, [frame, #-4] @ get lr | ||
| 56 | 1003: ldr r3, [frame, #0] @ get pc | ||
| 57 | sub save, r3, offset @ Correct PC for prefetching | ||
| 58 | bic save, save, mask | ||
| 59 | 1004: ldr r1, [save, #0] @ get instruction at function | ||
| 60 | mov r1, r1, lsr #10 | ||
| 61 | ldr r3, .Ldsi+4 | ||
| 62 | teq r1, r3 | ||
| 63 | subeq save, save, #4 | ||
| 64 | mov r0, save | ||
| 65 | bic r1, r2, mask | ||
| 66 | bl dump_backtrace_entry | ||
| 67 | |||
| 68 | ldr r0, [frame, #-8] @ get sp | ||
| 69 | sub r0, r0, #4 | ||
| 70 | 1005: ldr r1, [save, #4] @ get instruction at function+4 | ||
| 71 | mov r3, r1, lsr #10 | ||
| 72 | ldr r2, .Ldsi+4 | ||
| 73 | teq r3, r2 @ Check for stmia sp!, {args} | ||
| 74 | addeq save, save, #4 @ next instruction | ||
| 75 | bleq .Ldumpstm | ||
| 76 | |||
| 77 | sub r0, frame, #16 | ||
| 78 | 1006: ldr r1, [save, #4] @ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction | ||
| 79 | mov r3, r1, lsr #10 | ||
| 80 | ldr r2, .Ldsi | ||
| 81 | teq r3, r2 | ||
| 82 | bleq .Ldumpstm | ||
| 83 | |||
| 84 | /* | ||
| 85 | * A zero next framepointer means we're done. | ||
| 86 | */ | ||
| 87 | teq next, #0 | ||
| 88 | LOADREGS(eqfd, sp!, {r4 - r8, pc}) | ||
| 89 | |||
| 90 | /* | ||
| 91 | * The next framepointer must be above the | ||
| 92 | * current framepointer. | ||
| 93 | */ | ||
| 94 | cmp next, frame | ||
| 95 | mov frame, next | ||
| 96 | bhi 3b | ||
| 97 | b 1007f | ||
| 98 | |||
| 99 | /* | ||
| 100 | * Fixup for LDMDB | ||
| 101 | */ | ||
| 102 | .section .fixup,"ax" | ||
| 103 | .align 0 | ||
| 104 | 1007: ldr r0, =.Lbad | ||
| 105 | mov r1, frame | ||
| 106 | bl printk | ||
| 107 | LOADREGS(fd, sp!, {r4 - r8, pc}) | ||
| 108 | .ltorg | ||
| 109 | .previous | ||
| 110 | |||
| 111 | .section __ex_table,"a" | ||
| 112 | .align 3 | ||
| 113 | .long 1001b, 1007b | ||
| 114 | .long 1002b, 1007b | ||
| 115 | .long 1003b, 1007b | ||
| 116 | .long 1004b, 1007b | ||
| 117 | .long 1005b, 1007b | ||
| 118 | .long 1006b, 1007b | ||
| 119 | .previous | ||
| 120 | |||
| 121 | #define instr r4 | ||
| 122 | #define reg r5 | ||
| 123 | #define stack r6 | ||
| 124 | |||
| 125 | .Ldumpstm: stmfd sp!, {instr, reg, stack, r7, lr} | ||
| 126 | mov stack, r0 | ||
| 127 | mov instr, r1 | ||
| 128 | mov reg, #9 | ||
| 129 | mov r7, #0 | ||
| 130 | 1: mov r3, #1 | ||
| 131 | tst instr, r3, lsl reg | ||
| 132 | beq 2f | ||
| 133 | add r7, r7, #1 | ||
| 134 | teq r7, #4 | ||
| 135 | moveq r7, #0 | ||
| 136 | moveq r3, #'\n' | ||
| 137 | movne r3, #' ' | ||
| 138 | ldr r2, [stack], #-4 | ||
| 139 | mov r1, reg | ||
| 140 | adr r0, .Lfp | ||
| 141 | bl printk | ||
| 142 | 2: subs reg, reg, #1 | ||
| 143 | bpl 1b | ||
| 144 | teq r7, #0 | ||
| 145 | adrne r0, .Lcr | ||
| 146 | blne printk | ||
| 147 | mov r0, stack | ||
| 148 | LOADREGS(fd, sp!, {instr, reg, stack, r7, pc}) | ||
| 149 | |||
| 150 | .Lfp: .asciz " r%d = %08X%c" | ||
| 151 | .Lcr: .asciz "\n" | ||
| 152 | .Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" | ||
| 153 | .align | ||
| 154 | .Ldsi: .word 0x00e92dd8 >> 2 | ||
| 155 | .word 0x00e92d00 >> 2 | ||
| 156 | |||
| 157 | #endif | ||
diff --git a/arch/arm/lib/changebit.S b/arch/arm/lib/changebit.S new file mode 100644 index 000000000000..3af45cab70e1 --- /dev/null +++ b/arch/arm/lib/changebit.S | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/changebit.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-1996 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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | .text | ||
| 13 | |||
| 14 | /* Purpose : Function to change a bit | ||
| 15 | * Prototype: int change_bit(int bit, void *addr) | ||
| 16 | */ | ||
| 17 | ENTRY(_change_bit_be) | ||
| 18 | eor r0, r0, #0x18 @ big endian byte ordering | ||
| 19 | ENTRY(_change_bit_le) | ||
| 20 | and r2, r0, #7 | ||
| 21 | mov r3, #1 | ||
| 22 | mov r3, r3, lsl r2 | ||
| 23 | save_and_disable_irqs ip, r2 | ||
| 24 | ldrb r2, [r1, r0, lsr #3] | ||
| 25 | eor r2, r2, r3 | ||
| 26 | strb r2, [r1, r0, lsr #3] | ||
| 27 | restore_irqs ip | ||
| 28 | RETINSTR(mov,pc,lr) | ||
diff --git a/arch/arm/lib/clearbit.S b/arch/arm/lib/clearbit.S new file mode 100644 index 000000000000..069a2ce413f0 --- /dev/null +++ b/arch/arm/lib/clearbit.S | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/clearbit.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-1996 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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | .text | ||
| 13 | |||
| 14 | /* | ||
| 15 | * Purpose : Function to clear a bit | ||
| 16 | * Prototype: int clear_bit(int bit, void *addr) | ||
| 17 | */ | ||
| 18 | ENTRY(_clear_bit_be) | ||
| 19 | eor r0, r0, #0x18 @ big endian byte ordering | ||
| 20 | ENTRY(_clear_bit_le) | ||
| 21 | and r2, r0, #7 | ||
| 22 | mov r3, #1 | ||
| 23 | mov r3, r3, lsl r2 | ||
| 24 | save_and_disable_irqs ip, r2 | ||
| 25 | ldrb r2, [r1, r0, lsr #3] | ||
| 26 | bic r2, r2, r3 | ||
| 27 | strb r2, [r1, r0, lsr #3] | ||
| 28 | restore_irqs ip | ||
| 29 | RETINSTR(mov,pc,lr) | ||
| 30 | |||
| 31 | |||
diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S new file mode 100644 index 000000000000..4c38abdbe497 --- /dev/null +++ b/arch/arm/lib/copy_page.S | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/copypage.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-1999 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/constants.h> | ||
| 15 | |||
| 16 | #define COPY_COUNT (PAGE_SZ/64 PLD( -1 )) | ||
| 17 | |||
| 18 | .text | ||
| 19 | .align 5 | ||
| 20 | /* | ||
| 21 | * StrongARM optimised copy_page routine | ||
| 22 | * now 1.78bytes/cycle, was 1.60 bytes/cycle (50MHz bus -> 89MB/s) | ||
| 23 | * Note that we probably achieve closer to the 100MB/s target with | ||
| 24 | * the core clock switching. | ||
| 25 | */ | ||
| 26 | ENTRY(copy_page) | ||
| 27 | stmfd sp!, {r4, lr} @ 2 | ||
| 28 | PLD( pld [r1, #0] ) | ||
| 29 | PLD( pld [r1, #32] ) | ||
| 30 | mov r2, #COPY_COUNT @ 1 | ||
| 31 | ldmia r1!, {r3, r4, ip, lr} @ 4+1 | ||
| 32 | 1: PLD( pld [r1, #64] ) | ||
| 33 | PLD( pld [r1, #96] ) | ||
| 34 | 2: stmia r0!, {r3, r4, ip, lr} @ 4 | ||
| 35 | ldmia r1!, {r3, r4, ip, lr} @ 4+1 | ||
| 36 | stmia r0!, {r3, r4, ip, lr} @ 4 | ||
| 37 | ldmia r1!, {r3, r4, ip, lr} @ 4+1 | ||
| 38 | stmia r0!, {r3, r4, ip, lr} @ 4 | ||
| 39 | ldmia r1!, {r3, r4, ip, lr} @ 4 | ||
| 40 | subs r2, r2, #1 @ 1 | ||
| 41 | stmia r0!, {r3, r4, ip, lr} @ 4 | ||
| 42 | ldmgtia r1!, {r3, r4, ip, lr} @ 4 | ||
| 43 | bgt 1b @ 1 | ||
| 44 | PLD( ldmeqia r1!, {r3, r4, ip, lr} ) | ||
| 45 | PLD( beq 2b ) | ||
| 46 | LOADREGS(fd, sp!, {r4, pc}) @ 3 | ||
diff --git a/arch/arm/lib/csumipv6.S b/arch/arm/lib/csumipv6.S new file mode 100644 index 000000000000..7065a20ee8ad --- /dev/null +++ b/arch/arm/lib/csumipv6.S | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/csumipv6.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | |||
| 13 | .text | ||
| 14 | |||
| 15 | ENTRY(__csum_ipv6_magic) | ||
| 16 | str lr, [sp, #-4]! | ||
| 17 | adds ip, r2, r3 | ||
| 18 | ldmia r1, {r1 - r3, lr} | ||
| 19 | adcs ip, ip, r1 | ||
| 20 | adcs ip, ip, r2 | ||
| 21 | adcs ip, ip, r3 | ||
| 22 | adcs ip, ip, lr | ||
| 23 | ldmia r0, {r0 - r3} | ||
| 24 | adcs r0, ip, r0 | ||
| 25 | adcs r0, r0, r1 | ||
| 26 | adcs r0, r0, r2 | ||
| 27 | ldr r2, [sp, #4] | ||
| 28 | adcs r0, r0, r3 | ||
| 29 | adcs r0, r0, r2 | ||
| 30 | adcs r0, r0, #0 | ||
| 31 | LOADREGS(fd, sp!, {pc}) | ||
| 32 | |||
diff --git a/arch/arm/lib/csumpartial.S b/arch/arm/lib/csumpartial.S new file mode 100644 index 000000000000..cb5e3708f118 --- /dev/null +++ b/arch/arm/lib/csumpartial.S | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/csumpartial.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | |||
| 13 | .text | ||
| 14 | |||
| 15 | /* | ||
| 16 | * Function: __u32 csum_partial(const char *src, int len, __u32 sum) | ||
| 17 | * Params : r0 = buffer, r1 = len, r2 = checksum | ||
| 18 | * Returns : r0 = new checksum | ||
| 19 | */ | ||
| 20 | |||
| 21 | buf .req r0 | ||
| 22 | len .req r1 | ||
| 23 | sum .req r2 | ||
| 24 | td0 .req r3 | ||
| 25 | td1 .req r4 @ save before use | ||
| 26 | td2 .req r5 @ save before use | ||
| 27 | td3 .req lr | ||
| 28 | |||
| 29 | .zero: mov r0, sum | ||
| 30 | add sp, sp, #4 | ||
| 31 | ldr pc, [sp], #4 | ||
| 32 | |||
| 33 | /* | ||
| 34 | * Handle 0 to 7 bytes, with any alignment of source and | ||
| 35 | * destination pointers. Note that when we get here, C = 0 | ||
| 36 | */ | ||
| 37 | .less8: teq len, #0 @ check for zero count | ||
| 38 | beq .zero | ||
| 39 | |||
| 40 | /* we must have at least one byte. */ | ||
| 41 | tst buf, #1 @ odd address? | ||
| 42 | ldrneb td0, [buf], #1 | ||
| 43 | subne len, len, #1 | ||
| 44 | adcnes sum, sum, td0, put_byte_1 | ||
| 45 | |||
| 46 | .less4: tst len, #6 | ||
| 47 | beq .less8_byte | ||
| 48 | |||
| 49 | /* we are now half-word aligned */ | ||
| 50 | |||
| 51 | .less8_wordlp: | ||
| 52 | #if __LINUX_ARM_ARCH__ >= 4 | ||
| 53 | ldrh td0, [buf], #2 | ||
| 54 | sub len, len, #2 | ||
| 55 | #else | ||
| 56 | ldrb td0, [buf], #1 | ||
| 57 | ldrb td3, [buf], #1 | ||
| 58 | sub len, len, #2 | ||
| 59 | #ifndef __ARMEB__ | ||
| 60 | orr td0, td0, td3, lsl #8 | ||
| 61 | #else | ||
| 62 | orr td0, td3, td0, lsl #8 | ||
| 63 | #endif | ||
| 64 | #endif | ||
| 65 | adcs sum, sum, td0 | ||
| 66 | tst len, #6 | ||
| 67 | bne .less8_wordlp | ||
| 68 | |||
| 69 | .less8_byte: tst len, #1 @ odd number of bytes | ||
| 70 | ldrneb td0, [buf], #1 @ include last byte | ||
| 71 | adcnes sum, sum, td0, put_byte_0 @ update checksum | ||
| 72 | |||
| 73 | .done: adc r0, sum, #0 @ collect up the last carry | ||
| 74 | ldr td0, [sp], #4 | ||
| 75 | tst td0, #1 @ check buffer alignment | ||
| 76 | movne r0, r0, ror #8 @ rotate checksum by 8 bits | ||
| 77 | ldr pc, [sp], #4 @ return | ||
| 78 | |||
| 79 | .not_aligned: tst buf, #1 @ odd address | ||
| 80 | ldrneb td0, [buf], #1 @ make even | ||
| 81 | subne len, len, #1 | ||
| 82 | adcnes sum, sum, td0, put_byte_1 @ update checksum | ||
| 83 | |||
| 84 | tst buf, #2 @ 32-bit aligned? | ||
| 85 | #if __LINUX_ARM_ARCH__ >= 4 | ||
| 86 | ldrneh td0, [buf], #2 @ make 32-bit aligned | ||
| 87 | subne len, len, #2 | ||
| 88 | #else | ||
| 89 | ldrneb td0, [buf], #1 | ||
| 90 | ldrneb ip, [buf], #1 | ||
| 91 | subne len, len, #2 | ||
| 92 | #ifndef __ARMEB__ | ||
| 93 | orrne td0, td0, ip, lsl #8 | ||
| 94 | #else | ||
| 95 | orrne td0, ip, td0, lsl #8 | ||
| 96 | #endif | ||
| 97 | #endif | ||
| 98 | adcnes sum, sum, td0 @ update checksum | ||
| 99 | mov pc, lr | ||
| 100 | |||
| 101 | ENTRY(csum_partial) | ||
| 102 | stmfd sp!, {buf, lr} | ||
| 103 | cmp len, #8 @ Ensure that we have at least | ||
| 104 | blo .less8 @ 8 bytes to copy. | ||
| 105 | |||
| 106 | adds sum, sum, #0 @ C = 0 | ||
| 107 | tst buf, #3 @ Test destination alignment | ||
| 108 | blne .not_aligned @ aligh destination, return here | ||
| 109 | |||
| 110 | 1: bics ip, len, #31 | ||
| 111 | beq 3f | ||
| 112 | |||
| 113 | stmfd sp!, {r4 - r5} | ||
| 114 | 2: ldmia buf!, {td0, td1, td2, td3} | ||
| 115 | adcs sum, sum, td0 | ||
| 116 | adcs sum, sum, td1 | ||
| 117 | adcs sum, sum, td2 | ||
| 118 | adcs sum, sum, td3 | ||
| 119 | ldmia buf!, {td0, td1, td2, td3} | ||
| 120 | adcs sum, sum, td0 | ||
| 121 | adcs sum, sum, td1 | ||
| 122 | adcs sum, sum, td2 | ||
| 123 | adcs sum, sum, td3 | ||
| 124 | sub ip, ip, #32 | ||
| 125 | teq ip, #0 | ||
| 126 | bne 2b | ||
| 127 | ldmfd sp!, {r4 - r5} | ||
| 128 | |||
| 129 | 3: tst len, #0x1c @ should not change C | ||
| 130 | beq .less4 | ||
| 131 | |||
| 132 | 4: ldr td0, [buf], #4 | ||
| 133 | sub len, len, #4 | ||
| 134 | adcs sum, sum, td0 | ||
| 135 | tst len, #0x1c | ||
| 136 | bne 4b | ||
| 137 | b .less4 | ||
diff --git a/arch/arm/lib/csumpartialcopy.S b/arch/arm/lib/csumpartialcopy.S new file mode 100644 index 000000000000..990ee63b2465 --- /dev/null +++ b/arch/arm/lib/csumpartialcopy.S | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/csumpartialcopy.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | |||
| 13 | .text | ||
| 14 | |||
| 15 | /* Function: __u32 csum_partial_copy_nocheck(const char *src, char *dst, int len, __u32 sum) | ||
| 16 | * Params : r0 = src, r1 = dst, r2 = len, r3 = checksum | ||
| 17 | * Returns : r0 = new checksum | ||
| 18 | */ | ||
| 19 | |||
| 20 | .macro save_regs | ||
| 21 | stmfd sp!, {r1, r4 - r8, fp, ip, lr, pc} | ||
| 22 | .endm | ||
| 23 | |||
| 24 | .macro load_regs,flags | ||
| 25 | LOADREGS(\flags,fp,{r1, r4 - r8, fp, sp, pc}) | ||
| 26 | .endm | ||
| 27 | |||
| 28 | .macro load1b, reg1 | ||
| 29 | ldrb \reg1, [r0], #1 | ||
| 30 | .endm | ||
| 31 | |||
| 32 | .macro load2b, reg1, reg2 | ||
| 33 | ldrb \reg1, [r0], #1 | ||
| 34 | ldrb \reg2, [r0], #1 | ||
| 35 | .endm | ||
| 36 | |||
| 37 | .macro load1l, reg1 | ||
| 38 | ldr \reg1, [r0], #4 | ||
| 39 | .endm | ||
| 40 | |||
| 41 | .macro load2l, reg1, reg2 | ||
| 42 | ldr \reg1, [r0], #4 | ||
| 43 | ldr \reg2, [r0], #4 | ||
| 44 | .endm | ||
| 45 | |||
| 46 | .macro load4l, reg1, reg2, reg3, reg4 | ||
| 47 | ldmia r0!, {\reg1, \reg2, \reg3, \reg4} | ||
| 48 | .endm | ||
| 49 | |||
| 50 | #define FN_ENTRY ENTRY(csum_partial_copy_nocheck) | ||
| 51 | |||
| 52 | #include "csumpartialcopygeneric.S" | ||
diff --git a/arch/arm/lib/csumpartialcopygeneric.S b/arch/arm/lib/csumpartialcopygeneric.S new file mode 100644 index 000000000000..d3a2f4667db4 --- /dev/null +++ b/arch/arm/lib/csumpartialcopygeneric.S | |||
| @@ -0,0 +1,331 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/csumpartialcopygeneric.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2001 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 | |||
| 11 | /* | ||
| 12 | * unsigned int | ||
| 13 | * csum_partial_copy_xxx(const char *src, char *dst, int len, int sum, ) | ||
| 14 | * r0 = src, r1 = dst, r2 = len, r3 = sum | ||
| 15 | * Returns : r0 = checksum | ||
| 16 | * | ||
| 17 | * Note that 'tst' and 'teq' preserve the carry flag. | ||
| 18 | */ | ||
| 19 | |||
| 20 | src .req r0 | ||
| 21 | dst .req r1 | ||
| 22 | len .req r2 | ||
| 23 | sum .req r3 | ||
| 24 | |||
| 25 | .zero: mov r0, sum | ||
| 26 | load_regs ea | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Align an unaligned destination pointer. We know that | ||
| 30 | * we have >= 8 bytes here, so we don't need to check | ||
| 31 | * the length. Note that the source pointer hasn't been | ||
| 32 | * aligned yet. | ||
| 33 | */ | ||
| 34 | .dst_unaligned: tst dst, #1 | ||
| 35 | beq .dst_16bit | ||
| 36 | |||
| 37 | load1b ip | ||
| 38 | sub len, len, #1 | ||
| 39 | adcs sum, sum, ip, put_byte_1 @ update checksum | ||
| 40 | strb ip, [dst], #1 | ||
| 41 | tst dst, #2 | ||
| 42 | moveq pc, lr @ dst is now 32bit aligned | ||
| 43 | |||
| 44 | .dst_16bit: load2b r8, ip | ||
| 45 | sub len, len, #2 | ||
| 46 | adcs sum, sum, r8, put_byte_0 | ||
| 47 | strb r8, [dst], #1 | ||
| 48 | adcs sum, sum, ip, put_byte_1 | ||
| 49 | strb ip, [dst], #1 | ||
| 50 | mov pc, lr @ dst is now 32bit aligned | ||
| 51 | |||
| 52 | /* | ||
| 53 | * Handle 0 to 7 bytes, with any alignment of source and | ||
| 54 | * destination pointers. Note that when we get here, C = 0 | ||
| 55 | */ | ||
| 56 | .less8: teq len, #0 @ check for zero count | ||
| 57 | beq .zero | ||
| 58 | |||
| 59 | /* we must have at least one byte. */ | ||
| 60 | tst dst, #1 @ dst 16-bit aligned | ||
| 61 | beq .less8_aligned | ||
| 62 | |||
| 63 | /* Align dst */ | ||
| 64 | load1b ip | ||
| 65 | sub len, len, #1 | ||
| 66 | adcs sum, sum, ip, put_byte_1 @ update checksum | ||
| 67 | strb ip, [dst], #1 | ||
| 68 | tst len, #6 | ||
| 69 | beq .less8_byteonly | ||
| 70 | |||
| 71 | 1: load2b r8, ip | ||
| 72 | sub len, len, #2 | ||
| 73 | adcs sum, sum, r8, put_byte_0 | ||
| 74 | strb r8, [dst], #1 | ||
| 75 | adcs sum, sum, ip, put_byte_1 | ||
| 76 | strb ip, [dst], #1 | ||
| 77 | .less8_aligned: tst len, #6 | ||
| 78 | bne 1b | ||
| 79 | .less8_byteonly: | ||
| 80 | tst len, #1 | ||
| 81 | beq .done | ||
| 82 | load1b r8 | ||
| 83 | adcs sum, sum, r8, put_byte_0 @ update checksum | ||
| 84 | strb r8, [dst], #1 | ||
| 85 | b .done | ||
| 86 | |||
| 87 | FN_ENTRY | ||
| 88 | mov ip, sp | ||
| 89 | save_regs | ||
| 90 | sub fp, ip, #4 | ||
| 91 | |||
| 92 | cmp len, #8 @ Ensure that we have at least | ||
| 93 | blo .less8 @ 8 bytes to copy. | ||
| 94 | |||
| 95 | adds sum, sum, #0 @ C = 0 | ||
| 96 | tst dst, #3 @ Test destination alignment | ||
| 97 | blne .dst_unaligned @ align destination, return here | ||
| 98 | |||
| 99 | /* | ||
| 100 | * Ok, the dst pointer is now 32bit aligned, and we know | ||
| 101 | * that we must have more than 4 bytes to copy. Note | ||
| 102 | * that C contains the carry from the dst alignment above. | ||
| 103 | */ | ||
| 104 | |||
| 105 | tst src, #3 @ Test source alignment | ||
| 106 | bne .src_not_aligned | ||
| 107 | |||
| 108 | /* Routine for src & dst aligned */ | ||
| 109 | |||
| 110 | bics ip, len, #15 | ||
| 111 | beq 2f | ||
| 112 | |||
| 113 | 1: load4l r4, r5, r6, r7 | ||
| 114 | stmia dst!, {r4, r5, r6, r7} | ||
| 115 | adcs sum, sum, r4 | ||
| 116 | adcs sum, sum, r5 | ||
| 117 | adcs sum, sum, r6 | ||
| 118 | adcs sum, sum, r7 | ||
| 119 | sub ip, ip, #16 | ||
| 120 | teq ip, #0 | ||
| 121 | bne 1b | ||
| 122 | |||
| 123 | 2: ands ip, len, #12 | ||
| 124 | beq 4f | ||
| 125 | tst ip, #8 | ||
| 126 | beq 3f | ||
| 127 | load2l r4, r5 | ||
| 128 | stmia dst!, {r4, r5} | ||
| 129 | adcs sum, sum, r4 | ||
| 130 | adcs sum, sum, r5 | ||
| 131 | tst ip, #4 | ||
| 132 | beq 4f | ||
| 133 | |||
| 134 | 3: load1l r4 | ||
| 135 | str r4, [dst], #4 | ||
| 136 | adcs sum, sum, r4 | ||
| 137 | |||
| 138 | 4: ands len, len, #3 | ||
| 139 | beq .done | ||
| 140 | load1l r4 | ||
| 141 | tst len, #2 | ||
| 142 | mov r5, r4, get_byte_0 | ||
| 143 | beq .exit | ||
| 144 | adcs sum, sum, r4, push #16 | ||
| 145 | strb r5, [dst], #1 | ||
| 146 | mov r5, r4, get_byte_1 | ||
| 147 | strb r5, [dst], #1 | ||
| 148 | mov r5, r4, get_byte_2 | ||
| 149 | .exit: tst len, #1 | ||
| 150 | strneb r5, [dst], #1 | ||
| 151 | andne r5, r5, #255 | ||
| 152 | adcnes sum, sum, r5, put_byte_0 | ||
| 153 | |||
| 154 | /* | ||
| 155 | * If the dst pointer was not 16-bit aligned, we | ||
| 156 | * need to rotate the checksum here to get around | ||
| 157 | * the inefficient byte manipulations in the | ||
| 158 | * architecture independent code. | ||
| 159 | */ | ||
| 160 | .done: adc r0, sum, #0 | ||
| 161 | ldr sum, [sp, #0] @ dst | ||
| 162 | tst sum, #1 | ||
| 163 | movne r0, r0, ror #8 | ||
| 164 | load_regs ea | ||
| 165 | |||
| 166 | .src_not_aligned: | ||
| 167 | adc sum, sum, #0 @ include C from dst alignment | ||
| 168 | and ip, src, #3 | ||
| 169 | bic src, src, #3 | ||
| 170 | load1l r5 | ||
| 171 | cmp ip, #2 | ||
| 172 | beq .src2_aligned | ||
| 173 | bhi .src3_aligned | ||
| 174 | mov r4, r5, pull #8 @ C = 0 | ||
| 175 | bics ip, len, #15 | ||
| 176 | beq 2f | ||
| 177 | 1: load4l r5, r6, r7, r8 | ||
| 178 | orr r4, r4, r5, push #24 | ||
| 179 | mov r5, r5, pull #8 | ||
| 180 | orr r5, r5, r6, push #24 | ||
| 181 | mov r6, r6, pull #8 | ||
| 182 | orr r6, r6, r7, push #24 | ||
| 183 | mov r7, r7, pull #8 | ||
| 184 | orr r7, r7, r8, push #24 | ||
| 185 | stmia dst!, {r4, r5, r6, r7} | ||
| 186 | adcs sum, sum, r4 | ||
| 187 | adcs sum, sum, r5 | ||
| 188 | adcs sum, sum, r6 | ||
| 189 | adcs sum, sum, r7 | ||
| 190 | mov r4, r8, pull #8 | ||
| 191 | sub ip, ip, #16 | ||
| 192 | teq ip, #0 | ||
| 193 | bne 1b | ||
| 194 | 2: ands ip, len, #12 | ||
| 195 | beq 4f | ||
| 196 | tst ip, #8 | ||
| 197 | beq 3f | ||
| 198 | load2l r5, r6 | ||
| 199 | orr r4, r4, r5, push #24 | ||
| 200 | mov r5, r5, pull #8 | ||
| 201 | orr r5, r5, r6, push #24 | ||
| 202 | stmia dst!, {r4, r5} | ||
| 203 | adcs sum, sum, r4 | ||
| 204 | adcs sum, sum, r5 | ||
| 205 | mov r4, r6, pull #8 | ||
| 206 | tst ip, #4 | ||
| 207 | beq 4f | ||
| 208 | 3: load1l r5 | ||
| 209 | orr r4, r4, r5, push #24 | ||
| 210 | str r4, [dst], #4 | ||
| 211 | adcs sum, sum, r4 | ||
| 212 | mov r4, r5, pull #8 | ||
| 213 | 4: ands len, len, #3 | ||
| 214 | beq .done | ||
| 215 | mov r5, r4, get_byte_0 | ||
| 216 | tst len, #2 | ||
| 217 | beq .exit | ||
| 218 | adcs sum, sum, r4, push #16 | ||
| 219 | strb r5, [dst], #1 | ||
| 220 | mov r5, r4, get_byte_1 | ||
| 221 | strb r5, [dst], #1 | ||
| 222 | mov r5, r4, get_byte_2 | ||
| 223 | b .exit | ||
| 224 | |||
| 225 | .src2_aligned: mov r4, r5, pull #16 | ||
| 226 | adds sum, sum, #0 | ||
| 227 | bics ip, len, #15 | ||
| 228 | beq 2f | ||
| 229 | 1: load4l r5, r6, r7, r8 | ||
| 230 | orr r4, r4, r5, push #16 | ||
| 231 | mov r5, r5, pull #16 | ||
| 232 | orr r5, r5, r6, push #16 | ||
| 233 | mov r6, r6, pull #16 | ||
| 234 | orr r6, r6, r7, push #16 | ||
| 235 | mov r7, r7, pull #16 | ||
| 236 | orr r7, r7, r8, push #16 | ||
| 237 | stmia dst!, {r4, r5, r6, r7} | ||
| 238 | adcs sum, sum, r4 | ||
| 239 | adcs sum, sum, r5 | ||
| 240 | adcs sum, sum, r6 | ||
| 241 | adcs sum, sum, r7 | ||
| 242 | mov r4, r8, pull #16 | ||
| 243 | sub ip, ip, #16 | ||
| 244 | teq ip, #0 | ||
| 245 | bne 1b | ||
| 246 | 2: ands ip, len, #12 | ||
| 247 | beq 4f | ||
| 248 | tst ip, #8 | ||
| 249 | beq 3f | ||
| 250 | load2l r5, r6 | ||
| 251 | orr r4, r4, r5, push #16 | ||
| 252 | mov r5, r5, pull #16 | ||
| 253 | orr r5, r5, r6, push #16 | ||
| 254 | stmia dst!, {r4, r5} | ||
| 255 | adcs sum, sum, r4 | ||
| 256 | adcs sum, sum, r5 | ||
| 257 | mov r4, r6, pull #16 | ||
| 258 | tst ip, #4 | ||
| 259 | beq 4f | ||
| 260 | 3: load1l r5 | ||
| 261 | orr r4, r4, r5, push #16 | ||
| 262 | str r4, [dst], #4 | ||
| 263 | adcs sum, sum, r4 | ||
| 264 | mov r4, r5, pull #16 | ||
| 265 | 4: ands len, len, #3 | ||
| 266 | beq .done | ||
| 267 | mov r5, r4, get_byte_0 | ||
| 268 | tst len, #2 | ||
| 269 | beq .exit | ||
| 270 | adcs sum, sum, r4 | ||
| 271 | strb r5, [dst], #1 | ||
| 272 | mov r5, r4, get_byte_1 | ||
| 273 | strb r5, [dst], #1 | ||
| 274 | tst len, #1 | ||
| 275 | beq .done | ||
| 276 | load1b r5 | ||
| 277 | b .exit | ||
| 278 | |||
| 279 | .src3_aligned: mov r4, r5, pull #24 | ||
| 280 | adds sum, sum, #0 | ||
| 281 | bics ip, len, #15 | ||
| 282 | beq 2f | ||
| 283 | 1: load4l r5, r6, r7, r8 | ||
| 284 | orr r4, r4, r5, push #8 | ||
| 285 | mov r5, r5, pull #24 | ||
| 286 | orr r5, r5, r6, push #8 | ||
| 287 | mov r6, r6, pull #24 | ||
| 288 | orr r6, r6, r7, push #8 | ||
| 289 | mov r7, r7, pull #24 | ||
| 290 | orr r7, r7, r8, push #8 | ||
| 291 | stmia dst!, {r4, r5, r6, r7} | ||
| 292 | adcs sum, sum, r4 | ||
| 293 | adcs sum, sum, r5 | ||
| 294 | adcs sum, sum, r6 | ||
| 295 | adcs sum, sum, r7 | ||
| 296 | mov r4, r8, pull #24 | ||
| 297 | sub ip, ip, #16 | ||
| 298 | teq ip, #0 | ||
| 299 | bne 1b | ||
| 300 | 2: ands ip, len, #12 | ||
| 301 | beq 4f | ||
| 302 | tst ip, #8 | ||
| 303 | beq 3f | ||
| 304 | load2l r5, r6 | ||
| 305 | orr r4, r4, r5, push #8 | ||
| 306 | mov r5, r5, pull #24 | ||
| 307 | orr r5, r5, r6, push #8 | ||
| 308 | stmia dst!, {r4, r5} | ||
| 309 | adcs sum, sum, r4 | ||
| 310 | adcs sum, sum, r5 | ||
| 311 | mov r4, r6, pull #24 | ||
| 312 | tst ip, #4 | ||
| 313 | beq 4f | ||
| 314 | 3: load1l r5 | ||
| 315 | orr r4, r4, r5, push #8 | ||
| 316 | str r4, [dst], #4 | ||
| 317 | adcs sum, sum, r4 | ||
| 318 | mov r4, r5, pull #24 | ||
| 319 | 4: ands len, len, #3 | ||
| 320 | beq .done | ||
| 321 | mov r5, r4, get_byte_0 | ||
| 322 | tst len, #2 | ||
| 323 | beq .exit | ||
| 324 | strb r5, [dst], #1 | ||
| 325 | adcs sum, sum, r4 | ||
| 326 | load1l r4 | ||
| 327 | mov r5, r4, get_byte_0 | ||
| 328 | strb r5, [dst], #1 | ||
| 329 | adcs sum, sum, r4, push #24 | ||
| 330 | mov r5, r4, get_byte_1 | ||
| 331 | b .exit | ||
diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S new file mode 100644 index 000000000000..46a2dc962e9d --- /dev/null +++ b/arch/arm/lib/csumpartialcopyuser.S | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/csumpartialcopyuser.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-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 | * 27/03/03 Ian Molton Clean up CONFIG_CPU | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | #include <linux/linkage.h> | ||
| 14 | #include <asm/assembler.h> | ||
| 15 | #include <asm/errno.h> | ||
| 16 | #include <asm/constants.h> | ||
| 17 | |||
| 18 | .text | ||
| 19 | |||
| 20 | .macro save_regs | ||
| 21 | stmfd sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc} | ||
| 22 | .endm | ||
| 23 | |||
| 24 | .macro load_regs,flags | ||
| 25 | ldm\flags fp, {r1, r2, r4-r8, fp, sp, pc} | ||
| 26 | .endm | ||
| 27 | |||
| 28 | .macro load1b, reg1 | ||
| 29 | 9999: ldrbt \reg1, [r0], $1 | ||
| 30 | .section __ex_table, "a" | ||
| 31 | .align 3 | ||
| 32 | .long 9999b, 6001f | ||
| 33 | .previous | ||
| 34 | .endm | ||
| 35 | |||
| 36 | .macro load2b, reg1, reg2 | ||
| 37 | 9999: ldrbt \reg1, [r0], $1 | ||
| 38 | 9998: ldrbt \reg2, [r0], $1 | ||
| 39 | .section __ex_table, "a" | ||
| 40 | .long 9999b, 6001f | ||
| 41 | .long 9998b, 6001f | ||
| 42 | .previous | ||
| 43 | .endm | ||
| 44 | |||
| 45 | .macro load1l, reg1 | ||
| 46 | 9999: ldrt \reg1, [r0], $4 | ||
| 47 | .section __ex_table, "a" | ||
| 48 | .align 3 | ||
| 49 | .long 9999b, 6001f | ||
| 50 | .previous | ||
| 51 | .endm | ||
| 52 | |||
| 53 | .macro load2l, reg1, reg2 | ||
| 54 | 9999: ldrt \reg1, [r0], $4 | ||
| 55 | 9998: ldrt \reg2, [r0], $4 | ||
| 56 | .section __ex_table, "a" | ||
| 57 | .long 9999b, 6001f | ||
| 58 | .long 9998b, 6001f | ||
| 59 | .previous | ||
| 60 | .endm | ||
| 61 | |||
| 62 | .macro load4l, reg1, reg2, reg3, reg4 | ||
| 63 | 9999: ldrt \reg1, [r0], $4 | ||
| 64 | 9998: ldrt \reg2, [r0], $4 | ||
| 65 | 9997: ldrt \reg3, [r0], $4 | ||
| 66 | 9996: ldrt \reg4, [r0], $4 | ||
| 67 | .section __ex_table, "a" | ||
| 68 | .long 9999b, 6001f | ||
| 69 | .long 9998b, 6001f | ||
| 70 | .long 9997b, 6001f | ||
| 71 | .long 9996b, 6001f | ||
| 72 | .previous | ||
| 73 | .endm | ||
| 74 | |||
| 75 | /* | ||
| 76 | * unsigned int | ||
| 77 | * csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *err_ptr) | ||
| 78 | * r0 = src, r1 = dst, r2 = len, r3 = sum, [sp] = *err_ptr | ||
| 79 | * Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT | ||
| 80 | */ | ||
| 81 | |||
| 82 | #define FN_ENTRY ENTRY(csum_partial_copy_from_user) | ||
| 83 | |||
| 84 | #include "csumpartialcopygeneric.S" | ||
| 85 | |||
| 86 | /* | ||
| 87 | * FIXME: minor buglet here | ||
| 88 | * We don't return the checksum for the data present in the buffer. To do | ||
| 89 | * so properly, we would have to add in whatever registers were loaded before | ||
| 90 | * the fault, which, with the current asm above is not predictable. | ||
| 91 | */ | ||
| 92 | .section .fixup,"ax" | ||
| 93 | .align 4 | ||
| 94 | 6001: mov r4, #-EFAULT | ||
| 95 | ldr r5, [fp, #4] @ *err_ptr | ||
| 96 | str r4, [r5] | ||
| 97 | ldmia sp, {r1, r2} @ retrieve dst, len | ||
| 98 | add r2, r2, r1 | ||
| 99 | mov r0, #0 @ zero the buffer | ||
| 100 | 6002: teq r2, r1 | ||
| 101 | strneb r0, [r1], #1 | ||
| 102 | bne 6002b | ||
| 103 | load_regs ea | ||
| 104 | .previous | ||
diff --git a/arch/arm/lib/delay.S b/arch/arm/lib/delay.S new file mode 100644 index 000000000000..3c7f7e675dd8 --- /dev/null +++ b/arch/arm/lib/delay.S | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/delay.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995, 1996 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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | .text | ||
| 13 | |||
| 14 | LC0: .word loops_per_jiffy | ||
| 15 | |||
| 16 | /* | ||
| 17 | * 0 <= r0 <= 2000 | ||
| 18 | */ | ||
| 19 | ENTRY(__udelay) | ||
| 20 | mov r2, #0x6800 | ||
| 21 | orr r2, r2, #0x00db | ||
| 22 | mul r0, r2, r0 | ||
| 23 | ENTRY(__const_udelay) @ 0 <= r0 <= 0x01ffffff | ||
| 24 | ldr r2, LC0 | ||
| 25 | ldr r2, [r2] @ max = 0x0fffffff | ||
| 26 | mov r0, r0, lsr #11 @ max = 0x00003fff | ||
| 27 | mov r2, r2, lsr #11 @ max = 0x0003ffff | ||
| 28 | mul r0, r2, r0 @ max = 2^32-1 | ||
| 29 | movs r0, r0, lsr #6 | ||
| 30 | RETINSTR(moveq,pc,lr) | ||
| 31 | |||
| 32 | /* | ||
| 33 | * loops = (r0 * 0x10c6 * 100 * loops_per_jiffy) / 2^32 | ||
| 34 | * | ||
| 35 | * Oh, if only we had a cycle counter... | ||
| 36 | */ | ||
| 37 | |||
| 38 | @ Delay routine | ||
| 39 | ENTRY(__delay) | ||
| 40 | subs r0, r0, #1 | ||
| 41 | #if 0 | ||
| 42 | RETINSTR(movls,pc,lr) | ||
| 43 | subs r0, r0, #1 | ||
| 44 | RETINSTR(movls,pc,lr) | ||
| 45 | subs r0, r0, #1 | ||
| 46 | RETINSTR(movls,pc,lr) | ||
| 47 | subs r0, r0, #1 | ||
| 48 | RETINSTR(movls,pc,lr) | ||
| 49 | subs r0, r0, #1 | ||
| 50 | RETINSTR(movls,pc,lr) | ||
| 51 | subs r0, r0, #1 | ||
| 52 | RETINSTR(movls,pc,lr) | ||
| 53 | subs r0, r0, #1 | ||
| 54 | RETINSTR(movls,pc,lr) | ||
| 55 | subs r0, r0, #1 | ||
| 56 | #endif | ||
| 57 | bhi __delay | ||
| 58 | RETINSTR(mov,pc,lr) | ||
diff --git a/arch/arm/lib/div64.S b/arch/arm/lib/div64.S new file mode 100644 index 000000000000..ec9a1cd6176f --- /dev/null +++ b/arch/arm/lib/div64.S | |||
| @@ -0,0 +1,200 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/div64.S | ||
| 3 | * | ||
| 4 | * Optimized computation of 64-bit dividend / 32-bit divisor | ||
| 5 | * | ||
| 6 | * Author: Nicolas Pitre | ||
| 7 | * Created: Oct 5, 2003 | ||
| 8 | * Copyright: Monta Vista Software, Inc. | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/linkage.h> | ||
| 16 | |||
| 17 | #ifdef __ARMEB__ | ||
| 18 | #define xh r0 | ||
| 19 | #define xl r1 | ||
| 20 | #define yh r2 | ||
| 21 | #define yl r3 | ||
| 22 | #else | ||
| 23 | #define xl r0 | ||
| 24 | #define xh r1 | ||
| 25 | #define yl r2 | ||
| 26 | #define yh r3 | ||
| 27 | #endif | ||
| 28 | |||
| 29 | /* | ||
| 30 | * __do_div64: perform a division with 64-bit dividend and 32-bit divisor. | ||
| 31 | * | ||
| 32 | * Note: Calling convention is totally non standard for optimal code. | ||
| 33 | * This is meant to be used by do_div() from include/asm/div64.h only. | ||
| 34 | * | ||
| 35 | * Input parameters: | ||
| 36 | * xh-xl = dividend (clobbered) | ||
| 37 | * r4 = divisor (preserved) | ||
| 38 | * | ||
| 39 | * Output values: | ||
| 40 | * yh-yl = result | ||
| 41 | * xh = remainder | ||
| 42 | * | ||
| 43 | * Clobbered regs: xl, ip | ||
| 44 | */ | ||
| 45 | |||
| 46 | ENTRY(__do_div64) | ||
| 47 | |||
| 48 | @ Test for easy paths first. | ||
| 49 | subs ip, r4, #1 | ||
| 50 | bls 9f @ divisor is 0 or 1 | ||
| 51 | tst ip, r4 | ||
| 52 | beq 8f @ divisor is power of 2 | ||
| 53 | |||
| 54 | @ See if we need to handle upper 32-bit result. | ||
| 55 | cmp xh, r4 | ||
| 56 | mov yh, #0 | ||
| 57 | blo 3f | ||
| 58 | |||
| 59 | @ Align divisor with upper part of dividend. | ||
| 60 | @ The aligned divisor is stored in yl preserving the original. | ||
| 61 | @ The bit position is stored in ip. | ||
| 62 | |||
| 63 | #if __LINUX_ARM_ARCH__ >= 5 | ||
| 64 | |||
| 65 | clz yl, r4 | ||
| 66 | clz ip, xh | ||
| 67 | sub yl, yl, ip | ||
| 68 | mov ip, #1 | ||
| 69 | mov ip, ip, lsl yl | ||
| 70 | mov yl, r4, lsl yl | ||
| 71 | |||
| 72 | #else | ||
| 73 | |||
| 74 | mov yl, r4 | ||
| 75 | mov ip, #1 | ||
| 76 | 1: cmp yl, #0x80000000 | ||
| 77 | cmpcc yl, xh | ||
| 78 | movcc yl, yl, lsl #1 | ||
| 79 | movcc ip, ip, lsl #1 | ||
| 80 | bcc 1b | ||
| 81 | |||
| 82 | #endif | ||
| 83 | |||
| 84 | @ The division loop for needed upper bit positions. | ||
| 85 | @ Break out early if dividend reaches 0. | ||
| 86 | 2: cmp xh, yl | ||
| 87 | orrcs yh, yh, ip | ||
| 88 | subcss xh, xh, yl | ||
| 89 | movnes ip, ip, lsr #1 | ||
| 90 | mov yl, yl, lsr #1 | ||
| 91 | bne 2b | ||
| 92 | |||
| 93 | @ See if we need to handle lower 32-bit result. | ||
| 94 | 3: cmp xh, #0 | ||
| 95 | mov yl, #0 | ||
| 96 | cmpeq xl, r4 | ||
| 97 | movlo xh, xl | ||
| 98 | movlo pc, lr | ||
| 99 | |||
| 100 | @ The division loop for lower bit positions. | ||
| 101 | @ Here we shift remainer bits leftwards rather than moving the | ||
| 102 | @ divisor for comparisons, considering the carry-out bit as well. | ||
| 103 | mov ip, #0x80000000 | ||
| 104 | 4: movs xl, xl, lsl #1 | ||
| 105 | adcs xh, xh, xh | ||
| 106 | beq 6f | ||
| 107 | cmpcc xh, r4 | ||
| 108 | 5: orrcs yl, yl, ip | ||
| 109 | subcs xh, xh, r4 | ||
| 110 | movs ip, ip, lsr #1 | ||
| 111 | bne 4b | ||
| 112 | mov pc, lr | ||
| 113 | |||
| 114 | @ The top part of remainder became zero. If carry is set | ||
| 115 | @ (the 33th bit) this is a false positive so resume the loop. | ||
| 116 | @ Otherwise, if lower part is also null then we are done. | ||
| 117 | 6: bcs 5b | ||
| 118 | cmp xl, #0 | ||
| 119 | moveq pc, lr | ||
| 120 | |||
| 121 | @ We still have remainer bits in the low part. Bring them up. | ||
| 122 | |||
| 123 | #if __LINUX_ARM_ARCH__ >= 5 | ||
| 124 | |||
| 125 | clz xh, xl @ we know xh is zero here so... | ||
| 126 | add xh, xh, #1 | ||
| 127 | mov xl, xl, lsl xh | ||
| 128 | mov ip, ip, lsr xh | ||
| 129 | |||
| 130 | #else | ||
| 131 | |||
| 132 | 7: movs xl, xl, lsl #1 | ||
| 133 | mov ip, ip, lsr #1 | ||
| 134 | bcc 7b | ||
| 135 | |||
| 136 | #endif | ||
| 137 | |||
| 138 | @ Current remainder is now 1. It is worthless to compare with | ||
| 139 | @ divisor at this point since divisor can not be smaller than 3 here. | ||
| 140 | @ If possible, branch for another shift in the division loop. | ||
| 141 | @ If no bit position left then we are done. | ||
| 142 | movs ip, ip, lsr #1 | ||
| 143 | mov xh, #1 | ||
| 144 | bne 4b | ||
| 145 | mov pc, lr | ||
| 146 | |||
| 147 | 8: @ Division by a power of 2: determine what that divisor order is | ||
| 148 | @ then simply shift values around | ||
| 149 | |||
| 150 | #if __LINUX_ARM_ARCH__ >= 5 | ||
| 151 | |||
| 152 | clz ip, r4 | ||
| 153 | rsb ip, ip, #31 | ||
| 154 | |||
| 155 | #else | ||
| 156 | |||
| 157 | mov yl, r4 | ||
| 158 | cmp r4, #(1 << 16) | ||
| 159 | mov ip, #0 | ||
| 160 | movhs yl, yl, lsr #16 | ||
| 161 | movhs ip, #16 | ||
| 162 | |||
| 163 | cmp yl, #(1 << 8) | ||
| 164 | movhs yl, yl, lsr #8 | ||
| 165 | addhs ip, ip, #8 | ||
| 166 | |||
| 167 | cmp yl, #(1 << 4) | ||
| 168 | movhs yl, yl, lsr #4 | ||
| 169 | addhs ip, ip, #4 | ||
| 170 | |||
| 171 | cmp yl, #(1 << 2) | ||
| 172 | addhi ip, ip, #3 | ||
| 173 | addls ip, ip, yl, lsr #1 | ||
| 174 | |||
| 175 | #endif | ||
| 176 | |||
| 177 | mov yh, xh, lsr ip | ||
| 178 | mov yl, xl, lsr ip | ||
| 179 | rsb ip, ip, #32 | ||
| 180 | orr yl, yl, xh, lsl ip | ||
| 181 | mov xh, xl, lsl ip | ||
| 182 | mov xh, xh, lsr ip | ||
| 183 | mov pc, lr | ||
| 184 | |||
| 185 | @ eq -> division by 1: obvious enough... | ||
| 186 | 9: moveq yl, xl | ||
| 187 | moveq yh, xh | ||
| 188 | moveq xh, #0 | ||
| 189 | moveq pc, lr | ||
| 190 | |||
| 191 | @ Division by 0: | ||
| 192 | str lr, [sp, #-4]! | ||
| 193 | bl __div0 | ||
| 194 | |||
| 195 | @ as wrong as it could be... | ||
| 196 | mov yl, #0 | ||
| 197 | mov yh, #0 | ||
| 198 | mov xh, #0 | ||
| 199 | ldr pc, [sp], #4 | ||
| 200 | |||
diff --git a/arch/arm/lib/ecard.S b/arch/arm/lib/ecard.S new file mode 100644 index 000000000000..fb7b602a6f76 --- /dev/null +++ b/arch/arm/lib/ecard.S | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/ecard.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995, 1996 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 | * 27/03/03 Ian Molton Clean up CONFIG_CPU | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | #include <linux/linkage.h> | ||
| 14 | #include <asm/assembler.h> | ||
| 15 | #include <asm/hardware.h> | ||
| 16 | |||
| 17 | #define CPSR2SPSR(rt) \ | ||
| 18 | mrs rt, cpsr; \ | ||
| 19 | msr spsr_cxsf, rt | ||
| 20 | |||
| 21 | @ Purpose: call an expansion card loader to read bytes. | ||
| 22 | @ Proto : char read_loader(int offset, char *card_base, char *loader); | ||
| 23 | @ Returns: byte read | ||
| 24 | |||
| 25 | ENTRY(ecard_loader_read) | ||
| 26 | stmfd sp!, {r4 - r12, lr} | ||
| 27 | mov r11, r1 | ||
| 28 | mov r1, r0 | ||
| 29 | CPSR2SPSR(r0) | ||
| 30 | mov lr, pc | ||
| 31 | mov pc, r2 | ||
| 32 | LOADREGS(fd, sp!, {r4 - r12, pc}) | ||
| 33 | |||
| 34 | @ Purpose: call an expansion card loader to reset the card | ||
| 35 | @ Proto : void read_loader(int card_base, char *loader); | ||
| 36 | @ Returns: byte read | ||
| 37 | |||
| 38 | ENTRY(ecard_loader_reset) | ||
| 39 | stmfd sp!, {r4 - r12, lr} | ||
| 40 | mov r11, r0 | ||
| 41 | CPSR2SPSR(r0) | ||
| 42 | mov lr, pc | ||
| 43 | add pc, r1, #8 | ||
| 44 | LOADREGS(fd, sp!, {r4 - r12, pc}) | ||
| 45 | |||
diff --git a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S new file mode 100644 index 000000000000..f055d56ea68a --- /dev/null +++ b/arch/arm/lib/findbit.S | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/findbit.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 | * 16th March 2001 - John Ripley <jripley@sonicblue.com> | ||
| 11 | * Fixed so that "size" is an exclusive not an inclusive quantity. | ||
| 12 | * All users of these functions expect exclusive sizes, and may | ||
| 13 | * also call with zero size. | ||
| 14 | * Reworked by rmk. | ||
| 15 | */ | ||
| 16 | #include <linux/linkage.h> | ||
| 17 | #include <asm/assembler.h> | ||
| 18 | .text | ||
| 19 | |||
| 20 | /* | ||
| 21 | * Purpose : Find a 'zero' bit | ||
| 22 | * Prototype: int find_first_zero_bit(void *addr, unsigned int maxbit); | ||
| 23 | */ | ||
| 24 | ENTRY(_find_first_zero_bit_le) | ||
| 25 | teq r1, #0 | ||
| 26 | beq 3f | ||
| 27 | mov r2, #0 | ||
| 28 | 1: ldrb r3, [r0, r2, lsr #3] | ||
| 29 | eors r3, r3, #0xff @ invert bits | ||
| 30 | bne .found @ any now set - found zero bit | ||
| 31 | add r2, r2, #8 @ next bit pointer | ||
| 32 | 2: cmp r2, r1 @ any more? | ||
| 33 | blo 1b | ||
| 34 | 3: mov r0, r1 @ no free bits | ||
| 35 | RETINSTR(mov,pc,lr) | ||
| 36 | |||
| 37 | /* | ||
| 38 | * Purpose : Find next 'zero' bit | ||
| 39 | * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, int offset) | ||
| 40 | */ | ||
| 41 | ENTRY(_find_next_zero_bit_le) | ||
| 42 | teq r1, #0 | ||
| 43 | beq 3b | ||
| 44 | ands ip, r2, #7 | ||
| 45 | beq 1b @ If new byte, goto old routine | ||
| 46 | ldrb r3, [r0, r2, lsr #3] | ||
| 47 | eor r3, r3, #0xff @ now looking for a 1 bit | ||
| 48 | movs r3, r3, lsr ip @ shift off unused bits | ||
| 49 | bne .found | ||
| 50 | orr r2, r2, #7 @ if zero, then no bits here | ||
| 51 | add r2, r2, #1 @ align bit pointer | ||
| 52 | b 2b @ loop for next bit | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Purpose : Find a 'one' bit | ||
| 56 | * Prototype: int find_first_bit(const unsigned long *addr, unsigned int maxbit); | ||
| 57 | */ | ||
| 58 | ENTRY(_find_first_bit_le) | ||
| 59 | teq r1, #0 | ||
| 60 | beq 3f | ||
| 61 | mov r2, #0 | ||
| 62 | 1: ldrb r3, [r0, r2, lsr #3] | ||
| 63 | movs r3, r3 | ||
| 64 | bne .found @ any now set - found zero bit | ||
| 65 | add r2, r2, #8 @ next bit pointer | ||
| 66 | 2: cmp r2, r1 @ any more? | ||
| 67 | blo 1b | ||
| 68 | 3: mov r0, r1 @ no free bits | ||
| 69 | RETINSTR(mov,pc,lr) | ||
| 70 | |||
| 71 | /* | ||
| 72 | * Purpose : Find next 'one' bit | ||
| 73 | * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, int offset) | ||
| 74 | */ | ||
| 75 | ENTRY(_find_next_bit_le) | ||
| 76 | teq r1, #0 | ||
| 77 | beq 3b | ||
| 78 | ands ip, r2, #7 | ||
| 79 | beq 1b @ If new byte, goto old routine | ||
| 80 | ldrb r3, [r0, r2, lsr #3] | ||
| 81 | movs r3, r3, lsr ip @ shift off unused bits | ||
| 82 | bne .found | ||
| 83 | orr r2, r2, #7 @ if zero, then no bits here | ||
| 84 | add r2, r2, #1 @ align bit pointer | ||
| 85 | b 2b @ loop for next bit | ||
| 86 | |||
| 87 | #ifdef __ARMEB__ | ||
| 88 | |||
| 89 | ENTRY(_find_first_zero_bit_be) | ||
| 90 | teq r1, #0 | ||
| 91 | beq 3f | ||
| 92 | mov r2, #0 | ||
| 93 | 1: eor r3, r2, #0x18 @ big endian byte ordering | ||
| 94 | ldrb r3, [r0, r3, lsr #3] | ||
| 95 | eors r3, r3, #0xff @ invert bits | ||
| 96 | bne .found @ any now set - found zero bit | ||
| 97 | add r2, r2, #8 @ next bit pointer | ||
| 98 | 2: cmp r2, r1 @ any more? | ||
| 99 | blo 1b | ||
| 100 | 3: mov r0, r1 @ no free bits | ||
| 101 | RETINSTR(mov,pc,lr) | ||
| 102 | |||
| 103 | ENTRY(_find_next_zero_bit_be) | ||
| 104 | teq r1, #0 | ||
| 105 | beq 3b | ||
| 106 | ands ip, r2, #7 | ||
| 107 | beq 1b @ If new byte, goto old routine | ||
| 108 | eor r3, r2, #0x18 @ big endian byte ordering | ||
| 109 | ldrb r3, [r0, r3, lsr #3] | ||
| 110 | eor r3, r3, #0xff @ now looking for a 1 bit | ||
| 111 | movs r3, r3, lsr ip @ shift off unused bits | ||
| 112 | bne .found | ||
| 113 | orr r2, r2, #7 @ if zero, then no bits here | ||
| 114 | add r2, r2, #1 @ align bit pointer | ||
| 115 | b 2b @ loop for next bit | ||
| 116 | |||
| 117 | ENTRY(_find_first_bit_be) | ||
| 118 | teq r1, #0 | ||
| 119 | beq 3f | ||
| 120 | mov r2, #0 | ||
| 121 | 1: eor r3, r2, #0x18 @ big endian byte ordering | ||
| 122 | ldrb r3, [r0, r3, lsr #3] | ||
| 123 | movs r3, r3 | ||
| 124 | bne .found @ any now set - found zero bit | ||
| 125 | add r2, r2, #8 @ next bit pointer | ||
| 126 | 2: cmp r2, r1 @ any more? | ||
| 127 | blo 1b | ||
| 128 | 3: mov r0, r1 @ no free bits | ||
| 129 | RETINSTR(mov,pc,lr) | ||
| 130 | |||
| 131 | ENTRY(_find_next_bit_be) | ||
| 132 | teq r1, #0 | ||
| 133 | beq 3b | ||
| 134 | ands ip, r2, #7 | ||
| 135 | beq 1b @ If new byte, goto old routine | ||
| 136 | eor r3, r2, #0x18 @ big endian byte ordering | ||
| 137 | ldrb r3, [r0, r3, lsr #3] | ||
| 138 | movs r3, r3, lsr ip @ shift off unused bits | ||
| 139 | bne .found | ||
| 140 | orr r2, r2, #7 @ if zero, then no bits here | ||
| 141 | add r2, r2, #1 @ align bit pointer | ||
| 142 | b 2b @ loop for next bit | ||
| 143 | |||
| 144 | #endif | ||
| 145 | |||
| 146 | /* | ||
| 147 | * One or more bits in the LSB of r3 are assumed to be set. | ||
| 148 | */ | ||
| 149 | .found: | ||
| 150 | #if __LINUX_ARM_ARCH__ >= 5 | ||
| 151 | rsb r1, r3, #0 | ||
| 152 | and r3, r3, r1 | ||
| 153 | clz r3, r3 | ||
| 154 | rsb r3, r3, #31 | ||
| 155 | add r0, r2, r3 | ||
| 156 | #else | ||
| 157 | tst r3, #0x0f | ||
| 158 | addeq r2, r2, #4 | ||
| 159 | movne r3, r3, lsl #4 | ||
| 160 | tst r3, #0x30 | ||
| 161 | addeq r2, r2, #2 | ||
| 162 | movne r3, r3, lsl #2 | ||
| 163 | tst r3, #0x40 | ||
| 164 | addeq r2, r2, #1 | ||
| 165 | mov r0, r2 | ||
| 166 | #endif | ||
| 167 | RETINSTR(mov,pc,lr) | ||
| 168 | |||
diff --git a/arch/arm/lib/floppydma.S b/arch/arm/lib/floppydma.S new file mode 100644 index 000000000000..617150b1baef --- /dev/null +++ b/arch/arm/lib/floppydma.S | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/floppydma.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995, 1996 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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | .text | ||
| 13 | |||
| 14 | .global floppy_fiqin_end | ||
| 15 | ENTRY(floppy_fiqin_start) | ||
| 16 | subs r9, r9, #1 | ||
| 17 | ldrgtb r12, [r11, #-4] | ||
| 18 | ldrleb r12, [r11], #0 | ||
| 19 | strb r12, [r10], #1 | ||
| 20 | subs pc, lr, #4 | ||
| 21 | floppy_fiqin_end: | ||
| 22 | |||
| 23 | .global floppy_fiqout_end | ||
| 24 | ENTRY(floppy_fiqout_start) | ||
| 25 | subs r9, r9, #1 | ||
| 26 | ldrgeb r12, [r10], #1 | ||
| 27 | movlt r12, #0 | ||
| 28 | strleb r12, [r11], #0 | ||
| 29 | subles pc, lr, #4 | ||
| 30 | strb r12, [r11, #-4] | ||
| 31 | subs pc, lr, #4 | ||
| 32 | floppy_fiqout_end: | ||
diff --git a/arch/arm/lib/gcclib.h b/arch/arm/lib/gcclib.h new file mode 100644 index 000000000000..65314a3d9e27 --- /dev/null +++ b/arch/arm/lib/gcclib.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | /* gcclib.h -- definitions for various functions 'borrowed' from gcc-2.95.3 */ | ||
| 2 | /* I Molton 29/07/01 */ | ||
| 3 | |||
| 4 | #define BITS_PER_UNIT 8 | ||
| 5 | #define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT) | ||
| 6 | |||
| 7 | typedef unsigned int UQItype __attribute__ ((mode (QI))); | ||
| 8 | typedef int SItype __attribute__ ((mode (SI))); | ||
| 9 | typedef unsigned int USItype __attribute__ ((mode (SI))); | ||
| 10 | typedef int DItype __attribute__ ((mode (DI))); | ||
| 11 | typedef int word_type __attribute__ ((mode (__word__))); | ||
| 12 | typedef unsigned int UDItype __attribute__ ((mode (DI))); | ||
| 13 | |||
| 14 | #ifdef __ARMEB__ | ||
| 15 | struct DIstruct {SItype high, low;}; | ||
| 16 | #else | ||
| 17 | struct DIstruct {SItype low, high;}; | ||
| 18 | #endif | ||
| 19 | |||
| 20 | typedef union | ||
| 21 | { | ||
| 22 | struct DIstruct s; | ||
| 23 | DItype ll; | ||
| 24 | } DIunion; | ||
| 25 | |||
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S new file mode 100644 index 000000000000..64aa6f4fe5e4 --- /dev/null +++ b/arch/arm/lib/getuser.S | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/getuser.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 2001 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 | * Idea from x86 version, (C) Copyright 1998 Linus Torvalds | ||
| 11 | * | ||
| 12 | * These functions have a non-standard call interface to make them more | ||
| 13 | * efficient, especially as they return an error value in addition to | ||
| 14 | * the "real" return value. | ||
| 15 | * | ||
| 16 | * __get_user_X | ||
| 17 | * | ||
| 18 | * Inputs: r0 contains the address | ||
| 19 | * Outputs: r0 is the error code | ||
| 20 | * r2, r3 contains the zero-extended value | ||
| 21 | * lr corrupted | ||
| 22 | * | ||
| 23 | * No other registers must be altered. (see include/asm-arm/uaccess.h | ||
| 24 | * for specific ASM register usage). | ||
| 25 | * | ||
| 26 | * Note that ADDR_LIMIT is either 0 or 0xc0000000. | ||
| 27 | * Note also that it is intended that __get_user_bad is not global. | ||
| 28 | */ | ||
| 29 | #include <asm/constants.h> | ||
| 30 | #include <asm/thread_info.h> | ||
| 31 | #include <asm/errno.h> | ||
| 32 | |||
| 33 | .global __get_user_1 | ||
| 34 | __get_user_1: | ||
| 35 | 1: ldrbt r2, [r0] | ||
| 36 | mov r0, #0 | ||
| 37 | mov pc, lr | ||
| 38 | |||
| 39 | .global __get_user_2 | ||
| 40 | __get_user_2: | ||
| 41 | 2: ldrbt r2, [r0], #1 | ||
| 42 | 3: ldrbt r3, [r0] | ||
| 43 | #ifndef __ARMEB__ | ||
| 44 | orr r2, r2, r3, lsl #8 | ||
| 45 | #else | ||
| 46 | orr r2, r3, r2, lsl #8 | ||
| 47 | #endif | ||
| 48 | mov r0, #0 | ||
| 49 | mov pc, lr | ||
| 50 | |||
| 51 | .global __get_user_4 | ||
| 52 | __get_user_4: | ||
| 53 | 4: ldrt r2, [r0] | ||
| 54 | mov r0, #0 | ||
| 55 | mov pc, lr | ||
| 56 | |||
| 57 | .global __get_user_8 | ||
| 58 | __get_user_8: | ||
| 59 | 5: ldrt r2, [r0], #4 | ||
| 60 | 6: ldrt r3, [r0] | ||
| 61 | mov r0, #0 | ||
| 62 | mov pc, lr | ||
| 63 | |||
| 64 | __get_user_bad_8: | ||
| 65 | mov r3, #0 | ||
| 66 | __get_user_bad: | ||
| 67 | mov r2, #0 | ||
| 68 | mov r0, #-EFAULT | ||
| 69 | mov pc, lr | ||
| 70 | |||
| 71 | .section __ex_table, "a" | ||
| 72 | .long 1b, __get_user_bad | ||
| 73 | .long 2b, __get_user_bad | ||
| 74 | .long 3b, __get_user_bad | ||
| 75 | .long 4b, __get_user_bad | ||
| 76 | .long 5b, __get_user_bad_8 | ||
| 77 | .long 6b, __get_user_bad_8 | ||
| 78 | .previous | ||
diff --git a/arch/arm/lib/io-acorn.S b/arch/arm/lib/io-acorn.S new file mode 100644 index 000000000000..3aacd01d40e1 --- /dev/null +++ b/arch/arm/lib/io-acorn.S | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/io-acorn.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995, 1996 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 | * 27/03/03 Ian Molton Clean up CONFIG_CPU | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | #include <linux/linkage.h> | ||
| 14 | #include <asm/assembler.h> | ||
| 15 | #include <asm/hardware.h> | ||
| 16 | |||
| 17 | .text | ||
| 18 | .align | ||
| 19 | |||
| 20 | .iosl_warning: | ||
| 21 | .ascii "<4>insl/outsl not implemented, called from %08lX\0" | ||
| 22 | .align | ||
| 23 | |||
| 24 | /* | ||
| 25 | * These make no sense on Acorn machines. | ||
| 26 | * Print a warning message. | ||
| 27 | */ | ||
| 28 | ENTRY(insl) | ||
| 29 | ENTRY(outsl) | ||
| 30 | adr r0, .iosl_warning | ||
| 31 | mov r1, lr | ||
| 32 | b printk | ||
diff --git a/arch/arm/lib/io-readsb.S b/arch/arm/lib/io-readsb.S new file mode 100644 index 000000000000..081ef749298a --- /dev/null +++ b/arch/arm/lib/io-readsb.S | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/io-readsb.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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | |||
| 13 | .insb_align: rsb ip, ip, #4 | ||
| 14 | cmp ip, r2 | ||
| 15 | movgt ip, r2 | ||
| 16 | cmp ip, #2 | ||
| 17 | ldrb r3, [r0] | ||
| 18 | strb r3, [r1], #1 | ||
| 19 | ldrgeb r3, [r0] | ||
| 20 | strgeb r3, [r1], #1 | ||
| 21 | ldrgtb r3, [r0] | ||
| 22 | strgtb r3, [r1], #1 | ||
| 23 | subs r2, r2, ip | ||
| 24 | bne .insb_aligned | ||
| 25 | |||
| 26 | ENTRY(__raw_readsb) | ||
| 27 | teq r2, #0 @ do we have to check for the zero len? | ||
| 28 | moveq pc, lr | ||
| 29 | ands ip, r1, #3 | ||
| 30 | bne .insb_align | ||
| 31 | |||
| 32 | .insb_aligned: stmfd sp!, {r4 - r6, lr} | ||
| 33 | |||
| 34 | subs r2, r2, #16 | ||
| 35 | bmi .insb_no_16 | ||
| 36 | |||
| 37 | .insb_16_lp: ldrb r3, [r0] | ||
| 38 | ldrb r4, [r0] | ||
| 39 | ldrb r5, [r0] | ||
| 40 | mov r3, r3, put_byte_0 | ||
| 41 | ldrb r6, [r0] | ||
| 42 | orr r3, r3, r4, put_byte_1 | ||
| 43 | ldrb r4, [r0] | ||
| 44 | orr r3, r3, r5, put_byte_2 | ||
| 45 | ldrb r5, [r0] | ||
| 46 | orr r3, r3, r6, put_byte_3 | ||
| 47 | ldrb r6, [r0] | ||
| 48 | mov r4, r4, put_byte_0 | ||
| 49 | ldrb ip, [r0] | ||
| 50 | orr r4, r4, r5, put_byte_1 | ||
| 51 | ldrb r5, [r0] | ||
| 52 | orr r4, r4, r6, put_byte_2 | ||
| 53 | ldrb r6, [r0] | ||
| 54 | orr r4, r4, ip, put_byte_3 | ||
| 55 | ldrb ip, [r0] | ||
| 56 | mov r5, r5, put_byte_0 | ||
| 57 | ldrb lr, [r0] | ||
| 58 | orr r5, r5, r6, put_byte_1 | ||
| 59 | ldrb r6, [r0] | ||
| 60 | orr r5, r5, ip, put_byte_2 | ||
| 61 | ldrb ip, [r0] | ||
| 62 | orr r5, r5, lr, put_byte_3 | ||
| 63 | ldrb lr, [r0] | ||
| 64 | mov r6, r6, put_byte_0 | ||
| 65 | orr r6, r6, ip, put_byte_1 | ||
| 66 | ldrb ip, [r0] | ||
| 67 | orr r6, r6, lr, put_byte_2 | ||
| 68 | orr r6, r6, ip, put_byte_3 | ||
| 69 | stmia r1!, {r3 - r6} | ||
| 70 | |||
| 71 | subs r2, r2, #16 | ||
| 72 | bpl .insb_16_lp | ||
| 73 | |||
| 74 | tst r2, #15 | ||
| 75 | LOADREGS(eqfd, sp!, {r4 - r6, pc}) | ||
| 76 | |||
| 77 | .insb_no_16: tst r2, #8 | ||
| 78 | beq .insb_no_8 | ||
| 79 | |||
| 80 | ldrb r3, [r0] | ||
| 81 | ldrb r4, [r0] | ||
| 82 | ldrb r5, [r0] | ||
| 83 | mov r3, r3, put_byte_0 | ||
| 84 | ldrb r6, [r0] | ||
| 85 | orr r3, r3, r4, put_byte_1 | ||
| 86 | ldrb r4, [r0] | ||
| 87 | orr r3, r3, r5, put_byte_2 | ||
| 88 | ldrb r5, [r0] | ||
| 89 | orr r3, r3, r6, put_byte_3 | ||
| 90 | ldrb r6, [r0] | ||
| 91 | mov r4, r4, put_byte_0 | ||
| 92 | ldrb ip, [r0] | ||
| 93 | orr r4, r4, r5, put_byte_1 | ||
| 94 | orr r4, r4, r6, put_byte_2 | ||
| 95 | orr r4, r4, ip, put_byte_3 | ||
| 96 | stmia r1!, {r3, r4} | ||
| 97 | |||
| 98 | .insb_no_8: tst r2, #4 | ||
| 99 | beq .insb_no_4 | ||
| 100 | |||
| 101 | ldrb r3, [r0] | ||
| 102 | ldrb r4, [r0] | ||
| 103 | ldrb r5, [r0] | ||
| 104 | ldrb r6, [r0] | ||
| 105 | mov r3, r3, put_byte_0 | ||
| 106 | orr r3, r3, r4, put_byte_1 | ||
| 107 | orr r3, r3, r5, put_byte_2 | ||
| 108 | orr r3, r3, r6, put_byte_3 | ||
| 109 | str r3, [r1], #4 | ||
| 110 | |||
| 111 | .insb_no_4: ands r2, r2, #3 | ||
| 112 | LOADREGS(eqfd, sp!, {r4 - r6, pc}) | ||
| 113 | |||
| 114 | cmp r2, #2 | ||
| 115 | ldrb r3, [r0] | ||
| 116 | strb r3, [r1], #1 | ||
| 117 | ldrgeb r3, [r0] | ||
| 118 | strgeb r3, [r1], #1 | ||
| 119 | ldrgtb r3, [r0] | ||
| 120 | strgtb r3, [r1] | ||
| 121 | |||
| 122 | LOADREGS(fd, sp!, {r4 - r6, pc}) | ||
diff --git a/arch/arm/lib/io-readsl.S b/arch/arm/lib/io-readsl.S new file mode 100644 index 000000000000..75a9121cb23f --- /dev/null +++ b/arch/arm/lib/io-readsl.S | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/io-readsl.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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | |||
| 13 | ENTRY(__raw_readsl) | ||
| 14 | teq r2, #0 @ do we have to check for the zero len? | ||
| 15 | moveq pc, lr | ||
| 16 | ands ip, r1, #3 | ||
| 17 | bne 3f | ||
| 18 | |||
| 19 | subs r2, r2, #4 | ||
| 20 | bmi 2f | ||
| 21 | stmfd sp!, {r4, lr} | ||
| 22 | 1: ldr r3, [r0, #0] | ||
| 23 | ldr r4, [r0, #0] | ||
| 24 | ldr ip, [r0, #0] | ||
| 25 | ldr lr, [r0, #0] | ||
| 26 | subs r2, r2, #4 | ||
| 27 | stmia r1!, {r3, r4, ip, lr} | ||
| 28 | bpl 1b | ||
| 29 | ldmfd sp!, {r4, lr} | ||
| 30 | 2: movs r2, r2, lsl #31 | ||
| 31 | ldrcs r3, [r0, #0] | ||
| 32 | ldrcs ip, [r0, #0] | ||
| 33 | stmcsia r1!, {r3, ip} | ||
| 34 | ldrne r3, [r0, #0] | ||
| 35 | strne r3, [r1, #0] | ||
| 36 | mov pc, lr | ||
| 37 | |||
| 38 | 3: ldr r3, [r0] | ||
| 39 | cmp ip, #2 | ||
| 40 | mov ip, r3, get_byte_0 | ||
| 41 | strb ip, [r1], #1 | ||
| 42 | bgt 6f | ||
| 43 | mov ip, r3, get_byte_1 | ||
| 44 | strb ip, [r1], #1 | ||
| 45 | beq 5f | ||
| 46 | mov ip, r3, get_byte_2 | ||
| 47 | strb ip, [r1], #1 | ||
| 48 | |||
| 49 | 4: subs r2, r2, #1 | ||
| 50 | mov ip, r3, pull #24 | ||
| 51 | ldrne r3, [r0] | ||
| 52 | orrne ip, ip, r3, push #8 | ||
| 53 | strne ip, [r1], #4 | ||
| 54 | bne 4b | ||
| 55 | b 8f | ||
| 56 | |||
| 57 | 5: subs r2, r2, #1 | ||
| 58 | mov ip, r3, pull #16 | ||
| 59 | ldrne r3, [r0] | ||
| 60 | orrne ip, ip, r3, push #16 | ||
| 61 | strne ip, [r1], #4 | ||
| 62 | bne 5b | ||
| 63 | b 7f | ||
| 64 | |||
| 65 | 6: subs r2, r2, #1 | ||
| 66 | mov ip, r3, pull #8 | ||
| 67 | ldrne r3, [r0] | ||
| 68 | orrne ip, ip, r3, push #24 | ||
| 69 | strne ip, [r1], #4 | ||
| 70 | bne 6b | ||
| 71 | |||
| 72 | mov r3, ip, get_byte_2 | ||
| 73 | strb r3, [r1, #2] | ||
| 74 | 7: mov r3, ip, get_byte_1 | ||
| 75 | strb r3, [r1, #1] | ||
| 76 | 8: mov r3, ip, get_byte_0 | ||
| 77 | strb r3, [r1, #0] | ||
| 78 | mov pc, lr | ||
diff --git a/arch/arm/lib/io-readsw-armv3.S b/arch/arm/lib/io-readsw-armv3.S new file mode 100644 index 000000000000..476cf7f8a633 --- /dev/null +++ b/arch/arm/lib/io-readsw-armv3.S | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/io-readsw-armv3.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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | #include <asm/hardware.h> | ||
| 13 | |||
| 14 | .insw_bad_alignment: | ||
| 15 | adr r0, .insw_bad_align_msg | ||
| 16 | mov r2, lr | ||
| 17 | b panic | ||
| 18 | .insw_bad_align_msg: | ||
| 19 | .asciz "insw: bad buffer alignment (0x%p, lr=0x%08lX)\n" | ||
| 20 | .align | ||
| 21 | |||
| 22 | .insw_align: tst r1, #1 | ||
| 23 | bne .insw_bad_alignment | ||
| 24 | |||
| 25 | ldr r3, [r0] | ||
| 26 | strb r3, [r1], #1 | ||
| 27 | mov r3, r3, lsr #8 | ||
| 28 | strb r3, [r1], #1 | ||
| 29 | |||
| 30 | subs r2, r2, #1 | ||
| 31 | RETINSTR(moveq, pc, lr) | ||
| 32 | |||
| 33 | ENTRY(__raw_readsw) | ||
| 34 | teq r2, #0 @ do we have to check for the zero len? | ||
| 35 | moveq pc, lr | ||
| 36 | tst r1, #3 | ||
| 37 | bne .insw_align | ||
| 38 | |||
| 39 | .insw_aligned: mov ip, #0xff | ||
| 40 | orr ip, ip, ip, lsl #8 | ||
| 41 | stmfd sp!, {r4, r5, r6, lr} | ||
| 42 | |||
| 43 | subs r2, r2, #8 | ||
| 44 | bmi .no_insw_8 | ||
| 45 | |||
| 46 | .insw_8_lp: ldr r3, [r0] | ||
| 47 | and r3, r3, ip | ||
| 48 | ldr r4, [r0] | ||
| 49 | orr r3, r3, r4, lsl #16 | ||
| 50 | |||
| 51 | ldr r4, [r0] | ||
| 52 | and r4, r4, ip | ||
| 53 | ldr r5, [r0] | ||
| 54 | orr r4, r4, r5, lsl #16 | ||
| 55 | |||
| 56 | ldr r5, [r0] | ||
| 57 | and r5, r5, ip | ||
| 58 | ldr r6, [r0] | ||
| 59 | orr r5, r5, r6, lsl #16 | ||
| 60 | |||
| 61 | ldr r6, [r0] | ||
| 62 | and r6, r6, ip | ||
| 63 | ldr lr, [r0] | ||
| 64 | orr r6, r6, lr, lsl #16 | ||
| 65 | |||
| 66 | stmia r1!, {r3 - r6} | ||
| 67 | |||
| 68 | subs r2, r2, #8 | ||
| 69 | bpl .insw_8_lp | ||
| 70 | |||
| 71 | tst r2, #7 | ||
| 72 | LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) | ||
| 73 | |||
| 74 | .no_insw_8: tst r2, #4 | ||
| 75 | beq .no_insw_4 | ||
| 76 | |||
| 77 | ldr r3, [r0] | ||
| 78 | and r3, r3, ip | ||
| 79 | ldr r4, [r0] | ||
| 80 | orr r3, r3, r4, lsl #16 | ||
| 81 | |||
| 82 | ldr r4, [r0] | ||
| 83 | and r4, r4, ip | ||
| 84 | ldr r5, [r0] | ||
| 85 | orr r4, r4, r5, lsl #16 | ||
| 86 | |||
| 87 | stmia r1!, {r3, r4} | ||
| 88 | |||
| 89 | .no_insw_4: tst r2, #2 | ||
| 90 | beq .no_insw_2 | ||
| 91 | |||
| 92 | ldr r3, [r0] | ||
| 93 | and r3, r3, ip | ||
| 94 | ldr r4, [r0] | ||
| 95 | orr r3, r3, r4, lsl #16 | ||
| 96 | |||
| 97 | str r3, [r1], #4 | ||
| 98 | |||
| 99 | .no_insw_2: tst r2, #1 | ||
| 100 | ldrne r3, [r0] | ||
| 101 | strneb r3, [r1], #1 | ||
| 102 | movne r3, r3, lsr #8 | ||
| 103 | strneb r3, [r1] | ||
| 104 | |||
| 105 | LOADREGS(fd, sp!, {r4, r5, r6, pc}) | ||
| 106 | |||
| 107 | |||
diff --git a/arch/arm/lib/io-readsw-armv4.S b/arch/arm/lib/io-readsw-armv4.S new file mode 100644 index 000000000000..c92b66ecbe86 --- /dev/null +++ b/arch/arm/lib/io-readsw-armv4.S | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/io-readsw-armv4.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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | |||
| 13 | .macro pack, rd, hw1, hw2 | ||
| 14 | #ifndef __ARMEB__ | ||
| 15 | orr \rd, \hw1, \hw2, lsl #16 | ||
| 16 | #else | ||
| 17 | orr \rd, \hw2, \hw1, lsl #16 | ||
| 18 | #endif | ||
| 19 | .endm | ||
| 20 | |||
| 21 | .insw_align: movs ip, r1, lsl #31 | ||
| 22 | bne .insw_noalign | ||
| 23 | ldrh ip, [r0] | ||
| 24 | sub r2, r2, #1 | ||
| 25 | strh ip, [r1], #2 | ||
| 26 | |||
| 27 | ENTRY(__raw_readsw) | ||
| 28 | teq r2, #0 | ||
| 29 | moveq pc, lr | ||
| 30 | tst r1, #3 | ||
| 31 | bne .insw_align | ||
| 32 | |||
| 33 | stmfd sp!, {r4, r5, lr} | ||
| 34 | |||
| 35 | subs r2, r2, #8 | ||
| 36 | bmi .no_insw_8 | ||
| 37 | |||
| 38 | .insw_8_lp: ldrh r3, [r0] | ||
| 39 | ldrh r4, [r0] | ||
| 40 | pack r3, r3, r4 | ||
| 41 | |||
| 42 | ldrh r4, [r0] | ||
| 43 | ldrh r5, [r0] | ||
| 44 | pack r4, r4, r5 | ||
| 45 | |||
| 46 | ldrh r5, [r0] | ||
| 47 | ldrh ip, [r0] | ||
| 48 | pack r5, r5, ip | ||
| 49 | |||
| 50 | ldrh ip, [r0] | ||
| 51 | ldrh lr, [r0] | ||
| 52 | pack ip, ip, lr | ||
| 53 | |||
| 54 | subs r2, r2, #8 | ||
| 55 | stmia r1!, {r3 - r5, ip} | ||
| 56 | bpl .insw_8_lp | ||
| 57 | |||
| 58 | .no_insw_8: tst r2, #4 | ||
| 59 | beq .no_insw_4 | ||
| 60 | |||
| 61 | ldrh r3, [r0] | ||
| 62 | ldrh r4, [r0] | ||
| 63 | pack r3, r3, r4 | ||
| 64 | |||
| 65 | ldrh r4, [r0] | ||
| 66 | ldrh ip, [r0] | ||
| 67 | pack r4, r4, ip | ||
| 68 | |||
| 69 | stmia r1!, {r3, r4} | ||
| 70 | |||
| 71 | .no_insw_4: movs r2, r2, lsl #31 | ||
| 72 | bcc .no_insw_2 | ||
| 73 | |||
| 74 | ldrh r3, [r0] | ||
| 75 | ldrh ip, [r0] | ||
| 76 | pack r3, r3, ip | ||
| 77 | str r3, [r1], #4 | ||
| 78 | |||
| 79 | .no_insw_2: ldrneh r3, [r0] | ||
| 80 | strneh r3, [r1] | ||
| 81 | |||
| 82 | ldmfd sp!, {r4, r5, pc} | ||
| 83 | |||
| 84 | #ifdef __ARMEB__ | ||
| 85 | #define _BE_ONLY_(code...) code | ||
| 86 | #define _LE_ONLY_(code...) | ||
| 87 | #define push_hbyte0 lsr #8 | ||
| 88 | #define pull_hbyte1 lsl #24 | ||
| 89 | #else | ||
| 90 | #define _BE_ONLY_(code...) | ||
| 91 | #define _LE_ONLY_(code...) code | ||
| 92 | #define push_hbyte0 lsl #24 | ||
| 93 | #define pull_hbyte1 lsr #8 | ||
| 94 | #endif | ||
| 95 | |||
| 96 | .insw_noalign: stmfd sp!, {r4, lr} | ||
| 97 | ldrccb ip, [r1, #-1]! | ||
| 98 | bcc 1f | ||
| 99 | |||
| 100 | ldrh ip, [r0] | ||
| 101 | sub r2, r2, #1 | ||
| 102 | _BE_ONLY_( mov ip, ip, ror #8 ) | ||
| 103 | strb ip, [r1], #1 | ||
| 104 | _LE_ONLY_( mov ip, ip, lsr #8 ) | ||
| 105 | _BE_ONLY_( mov ip, ip, lsr #24 ) | ||
| 106 | |||
| 107 | 1: subs r2, r2, #2 | ||
| 108 | bmi 3f | ||
| 109 | _BE_ONLY_( mov ip, ip, lsl #24 ) | ||
| 110 | |||
| 111 | 2: ldrh r3, [r0] | ||
| 112 | ldrh r4, [r0] | ||
| 113 | subs r2, r2, #2 | ||
| 114 | orr ip, ip, r3, lsl #8 | ||
| 115 | orr ip, ip, r4, push_hbyte0 | ||
| 116 | str ip, [r1], #4 | ||
| 117 | mov ip, r4, pull_hbyte1 | ||
| 118 | bpl 2b | ||
| 119 | |||
| 120 | _BE_ONLY_( mov ip, ip, lsr #24 ) | ||
| 121 | |||
| 122 | 3: tst r2, #1 | ||
| 123 | strb ip, [r1], #1 | ||
| 124 | ldrneh ip, [r0] | ||
| 125 | _BE_ONLY_( movne ip, ip, ror #8 ) | ||
| 126 | strneb ip, [r1], #1 | ||
| 127 | _LE_ONLY_( movne ip, ip, lsr #8 ) | ||
| 128 | _BE_ONLY_( movne ip, ip, lsr #24 ) | ||
| 129 | strneb ip, [r1] | ||
| 130 | ldmfd sp!, {r4, pc} | ||
diff --git a/arch/arm/lib/io-shark.c b/arch/arm/lib/io-shark.c new file mode 100644 index 000000000000..108d4573e970 --- /dev/null +++ b/arch/arm/lib/io-shark.c | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/io-shark.c | ||
| 3 | * | ||
| 4 | * by Alexander Schulz | ||
| 5 | * | ||
| 6 | * derived from: | ||
| 7 | * linux/arch/arm/lib/io-ebsa.S | ||
| 8 | * Copyright (C) 1995, 1996 Russell King | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | |||
| 16 | #include <asm/io.h> | ||
| 17 | |||
| 18 | void print_warning(void) | ||
| 19 | { | ||
| 20 | printk(KERN_WARNING "ins?/outs? not implemented on this architecture\n"); | ||
| 21 | } | ||
| 22 | |||
| 23 | void insl(unsigned int port, void *to, int len) | ||
| 24 | { | ||
| 25 | print_warning(); | ||
| 26 | } | ||
| 27 | |||
| 28 | void insb(unsigned int port, void *to, int len) | ||
| 29 | { | ||
| 30 | print_warning(); | ||
| 31 | } | ||
| 32 | |||
| 33 | void outsl(unsigned int port, const void *from, int len) | ||
| 34 | { | ||
| 35 | print_warning(); | ||
| 36 | } | ||
| 37 | |||
| 38 | void outsb(unsigned int port, const void *from, int len) | ||
| 39 | { | ||
| 40 | print_warning(); | ||
| 41 | } | ||
| 42 | |||
| 43 | /* these should be in assembler again */ | ||
| 44 | |||
| 45 | /* | ||
| 46 | * Purpose: read a block of data from a hardware register to memory. | ||
| 47 | * Proto : insw(int from_port, void *to, int len_in_words); | ||
| 48 | * Proto : inswb(int from_port, void *to, int len_in_bytes); | ||
| 49 | * Notes : increment to | ||
| 50 | */ | ||
| 51 | |||
| 52 | void insw(unsigned int port, void *to, int len) | ||
| 53 | { | ||
| 54 | int i; | ||
| 55 | |||
| 56 | for (i = 0; i < len; i++) | ||
| 57 | ((unsigned short *) to)[i] = inw(port); | ||
| 58 | } | ||
| 59 | |||
| 60 | void inswb(unsigned int port, void *to, int len) | ||
| 61 | { | ||
| 62 | insw(port, to, len >> 2); | ||
| 63 | } | ||
| 64 | |||
| 65 | /* | ||
| 66 | * Purpose: write a block of data from memory to a hardware register. | ||
| 67 | * Proto : outsw(int to_reg, void *from, int len_in_words); | ||
| 68 | * Proto : outswb(int to_reg, void *from, int len_in_bytes); | ||
| 69 | * Notes : increments from | ||
| 70 | */ | ||
| 71 | |||
| 72 | void outsw(unsigned int port, const void *from, int len) | ||
| 73 | { | ||
| 74 | int i; | ||
| 75 | |||
| 76 | for (i = 0; i < len; i++) | ||
| 77 | outw(((unsigned short *) from)[i], port); | ||
| 78 | } | ||
| 79 | |||
| 80 | void outswb(unsigned int port, const void *from, int len) | ||
| 81 | { | ||
| 82 | outsw(port, from, len >> 2); | ||
| 83 | } | ||
diff --git a/arch/arm/lib/io-writesb.S b/arch/arm/lib/io-writesb.S new file mode 100644 index 000000000000..70b2561bdb09 --- /dev/null +++ b/arch/arm/lib/io-writesb.S | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/io-writesb.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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | |||
| 13 | .macro outword, rd | ||
| 14 | #ifndef __ARMEB__ | ||
| 15 | strb \rd, [r0] | ||
| 16 | mov \rd, \rd, lsr #8 | ||
| 17 | strb \rd, [r0] | ||
| 18 | mov \rd, \rd, lsr #8 | ||
| 19 | strb \rd, [r0] | ||
| 20 | mov \rd, \rd, lsr #8 | ||
| 21 | strb \rd, [r0] | ||
| 22 | #else | ||
| 23 | mov lr, \rd, lsr #24 | ||
| 24 | strb lr, [r0] | ||
| 25 | mov lr, \rd, lsr #16 | ||
| 26 | strb lr, [r0] | ||
| 27 | mov lr, \rd, lsr #8 | ||
| 28 | strb lr, [r0] | ||
| 29 | strb \rd, [r0] | ||
| 30 | #endif | ||
| 31 | .endm | ||
| 32 | |||
| 33 | .outsb_align: rsb ip, ip, #4 | ||
| 34 | cmp ip, r2 | ||
| 35 | movgt ip, r2 | ||
| 36 | cmp ip, #2 | ||
| 37 | ldrb r3, [r1], #1 | ||
| 38 | strb r3, [r0] | ||
| 39 | ldrgeb r3, [r1], #1 | ||
| 40 | strgeb r3, [r0] | ||
| 41 | ldrgtb r3, [r1], #1 | ||
| 42 | strgtb r3, [r0] | ||
| 43 | subs r2, r2, ip | ||
| 44 | bne .outsb_aligned | ||
| 45 | |||
| 46 | ENTRY(__raw_writesb) | ||
| 47 | teq r2, #0 @ do we have to check for the zero len? | ||
| 48 | moveq pc, lr | ||
| 49 | ands ip, r1, #3 | ||
| 50 | bne .outsb_align | ||
| 51 | |||
| 52 | .outsb_aligned: stmfd sp!, {r4, r5, lr} | ||
| 53 | |||
| 54 | subs r2, r2, #16 | ||
| 55 | bmi .outsb_no_16 | ||
| 56 | |||
| 57 | .outsb_16_lp: ldmia r1!, {r3, r4, r5, ip} | ||
| 58 | outword r3 | ||
| 59 | outword r4 | ||
| 60 | outword r5 | ||
| 61 | outword ip | ||
| 62 | subs r2, r2, #16 | ||
| 63 | bpl .outsb_16_lp | ||
| 64 | |||
| 65 | tst r2, #15 | ||
| 66 | LOADREGS(eqfd, sp!, {r4, r5, pc}) | ||
| 67 | |||
| 68 | .outsb_no_16: tst r2, #8 | ||
| 69 | beq .outsb_no_8 | ||
| 70 | |||
| 71 | ldmia r1!, {r3, r4} | ||
| 72 | outword r3 | ||
| 73 | outword r4 | ||
| 74 | |||
| 75 | .outsb_no_8: tst r2, #4 | ||
| 76 | beq .outsb_no_4 | ||
| 77 | |||
| 78 | ldr r3, [r1], #4 | ||
| 79 | outword r3 | ||
| 80 | |||
| 81 | .outsb_no_4: ands r2, r2, #3 | ||
| 82 | LOADREGS(eqfd, sp!, {r4, r5, pc}) | ||
| 83 | |||
| 84 | cmp r2, #2 | ||
| 85 | ldrb r3, [r1], #1 | ||
| 86 | strb r3, [r0] | ||
| 87 | ldrgeb r3, [r1], #1 | ||
| 88 | strgeb r3, [r0] | ||
| 89 | ldrgtb r3, [r1] | ||
| 90 | strgtb r3, [r0] | ||
| 91 | |||
| 92 | LOADREGS(fd, sp!, {r4, r5, pc}) | ||
diff --git a/arch/arm/lib/io-writesl.S b/arch/arm/lib/io-writesl.S new file mode 100644 index 000000000000..f8f14dd227ca --- /dev/null +++ b/arch/arm/lib/io-writesl.S | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/io-writesl.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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | |||
| 13 | ENTRY(__raw_writesl) | ||
| 14 | teq r2, #0 @ do we have to check for the zero len? | ||
| 15 | moveq pc, lr | ||
| 16 | ands ip, r1, #3 | ||
| 17 | bne 3f | ||
| 18 | |||
| 19 | subs r2, r2, #4 | ||
| 20 | bmi 2f | ||
| 21 | stmfd sp!, {r4, lr} | ||
| 22 | 1: ldmia r1!, {r3, r4, ip, lr} | ||
| 23 | subs r2, r2, #4 | ||
| 24 | str r3, [r0, #0] | ||
| 25 | str r4, [r0, #0] | ||
| 26 | str ip, [r0, #0] | ||
| 27 | str lr, [r0, #0] | ||
| 28 | bpl 1b | ||
| 29 | ldmfd sp!, {r4, lr} | ||
| 30 | 2: movs r2, r2, lsl #31 | ||
| 31 | ldmcsia r1!, {r3, ip} | ||
| 32 | strcs r3, [r0, #0] | ||
| 33 | ldrne r3, [r1, #0] | ||
| 34 | strcs ip, [r0, #0] | ||
| 35 | strne r3, [r0, #0] | ||
| 36 | mov pc, lr | ||
| 37 | |||
| 38 | 3: bic r1, r1, #3 | ||
| 39 | ldr r3, [r1], #4 | ||
| 40 | cmp ip, #2 | ||
| 41 | blt 5f | ||
| 42 | bgt 6f | ||
| 43 | |||
| 44 | 4: mov ip, r3, pull #16 | ||
| 45 | ldr r3, [r1], #4 | ||
| 46 | subs r2, r2, #1 | ||
| 47 | orr ip, ip, r3, push #16 | ||
| 48 | str ip, [r0] | ||
| 49 | bne 4b | ||
| 50 | mov pc, lr | ||
| 51 | |||
| 52 | 5: mov ip, r3, pull #8 | ||
| 53 | ldr r3, [r1], #4 | ||
| 54 | subs r2, r2, #1 | ||
| 55 | orr ip, ip, r3, push #24 | ||
| 56 | str ip, [r0] | ||
| 57 | bne 5b | ||
| 58 | mov pc, lr | ||
| 59 | |||
| 60 | 6: mov ip, r3, pull #24 | ||
| 61 | ldr r3, [r1], #4 | ||
| 62 | subs r2, r2, #1 | ||
| 63 | orr ip, ip, r3, push #8 | ||
| 64 | str ip, [r0] | ||
| 65 | bne 6b | ||
| 66 | mov pc, lr | ||
diff --git a/arch/arm/lib/io-writesw-armv3.S b/arch/arm/lib/io-writesw-armv3.S new file mode 100644 index 000000000000..950e7e310f1a --- /dev/null +++ b/arch/arm/lib/io-writesw-armv3.S | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/io-writesw-armv3.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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | #include <asm/hardware.h> | ||
| 13 | |||
| 14 | .outsw_bad_alignment: | ||
| 15 | adr r0, .outsw_bad_align_msg | ||
| 16 | mov r2, lr | ||
| 17 | b panic | ||
| 18 | .outsw_bad_align_msg: | ||
| 19 | .asciz "outsw: bad buffer alignment (0x%p, lr=0x%08lX)\n" | ||
| 20 | .align | ||
| 21 | |||
| 22 | .outsw_align: tst r1, #1 | ||
| 23 | bne .outsw_bad_alignment | ||
| 24 | |||
| 25 | add r1, r1, #2 | ||
| 26 | |||
| 27 | ldr r3, [r1, #-4] | ||
| 28 | mov r3, r3, lsr #16 | ||
| 29 | orr r3, r3, r3, lsl #16 | ||
| 30 | str r3, [r0] | ||
| 31 | subs r2, r2, #1 | ||
| 32 | RETINSTR(moveq, pc, lr) | ||
| 33 | |||
| 34 | ENTRY(__raw_writesw) | ||
| 35 | teq r2, #0 @ do we have to check for the zero len? | ||
| 36 | moveq pc, lr | ||
| 37 | tst r1, #3 | ||
| 38 | bne .outsw_align | ||
| 39 | |||
| 40 | .outsw_aligned: stmfd sp!, {r4, r5, r6, lr} | ||
| 41 | |||
| 42 | subs r2, r2, #8 | ||
| 43 | bmi .no_outsw_8 | ||
| 44 | |||
| 45 | .outsw_8_lp: ldmia r1!, {r3, r4, r5, r6} | ||
| 46 | |||
| 47 | mov ip, r3, lsl #16 | ||
| 48 | orr ip, ip, ip, lsr #16 | ||
| 49 | str ip, [r0] | ||
| 50 | |||
| 51 | mov ip, r3, lsr #16 | ||
| 52 | orr ip, ip, ip, lsl #16 | ||
| 53 | str ip, [r0] | ||
| 54 | |||
| 55 | mov ip, r4, lsl #16 | ||
| 56 | orr ip, ip, ip, lsr #16 | ||
| 57 | str ip, [r0] | ||
| 58 | |||
| 59 | mov ip, r4, lsr #16 | ||
| 60 | orr ip, ip, ip, lsl #16 | ||
| 61 | str ip, [r0] | ||
| 62 | |||
| 63 | mov ip, r5, lsl #16 | ||
| 64 | orr ip, ip, ip, lsr #16 | ||
| 65 | str ip, [r0] | ||
| 66 | |||
| 67 | mov ip, r5, lsr #16 | ||
| 68 | orr ip, ip, ip, lsl #16 | ||
| 69 | str ip, [r0] | ||
| 70 | |||
| 71 | mov ip, r6, lsl #16 | ||
| 72 | orr ip, ip, ip, lsr #16 | ||
| 73 | str ip, [r0] | ||
| 74 | |||
| 75 | mov ip, r6, lsr #16 | ||
| 76 | orr ip, ip, ip, lsl #16 | ||
| 77 | str ip, [r0] | ||
| 78 | |||
| 79 | subs r2, r2, #8 | ||
| 80 | bpl .outsw_8_lp | ||
| 81 | |||
| 82 | tst r2, #7 | ||
| 83 | LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) | ||
| 84 | |||
| 85 | .no_outsw_8: tst r2, #4 | ||
| 86 | beq .no_outsw_4 | ||
| 87 | |||
| 88 | ldmia r1!, {r3, r4} | ||
| 89 | |||
| 90 | mov ip, r3, lsl #16 | ||
| 91 | orr ip, ip, ip, lsr #16 | ||
| 92 | str ip, [r0] | ||
| 93 | |||
| 94 | mov ip, r3, lsr #16 | ||
| 95 | orr ip, ip, ip, lsl #16 | ||
| 96 | str ip, [r0] | ||
| 97 | |||
| 98 | mov ip, r4, lsl #16 | ||
| 99 | orr ip, ip, ip, lsr #16 | ||
| 100 | str ip, [r0] | ||
| 101 | |||
| 102 | mov ip, r4, lsr #16 | ||
| 103 | orr ip, ip, ip, lsl #16 | ||
| 104 | str ip, [r0] | ||
| 105 | |||
| 106 | .no_outsw_4: tst r2, #2 | ||
| 107 | beq .no_outsw_2 | ||
| 108 | |||
| 109 | ldr r3, [r1], #4 | ||
| 110 | |||
| 111 | mov ip, r3, lsl #16 | ||
| 112 | orr ip, ip, ip, lsr #16 | ||
| 113 | str ip, [r0] | ||
| 114 | |||
| 115 | mov ip, r3, lsr #16 | ||
| 116 | orr ip, ip, ip, lsl #16 | ||
| 117 | str ip, [r0] | ||
| 118 | |||
| 119 | .no_outsw_2: tst r2, #1 | ||
| 120 | |||
| 121 | ldrne r3, [r1] | ||
| 122 | |||
| 123 | movne ip, r3, lsl #16 | ||
| 124 | orrne ip, ip, ip, lsr #16 | ||
| 125 | strne ip, [r0] | ||
| 126 | |||
| 127 | LOADREGS(fd, sp!, {r4, r5, r6, pc}) | ||
diff --git a/arch/arm/lib/io-writesw-armv4.S b/arch/arm/lib/io-writesw-armv4.S new file mode 100644 index 000000000000..6d1d7c27806e --- /dev/null +++ b/arch/arm/lib/io-writesw-armv4.S | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/io-writesw-armv4.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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | |||
| 13 | .macro outword, rd | ||
| 14 | #ifndef __ARMEB__ | ||
| 15 | strh \rd, [r0] | ||
| 16 | mov \rd, \rd, lsr #16 | ||
| 17 | strh \rd, [r0] | ||
| 18 | #else | ||
| 19 | mov lr, \rd, lsr #16 | ||
| 20 | strh lr, [r0] | ||
| 21 | strh \rd, [r0] | ||
| 22 | #endif | ||
| 23 | .endm | ||
| 24 | |||
| 25 | .outsw_align: movs ip, r1, lsl #31 | ||
| 26 | bne .outsw_noalign | ||
| 27 | |||
| 28 | ldrh r3, [r1], #2 | ||
| 29 | sub r2, r2, #1 | ||
| 30 | strh r3, [r0] | ||
| 31 | |||
| 32 | ENTRY(__raw_writesw) | ||
| 33 | teq r2, #0 | ||
| 34 | moveq pc, lr | ||
| 35 | ands r3, r1, #3 | ||
| 36 | bne .outsw_align | ||
| 37 | |||
| 38 | stmfd sp!, {r4, r5, lr} | ||
| 39 | |||
| 40 | subs r2, r2, #8 | ||
| 41 | bmi .no_outsw_8 | ||
| 42 | |||
| 43 | .outsw_8_lp: ldmia r1!, {r3, r4, r5, ip} | ||
| 44 | subs r2, r2, #8 | ||
| 45 | outword r3 | ||
| 46 | outword r4 | ||
| 47 | outword r5 | ||
| 48 | outword ip | ||
| 49 | bpl .outsw_8_lp | ||
| 50 | |||
| 51 | .no_outsw_8: tst r2, #4 | ||
| 52 | beq .no_outsw_4 | ||
| 53 | |||
| 54 | ldmia r1!, {r3, ip} | ||
| 55 | outword r3 | ||
| 56 | outword ip | ||
| 57 | |||
| 58 | .no_outsw_4: movs r2, r2, lsl #31 | ||
| 59 | bcc .no_outsw_2 | ||
| 60 | |||
| 61 | ldr r3, [r1], #4 | ||
| 62 | outword r3 | ||
| 63 | |||
| 64 | .no_outsw_2: ldrneh r3, [r1] | ||
| 65 | strneh r3, [r0] | ||
| 66 | |||
| 67 | ldmfd sp!, {r4, r5, pc} | ||
| 68 | |||
| 69 | #ifdef __ARMEB__ | ||
| 70 | #define pull_hbyte0 lsl #8 | ||
| 71 | #define push_hbyte1 lsr #24 | ||
| 72 | #else | ||
| 73 | #define pull_hbyte0 lsr #24 | ||
| 74 | #define push_hbyte1 lsl #8 | ||
| 75 | #endif | ||
| 76 | |||
| 77 | .outsw_noalign: ldr r3, [r1, -r3]! | ||
| 78 | subcs r2, r2, #1 | ||
| 79 | bcs 2f | ||
| 80 | subs r2, r2, #2 | ||
| 81 | bmi 3f | ||
| 82 | |||
| 83 | 1: mov ip, r3, lsr #8 | ||
| 84 | strh ip, [r0] | ||
| 85 | 2: mov ip, r3, pull_hbyte0 | ||
| 86 | ldr r3, [r1, #4]! | ||
| 87 | subs r2, r2, #2 | ||
| 88 | orr ip, ip, r3, push_hbyte1 | ||
| 89 | strh ip, [r0] | ||
| 90 | bpl 2b | ||
| 91 | |||
| 92 | 3: tst r2, #1 | ||
| 93 | 2: movne ip, r3, lsr #8 | ||
| 94 | strneh ip, [r0] | ||
| 95 | mov pc, lr | ||
diff --git a/arch/arm/lib/lib1funcs.S b/arch/arm/lib/lib1funcs.S new file mode 100644 index 000000000000..59026029d017 --- /dev/null +++ b/arch/arm/lib/lib1funcs.S | |||
| @@ -0,0 +1,314 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines | ||
| 3 | * | ||
| 4 | * Author: Nicolas Pitre <nico@cam.org> | ||
| 5 | * - contributed to gcc-3.4 on Sep 30, 2003 | ||
| 6 | * - adapted for the Linux kernel on Oct 2, 2003 | ||
| 7 | */ | ||
| 8 | |||
| 9 | /* Copyright 1995, 1996, 1998, 1999, 2000, 2003 Free Software Foundation, Inc. | ||
| 10 | |||
| 11 | This file is free software; you can redistribute it and/or modify it | ||
| 12 | under the terms of the GNU General Public License as published by the | ||
| 13 | Free Software Foundation; either version 2, or (at your option) any | ||
| 14 | later version. | ||
| 15 | |||
| 16 | In addition to the permissions in the GNU General Public License, the | ||
| 17 | Free Software Foundation gives you unlimited permission to link the | ||
| 18 | compiled version of this file into combinations with other programs, | ||
| 19 | and to distribute those combinations without any restriction coming | ||
| 20 | from the use of this file. (The General Public License restrictions | ||
| 21 | do apply in other respects; for example, they cover modification of | ||
| 22 | the file, and distribution when not linked into a combine | ||
| 23 | executable.) | ||
| 24 | |||
| 25 | This file is distributed in the hope that it will be useful, but | ||
| 26 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 28 | General Public License for more details. | ||
| 29 | |||
| 30 | You should have received a copy of the GNU General Public License | ||
| 31 | along with this program; see the file COPYING. If not, write to | ||
| 32 | the Free Software Foundation, 59 Temple Place - Suite 330, | ||
| 33 | Boston, MA 02111-1307, USA. */ | ||
| 34 | |||
| 35 | |||
| 36 | #include <linux/linkage.h> | ||
| 37 | #include <asm/assembler.h> | ||
| 38 | |||
| 39 | |||
| 40 | .macro ARM_DIV_BODY dividend, divisor, result, curbit | ||
| 41 | |||
| 42 | #if __LINUX_ARM_ARCH__ >= 5 | ||
| 43 | |||
| 44 | clz \curbit, \divisor | ||
| 45 | clz \result, \dividend | ||
| 46 | sub \result, \curbit, \result | ||
| 47 | mov \curbit, #1 | ||
| 48 | mov \divisor, \divisor, lsl \result | ||
| 49 | mov \curbit, \curbit, lsl \result | ||
| 50 | mov \result, #0 | ||
| 51 | |||
| 52 | #else | ||
| 53 | |||
| 54 | @ Initially shift the divisor left 3 bits if possible, | ||
| 55 | @ set curbit accordingly. This allows for curbit to be located | ||
| 56 | @ at the left end of each 4 bit nibbles in the division loop | ||
| 57 | @ to save one loop in most cases. | ||
| 58 | tst \divisor, #0xe0000000 | ||
| 59 | moveq \divisor, \divisor, lsl #3 | ||
| 60 | moveq \curbit, #8 | ||
| 61 | movne \curbit, #1 | ||
| 62 | |||
| 63 | @ Unless the divisor is very big, shift it up in multiples of | ||
| 64 | @ four bits, since this is the amount of unwinding in the main | ||
| 65 | @ division loop. Continue shifting until the divisor is | ||
| 66 | @ larger than the dividend. | ||
| 67 | 1: cmp \divisor, #0x10000000 | ||
| 68 | cmplo \divisor, \dividend | ||
| 69 | movlo \divisor, \divisor, lsl #4 | ||
| 70 | movlo \curbit, \curbit, lsl #4 | ||
| 71 | blo 1b | ||
| 72 | |||
| 73 | @ For very big divisors, we must shift it a bit at a time, or | ||
| 74 | @ we will be in danger of overflowing. | ||
| 75 | 1: cmp \divisor, #0x80000000 | ||
| 76 | cmplo \divisor, \dividend | ||
| 77 | movlo \divisor, \divisor, lsl #1 | ||
| 78 | movlo \curbit, \curbit, lsl #1 | ||
| 79 | blo 1b | ||
| 80 | |||
| 81 | mov \result, #0 | ||
| 82 | |||
| 83 | #endif | ||
| 84 | |||
| 85 | @ Division loop | ||
| 86 | 1: cmp \dividend, \divisor | ||
| 87 | subhs \dividend, \dividend, \divisor | ||
| 88 | orrhs \result, \result, \curbit | ||
| 89 | cmp \dividend, \divisor, lsr #1 | ||
| 90 | subhs \dividend, \dividend, \divisor, lsr #1 | ||
| 91 | orrhs \result, \result, \curbit, lsr #1 | ||
| 92 | cmp \dividend, \divisor, lsr #2 | ||
| 93 | subhs \dividend, \dividend, \divisor, lsr #2 | ||
| 94 | orrhs \result, \result, \curbit, lsr #2 | ||
| 95 | cmp \dividend, \divisor, lsr #3 | ||
| 96 | subhs \dividend, \dividend, \divisor, lsr #3 | ||
| 97 | orrhs \result, \result, \curbit, lsr #3 | ||
| 98 | cmp \dividend, #0 @ Early termination? | ||
| 99 | movnes \curbit, \curbit, lsr #4 @ No, any more bits to do? | ||
| 100 | movne \divisor, \divisor, lsr #4 | ||
| 101 | bne 1b | ||
| 102 | |||
| 103 | .endm | ||
| 104 | |||
| 105 | |||
| 106 | .macro ARM_DIV2_ORDER divisor, order | ||
| 107 | |||
| 108 | #if __LINUX_ARM_ARCH__ >= 5 | ||
| 109 | |||
| 110 | clz \order, \divisor | ||
| 111 | rsb \order, \order, #31 | ||
| 112 | |||
| 113 | #else | ||
| 114 | |||
| 115 | cmp \divisor, #(1 << 16) | ||
| 116 | movhs \divisor, \divisor, lsr #16 | ||
| 117 | movhs \order, #16 | ||
| 118 | movlo \order, #0 | ||
| 119 | |||
| 120 | cmp \divisor, #(1 << 8) | ||
| 121 | movhs \divisor, \divisor, lsr #8 | ||
| 122 | addhs \order, \order, #8 | ||
| 123 | |||
| 124 | cmp \divisor, #(1 << 4) | ||
| 125 | movhs \divisor, \divisor, lsr #4 | ||
| 126 | addhs \order, \order, #4 | ||
| 127 | |||
| 128 | cmp \divisor, #(1 << 2) | ||
| 129 | addhi \order, \order, #3 | ||
| 130 | addls \order, \order, \divisor, lsr #1 | ||
| 131 | |||
| 132 | #endif | ||
| 133 | |||
| 134 | .endm | ||
| 135 | |||
| 136 | |||
| 137 | .macro ARM_MOD_BODY dividend, divisor, order, spare | ||
| 138 | |||
| 139 | #if __LINUX_ARM_ARCH__ >= 5 | ||
| 140 | |||
| 141 | clz \order, \divisor | ||
| 142 | clz \spare, \dividend | ||
| 143 | sub \order, \order, \spare | ||
| 144 | mov \divisor, \divisor, lsl \order | ||
| 145 | |||
| 146 | #else | ||
| 147 | |||
| 148 | mov \order, #0 | ||
| 149 | |||
| 150 | @ Unless the divisor is very big, shift it up in multiples of | ||
| 151 | @ four bits, since this is the amount of unwinding in the main | ||
| 152 | @ division loop. Continue shifting until the divisor is | ||
| 153 | @ larger than the dividend. | ||
| 154 | 1: cmp \divisor, #0x10000000 | ||
| 155 | cmplo \divisor, \dividend | ||
| 156 | movlo \divisor, \divisor, lsl #4 | ||
| 157 | addlo \order, \order, #4 | ||
| 158 | blo 1b | ||
| 159 | |||
| 160 | @ For very big divisors, we must shift it a bit at a time, or | ||
| 161 | @ we will be in danger of overflowing. | ||
| 162 | 1: cmp \divisor, #0x80000000 | ||
| 163 | cmplo \divisor, \dividend | ||
| 164 | movlo \divisor, \divisor, lsl #1 | ||
| 165 | addlo \order, \order, #1 | ||
| 166 | blo 1b | ||
| 167 | |||
| 168 | #endif | ||
| 169 | |||
| 170 | @ Perform all needed substractions to keep only the reminder. | ||
| 171 | @ Do comparisons in batch of 4 first. | ||
| 172 | subs \order, \order, #3 @ yes, 3 is intended here | ||
| 173 | blt 2f | ||
| 174 | |||
| 175 | 1: cmp \dividend, \divisor | ||
| 176 | subhs \dividend, \dividend, \divisor | ||
| 177 | cmp \dividend, \divisor, lsr #1 | ||
| 178 | subhs \dividend, \dividend, \divisor, lsr #1 | ||
| 179 | cmp \dividend, \divisor, lsr #2 | ||
| 180 | subhs \dividend, \dividend, \divisor, lsr #2 | ||
| 181 | cmp \dividend, \divisor, lsr #3 | ||
| 182 | subhs \dividend, \dividend, \divisor, lsr #3 | ||
| 183 | cmp \dividend, #1 | ||
| 184 | mov \divisor, \divisor, lsr #4 | ||
| 185 | subges \order, \order, #4 | ||
| 186 | bge 1b | ||
| 187 | |||
| 188 | tst \order, #3 | ||
| 189 | teqne \dividend, #0 | ||
| 190 | beq 5f | ||
| 191 | |||
| 192 | @ Either 1, 2 or 3 comparison/substractions are left. | ||
| 193 | 2: cmn \order, #2 | ||
| 194 | blt 4f | ||
| 195 | beq 3f | ||
| 196 | cmp \dividend, \divisor | ||
| 197 | subhs \dividend, \dividend, \divisor | ||
| 198 | mov \divisor, \divisor, lsr #1 | ||
| 199 | 3: cmp \dividend, \divisor | ||
| 200 | subhs \dividend, \dividend, \divisor | ||
| 201 | mov \divisor, \divisor, lsr #1 | ||
| 202 | 4: cmp \dividend, \divisor | ||
| 203 | subhs \dividend, \dividend, \divisor | ||
| 204 | 5: | ||
| 205 | .endm | ||
| 206 | |||
| 207 | |||
| 208 | ENTRY(__udivsi3) | ||
| 209 | |||
| 210 | subs r2, r1, #1 | ||
| 211 | moveq pc, lr | ||
| 212 | bcc Ldiv0 | ||
| 213 | cmp r0, r1 | ||
| 214 | bls 11f | ||
| 215 | tst r1, r2 | ||
| 216 | beq 12f | ||
| 217 | |||
| 218 | ARM_DIV_BODY r0, r1, r2, r3 | ||
| 219 | |||
| 220 | mov r0, r2 | ||
| 221 | mov pc, lr | ||
| 222 | |||
| 223 | 11: moveq r0, #1 | ||
| 224 | movne r0, #0 | ||
| 225 | mov pc, lr | ||
| 226 | |||
| 227 | 12: ARM_DIV2_ORDER r1, r2 | ||
| 228 | |||
| 229 | mov r0, r0, lsr r2 | ||
| 230 | mov pc, lr | ||
| 231 | |||
| 232 | |||
| 233 | ENTRY(__umodsi3) | ||
| 234 | |||
| 235 | subs r2, r1, #1 @ compare divisor with 1 | ||
| 236 | bcc Ldiv0 | ||
| 237 | cmpne r0, r1 @ compare dividend with divisor | ||
| 238 | moveq r0, #0 | ||
| 239 | tsthi r1, r2 @ see if divisor is power of 2 | ||
| 240 | andeq r0, r0, r2 | ||
| 241 | movls pc, lr | ||
| 242 | |||
| 243 | ARM_MOD_BODY r0, r1, r2, r3 | ||
| 244 | |||
| 245 | mov pc, lr | ||
| 246 | |||
| 247 | |||
| 248 | ENTRY(__divsi3) | ||
| 249 | |||
| 250 | cmp r1, #0 | ||
| 251 | eor ip, r0, r1 @ save the sign of the result. | ||
| 252 | beq Ldiv0 | ||
| 253 | rsbmi r1, r1, #0 @ loops below use unsigned. | ||
| 254 | subs r2, r1, #1 @ division by 1 or -1 ? | ||
| 255 | beq 10f | ||
| 256 | movs r3, r0 | ||
| 257 | rsbmi r3, r0, #0 @ positive dividend value | ||
| 258 | cmp r3, r1 | ||
| 259 | bls 11f | ||
| 260 | tst r1, r2 @ divisor is power of 2 ? | ||
| 261 | beq 12f | ||
| 262 | |||
| 263 | ARM_DIV_BODY r3, r1, r0, r2 | ||
| 264 | |||
| 265 | cmp ip, #0 | ||
| 266 | rsbmi r0, r0, #0 | ||
| 267 | mov pc, lr | ||
| 268 | |||
| 269 | 10: teq ip, r0 @ same sign ? | ||
| 270 | rsbmi r0, r0, #0 | ||
| 271 | mov pc, lr | ||
| 272 | |||
| 273 | 11: movlo r0, #0 | ||
| 274 | moveq r0, ip, asr #31 | ||
| 275 | orreq r0, r0, #1 | ||
| 276 | mov pc, lr | ||
| 277 | |||
| 278 | 12: ARM_DIV2_ORDER r1, r2 | ||
| 279 | |||
| 280 | cmp ip, #0 | ||
| 281 | mov r0, r3, lsr r2 | ||
| 282 | rsbmi r0, r0, #0 | ||
| 283 | mov pc, lr | ||
| 284 | |||
| 285 | |||
| 286 | ENTRY(__modsi3) | ||
| 287 | |||
| 288 | cmp r1, #0 | ||
| 289 | beq Ldiv0 | ||
| 290 | rsbmi r1, r1, #0 @ loops below use unsigned. | ||
| 291 | movs ip, r0 @ preserve sign of dividend | ||
| 292 | rsbmi r0, r0, #0 @ if negative make positive | ||
| 293 | subs r2, r1, #1 @ compare divisor with 1 | ||
| 294 | cmpne r0, r1 @ compare dividend with divisor | ||
| 295 | moveq r0, #0 | ||
| 296 | tsthi r1, r2 @ see if divisor is power of 2 | ||
| 297 | andeq r0, r0, r2 | ||
| 298 | bls 10f | ||
| 299 | |||
| 300 | ARM_MOD_BODY r0, r1, r2, r3 | ||
| 301 | |||
| 302 | 10: cmp ip, #0 | ||
| 303 | rsbmi r0, r0, #0 | ||
| 304 | mov pc, lr | ||
| 305 | |||
| 306 | |||
| 307 | Ldiv0: | ||
| 308 | |||
| 309 | str lr, [sp, #-4]! | ||
| 310 | bl __div0 | ||
| 311 | mov r0, #0 @ About as wrong as it could be. | ||
| 312 | ldr pc, [sp], #4 | ||
| 313 | |||
| 314 | |||
diff --git a/arch/arm/lib/longlong.h b/arch/arm/lib/longlong.h new file mode 100644 index 000000000000..179eea4edc35 --- /dev/null +++ b/arch/arm/lib/longlong.h | |||
| @@ -0,0 +1,183 @@ | |||
| 1 | /* longlong.h -- based on code from gcc-2.95.3 | ||
| 2 | |||
| 3 | definitions for mixed size 32/64 bit arithmetic. | ||
| 4 | Copyright (C) 1991, 92, 94, 95, 96, 1997, 1998 Free Software Foundation, Inc. | ||
| 5 | |||
| 6 | This definition file is free software; you can redistribute it | ||
| 7 | and/or modify it under the terms of the GNU General Public | ||
| 8 | License as published by the Free Software Foundation; either | ||
| 9 | version 2, or (at your option) any later version. | ||
| 10 | |||
| 11 | This definition file is distributed in the hope that it will be | ||
| 12 | useful, but WITHOUT ANY WARRANTY; without even the implied | ||
| 13 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 14 | See the GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 19 | Boston, MA 02111-1307, USA. */ | ||
| 20 | |||
| 21 | /* Borrowed from GCC 2.95.3, I Molton 29/07/01 */ | ||
| 22 | |||
| 23 | #ifndef SI_TYPE_SIZE | ||
| 24 | #define SI_TYPE_SIZE 32 | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #define __BITS4 (SI_TYPE_SIZE / 4) | ||
| 28 | #define __ll_B (1L << (SI_TYPE_SIZE / 2)) | ||
| 29 | #define __ll_lowpart(t) ((USItype) (t) % __ll_B) | ||
| 30 | #define __ll_highpart(t) ((USItype) (t) / __ll_B) | ||
| 31 | |||
| 32 | /* Define auxiliary asm macros. | ||
| 33 | |||
| 34 | 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) | ||
| 35 | multiplies two USItype integers MULTIPLER and MULTIPLICAND, | ||
| 36 | and generates a two-part USItype product in HIGH_PROD and | ||
| 37 | LOW_PROD. | ||
| 38 | |||
| 39 | 2) __umulsidi3(a,b) multiplies two USItype integers A and B, | ||
| 40 | and returns a UDItype product. This is just a variant of umul_ppmm. | ||
| 41 | |||
| 42 | 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, | ||
| 43 | denominator) divides a two-word unsigned integer, composed by the | ||
| 44 | integers HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and | ||
| 45 | places the quotient in QUOTIENT and the remainder in REMAINDER. | ||
| 46 | HIGH_NUMERATOR must be less than DENOMINATOR for correct operation. | ||
| 47 | If, in addition, the most significant bit of DENOMINATOR must be 1, | ||
| 48 | then the pre-processor symbol UDIV_NEEDS_NORMALIZATION is defined to 1. | ||
| 49 | |||
| 50 | 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator, | ||
| 51 | denominator). Like udiv_qrnnd but the numbers are signed. The | ||
| 52 | quotient is rounded towards 0. | ||
| 53 | |||
| 54 | 5) count_leading_zeros(count, x) counts the number of zero-bits from | ||
| 55 | the msb to the first non-zero bit. This is the number of steps X | ||
| 56 | needs to be shifted left to set the msb. Undefined for X == 0. | ||
| 57 | |||
| 58 | 6) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, | ||
| 59 | high_addend_2, low_addend_2) adds two two-word unsigned integers, | ||
| 60 | composed by HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and | ||
| 61 | LOW_ADDEND_2 respectively. The result is placed in HIGH_SUM and | ||
| 62 | LOW_SUM. Overflow (i.e. carry out) is not stored anywhere, and is | ||
| 63 | lost. | ||
| 64 | |||
| 65 | 7) sub_ddmmss(high_difference, low_difference, high_minuend, | ||
| 66 | low_minuend, high_subtrahend, low_subtrahend) subtracts two | ||
| 67 | two-word unsigned integers, composed by HIGH_MINUEND_1 and | ||
| 68 | LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and LOW_SUBTRAHEND_2 | ||
| 69 | respectively. The result is placed in HIGH_DIFFERENCE and | ||
| 70 | LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, | ||
| 71 | and is lost. | ||
| 72 | |||
| 73 | If any of these macros are left undefined for a particular CPU, | ||
| 74 | C macros are used. */ | ||
| 75 | |||
| 76 | #if defined (__arm__) | ||
| 77 | #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ | ||
| 78 | __asm__ ("adds %1, %4, %5 \n\ | ||
| 79 | adc %0, %2, %3" \ | ||
| 80 | : "=r" ((USItype) (sh)), \ | ||
| 81 | "=&r" ((USItype) (sl)) \ | ||
| 82 | : "%r" ((USItype) (ah)), \ | ||
| 83 | "rI" ((USItype) (bh)), \ | ||
| 84 | "%r" ((USItype) (al)), \ | ||
| 85 | "rI" ((USItype) (bl))) | ||
| 86 | #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ | ||
| 87 | __asm__ ("subs %1, %4, %5 \n\ | ||
| 88 | sbc %0, %2, %3" \ | ||
| 89 | : "=r" ((USItype) (sh)), \ | ||
| 90 | "=&r" ((USItype) (sl)) \ | ||
| 91 | : "r" ((USItype) (ah)), \ | ||
| 92 | "rI" ((USItype) (bh)), \ | ||
| 93 | "r" ((USItype) (al)), \ | ||
| 94 | "rI" ((USItype) (bl))) | ||
| 95 | #define umul_ppmm(xh, xl, a, b) \ | ||
| 96 | {register USItype __t0, __t1, __t2; \ | ||
| 97 | __asm__ ("%@ Inlined umul_ppmm \n\ | ||
| 98 | mov %2, %5, lsr #16 \n\ | ||
| 99 | mov %0, %6, lsr #16 \n\ | ||
| 100 | bic %3, %5, %2, lsl #16 \n\ | ||
| 101 | bic %4, %6, %0, lsl #16 \n\ | ||
| 102 | mul %1, %3, %4 \n\ | ||
| 103 | mul %4, %2, %4 \n\ | ||
| 104 | mul %3, %0, %3 \n\ | ||
| 105 | mul %0, %2, %0 \n\ | ||
| 106 | adds %3, %4, %3 \n\ | ||
| 107 | addcs %0, %0, #65536 \n\ | ||
| 108 | adds %1, %1, %3, lsl #16 \n\ | ||
| 109 | adc %0, %0, %3, lsr #16" \ | ||
| 110 | : "=&r" ((USItype) (xh)), \ | ||
| 111 | "=r" ((USItype) (xl)), \ | ||
| 112 | "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ | ||
| 113 | : "r" ((USItype) (a)), \ | ||
| 114 | "r" ((USItype) (b)));} | ||
| 115 | #define UMUL_TIME 20 | ||
| 116 | #define UDIV_TIME 100 | ||
| 117 | #endif /* __arm__ */ | ||
| 118 | |||
| 119 | #define __umulsidi3(u, v) \ | ||
| 120 | ({DIunion __w; \ | ||
| 121 | umul_ppmm (__w.s.high, __w.s.low, u, v); \ | ||
| 122 | __w.ll; }) | ||
| 123 | |||
| 124 | #define __udiv_qrnnd_c(q, r, n1, n0, d) \ | ||
| 125 | do { \ | ||
| 126 | USItype __d1, __d0, __q1, __q0; \ | ||
| 127 | USItype __r1, __r0, __m; \ | ||
| 128 | __d1 = __ll_highpart (d); \ | ||
| 129 | __d0 = __ll_lowpart (d); \ | ||
| 130 | \ | ||
| 131 | __r1 = (n1) % __d1; \ | ||
| 132 | __q1 = (n1) / __d1; \ | ||
| 133 | __m = (USItype) __q1 * __d0; \ | ||
| 134 | __r1 = __r1 * __ll_B | __ll_highpart (n0); \ | ||
| 135 | if (__r1 < __m) \ | ||
| 136 | { \ | ||
| 137 | __q1--, __r1 += (d); \ | ||
| 138 | if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ | ||
| 139 | if (__r1 < __m) \ | ||
| 140 | __q1--, __r1 += (d); \ | ||
| 141 | } \ | ||
| 142 | __r1 -= __m; \ | ||
| 143 | \ | ||
| 144 | __r0 = __r1 % __d1; \ | ||
| 145 | __q0 = __r1 / __d1; \ | ||
| 146 | __m = (USItype) __q0 * __d0; \ | ||
| 147 | __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ | ||
| 148 | if (__r0 < __m) \ | ||
| 149 | { \ | ||
| 150 | __q0--, __r0 += (d); \ | ||
| 151 | if (__r0 >= (d)) \ | ||
| 152 | if (__r0 < __m) \ | ||
| 153 | __q0--, __r0 += (d); \ | ||
| 154 | } \ | ||
| 155 | __r0 -= __m; \ | ||
| 156 | \ | ||
| 157 | (q) = (USItype) __q1 * __ll_B | __q0; \ | ||
| 158 | (r) = __r0; \ | ||
| 159 | } while (0) | ||
| 160 | |||
| 161 | #define UDIV_NEEDS_NORMALIZATION 1 | ||
| 162 | #define udiv_qrnnd __udiv_qrnnd_c | ||
| 163 | |||
| 164 | #define count_leading_zeros(count, x) \ | ||
| 165 | do { \ | ||
| 166 | USItype __xr = (x); \ | ||
| 167 | USItype __a; \ | ||
| 168 | \ | ||
| 169 | if (SI_TYPE_SIZE <= 32) \ | ||
| 170 | { \ | ||
| 171 | __a = __xr < ((USItype)1<<2*__BITS4) \ | ||
| 172 | ? (__xr < ((USItype)1<<__BITS4) ? 0 : __BITS4) \ | ||
| 173 | : (__xr < ((USItype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ | ||
| 174 | } \ | ||
| 175 | else \ | ||
| 176 | { \ | ||
| 177 | for (__a = SI_TYPE_SIZE - 8; __a > 0; __a -= 8) \ | ||
| 178 | if (((__xr >> __a) & 0xff) != 0) \ | ||
| 179 | break; \ | ||
| 180 | } \ | ||
| 181 | \ | ||
| 182 | (count) = SI_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ | ||
| 183 | } while (0) | ||
diff --git a/arch/arm/lib/lshrdi3.c b/arch/arm/lib/lshrdi3.c new file mode 100644 index 000000000000..b666f1bad451 --- /dev/null +++ b/arch/arm/lib/lshrdi3.c | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | /* More subroutines needed by GCC output code on some machines. */ | ||
| 2 | /* Compile this one with gcc. */ | ||
| 3 | /* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU CC. | ||
| 6 | |||
| 7 | GNU CC is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation; either version 2, or (at your option) | ||
| 10 | any later version. | ||
| 11 | |||
| 12 | GNU CC is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU CC; see the file COPYING. If not, write to | ||
| 19 | the Free Software Foundation, 59 Temple Place - Suite 330, | ||
| 20 | Boston, MA 02111-1307, USA. */ | ||
| 21 | |||
| 22 | /* As a special exception, if you link this library with other files, | ||
| 23 | some of which are compiled with GCC, to produce an executable, | ||
| 24 | this library does not by itself cause the resulting executable | ||
| 25 | to be covered by the GNU General Public License. | ||
| 26 | This exception does not however invalidate any other reasons why | ||
| 27 | the executable file might be covered by the GNU General Public License. | ||
| 28 | */ | ||
| 29 | /* support functions required by the kernel. based on code from gcc-2.95.3 */ | ||
| 30 | /* I Molton 29/07/01 */ | ||
| 31 | |||
| 32 | #include "gcclib.h" | ||
| 33 | |||
| 34 | DItype | ||
| 35 | __lshrdi3 (DItype u, word_type b) | ||
| 36 | { | ||
| 37 | DIunion w; | ||
| 38 | word_type bm; | ||
| 39 | DIunion uu; | ||
| 40 | |||
| 41 | if (b == 0) | ||
| 42 | return u; | ||
| 43 | |||
| 44 | uu.ll = u; | ||
| 45 | |||
| 46 | bm = (sizeof (SItype) * BITS_PER_UNIT) - b; | ||
| 47 | if (bm <= 0) | ||
| 48 | { | ||
| 49 | w.s.high = 0; | ||
| 50 | w.s.low = (USItype)uu.s.high >> -bm; | ||
| 51 | } | ||
| 52 | else | ||
| 53 | { | ||
| 54 | USItype carries = (USItype)uu.s.high << bm; | ||
| 55 | w.s.high = (USItype)uu.s.high >> b; | ||
| 56 | w.s.low = ((USItype)uu.s.low >> b) | carries; | ||
| 57 | } | ||
| 58 | |||
| 59 | return w.ll; | ||
| 60 | } | ||
| 61 | |||
diff --git a/arch/arm/lib/memchr.S b/arch/arm/lib/memchr.S new file mode 100644 index 000000000000..ac34fe55d21a --- /dev/null +++ b/arch/arm/lib/memchr.S | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/memchr.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 | |||
| 15 | .text | ||
| 16 | .align 5 | ||
| 17 | ENTRY(memchr) | ||
| 18 | 1: subs r2, r2, #1 | ||
| 19 | bmi 2f | ||
| 20 | ldrb r3, [r0], #1 | ||
| 21 | teq r3, r1 | ||
| 22 | bne 1b | ||
| 23 | sub r0, r0, #1 | ||
| 24 | 2: movne r0, #0 | ||
| 25 | RETINSTR(mov,pc,lr) | ||
diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S new file mode 100644 index 000000000000..f5a593ceb8cc --- /dev/null +++ b/arch/arm/lib/memcpy.S | |||
| @@ -0,0 +1,393 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/memcpy.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-1999 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 | |||
| 15 | .text | ||
| 16 | |||
| 17 | #define ENTER \ | ||
| 18 | mov ip,sp ;\ | ||
| 19 | stmfd sp!,{r0,r4-r9,fp,ip,lr,pc} ;\ | ||
| 20 | sub fp,ip,#4 | ||
| 21 | |||
| 22 | #define EXIT \ | ||
| 23 | LOADREGS(ea, fp, {r0, r4 - r9, fp, sp, pc}) | ||
| 24 | |||
| 25 | #define EXITEQ \ | ||
| 26 | LOADREGS(eqea, fp, {r0, r4 - r9, fp, sp, pc}) | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Prototype: void memcpy(void *to,const void *from,unsigned long n); | ||
| 30 | */ | ||
| 31 | ENTRY(memcpy) | ||
| 32 | ENTRY(memmove) | ||
| 33 | ENTER | ||
| 34 | cmp r1, r0 | ||
| 35 | bcc 23f | ||
| 36 | subs r2, r2, #4 | ||
| 37 | blt 6f | ||
| 38 | PLD( pld [r1, #0] ) | ||
| 39 | ands ip, r0, #3 | ||
| 40 | bne 7f | ||
| 41 | ands ip, r1, #3 | ||
| 42 | bne 8f | ||
| 43 | |||
| 44 | 1: subs r2, r2, #8 | ||
| 45 | blt 5f | ||
| 46 | subs r2, r2, #20 | ||
| 47 | blt 4f | ||
| 48 | PLD( pld [r1, #28] ) | ||
| 49 | PLD( subs r2, r2, #64 ) | ||
| 50 | PLD( blt 3f ) | ||
| 51 | 2: PLD( pld [r1, #60] ) | ||
| 52 | PLD( pld [r1, #92] ) | ||
| 53 | ldmia r1!, {r3 - r9, ip} | ||
| 54 | subs r2, r2, #32 | ||
| 55 | stmgeia r0!, {r3 - r9, ip} | ||
| 56 | ldmgeia r1!, {r3 - r9, ip} | ||
| 57 | subges r2, r2, #32 | ||
| 58 | stmia r0!, {r3 - r9, ip} | ||
| 59 | bge 2b | ||
| 60 | 3: PLD( ldmia r1!, {r3 - r9, ip} ) | ||
| 61 | PLD( adds r2, r2, #32 ) | ||
| 62 | PLD( stmgeia r0!, {r3 - r9, ip} ) | ||
| 63 | PLD( ldmgeia r1!, {r3 - r9, ip} ) | ||
| 64 | PLD( subges r2, r2, #32 ) | ||
| 65 | PLD( stmia r0!, {r3 - r9, ip} ) | ||
| 66 | 4: cmn r2, #16 | ||
| 67 | ldmgeia r1!, {r3 - r6} | ||
| 68 | subge r2, r2, #16 | ||
| 69 | stmgeia r0!, {r3 - r6} | ||
| 70 | adds r2, r2, #20 | ||
| 71 | ldmgeia r1!, {r3 - r5} | ||
| 72 | subge r2, r2, #12 | ||
| 73 | stmgeia r0!, {r3 - r5} | ||
| 74 | 5: adds r2, r2, #8 | ||
| 75 | blt 6f | ||
| 76 | subs r2, r2, #4 | ||
| 77 | ldrlt r3, [r1], #4 | ||
| 78 | ldmgeia r1!, {r4, r5} | ||
| 79 | subge r2, r2, #4 | ||
| 80 | strlt r3, [r0], #4 | ||
| 81 | stmgeia r0!, {r4, r5} | ||
| 82 | |||
| 83 | 6: adds r2, r2, #4 | ||
| 84 | EXITEQ | ||
| 85 | cmp r2, #2 | ||
| 86 | ldrb r3, [r1], #1 | ||
| 87 | ldrgeb r4, [r1], #1 | ||
| 88 | ldrgtb r5, [r1], #1 | ||
| 89 | strb r3, [r0], #1 | ||
| 90 | strgeb r4, [r0], #1 | ||
| 91 | strgtb r5, [r0], #1 | ||
| 92 | EXIT | ||
| 93 | |||
| 94 | 7: rsb ip, ip, #4 | ||
| 95 | cmp ip, #2 | ||
| 96 | ldrb r3, [r1], #1 | ||
| 97 | ldrgeb r4, [r1], #1 | ||
| 98 | ldrgtb r5, [r1], #1 | ||
| 99 | strb r3, [r0], #1 | ||
| 100 | strgeb r4, [r0], #1 | ||
| 101 | strgtb r5, [r0], #1 | ||
| 102 | subs r2, r2, ip | ||
| 103 | blt 6b | ||
| 104 | ands ip, r1, #3 | ||
| 105 | beq 1b | ||
| 106 | |||
| 107 | 8: bic r1, r1, #3 | ||
| 108 | ldr r7, [r1], #4 | ||
| 109 | cmp ip, #2 | ||
| 110 | bgt 18f | ||
| 111 | beq 13f | ||
| 112 | cmp r2, #12 | ||
| 113 | blt 11f | ||
| 114 | PLD( pld [r1, #12] ) | ||
| 115 | sub r2, r2, #12 | ||
| 116 | PLD( subs r2, r2, #32 ) | ||
| 117 | PLD( blt 10f ) | ||
| 118 | PLD( pld [r1, #28] ) | ||
| 119 | 9: PLD( pld [r1, #44] ) | ||
| 120 | 10: mov r3, r7, pull #8 | ||
| 121 | ldmia r1!, {r4 - r7} | ||
| 122 | subs r2, r2, #16 | ||
| 123 | orr r3, r3, r4, push #24 | ||
| 124 | mov r4, r4, pull #8 | ||
| 125 | orr r4, r4, r5, push #24 | ||
| 126 | mov r5, r5, pull #8 | ||
| 127 | orr r5, r5, r6, push #24 | ||
| 128 | mov r6, r6, pull #8 | ||
| 129 | orr r6, r6, r7, push #24 | ||
| 130 | stmia r0!, {r3 - r6} | ||
| 131 | bge 9b | ||
| 132 | PLD( cmn r2, #32 ) | ||
| 133 | PLD( bge 10b ) | ||
| 134 | PLD( add r2, r2, #32 ) | ||
| 135 | adds r2, r2, #12 | ||
| 136 | blt 12f | ||
| 137 | 11: mov r3, r7, pull #8 | ||
| 138 | ldr r7, [r1], #4 | ||
| 139 | subs r2, r2, #4 | ||
| 140 | orr r3, r3, r7, push #24 | ||
| 141 | str r3, [r0], #4 | ||
| 142 | bge 11b | ||
| 143 | 12: sub r1, r1, #3 | ||
| 144 | b 6b | ||
| 145 | |||
| 146 | 13: cmp r2, #12 | ||
| 147 | blt 16f | ||
| 148 | PLD( pld [r1, #12] ) | ||
| 149 | sub r2, r2, #12 | ||
| 150 | PLD( subs r2, r2, #32 ) | ||
| 151 | PLD( blt 15f ) | ||
| 152 | PLD( pld [r1, #28] ) | ||
| 153 | 14: PLD( pld [r1, #44] ) | ||
| 154 | 15: mov r3, r7, pull #16 | ||
| 155 | ldmia r1!, {r4 - r7} | ||
| 156 | subs r2, r2, #16 | ||
| 157 | orr r3, r3, r4, push #16 | ||
| 158 | mov r4, r4, pull #16 | ||
| 159 | orr r4, r4, r5, push #16 | ||
| 160 | mov r5, r5, pull #16 | ||
| 161 | orr r5, r5, r6, push #16 | ||
| 162 | mov r6, r6, pull #16 | ||
| 163 | orr r6, r6, r7, push #16 | ||
| 164 | stmia r0!, {r3 - r6} | ||
| 165 | bge 14b | ||
| 166 | PLD( cmn r2, #32 ) | ||
| 167 | PLD( bge 15b ) | ||
| 168 | PLD( add r2, r2, #32 ) | ||
| 169 | adds r2, r2, #12 | ||
| 170 | blt 17f | ||
| 171 | 16: mov r3, r7, pull #16 | ||
| 172 | ldr r7, [r1], #4 | ||
| 173 | subs r2, r2, #4 | ||
| 174 | orr r3, r3, r7, push #16 | ||
| 175 | str r3, [r0], #4 | ||
| 176 | bge 16b | ||
| 177 | 17: sub r1, r1, #2 | ||
| 178 | b 6b | ||
| 179 | |||
| 180 | 18: cmp r2, #12 | ||
| 181 | blt 21f | ||
| 182 | PLD( pld [r1, #12] ) | ||
| 183 | sub r2, r2, #12 | ||
| 184 | PLD( subs r2, r2, #32 ) | ||
| 185 | PLD( blt 20f ) | ||
| 186 | PLD( pld [r1, #28] ) | ||
| 187 | 19: PLD( pld [r1, #44] ) | ||
| 188 | 20: mov r3, r7, pull #24 | ||
| 189 | ldmia r1!, {r4 - r7} | ||
| 190 | subs r2, r2, #16 | ||
| 191 | orr r3, r3, r4, push #8 | ||
| 192 | mov r4, r4, pull #24 | ||
| 193 | orr r4, r4, r5, push #8 | ||
| 194 | mov r5, r5, pull #24 | ||
| 195 | orr r5, r5, r6, push #8 | ||
| 196 | mov r6, r6, pull #24 | ||
| 197 | orr r6, r6, r7, push #8 | ||
| 198 | stmia r0!, {r3 - r6} | ||
| 199 | bge 19b | ||
| 200 | PLD( cmn r2, #32 ) | ||
| 201 | PLD( bge 20b ) | ||
| 202 | PLD( add r2, r2, #32 ) | ||
| 203 | adds r2, r2, #12 | ||
| 204 | blt 22f | ||
| 205 | 21: mov r3, r7, pull #24 | ||
| 206 | ldr r7, [r1], #4 | ||
| 207 | subs r2, r2, #4 | ||
| 208 | orr r3, r3, r7, push #8 | ||
| 209 | str r3, [r0], #4 | ||
| 210 | bge 21b | ||
| 211 | 22: sub r1, r1, #1 | ||
| 212 | b 6b | ||
| 213 | |||
| 214 | |||
| 215 | 23: add r1, r1, r2 | ||
| 216 | add r0, r0, r2 | ||
| 217 | subs r2, r2, #4 | ||
| 218 | blt 29f | ||
| 219 | PLD( pld [r1, #-4] ) | ||
| 220 | ands ip, r0, #3 | ||
| 221 | bne 30f | ||
| 222 | ands ip, r1, #3 | ||
| 223 | bne 31f | ||
| 224 | |||
| 225 | 24: subs r2, r2, #8 | ||
| 226 | blt 28f | ||
| 227 | subs r2, r2, #20 | ||
| 228 | blt 27f | ||
| 229 | PLD( pld [r1, #-32] ) | ||
| 230 | PLD( subs r2, r2, #64 ) | ||
| 231 | PLD( blt 26f ) | ||
| 232 | 25: PLD( pld [r1, #-64] ) | ||
| 233 | PLD( pld [r1, #-96] ) | ||
| 234 | ldmdb r1!, {r3 - r9, ip} | ||
| 235 | subs r2, r2, #32 | ||
| 236 | stmgedb r0!, {r3 - r9, ip} | ||
| 237 | ldmgedb r1!, {r3 - r9, ip} | ||
| 238 | subges r2, r2, #32 | ||
| 239 | stmdb r0!, {r3 - r9, ip} | ||
| 240 | bge 25b | ||
| 241 | 26: PLD( ldmdb r1!, {r3 - r9, ip} ) | ||
| 242 | PLD( adds r2, r2, #32 ) | ||
| 243 | PLD( stmgedb r0!, {r3 - r9, ip} ) | ||
| 244 | PLD( ldmgedb r1!, {r3 - r9, ip} ) | ||
| 245 | PLD( subges r2, r2, #32 ) | ||
| 246 | PLD( stmdb r0!, {r3 - r9, ip} ) | ||
| 247 | 27: cmn r2, #16 | ||
| 248 | ldmgedb r1!, {r3 - r6} | ||
| 249 | subge r2, r2, #16 | ||
| 250 | stmgedb r0!, {r3 - r6} | ||
| 251 | adds r2, r2, #20 | ||
| 252 | ldmgedb r1!, {r3 - r5} | ||
| 253 | subge r2, r2, #12 | ||
| 254 | stmgedb r0!, {r3 - r5} | ||
| 255 | 28: adds r2, r2, #8 | ||
| 256 | blt 29f | ||
| 257 | subs r2, r2, #4 | ||
| 258 | ldrlt r3, [r1, #-4]! | ||
| 259 | ldmgedb r1!, {r4, r5} | ||
| 260 | subge r2, r2, #4 | ||
| 261 | strlt r3, [r0, #-4]! | ||
| 262 | stmgedb r0!, {r4, r5} | ||
| 263 | |||
| 264 | 29: adds r2, r2, #4 | ||
| 265 | EXITEQ | ||
| 266 | cmp r2, #2 | ||
| 267 | ldrb r3, [r1, #-1]! | ||
| 268 | ldrgeb r4, [r1, #-1]! | ||
| 269 | ldrgtb r5, [r1, #-1]! | ||
| 270 | strb r3, [r0, #-1]! | ||
| 271 | strgeb r4, [r0, #-1]! | ||
| 272 | strgtb r5, [r0, #-1]! | ||
| 273 | EXIT | ||
| 274 | |||
| 275 | 30: cmp ip, #2 | ||
| 276 | ldrb r3, [r1, #-1]! | ||
| 277 | ldrgeb r4, [r1, #-1]! | ||
| 278 | ldrgtb r5, [r1, #-1]! | ||
| 279 | strb r3, [r0, #-1]! | ||
| 280 | strgeb r4, [r0, #-1]! | ||
| 281 | strgtb r5, [r0, #-1]! | ||
| 282 | subs r2, r2, ip | ||
| 283 | blt 29b | ||
| 284 | ands ip, r1, #3 | ||
| 285 | beq 24b | ||
| 286 | |||
| 287 | 31: bic r1, r1, #3 | ||
| 288 | ldr r3, [r1], #0 | ||
| 289 | cmp ip, #2 | ||
| 290 | blt 41f | ||
| 291 | beq 36f | ||
| 292 | cmp r2, #12 | ||
| 293 | blt 34f | ||
| 294 | PLD( pld [r1, #-16] ) | ||
| 295 | sub r2, r2, #12 | ||
| 296 | PLD( subs r2, r2, #32 ) | ||
| 297 | PLD( blt 33f ) | ||
| 298 | PLD( pld [r1, #-32] ) | ||
| 299 | 32: PLD( pld [r1, #-48] ) | ||
| 300 | 33: mov r7, r3, push #8 | ||
| 301 | ldmdb r1!, {r3, r4, r5, r6} | ||
| 302 | subs r2, r2, #16 | ||
| 303 | orr r7, r7, r6, pull #24 | ||
| 304 | mov r6, r6, push #8 | ||
| 305 | orr r6, r6, r5, pull #24 | ||
| 306 | mov r5, r5, push #8 | ||
| 307 | orr r5, r5, r4, pull #24 | ||
| 308 | mov r4, r4, push #8 | ||
| 309 | orr r4, r4, r3, pull #24 | ||
| 310 | stmdb r0!, {r4, r5, r6, r7} | ||
| 311 | bge 32b | ||
| 312 | PLD( cmn r2, #32 ) | ||
| 313 | PLD( bge 33b ) | ||
| 314 | PLD( add r2, r2, #32 ) | ||
| 315 | adds r2, r2, #12 | ||
| 316 | blt 35f | ||
| 317 | 34: mov ip, r3, push #8 | ||
| 318 | ldr r3, [r1, #-4]! | ||
| 319 | subs r2, r2, #4 | ||
| 320 | orr ip, ip, r3, pull #24 | ||
| 321 | str ip, [r0, #-4]! | ||
| 322 | bge 34b | ||
| 323 | 35: add r1, r1, #3 | ||
| 324 | b 29b | ||
| 325 | |||
| 326 | 36: cmp r2, #12 | ||
| 327 | blt 39f | ||
| 328 | PLD( pld [r1, #-16] ) | ||
| 329 | sub r2, r2, #12 | ||
| 330 | PLD( subs r2, r2, #32 ) | ||
| 331 | PLD( blt 38f ) | ||
| 332 | PLD( pld [r1, #-32] ) | ||
| 333 | 37: PLD( pld [r1, #-48] ) | ||
| 334 | 38: mov r7, r3, push #16 | ||
| 335 | ldmdb r1!, {r3, r4, r5, r6} | ||
| 336 | subs r2, r2, #16 | ||
| 337 | orr r7, r7, r6, pull #16 | ||
| 338 | mov r6, r6, push #16 | ||
| 339 | orr r6, r6, r5, pull #16 | ||
| 340 | mov r5, r5, push #16 | ||
| 341 | orr r5, r5, r4, pull #16 | ||
| 342 | mov r4, r4, push #16 | ||
| 343 | orr r4, r4, r3, pull #16 | ||
| 344 | stmdb r0!, {r4, r5, r6, r7} | ||
| 345 | bge 37b | ||
| 346 | PLD( cmn r2, #32 ) | ||
| 347 | PLD( bge 38b ) | ||
| 348 | PLD( add r2, r2, #32 ) | ||
| 349 | adds r2, r2, #12 | ||
| 350 | blt 40f | ||
| 351 | 39: mov ip, r3, push #16 | ||
| 352 | ldr r3, [r1, #-4]! | ||
| 353 | subs r2, r2, #4 | ||
| 354 | orr ip, ip, r3, pull #16 | ||
| 355 | str ip, [r0, #-4]! | ||
| 356 | bge 39b | ||
| 357 | 40: add r1, r1, #2 | ||
| 358 | b 29b | ||
| 359 | |||
| 360 | 41: cmp r2, #12 | ||
| 361 | blt 44f | ||
| 362 | PLD( pld [r1, #-16] ) | ||
| 363 | sub r2, r2, #12 | ||
| 364 | PLD( subs r2, r2, #32 ) | ||
| 365 | PLD( blt 43f ) | ||
| 366 | PLD( pld [r1, #-32] ) | ||
| 367 | 42: PLD( pld [r1, #-48] ) | ||
| 368 | 43: mov r7, r3, push #24 | ||
| 369 | ldmdb r1!, {r3, r4, r5, r6} | ||
| 370 | subs r2, r2, #16 | ||
| 371 | orr r7, r7, r6, pull #8 | ||
| 372 | mov r6, r6, push #24 | ||
| 373 | orr r6, r6, r5, pull #8 | ||
| 374 | mov r5, r5, push #24 | ||
| 375 | orr r5, r5, r4, pull #8 | ||
| 376 | mov r4, r4, push #24 | ||
| 377 | orr r4, r4, r3, pull #8 | ||
| 378 | stmdb r0!, {r4, r5, r6, r7} | ||
| 379 | bge 42b | ||
| 380 | PLD( cmn r2, #32 ) | ||
| 381 | PLD( bge 43b ) | ||
| 382 | PLD( add r2, r2, #32 ) | ||
| 383 | adds r2, r2, #12 | ||
| 384 | blt 45f | ||
| 385 | 44: mov ip, r3, push #24 | ||
| 386 | ldr r3, [r1, #-4]! | ||
| 387 | subs r2, r2, #4 | ||
| 388 | orr ip, ip, r3, pull #8 | ||
| 389 | str ip, [r0, #-4]! | ||
| 390 | bge 44b | ||
| 391 | 45: add r1, r1, #1 | ||
| 392 | b 29b | ||
| 393 | |||
diff --git a/arch/arm/lib/memset.S b/arch/arm/lib/memset.S new file mode 100644 index 000000000000..a1795f599937 --- /dev/null +++ b/arch/arm/lib/memset.S | |||
| @@ -0,0 +1,80 @@ | |||
| 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 | |||
| 15 | .text | ||
| 16 | .align 5 | ||
| 17 | .word 0 | ||
| 18 | |||
| 19 | 1: subs r2, r2, #4 @ 1 do we have enough | ||
| 20 | blt 5f @ 1 bytes to align with? | ||
| 21 | cmp r3, #2 @ 1 | ||
| 22 | strltb r1, [r0], #1 @ 1 | ||
| 23 | strleb r1, [r0], #1 @ 1 | ||
| 24 | strb r1, [r0], #1 @ 1 | ||
| 25 | add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3)) | ||
| 26 | /* | ||
| 27 | * The pointer is now aligned and the length is adjusted. Try doing the | ||
| 28 | * memzero again. | ||
| 29 | */ | ||
| 30 | |||
| 31 | ENTRY(memset) | ||
| 32 | ands r3, r0, #3 @ 1 unaligned? | ||
| 33 | bne 1b @ 1 | ||
| 34 | /* | ||
| 35 | * we know that the pointer in r0 is aligned to a word boundary. | ||
| 36 | */ | ||
| 37 | orr r1, r1, r1, lsl #8 | ||
| 38 | orr r1, r1, r1, lsl #16 | ||
| 39 | mov r3, r1 | ||
| 40 | cmp r2, #16 | ||
| 41 | blt 4f | ||
| 42 | /* | ||
| 43 | * We need an extra register for this loop - save the return address and | ||
| 44 | * use the LR | ||
| 45 | */ | ||
| 46 | str lr, [sp, #-4]! | ||
| 47 | mov ip, r1 | ||
| 48 | mov lr, r1 | ||
| 49 | |||
| 50 | 2: subs r2, r2, #64 | ||
| 51 | stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time. | ||
| 52 | stmgeia r0!, {r1, r3, ip, lr} | ||
| 53 | stmgeia r0!, {r1, r3, ip, lr} | ||
| 54 | stmgeia r0!, {r1, r3, ip, lr} | ||
| 55 | bgt 2b | ||
| 56 | LOADREGS(eqfd, sp!, {pc}) @ Now <64 bytes to go. | ||
| 57 | /* | ||
| 58 | * No need to correct the count; we're only testing bits from now on | ||
| 59 | */ | ||
| 60 | tst r2, #32 | ||
| 61 | stmneia r0!, {r1, r3, ip, lr} | ||
| 62 | stmneia r0!, {r1, r3, ip, lr} | ||
| 63 | tst r2, #16 | ||
| 64 | stmneia r0!, {r1, r3, ip, lr} | ||
| 65 | ldr lr, [sp], #4 | ||
| 66 | |||
| 67 | 4: tst r2, #8 | ||
| 68 | stmneia r0!, {r1, r3} | ||
| 69 | tst r2, #4 | ||
| 70 | strne r1, [r0], #4 | ||
| 71 | /* | ||
| 72 | * When we get here, we've got less than 4 bytes to zero. We | ||
| 73 | * may have an unaligned pointer as well. | ||
| 74 | */ | ||
| 75 | 5: tst r2, #2 | ||
| 76 | strneb r1, [r0], #1 | ||
| 77 | strneb r1, [r0], #1 | ||
| 78 | tst r2, #1 | ||
| 79 | strneb r1, [r0], #1 | ||
| 80 | RETINSTR(mov,pc,lr) | ||
diff --git a/arch/arm/lib/memzero.S b/arch/arm/lib/memzero.S new file mode 100644 index 000000000000..51ccc60160fd --- /dev/null +++ b/arch/arm/lib/memzero.S | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/memzero.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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | |||
| 13 | .text | ||
| 14 | .align 5 | ||
| 15 | .word 0 | ||
| 16 | /* | ||
| 17 | * Align the pointer in r0. r3 contains the number of bytes that we are | ||
| 18 | * mis-aligned by, and r1 is the number of bytes. If r1 < 4, then we | ||
| 19 | * don't bother; we use byte stores instead. | ||
| 20 | */ | ||
| 21 | 1: subs r1, r1, #4 @ 1 do we have enough | ||
| 22 | blt 5f @ 1 bytes to align with? | ||
| 23 | cmp r3, #2 @ 1 | ||
| 24 | strltb r2, [r0], #1 @ 1 | ||
| 25 | strleb r2, [r0], #1 @ 1 | ||
| 26 | strb r2, [r0], #1 @ 1 | ||
| 27 | add r1, r1, r3 @ 1 (r1 = r1 - (4 - r3)) | ||
| 28 | /* | ||
| 29 | * The pointer is now aligned and the length is adjusted. Try doing the | ||
| 30 | * memzero again. | ||
| 31 | */ | ||
| 32 | |||
| 33 | ENTRY(__memzero) | ||
| 34 | mov r2, #0 @ 1 | ||
| 35 | ands r3, r0, #3 @ 1 unaligned? | ||
| 36 | bne 1b @ 1 | ||
| 37 | /* | ||
| 38 | * r3 = 0, and we know that the pointer in r0 is aligned to a word boundary. | ||
| 39 | */ | ||
| 40 | cmp r1, #16 @ 1 we can skip this chunk if we | ||
| 41 | blt 4f @ 1 have < 16 bytes | ||
| 42 | /* | ||
| 43 | * We need an extra register for this loop - save the return address and | ||
| 44 | * use the LR | ||
| 45 | */ | ||
| 46 | str lr, [sp, #-4]! @ 1 | ||
| 47 | mov ip, r2 @ 1 | ||
| 48 | mov lr, r2 @ 1 | ||
| 49 | |||
| 50 | 3: subs r1, r1, #64 @ 1 write 32 bytes out per loop | ||
| 51 | stmgeia r0!, {r2, r3, ip, lr} @ 4 | ||
| 52 | stmgeia r0!, {r2, r3, ip, lr} @ 4 | ||
| 53 | stmgeia r0!, {r2, r3, ip, lr} @ 4 | ||
| 54 | stmgeia r0!, {r2, r3, ip, lr} @ 4 | ||
| 55 | bgt 3b @ 1 | ||
| 56 | LOADREGS(eqfd, sp!, {pc}) @ 1/2 quick exit | ||
| 57 | /* | ||
| 58 | * No need to correct the count; we're only testing bits from now on | ||
| 59 | */ | ||
| 60 | tst r1, #32 @ 1 | ||
| 61 | stmneia r0!, {r2, r3, ip, lr} @ 4 | ||
| 62 | stmneia r0!, {r2, r3, ip, lr} @ 4 | ||
| 63 | tst r1, #16 @ 1 16 bytes or more? | ||
| 64 | stmneia r0!, {r2, r3, ip, lr} @ 4 | ||
| 65 | ldr lr, [sp], #4 @ 1 | ||
| 66 | |||
| 67 | 4: tst r1, #8 @ 1 8 bytes or more? | ||
| 68 | stmneia r0!, {r2, r3} @ 2 | ||
| 69 | tst r1, #4 @ 1 4 bytes or more? | ||
| 70 | strne r2, [r0], #4 @ 1 | ||
| 71 | /* | ||
| 72 | * When we get here, we've got less than 4 bytes to zero. We | ||
| 73 | * may have an unaligned pointer as well. | ||
| 74 | */ | ||
| 75 | 5: tst r1, #2 @ 1 2 bytes or more? | ||
| 76 | strneb r2, [r0], #1 @ 1 | ||
| 77 | strneb r2, [r0], #1 @ 1 | ||
| 78 | tst r1, #1 @ 1 a byte left over | ||
| 79 | strneb r2, [r0], #1 @ 1 | ||
| 80 | RETINSTR(mov,pc,lr) @ 1 | ||
diff --git a/arch/arm/lib/muldi3.c b/arch/arm/lib/muldi3.c new file mode 100644 index 000000000000..44d611b1cfdb --- /dev/null +++ b/arch/arm/lib/muldi3.c | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* More subroutines needed by GCC output code on some machines. */ | ||
| 2 | /* Compile this one with gcc. */ | ||
| 3 | /* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU CC. | ||
| 6 | |||
| 7 | GNU CC is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation; either version 2, or (at your option) | ||
| 10 | any later version. | ||
| 11 | |||
| 12 | GNU CC is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU CC; see the file COPYING. If not, write to | ||
| 19 | the Free Software Foundation, 59 Temple Place - Suite 330, | ||
| 20 | Boston, MA 02111-1307, USA. */ | ||
| 21 | |||
| 22 | /* As a special exception, if you link this library with other files, | ||
| 23 | some of which are compiled with GCC, to produce an executable, | ||
| 24 | this library does not by itself cause the resulting executable | ||
| 25 | to be covered by the GNU General Public License. | ||
| 26 | This exception does not however invalidate any other reasons why | ||
| 27 | the executable file might be covered by the GNU General Public License. | ||
| 28 | */ | ||
| 29 | /* support functions required by the kernel. based on code from gcc-2.95.3 */ | ||
| 30 | /* I Molton 29/07/01 */ | ||
| 31 | |||
| 32 | #include "gcclib.h" | ||
| 33 | |||
| 34 | #define umul_ppmm(xh, xl, a, b) \ | ||
| 35 | {register USItype __t0, __t1, __t2; \ | ||
| 36 | __asm__ ("%@ Inlined umul_ppmm \n\ | ||
| 37 | mov %2, %5, lsr #16 \n\ | ||
| 38 | mov %0, %6, lsr #16 \n\ | ||
| 39 | bic %3, %5, %2, lsl #16 \n\ | ||
| 40 | bic %4, %6, %0, lsl #16 \n\ | ||
| 41 | mul %1, %3, %4 \n\ | ||
| 42 | mul %4, %2, %4 \n\ | ||
| 43 | mul %3, %0, %3 \n\ | ||
| 44 | mul %0, %2, %0 \n\ | ||
| 45 | adds %3, %4, %3 \n\ | ||
| 46 | addcs %0, %0, #65536 \n\ | ||
| 47 | adds %1, %1, %3, lsl #16 \n\ | ||
| 48 | adc %0, %0, %3, lsr #16" \ | ||
| 49 | : "=&r" ((USItype) (xh)), \ | ||
| 50 | "=r" ((USItype) (xl)), \ | ||
| 51 | "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ | ||
| 52 | : "r" ((USItype) (a)), \ | ||
| 53 | "r" ((USItype) (b)));} | ||
| 54 | |||
| 55 | |||
| 56 | #define __umulsidi3(u, v) \ | ||
| 57 | ({DIunion __w; \ | ||
| 58 | umul_ppmm (__w.s.high, __w.s.low, u, v); \ | ||
| 59 | __w.ll; }) | ||
| 60 | |||
| 61 | |||
| 62 | DItype | ||
| 63 | __muldi3 (DItype u, DItype v) | ||
| 64 | { | ||
| 65 | DIunion w; | ||
| 66 | DIunion uu, vv; | ||
| 67 | |||
| 68 | uu.ll = u, | ||
| 69 | vv.ll = v; | ||
| 70 | |||
| 71 | w.ll = __umulsidi3 (uu.s.low, vv.s.low); | ||
| 72 | w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high | ||
| 73 | + (USItype) uu.s.high * (USItype) vv.s.low); | ||
| 74 | |||
| 75 | return w.ll; | ||
| 76 | } | ||
| 77 | |||
diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S new file mode 100644 index 000000000000..b09398d95aac --- /dev/null +++ b/arch/arm/lib/putuser.S | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/putuser.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 2001 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 | * Idea from x86 version, (C) Copyright 1998 Linus Torvalds | ||
| 11 | * | ||
| 12 | * These functions have a non-standard call interface to make | ||
| 13 | * them more efficient, especially as they return an error | ||
| 14 | * value in addition to the "real" return value. | ||
| 15 | * | ||
| 16 | * __put_user_X | ||
| 17 | * | ||
| 18 | * Inputs: r0 contains the address | ||
| 19 | * r2, r3 contains the value | ||
| 20 | * Outputs: r0 is the error code | ||
| 21 | * lr corrupted | ||
| 22 | * | ||
| 23 | * No other registers must be altered. (see include/asm-arm/uaccess.h | ||
| 24 | * for specific ASM register usage). | ||
| 25 | * | ||
| 26 | * Note that ADDR_LIMIT is either 0 or 0xc0000000 | ||
| 27 | * Note also that it is intended that __put_user_bad is not global. | ||
| 28 | */ | ||
| 29 | #include <asm/constants.h> | ||
| 30 | #include <asm/thread_info.h> | ||
| 31 | #include <asm/errno.h> | ||
| 32 | |||
| 33 | .global __put_user_1 | ||
| 34 | __put_user_1: | ||
| 35 | 1: strbt r2, [r0] | ||
| 36 | mov r0, #0 | ||
| 37 | mov pc, lr | ||
| 38 | |||
| 39 | .global __put_user_2 | ||
| 40 | __put_user_2: | ||
| 41 | mov ip, r2, lsr #8 | ||
| 42 | #ifndef __ARMEB__ | ||
| 43 | 2: strbt r2, [r0], #1 | ||
| 44 | 3: strbt ip, [r0] | ||
| 45 | #else | ||
| 46 | 2: strbt ip, [r0], #1 | ||
| 47 | 3: strbt r2, [r0] | ||
| 48 | #endif | ||
| 49 | mov r0, #0 | ||
| 50 | mov pc, lr | ||
| 51 | |||
| 52 | .global __put_user_4 | ||
| 53 | __put_user_4: | ||
| 54 | 4: strt r2, [r0] | ||
| 55 | mov r0, #0 | ||
| 56 | mov pc, lr | ||
| 57 | |||
| 58 | .global __put_user_8 | ||
| 59 | __put_user_8: | ||
| 60 | 5: strt r2, [r0], #4 | ||
| 61 | 6: strt r3, [r0] | ||
| 62 | mov r0, #0 | ||
| 63 | mov pc, lr | ||
| 64 | |||
| 65 | __put_user_bad: | ||
| 66 | mov r0, #-EFAULT | ||
| 67 | mov pc, lr | ||
| 68 | |||
| 69 | .section __ex_table, "a" | ||
| 70 | .long 1b, __put_user_bad | ||
| 71 | .long 2b, __put_user_bad | ||
| 72 | .long 3b, __put_user_bad | ||
| 73 | .long 4b, __put_user_bad | ||
| 74 | .long 5b, __put_user_bad | ||
| 75 | .long 6b, __put_user_bad | ||
| 76 | .previous | ||
diff --git a/arch/arm/lib/setbit.S b/arch/arm/lib/setbit.S new file mode 100644 index 000000000000..8f337df5d99b --- /dev/null +++ b/arch/arm/lib/setbit.S | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/setbit.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-1996 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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | .text | ||
| 13 | |||
| 14 | /* | ||
| 15 | * Purpose : Function to set a bit | ||
| 16 | * Prototype: int set_bit(int bit, void *addr) | ||
| 17 | */ | ||
| 18 | ENTRY(_set_bit_be) | ||
| 19 | eor r0, r0, #0x18 @ big endian byte ordering | ||
| 20 | ENTRY(_set_bit_le) | ||
| 21 | and r2, r0, #7 | ||
| 22 | mov r3, #1 | ||
| 23 | mov r3, r3, lsl r2 | ||
| 24 | save_and_disable_irqs ip, r2 | ||
| 25 | ldrb r2, [r1, r0, lsr #3] | ||
| 26 | orr r2, r2, r3 | ||
| 27 | strb r2, [r1, r0, lsr #3] | ||
| 28 | restore_irqs ip | ||
| 29 | RETINSTR(mov,pc,lr) | ||
diff --git a/arch/arm/lib/strchr.S b/arch/arm/lib/strchr.S new file mode 100644 index 000000000000..5b9b493733fc --- /dev/null +++ b/arch/arm/lib/strchr.S | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/strchr.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 | |||
| 15 | .text | ||
| 16 | .align 5 | ||
| 17 | ENTRY(strchr) | ||
| 18 | and r1, r1, #0xff | ||
| 19 | 1: ldrb r2, [r0], #1 | ||
| 20 | teq r2, r1 | ||
| 21 | teqne r2, #0 | ||
| 22 | bne 1b | ||
| 23 | teq r2, r1 | ||
| 24 | movne r0, #0 | ||
| 25 | subeq r0, r0, #1 | ||
| 26 | RETINSTR(mov,pc,lr) | ||
diff --git a/arch/arm/lib/strncpy_from_user.S b/arch/arm/lib/strncpy_from_user.S new file mode 100644 index 000000000000..629cc8775276 --- /dev/null +++ b/arch/arm/lib/strncpy_from_user.S | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/strncpy_from_user.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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | #include <asm/errno.h> | ||
| 13 | |||
| 14 | .text | ||
| 15 | .align 5 | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Copy a string from user space to kernel space. | ||
| 19 | * r0 = dst, r1 = src, r2 = byte length | ||
| 20 | * returns the number of characters copied (strlen of copied string), | ||
| 21 | * -EFAULT on exception, or "len" if we fill the whole buffer | ||
| 22 | */ | ||
| 23 | ENTRY(__arch_strncpy_from_user) | ||
| 24 | save_lr | ||
| 25 | mov ip, r1 | ||
| 26 | 1: subs r2, r2, #1 | ||
| 27 | USER( ldrplbt r3, [r1], #1) | ||
| 28 | bmi 2f | ||
| 29 | strb r3, [r0], #1 | ||
| 30 | teq r3, #0 | ||
| 31 | bne 1b | ||
| 32 | sub r1, r1, #1 @ take NUL character out of count | ||
| 33 | 2: sub r0, r1, ip | ||
| 34 | restore_pc | ||
| 35 | |||
| 36 | .section .fixup,"ax" | ||
| 37 | .align 0 | ||
| 38 | 9001: mov r3, #0 | ||
| 39 | strb r3, [r0, #0] @ null terminate | ||
| 40 | mov r0, #-EFAULT | ||
| 41 | restore_pc | ||
| 42 | .previous | ||
| 43 | |||
diff --git a/arch/arm/lib/strnlen_user.S b/arch/arm/lib/strnlen_user.S new file mode 100644 index 000000000000..67bcd8268128 --- /dev/null +++ b/arch/arm/lib/strnlen_user.S | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/strnlen_user.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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | #include <asm/errno.h> | ||
| 13 | |||
| 14 | .text | ||
| 15 | .align 5 | ||
| 16 | |||
| 17 | /* Prototype: unsigned long __arch_strnlen_user(const char *str, long n) | ||
| 18 | * Purpose : get length of a string in user memory | ||
| 19 | * Params : str - address of string in user memory | ||
| 20 | * Returns : length of string *including terminator* | ||
| 21 | * or zero on exception, or n + 1 if too long | ||
| 22 | */ | ||
| 23 | ENTRY(__arch_strnlen_user) | ||
| 24 | save_lr | ||
| 25 | mov r2, r0 | ||
| 26 | 1: | ||
| 27 | USER( ldrbt r3, [r0], #1) | ||
| 28 | teq r3, #0 | ||
| 29 | beq 2f | ||
| 30 | subs r1, r1, #1 | ||
| 31 | bne 1b | ||
| 32 | add r0, r0, #1 | ||
| 33 | 2: sub r0, r0, r2 | ||
| 34 | restore_pc | ||
| 35 | |||
| 36 | .section .fixup,"ax" | ||
| 37 | .align 0 | ||
| 38 | 9001: mov r0, #0 | ||
| 39 | restore_pc | ||
| 40 | .previous | ||
diff --git a/arch/arm/lib/strrchr.S b/arch/arm/lib/strrchr.S new file mode 100644 index 000000000000..fa923f026f15 --- /dev/null +++ b/arch/arm/lib/strrchr.S | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/strrchr.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 | |||
| 15 | .text | ||
| 16 | .align 5 | ||
| 17 | ENTRY(strrchr) | ||
| 18 | mov r3, #0 | ||
| 19 | 1: ldrb r2, [r0], #1 | ||
| 20 | teq r2, r1 | ||
| 21 | subeq r3, r0, #1 | ||
| 22 | teq r2, #0 | ||
| 23 | bne 1b | ||
| 24 | mov r0, r3 | ||
| 25 | RETINSTR(mov,pc,lr) | ||
diff --git a/arch/arm/lib/testchangebit.S b/arch/arm/lib/testchangebit.S new file mode 100644 index 000000000000..4aba4676b984 --- /dev/null +++ b/arch/arm/lib/testchangebit.S | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/testchangebit.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-1996 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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | .text | ||
| 13 | |||
| 14 | ENTRY(_test_and_change_bit_be) | ||
| 15 | eor r0, r0, #0x18 @ big endian byte ordering | ||
| 16 | ENTRY(_test_and_change_bit_le) | ||
| 17 | add r1, r1, r0, lsr #3 | ||
| 18 | and r3, r0, #7 | ||
| 19 | mov r0, #1 | ||
| 20 | save_and_disable_irqs ip, r2 | ||
| 21 | ldrb r2, [r1] | ||
| 22 | tst r2, r0, lsl r3 | ||
| 23 | eor r2, r2, r0, lsl r3 | ||
| 24 | strb r2, [r1] | ||
| 25 | restore_irqs ip | ||
| 26 | moveq r0, #0 | ||
| 27 | RETINSTR(mov,pc,lr) | ||
| 28 | |||
| 29 | |||
diff --git a/arch/arm/lib/testclearbit.S b/arch/arm/lib/testclearbit.S new file mode 100644 index 000000000000..e07c5bd24307 --- /dev/null +++ b/arch/arm/lib/testclearbit.S | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/testclearbit.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-1996 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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | .text | ||
| 13 | |||
| 14 | ENTRY(_test_and_clear_bit_be) | ||
| 15 | eor r0, r0, #0x18 @ big endian byte ordering | ||
| 16 | ENTRY(_test_and_clear_bit_le) | ||
| 17 | add r1, r1, r0, lsr #3 @ Get byte offset | ||
| 18 | and r3, r0, #7 @ Get bit offset | ||
| 19 | mov r0, #1 | ||
| 20 | save_and_disable_irqs ip, r2 | ||
| 21 | ldrb r2, [r1] | ||
| 22 | tst r2, r0, lsl r3 | ||
| 23 | bic r2, r2, r0, lsl r3 | ||
| 24 | strb r2, [r1] | ||
| 25 | restore_irqs ip | ||
| 26 | moveq r0, #0 | ||
| 27 | RETINSTR(mov,pc,lr) | ||
| 28 | |||
| 29 | |||
diff --git a/arch/arm/lib/testsetbit.S b/arch/arm/lib/testsetbit.S new file mode 100644 index 000000000000..a570fc74cddd --- /dev/null +++ b/arch/arm/lib/testsetbit.S | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/testsetbit.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-1996 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 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | .text | ||
| 13 | |||
| 14 | ENTRY(_test_and_set_bit_be) | ||
| 15 | eor r0, r0, #0x18 @ big endian byte ordering | ||
| 16 | ENTRY(_test_and_set_bit_le) | ||
| 17 | add r1, r1, r0, lsr #3 @ Get byte offset | ||
| 18 | and r3, r0, #7 @ Get bit offset | ||
| 19 | mov r0, #1 | ||
| 20 | save_and_disable_irqs ip, r2 | ||
| 21 | ldrb r2, [r1] | ||
| 22 | tst r2, r0, lsl r3 | ||
| 23 | orr r2, r2, r0, lsl r3 | ||
| 24 | strb r2, [r1] | ||
| 25 | restore_irqs ip | ||
| 26 | moveq r0, #0 | ||
| 27 | RETINSTR(mov,pc,lr) | ||
| 28 | |||
| 29 | |||
diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S new file mode 100644 index 000000000000..d3ed0636c008 --- /dev/null +++ b/arch/arm/lib/uaccess.S | |||
| @@ -0,0 +1,697 @@ | |||
| 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 | |||
| 18 | .text | ||
| 19 | |||
| 20 | #define PAGE_SHIFT 12 | ||
| 21 | |||
| 22 | /* Prototype: int __arch_copy_to_user(void *to, const char *from, size_t n) | ||
| 23 | * Purpose : copy a block to user memory from kernel memory | ||
| 24 | * Params : to - user memory | ||
| 25 | * : from - kernel memory | ||
| 26 | * : n - number of bytes to copy | ||
| 27 | * Returns : Number of bytes NOT copied. | ||
| 28 | */ | ||
| 29 | |||
| 30 | .c2u_dest_not_aligned: | ||
| 31 | rsb ip, ip, #4 | ||
| 32 | cmp ip, #2 | ||
| 33 | ldrb r3, [r1], #1 | ||
| 34 | USER( strbt r3, [r0], #1) @ May fault | ||
| 35 | ldrgeb r3, [r1], #1 | ||
| 36 | USER( strgebt r3, [r0], #1) @ May fault | ||
| 37 | ldrgtb r3, [r1], #1 | ||
| 38 | USER( strgtbt r3, [r0], #1) @ May fault | ||
| 39 | sub r2, r2, ip | ||
| 40 | b .c2u_dest_aligned | ||
| 41 | |||
| 42 | ENTRY(__arch_copy_to_user) | ||
| 43 | stmfd sp!, {r2, r4 - r7, lr} | ||
| 44 | cmp r2, #4 | ||
| 45 | blt .c2u_not_enough | ||
| 46 | PLD( pld [r1, #0] ) | ||
| 47 | PLD( pld [r0, #0] ) | ||
| 48 | ands ip, r0, #3 | ||
| 49 | bne .c2u_dest_not_aligned | ||
| 50 | .c2u_dest_aligned: | ||
| 51 | |||
| 52 | ands ip, r1, #3 | ||
| 53 | bne .c2u_src_not_aligned | ||
| 54 | /* | ||
| 55 | * Seeing as there has to be at least 8 bytes to copy, we can | ||
| 56 | * copy one word, and force a user-mode page fault... | ||
| 57 | */ | ||
| 58 | |||
| 59 | .c2u_0fupi: subs r2, r2, #4 | ||
| 60 | addmi ip, r2, #4 | ||
| 61 | bmi .c2u_0nowords | ||
| 62 | ldr r3, [r1], #4 | ||
| 63 | USER( strt r3, [r0], #4) @ May fault | ||
| 64 | mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction | ||
| 65 | rsb ip, ip, #0 | ||
| 66 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
| 67 | beq .c2u_0fupi | ||
| 68 | /* | ||
| 69 | * ip = max no. of bytes to copy before needing another "strt" insn | ||
| 70 | */ | ||
| 71 | cmp r2, ip | ||
| 72 | movlt ip, r2 | ||
| 73 | sub r2, r2, ip | ||
| 74 | subs ip, ip, #32 | ||
| 75 | blt .c2u_0rem8lp | ||
| 76 | PLD( pld [r1, #28] ) | ||
| 77 | PLD( pld [r0, #28] ) | ||
| 78 | PLD( subs ip, ip, #64 ) | ||
| 79 | PLD( blt .c2u_0cpynopld ) | ||
| 80 | PLD( pld [r1, #60] ) | ||
| 81 | PLD( pld [r0, #60] ) | ||
| 82 | |||
| 83 | .c2u_0cpy8lp: | ||
| 84 | PLD( pld [r1, #92] ) | ||
| 85 | PLD( pld [r0, #92] ) | ||
| 86 | .c2u_0cpynopld: ldmia r1!, {r3 - r6} | ||
| 87 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
| 88 | ldmia r1!, {r3 - r6} | ||
| 89 | subs ip, ip, #32 | ||
| 90 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
| 91 | bpl .c2u_0cpy8lp | ||
| 92 | PLD( cmn ip, #64 ) | ||
| 93 | PLD( bge .c2u_0cpynopld ) | ||
| 94 | PLD( add ip, ip, #64 ) | ||
| 95 | |||
| 96 | .c2u_0rem8lp: cmn ip, #16 | ||
| 97 | ldmgeia r1!, {r3 - r6} | ||
| 98 | stmgeia r0!, {r3 - r6} @ Shouldnt fault | ||
| 99 | tst ip, #8 | ||
| 100 | ldmneia r1!, {r3 - r4} | ||
| 101 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
| 102 | tst ip, #4 | ||
| 103 | ldrne r3, [r1], #4 | ||
| 104 | strnet r3, [r0], #4 @ Shouldnt fault | ||
| 105 | ands ip, ip, #3 | ||
| 106 | beq .c2u_0fupi | ||
| 107 | .c2u_0nowords: teq ip, #0 | ||
| 108 | beq .c2u_finished | ||
| 109 | .c2u_nowords: cmp ip, #2 | ||
| 110 | ldrb r3, [r1], #1 | ||
| 111 | USER( strbt r3, [r0], #1) @ May fault | ||
| 112 | ldrgeb r3, [r1], #1 | ||
| 113 | USER( strgebt r3, [r0], #1) @ May fault | ||
| 114 | ldrgtb r3, [r1], #1 | ||
| 115 | USER( strgtbt r3, [r0], #1) @ May fault | ||
| 116 | b .c2u_finished | ||
| 117 | |||
| 118 | .c2u_not_enough: | ||
| 119 | movs ip, r2 | ||
| 120 | bne .c2u_nowords | ||
| 121 | .c2u_finished: mov r0, #0 | ||
| 122 | LOADREGS(fd,sp!,{r2, r4 - r7, pc}) | ||
| 123 | |||
| 124 | .c2u_src_not_aligned: | ||
| 125 | bic r1, r1, #3 | ||
| 126 | ldr r7, [r1], #4 | ||
| 127 | cmp ip, #2 | ||
| 128 | bgt .c2u_3fupi | ||
| 129 | beq .c2u_2fupi | ||
| 130 | .c2u_1fupi: subs r2, r2, #4 | ||
| 131 | addmi ip, r2, #4 | ||
| 132 | bmi .c2u_1nowords | ||
| 133 | mov r3, r7, pull #8 | ||
| 134 | ldr r7, [r1], #4 | ||
| 135 | orr r3, r3, r7, push #24 | ||
| 136 | USER( strt r3, [r0], #4) @ May fault | ||
| 137 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
| 138 | rsb ip, ip, #0 | ||
| 139 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
| 140 | beq .c2u_1fupi | ||
| 141 | cmp r2, ip | ||
| 142 | movlt ip, r2 | ||
| 143 | sub r2, r2, ip | ||
| 144 | subs ip, ip, #16 | ||
| 145 | blt .c2u_1rem8lp | ||
| 146 | PLD( pld [r1, #12] ) | ||
| 147 | PLD( pld [r0, #12] ) | ||
| 148 | PLD( subs ip, ip, #32 ) | ||
| 149 | PLD( blt .c2u_1cpynopld ) | ||
| 150 | PLD( pld [r1, #28] ) | ||
| 151 | PLD( pld [r0, #28] ) | ||
| 152 | |||
| 153 | .c2u_1cpy8lp: | ||
| 154 | PLD( pld [r1, #44] ) | ||
| 155 | PLD( pld [r0, #44] ) | ||
| 156 | .c2u_1cpynopld: mov r3, r7, pull #8 | ||
| 157 | ldmia r1!, {r4 - r7} | ||
| 158 | subs ip, ip, #16 | ||
| 159 | orr r3, r3, r4, push #24 | ||
| 160 | mov r4, r4, pull #8 | ||
| 161 | orr r4, r4, r5, push #24 | ||
| 162 | mov r5, r5, pull #8 | ||
| 163 | orr r5, r5, r6, push #24 | ||
| 164 | mov r6, r6, pull #8 | ||
| 165 | orr r6, r6, r7, push #24 | ||
| 166 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
| 167 | bpl .c2u_1cpy8lp | ||
| 168 | PLD( cmn ip, #32 ) | ||
| 169 | PLD( bge .c2u_1cpynopld ) | ||
| 170 | PLD( add ip, ip, #32 ) | ||
| 171 | |||
| 172 | .c2u_1rem8lp: tst ip, #8 | ||
| 173 | movne r3, r7, pull #8 | ||
| 174 | ldmneia r1!, {r4, r7} | ||
| 175 | orrne r3, r3, r4, push #24 | ||
| 176 | movne r4, r4, pull #8 | ||
| 177 | orrne r4, r4, r7, push #24 | ||
| 178 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
| 179 | tst ip, #4 | ||
| 180 | movne r3, r7, pull #8 | ||
| 181 | ldrne r7, [r1], #4 | ||
| 182 | orrne r3, r3, r7, push #24 | ||
| 183 | strnet r3, [r0], #4 @ Shouldnt fault | ||
| 184 | ands ip, ip, #3 | ||
| 185 | beq .c2u_1fupi | ||
| 186 | .c2u_1nowords: mov r3, r7, get_byte_1 | ||
| 187 | teq ip, #0 | ||
| 188 | beq .c2u_finished | ||
| 189 | cmp ip, #2 | ||
| 190 | USER( strbt r3, [r0], #1) @ May fault | ||
| 191 | movge r3, r7, get_byte_2 | ||
| 192 | USER( strgebt r3, [r0], #1) @ May fault | ||
| 193 | movgt r3, r7, get_byte_3 | ||
| 194 | USER( strgtbt r3, [r0], #1) @ May fault | ||
| 195 | b .c2u_finished | ||
| 196 | |||
| 197 | .c2u_2fupi: subs r2, r2, #4 | ||
| 198 | addmi ip, r2, #4 | ||
| 199 | bmi .c2u_2nowords | ||
| 200 | mov r3, r7, pull #16 | ||
| 201 | ldr r7, [r1], #4 | ||
| 202 | orr r3, r3, r7, push #16 | ||
| 203 | USER( strt r3, [r0], #4) @ May fault | ||
| 204 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
| 205 | rsb ip, ip, #0 | ||
| 206 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
| 207 | beq .c2u_2fupi | ||
| 208 | cmp r2, ip | ||
| 209 | movlt ip, r2 | ||
| 210 | sub r2, r2, ip | ||
| 211 | subs ip, ip, #16 | ||
| 212 | blt .c2u_2rem8lp | ||
| 213 | PLD( pld [r1, #12] ) | ||
| 214 | PLD( pld [r0, #12] ) | ||
| 215 | PLD( subs ip, ip, #32 ) | ||
| 216 | PLD( blt .c2u_2cpynopld ) | ||
| 217 | PLD( pld [r1, #28] ) | ||
| 218 | PLD( pld [r0, #28] ) | ||
| 219 | |||
| 220 | .c2u_2cpy8lp: | ||
| 221 | PLD( pld [r1, #44] ) | ||
| 222 | PLD( pld [r0, #44] ) | ||
| 223 | .c2u_2cpynopld: mov r3, r7, pull #16 | ||
| 224 | ldmia r1!, {r4 - r7} | ||
| 225 | subs ip, ip, #16 | ||
| 226 | orr r3, r3, r4, push #16 | ||
| 227 | mov r4, r4, pull #16 | ||
| 228 | orr r4, r4, r5, push #16 | ||
| 229 | mov r5, r5, pull #16 | ||
| 230 | orr r5, r5, r6, push #16 | ||
| 231 | mov r6, r6, pull #16 | ||
| 232 | orr r6, r6, r7, push #16 | ||
| 233 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
| 234 | bpl .c2u_2cpy8lp | ||
| 235 | PLD( cmn ip, #32 ) | ||
| 236 | PLD( bge .c2u_2cpynopld ) | ||
| 237 | PLD( add ip, ip, #32 ) | ||
| 238 | |||
| 239 | .c2u_2rem8lp: tst ip, #8 | ||
| 240 | movne r3, r7, pull #16 | ||
| 241 | ldmneia r1!, {r4, r7} | ||
| 242 | orrne r3, r3, r4, push #16 | ||
| 243 | movne r4, r4, pull #16 | ||
| 244 | orrne r4, r4, r7, push #16 | ||
| 245 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
| 246 | tst ip, #4 | ||
| 247 | movne r3, r7, pull #16 | ||
| 248 | ldrne r7, [r1], #4 | ||
| 249 | orrne r3, r3, r7, push #16 | ||
| 250 | strnet r3, [r0], #4 @ Shouldnt fault | ||
| 251 | ands ip, ip, #3 | ||
| 252 | beq .c2u_2fupi | ||
| 253 | .c2u_2nowords: mov r3, r7, get_byte_2 | ||
| 254 | teq ip, #0 | ||
| 255 | beq .c2u_finished | ||
| 256 | cmp ip, #2 | ||
| 257 | USER( strbt r3, [r0], #1) @ May fault | ||
| 258 | movge r3, r7, get_byte_3 | ||
| 259 | USER( strgebt r3, [r0], #1) @ May fault | ||
| 260 | ldrgtb r3, [r1], #0 | ||
| 261 | USER( strgtbt r3, [r0], #1) @ May fault | ||
| 262 | b .c2u_finished | ||
| 263 | |||
| 264 | .c2u_3fupi: subs r2, r2, #4 | ||
| 265 | addmi ip, r2, #4 | ||
| 266 | bmi .c2u_3nowords | ||
| 267 | mov r3, r7, pull #24 | ||
| 268 | ldr r7, [r1], #4 | ||
| 269 | orr r3, r3, r7, push #8 | ||
| 270 | USER( strt r3, [r0], #4) @ May fault | ||
| 271 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
| 272 | rsb ip, ip, #0 | ||
| 273 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
| 274 | beq .c2u_3fupi | ||
| 275 | cmp r2, ip | ||
| 276 | movlt ip, r2 | ||
| 277 | sub r2, r2, ip | ||
| 278 | subs ip, ip, #16 | ||
| 279 | blt .c2u_3rem8lp | ||
| 280 | PLD( pld [r1, #12] ) | ||
| 281 | PLD( pld [r0, #12] ) | ||
| 282 | PLD( subs ip, ip, #32 ) | ||
| 283 | PLD( blt .c2u_3cpynopld ) | ||
| 284 | PLD( pld [r1, #28] ) | ||
| 285 | PLD( pld [r0, #28] ) | ||
| 286 | |||
| 287 | .c2u_3cpy8lp: | ||
| 288 | PLD( pld [r1, #44] ) | ||
| 289 | PLD( pld [r0, #44] ) | ||
| 290 | .c2u_3cpynopld: mov r3, r7, pull #24 | ||
| 291 | ldmia r1!, {r4 - r7} | ||
| 292 | subs ip, ip, #16 | ||
| 293 | orr r3, r3, r4, push #8 | ||
| 294 | mov r4, r4, pull #24 | ||
| 295 | orr r4, r4, r5, push #8 | ||
| 296 | mov r5, r5, pull #24 | ||
| 297 | orr r5, r5, r6, push #8 | ||
| 298 | mov r6, r6, pull #24 | ||
| 299 | orr r6, r6, r7, push #8 | ||
| 300 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
| 301 | bpl .c2u_3cpy8lp | ||
| 302 | PLD( cmn ip, #32 ) | ||
| 303 | PLD( bge .c2u_3cpynopld ) | ||
| 304 | PLD( add ip, ip, #32 ) | ||
| 305 | |||
| 306 | .c2u_3rem8lp: tst ip, #8 | ||
| 307 | movne r3, r7, pull #24 | ||
| 308 | ldmneia r1!, {r4, r7} | ||
| 309 | orrne r3, r3, r4, push #8 | ||
| 310 | movne r4, r4, pull #24 | ||
| 311 | orrne r4, r4, r7, push #8 | ||
| 312 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
| 313 | tst ip, #4 | ||
| 314 | movne r3, r7, pull #24 | ||
| 315 | ldrne r7, [r1], #4 | ||
| 316 | orrne r3, r3, r7, push #8 | ||
| 317 | strnet r3, [r0], #4 @ Shouldnt fault | ||
| 318 | ands ip, ip, #3 | ||
| 319 | beq .c2u_3fupi | ||
| 320 | .c2u_3nowords: mov r3, r7, get_byte_3 | ||
| 321 | teq ip, #0 | ||
| 322 | beq .c2u_finished | ||
| 323 | cmp ip, #2 | ||
| 324 | USER( strbt r3, [r0], #1) @ May fault | ||
| 325 | ldrgeb r3, [r1], #1 | ||
| 326 | USER( strgebt r3, [r0], #1) @ May fault | ||
| 327 | ldrgtb r3, [r1], #0 | ||
| 328 | USER( strgtbt r3, [r0], #1) @ May fault | ||
| 329 | b .c2u_finished | ||
| 330 | |||
| 331 | .section .fixup,"ax" | ||
| 332 | .align 0 | ||
| 333 | 9001: LOADREGS(fd,sp!, {r0, r4 - r7, pc}) | ||
| 334 | .previous | ||
| 335 | |||
| 336 | /* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n); | ||
| 337 | * Purpose : copy a block from user memory to kernel memory | ||
| 338 | * Params : to - kernel memory | ||
| 339 | * : from - user memory | ||
| 340 | * : n - number of bytes to copy | ||
| 341 | * Returns : Number of bytes NOT copied. | ||
| 342 | */ | ||
| 343 | .cfu_dest_not_aligned: | ||
| 344 | rsb ip, ip, #4 | ||
| 345 | cmp ip, #2 | ||
| 346 | USER( ldrbt r3, [r1], #1) @ May fault | ||
| 347 | strb r3, [r0], #1 | ||
| 348 | USER( ldrgebt r3, [r1], #1) @ May fault | ||
| 349 | strgeb r3, [r0], #1 | ||
| 350 | USER( ldrgtbt r3, [r1], #1) @ May fault | ||
| 351 | strgtb r3, [r0], #1 | ||
| 352 | sub r2, r2, ip | ||
| 353 | b .cfu_dest_aligned | ||
| 354 | |||
| 355 | ENTRY(__arch_copy_from_user) | ||
| 356 | stmfd sp!, {r0, r2, r4 - r7, lr} | ||
| 357 | cmp r2, #4 | ||
| 358 | blt .cfu_not_enough | ||
| 359 | PLD( pld [r1, #0] ) | ||
| 360 | PLD( pld [r0, #0] ) | ||
| 361 | ands ip, r0, #3 | ||
| 362 | bne .cfu_dest_not_aligned | ||
| 363 | .cfu_dest_aligned: | ||
| 364 | ands ip, r1, #3 | ||
| 365 | bne .cfu_src_not_aligned | ||
| 366 | /* | ||
| 367 | * Seeing as there has to be at least 8 bytes to copy, we can | ||
| 368 | * copy one word, and force a user-mode page fault... | ||
| 369 | */ | ||
| 370 | |||
| 371 | .cfu_0fupi: subs r2, r2, #4 | ||
| 372 | addmi ip, r2, #4 | ||
| 373 | bmi .cfu_0nowords | ||
| 374 | USER( ldrt r3, [r1], #4) | ||
| 375 | str r3, [r0], #4 | ||
| 376 | mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction | ||
| 377 | rsb ip, ip, #0 | ||
| 378 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
| 379 | beq .cfu_0fupi | ||
| 380 | /* | ||
| 381 | * ip = max no. of bytes to copy before needing another "strt" insn | ||
| 382 | */ | ||
| 383 | cmp r2, ip | ||
| 384 | movlt ip, r2 | ||
| 385 | sub r2, r2, ip | ||
| 386 | subs ip, ip, #32 | ||
| 387 | blt .cfu_0rem8lp | ||
| 388 | PLD( pld [r1, #28] ) | ||
| 389 | PLD( pld [r0, #28] ) | ||
| 390 | PLD( subs ip, ip, #64 ) | ||
| 391 | PLD( blt .cfu_0cpynopld ) | ||
| 392 | PLD( pld [r1, #60] ) | ||
| 393 | PLD( pld [r0, #60] ) | ||
| 394 | |||
| 395 | .cfu_0cpy8lp: | ||
| 396 | PLD( pld [r1, #92] ) | ||
| 397 | PLD( pld [r0, #92] ) | ||
| 398 | .cfu_0cpynopld: ldmia r1!, {r3 - r6} @ Shouldnt fault | ||
| 399 | stmia r0!, {r3 - r6} | ||
| 400 | ldmia r1!, {r3 - r6} @ Shouldnt fault | ||
| 401 | subs ip, ip, #32 | ||
| 402 | stmia r0!, {r3 - r6} | ||
| 403 | bpl .cfu_0cpy8lp | ||
| 404 | PLD( cmn ip, #64 ) | ||
| 405 | PLD( bge .cfu_0cpynopld ) | ||
| 406 | PLD( add ip, ip, #64 ) | ||
| 407 | |||
| 408 | .cfu_0rem8lp: cmn ip, #16 | ||
| 409 | ldmgeia r1!, {r3 - r6} @ Shouldnt fault | ||
| 410 | stmgeia r0!, {r3 - r6} | ||
| 411 | tst ip, #8 | ||
| 412 | ldmneia r1!, {r3 - r4} @ Shouldnt fault | ||
| 413 | stmneia r0!, {r3 - r4} | ||
| 414 | tst ip, #4 | ||
| 415 | ldrnet r3, [r1], #4 @ Shouldnt fault | ||
| 416 | strne r3, [r0], #4 | ||
| 417 | ands ip, ip, #3 | ||
| 418 | beq .cfu_0fupi | ||
| 419 | .cfu_0nowords: teq ip, #0 | ||
| 420 | beq .cfu_finished | ||
| 421 | .cfu_nowords: cmp ip, #2 | ||
| 422 | USER( ldrbt r3, [r1], #1) @ May fault | ||
| 423 | strb r3, [r0], #1 | ||
| 424 | USER( ldrgebt r3, [r1], #1) @ May fault | ||
| 425 | strgeb r3, [r0], #1 | ||
| 426 | USER( ldrgtbt r3, [r1], #1) @ May fault | ||
| 427 | strgtb r3, [r0], #1 | ||
| 428 | b .cfu_finished | ||
| 429 | |||
| 430 | .cfu_not_enough: | ||
| 431 | movs ip, r2 | ||
| 432 | bne .cfu_nowords | ||
| 433 | .cfu_finished: mov r0, #0 | ||
| 434 | add sp, sp, #8 | ||
| 435 | LOADREGS(fd,sp!,{r4 - r7, pc}) | ||
| 436 | |||
| 437 | .cfu_src_not_aligned: | ||
| 438 | bic r1, r1, #3 | ||
| 439 | USER( ldrt r7, [r1], #4) @ May fault | ||
| 440 | cmp ip, #2 | ||
| 441 | bgt .cfu_3fupi | ||
| 442 | beq .cfu_2fupi | ||
| 443 | .cfu_1fupi: subs r2, r2, #4 | ||
| 444 | addmi ip, r2, #4 | ||
| 445 | bmi .cfu_1nowords | ||
| 446 | mov r3, r7, pull #8 | ||
| 447 | USER( ldrt r7, [r1], #4) @ May fault | ||
| 448 | orr r3, r3, r7, push #24 | ||
| 449 | str r3, [r0], #4 | ||
| 450 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
| 451 | rsb ip, ip, #0 | ||
| 452 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
| 453 | beq .cfu_1fupi | ||
| 454 | cmp r2, ip | ||
| 455 | movlt ip, r2 | ||
| 456 | sub r2, r2, ip | ||
| 457 | subs ip, ip, #16 | ||
| 458 | blt .cfu_1rem8lp | ||
| 459 | PLD( pld [r1, #12] ) | ||
| 460 | PLD( pld [r0, #12] ) | ||
| 461 | PLD( subs ip, ip, #32 ) | ||
| 462 | PLD( blt .cfu_1cpynopld ) | ||
| 463 | PLD( pld [r1, #28] ) | ||
| 464 | PLD( pld [r0, #28] ) | ||
| 465 | |||
| 466 | .cfu_1cpy8lp: | ||
| 467 | PLD( pld [r1, #44] ) | ||
| 468 | PLD( pld [r0, #44] ) | ||
| 469 | .cfu_1cpynopld: mov r3, r7, pull #8 | ||
| 470 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
| 471 | subs ip, ip, #16 | ||
| 472 | orr r3, r3, r4, push #24 | ||
| 473 | mov r4, r4, pull #8 | ||
| 474 | orr r4, r4, r5, push #24 | ||
| 475 | mov r5, r5, pull #8 | ||
| 476 | orr r5, r5, r6, push #24 | ||
| 477 | mov r6, r6, pull #8 | ||
| 478 | orr r6, r6, r7, push #24 | ||
| 479 | stmia r0!, {r3 - r6} | ||
| 480 | bpl .cfu_1cpy8lp | ||
| 481 | PLD( cmn ip, #32 ) | ||
| 482 | PLD( bge .cfu_1cpynopld ) | ||
| 483 | PLD( add ip, ip, #32 ) | ||
| 484 | |||
| 485 | .cfu_1rem8lp: tst ip, #8 | ||
| 486 | movne r3, r7, pull #8 | ||
| 487 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
| 488 | orrne r3, r3, r4, push #24 | ||
| 489 | movne r4, r4, pull #8 | ||
| 490 | orrne r4, r4, r7, push #24 | ||
| 491 | stmneia r0!, {r3 - r4} | ||
| 492 | tst ip, #4 | ||
| 493 | movne r3, r7, pull #8 | ||
| 494 | USER( ldrnet r7, [r1], #4) @ May fault | ||
| 495 | orrne r3, r3, r7, push #24 | ||
| 496 | strne r3, [r0], #4 | ||
| 497 | ands ip, ip, #3 | ||
| 498 | beq .cfu_1fupi | ||
| 499 | .cfu_1nowords: mov r3, r7, get_byte_1 | ||
| 500 | teq ip, #0 | ||
| 501 | beq .cfu_finished | ||
| 502 | cmp ip, #2 | ||
| 503 | strb r3, [r0], #1 | ||
| 504 | movge r3, r7, get_byte_2 | ||
| 505 | strgeb r3, [r0], #1 | ||
| 506 | movgt r3, r7, get_byte_3 | ||
| 507 | strgtb r3, [r0], #1 | ||
| 508 | b .cfu_finished | ||
| 509 | |||
| 510 | .cfu_2fupi: subs r2, r2, #4 | ||
| 511 | addmi ip, r2, #4 | ||
| 512 | bmi .cfu_2nowords | ||
| 513 | mov r3, r7, pull #16 | ||
| 514 | USER( ldrt r7, [r1], #4) @ May fault | ||
| 515 | orr r3, r3, r7, push #16 | ||
| 516 | str r3, [r0], #4 | ||
| 517 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
| 518 | rsb ip, ip, #0 | ||
| 519 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
| 520 | beq .cfu_2fupi | ||
| 521 | cmp r2, ip | ||
| 522 | movlt ip, r2 | ||
| 523 | sub r2, r2, ip | ||
| 524 | subs ip, ip, #16 | ||
| 525 | blt .cfu_2rem8lp | ||
| 526 | PLD( pld [r1, #12] ) | ||
| 527 | PLD( pld [r0, #12] ) | ||
| 528 | PLD( subs ip, ip, #32 ) | ||
| 529 | PLD( blt .cfu_2cpynopld ) | ||
| 530 | PLD( pld [r1, #28] ) | ||
| 531 | PLD( pld [r0, #28] ) | ||
| 532 | |||
| 533 | .cfu_2cpy8lp: | ||
| 534 | PLD( pld [r1, #44] ) | ||
| 535 | PLD( pld [r0, #44] ) | ||
| 536 | .cfu_2cpynopld: mov r3, r7, pull #16 | ||
| 537 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
| 538 | subs ip, ip, #16 | ||
| 539 | orr r3, r3, r4, push #16 | ||
| 540 | mov r4, r4, pull #16 | ||
| 541 | orr r4, r4, r5, push #16 | ||
| 542 | mov r5, r5, pull #16 | ||
| 543 | orr r5, r5, r6, push #16 | ||
| 544 | mov r6, r6, pull #16 | ||
| 545 | orr r6, r6, r7, push #16 | ||
| 546 | stmia r0!, {r3 - r6} | ||
| 547 | bpl .cfu_2cpy8lp | ||
| 548 | PLD( cmn ip, #32 ) | ||
| 549 | PLD( bge .cfu_2cpynopld ) | ||
| 550 | PLD( add ip, ip, #32 ) | ||
| 551 | |||
| 552 | .cfu_2rem8lp: tst ip, #8 | ||
| 553 | movne r3, r7, pull #16 | ||
| 554 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
| 555 | orrne r3, r3, r4, push #16 | ||
| 556 | movne r4, r4, pull #16 | ||
| 557 | orrne r4, r4, r7, push #16 | ||
| 558 | stmneia r0!, {r3 - r4} | ||
| 559 | tst ip, #4 | ||
| 560 | movne r3, r7, pull #16 | ||
| 561 | USER( ldrnet r7, [r1], #4) @ May fault | ||
| 562 | orrne r3, r3, r7, push #16 | ||
| 563 | strne r3, [r0], #4 | ||
| 564 | ands ip, ip, #3 | ||
| 565 | beq .cfu_2fupi | ||
| 566 | .cfu_2nowords: mov r3, r7, get_byte_2 | ||
| 567 | teq ip, #0 | ||
| 568 | beq .cfu_finished | ||
| 569 | cmp ip, #2 | ||
| 570 | strb r3, [r0], #1 | ||
| 571 | movge r3, r7, get_byte_3 | ||
| 572 | strgeb r3, [r0], #1 | ||
| 573 | USER( ldrgtbt r3, [r1], #0) @ May fault | ||
| 574 | strgtb r3, [r0], #1 | ||
| 575 | b .cfu_finished | ||
| 576 | |||
| 577 | .cfu_3fupi: subs r2, r2, #4 | ||
| 578 | addmi ip, r2, #4 | ||
| 579 | bmi .cfu_3nowords | ||
| 580 | mov r3, r7, pull #24 | ||
| 581 | USER( ldrt r7, [r1], #4) @ May fault | ||
| 582 | orr r3, r3, r7, push #8 | ||
| 583 | str r3, [r0], #4 | ||
| 584 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
| 585 | rsb ip, ip, #0 | ||
| 586 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
| 587 | beq .cfu_3fupi | ||
| 588 | cmp r2, ip | ||
| 589 | movlt ip, r2 | ||
| 590 | sub r2, r2, ip | ||
| 591 | subs ip, ip, #16 | ||
| 592 | blt .cfu_3rem8lp | ||
| 593 | PLD( pld [r1, #12] ) | ||
| 594 | PLD( pld [r0, #12] ) | ||
| 595 | PLD( subs ip, ip, #32 ) | ||
| 596 | PLD( blt .cfu_3cpynopld ) | ||
| 597 | PLD( pld [r1, #28] ) | ||
| 598 | PLD( pld [r0, #28] ) | ||
| 599 | |||
| 600 | .cfu_3cpy8lp: | ||
| 601 | PLD( pld [r1, #44] ) | ||
| 602 | PLD( pld [r0, #44] ) | ||
| 603 | .cfu_3cpynopld: mov r3, r7, pull #24 | ||
| 604 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
| 605 | orr r3, r3, r4, push #8 | ||
| 606 | mov r4, r4, pull #24 | ||
| 607 | orr r4, r4, r5, push #8 | ||
| 608 | mov r5, r5, pull #24 | ||
| 609 | orr r5, r5, r6, push #8 | ||
| 610 | mov r6, r6, pull #24 | ||
| 611 | orr r6, r6, r7, push #8 | ||
| 612 | stmia r0!, {r3 - r6} | ||
| 613 | subs ip, ip, #16 | ||
| 614 | bpl .cfu_3cpy8lp | ||
| 615 | PLD( cmn ip, #32 ) | ||
| 616 | PLD( bge .cfu_3cpynopld ) | ||
| 617 | PLD( add ip, ip, #32 ) | ||
| 618 | |||
| 619 | .cfu_3rem8lp: tst ip, #8 | ||
| 620 | movne r3, r7, pull #24 | ||
| 621 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
| 622 | orrne r3, r3, r4, push #8 | ||
| 623 | movne r4, r4, pull #24 | ||
| 624 | orrne r4, r4, r7, push #8 | ||
| 625 | stmneia r0!, {r3 - r4} | ||
| 626 | tst ip, #4 | ||
| 627 | movne r3, r7, pull #24 | ||
| 628 | USER( ldrnet r7, [r1], #4) @ May fault | ||
| 629 | orrne r3, r3, r7, push #8 | ||
| 630 | strne r3, [r0], #4 | ||
| 631 | ands ip, ip, #3 | ||
| 632 | beq .cfu_3fupi | ||
| 633 | .cfu_3nowords: mov r3, r7, get_byte_3 | ||
| 634 | teq ip, #0 | ||
| 635 | beq .cfu_finished | ||
| 636 | cmp ip, #2 | ||
| 637 | strb r3, [r0], #1 | ||
| 638 | USER( ldrgebt r3, [r1], #1) @ May fault | ||
| 639 | strgeb r3, [r0], #1 | ||
| 640 | USER( ldrgtbt r3, [r1], #1) @ May fault | ||
| 641 | strgtb r3, [r0], #1 | ||
| 642 | b .cfu_finished | ||
| 643 | |||
| 644 | .section .fixup,"ax" | ||
| 645 | .align 0 | ||
| 646 | /* | ||
| 647 | * We took an exception. r0 contains a pointer to | ||
| 648 | * the byte not copied. | ||
| 649 | */ | ||
| 650 | 9001: ldr r2, [sp], #4 @ void *to | ||
| 651 | sub r2, r0, r2 @ bytes copied | ||
| 652 | ldr r1, [sp], #4 @ unsigned long count | ||
| 653 | subs r4, r1, r2 @ bytes left to copy | ||
| 654 | movne r1, r4 | ||
| 655 | blne __memzero | ||
| 656 | mov r0, r4 | ||
| 657 | LOADREGS(fd,sp!, {r4 - r7, pc}) | ||
| 658 | .previous | ||
| 659 | |||
| 660 | /* Prototype: int __arch_clear_user(void *addr, size_t sz) | ||
| 661 | * Purpose : clear some user memory | ||
| 662 | * Params : addr - user memory address to clear | ||
| 663 | * : sz - number of bytes to clear | ||
| 664 | * Returns : number of bytes NOT cleared | ||
| 665 | */ | ||
| 666 | ENTRY(__arch_clear_user) | ||
| 667 | stmfd sp!, {r1, lr} | ||
| 668 | mov r2, #0 | ||
| 669 | cmp r1, #4 | ||
| 670 | blt 2f | ||
| 671 | ands ip, r0, #3 | ||
| 672 | beq 1f | ||
| 673 | cmp ip, #2 | ||
| 674 | USER( strbt r2, [r0], #1) | ||
| 675 | USER( strlebt r2, [r0], #1) | ||
| 676 | USER( strltbt r2, [r0], #1) | ||
| 677 | rsb ip, ip, #4 | ||
| 678 | sub r1, r1, ip @ 7 6 5 4 3 2 1 | ||
| 679 | 1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 | ||
| 680 | USER( strplt r2, [r0], #4) | ||
| 681 | USER( strplt r2, [r0], #4) | ||
| 682 | bpl 1b | ||
| 683 | adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 | ||
| 684 | USER( strplt r2, [r0], #4) | ||
| 685 | 2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x | ||
| 686 | USER( strnebt r2, [r0], #1) | ||
| 687 | USER( strnebt r2, [r0], #1) | ||
| 688 | tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 | ||
| 689 | USER( strnebt r2, [r0], #1) | ||
| 690 | mov r0, #0 | ||
| 691 | LOADREGS(fd,sp!, {r1, pc}) | ||
| 692 | |||
| 693 | .section .fixup,"ax" | ||
| 694 | .align 0 | ||
| 695 | 9001: LOADREGS(fd,sp!, {r0, pc}) | ||
| 696 | .previous | ||
| 697 | |||
diff --git a/arch/arm/lib/ucmpdi2.c b/arch/arm/lib/ucmpdi2.c new file mode 100644 index 000000000000..6c6ae63efa02 --- /dev/null +++ b/arch/arm/lib/ucmpdi2.c | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | /* More subroutines needed by GCC output code on some machines. */ | ||
| 2 | /* Compile this one with gcc. */ | ||
| 3 | /* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU CC. | ||
| 6 | |||
| 7 | GNU CC is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation; either version 2, or (at your option) | ||
| 10 | any later version. | ||
| 11 | |||
| 12 | GNU CC is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU CC; see the file COPYING. If not, write to | ||
| 19 | the Free Software Foundation, 59 Temple Place - Suite 330, | ||
| 20 | Boston, MA 02111-1307, USA. */ | ||
| 21 | |||
| 22 | /* As a special exception, if you link this library with other files, | ||
| 23 | some of which are compiled with GCC, to produce an executable, | ||
| 24 | this library does not by itself cause the resulting executable | ||
| 25 | to be covered by the GNU General Public License. | ||
| 26 | This exception does not however invalidate any other reasons why | ||
| 27 | the executable file might be covered by the GNU General Public License. | ||
| 28 | */ | ||
| 29 | /* support functions required by the kernel. based on code from gcc-2.95.3 */ | ||
| 30 | /* I Molton 29/07/01 */ | ||
| 31 | |||
| 32 | #include "gcclib.h" | ||
| 33 | |||
| 34 | word_type | ||
| 35 | __ucmpdi2 (DItype a, DItype b) | ||
| 36 | { | ||
| 37 | DIunion au, bu; | ||
| 38 | |||
| 39 | au.ll = a, bu.ll = b; | ||
| 40 | |||
| 41 | if ((USItype) au.s.high < (USItype) bu.s.high) | ||
| 42 | return 0; | ||
| 43 | else if ((USItype) au.s.high > (USItype) bu.s.high) | ||
| 44 | return 2; | ||
| 45 | if ((USItype) au.s.low < (USItype) bu.s.low) | ||
| 46 | return 0; | ||
| 47 | else if ((USItype) au.s.low > (USItype) bu.s.low) | ||
| 48 | return 2; | ||
| 49 | return 1; | ||
| 50 | } | ||
| 51 | |||
diff --git a/arch/arm/lib/udivdi3.c b/arch/arm/lib/udivdi3.c new file mode 100644 index 000000000000..d25195f673f4 --- /dev/null +++ b/arch/arm/lib/udivdi3.c | |||
| @@ -0,0 +1,242 @@ | |||
| 1 | /* More subroutines needed by GCC output code on some machines. */ | ||
| 2 | /* Compile this one with gcc. */ | ||
| 3 | /* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU CC. | ||
| 6 | |||
| 7 | GNU CC is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation; either version 2, or (at your option) | ||
| 10 | any later version. | ||
| 11 | |||
| 12 | GNU CC is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU CC; see the file COPYING. If not, write to | ||
| 19 | the Free Software Foundation, 59 Temple Place - Suite 330, | ||
| 20 | Boston, MA 02111-1307, USA. */ | ||
| 21 | |||
| 22 | /* As a special exception, if you link this library with other files, | ||
| 23 | some of which are compiled with GCC, to produce an executable, | ||
| 24 | this library does not by itself cause the resulting executable | ||
| 25 | to be covered by the GNU General Public License. | ||
| 26 | This exception does not however invalidate any other reasons why | ||
| 27 | the executable file might be covered by the GNU General Public License. | ||
| 28 | */ | ||
| 29 | /* support functions required by the kernel. based on code from gcc-2.95.3 */ | ||
| 30 | /* I Molton 29/07/01 */ | ||
| 31 | |||
| 32 | #include "gcclib.h" | ||
| 33 | #include "longlong.h" | ||
| 34 | |||
| 35 | static const UQItype __clz_tab[] = | ||
| 36 | { | ||
| 37 | 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, | ||
| 38 | 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, | ||
| 39 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, | ||
| 40 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, | ||
| 41 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, | ||
| 42 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, | ||
| 43 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, | ||
| 44 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, | ||
| 45 | }; | ||
| 46 | |||
| 47 | UDItype | ||
| 48 | __udivmoddi4 (UDItype n, UDItype d, UDItype *rp) | ||
| 49 | { | ||
| 50 | DIunion ww; | ||
| 51 | DIunion nn, dd; | ||
| 52 | DIunion rr; | ||
| 53 | USItype d0, d1, n0, n1, n2; | ||
| 54 | USItype q0, q1; | ||
| 55 | USItype b, bm; | ||
| 56 | |||
| 57 | nn.ll = n; | ||
| 58 | dd.ll = d; | ||
| 59 | |||
| 60 | d0 = dd.s.low; | ||
| 61 | d1 = dd.s.high; | ||
| 62 | n0 = nn.s.low; | ||
| 63 | n1 = nn.s.high; | ||
| 64 | |||
| 65 | if (d1 == 0) | ||
| 66 | { | ||
| 67 | if (d0 > n1) | ||
| 68 | { | ||
| 69 | /* 0q = nn / 0D */ | ||
| 70 | |||
| 71 | count_leading_zeros (bm, d0); | ||
| 72 | |||
| 73 | if (bm != 0) | ||
| 74 | { | ||
| 75 | /* Normalize, i.e. make the most significant bit of the | ||
| 76 | denominator set. */ | ||
| 77 | |||
| 78 | d0 = d0 << bm; | ||
| 79 | n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm)); | ||
| 80 | n0 = n0 << bm; | ||
| 81 | } | ||
| 82 | |||
| 83 | udiv_qrnnd (q0, n0, n1, n0, d0); | ||
| 84 | q1 = 0; | ||
| 85 | |||
| 86 | /* Remainder in n0 >> bm. */ | ||
| 87 | } | ||
| 88 | else | ||
| 89 | { | ||
| 90 | /* qq = NN / 0d */ | ||
| 91 | |||
| 92 | if (d0 == 0) | ||
| 93 | d0 = 1 / d0; /* Divide intentionally by zero. */ | ||
| 94 | |||
| 95 | count_leading_zeros (bm, d0); | ||
| 96 | |||
| 97 | if (bm == 0) | ||
| 98 | { | ||
| 99 | /* From (n1 >= d0) /\ (the most significant bit of d0 is set), | ||
| 100 | conclude (the most significant bit of n1 is set) /\ (the | ||
| 101 | leading quotient digit q1 = 1). | ||
| 102 | |||
| 103 | This special case is necessary, not an optimization. | ||
| 104 | (Shifts counts of SI_TYPE_SIZE are undefined.) */ | ||
| 105 | |||
| 106 | n1 -= d0; | ||
| 107 | q1 = 1; | ||
| 108 | } | ||
| 109 | else | ||
| 110 | { | ||
| 111 | /* Normalize. */ | ||
| 112 | |||
| 113 | b = SI_TYPE_SIZE - bm; | ||
| 114 | |||
| 115 | d0 = d0 << bm; | ||
| 116 | n2 = n1 >> b; | ||
| 117 | n1 = (n1 << bm) | (n0 >> b); | ||
| 118 | n0 = n0 << bm; | ||
| 119 | |||
| 120 | udiv_qrnnd (q1, n1, n2, n1, d0); | ||
| 121 | } | ||
| 122 | |||
| 123 | /* n1 != d0... */ | ||
| 124 | |||
| 125 | udiv_qrnnd (q0, n0, n1, n0, d0); | ||
| 126 | |||
| 127 | /* Remainder in n0 >> bm. */ | ||
| 128 | } | ||
| 129 | |||
| 130 | if (rp != 0) | ||
| 131 | { | ||
| 132 | rr.s.low = n0 >> bm; | ||
| 133 | rr.s.high = 0; | ||
| 134 | *rp = rr.ll; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | else | ||
| 138 | { | ||
| 139 | if (d1 > n1) | ||
| 140 | { | ||
| 141 | /* 00 = nn / DD */ | ||
| 142 | |||
| 143 | q0 = 0; | ||
| 144 | q1 = 0; | ||
| 145 | |||
| 146 | /* Remainder in n1n0. */ | ||
| 147 | if (rp != 0) | ||
| 148 | { | ||
| 149 | rr.s.low = n0; | ||
| 150 | rr.s.high = n1; | ||
| 151 | *rp = rr.ll; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | else | ||
| 155 | { | ||
| 156 | /* 0q = NN / dd */ | ||
| 157 | |||
| 158 | count_leading_zeros (bm, d1); | ||
| 159 | if (bm == 0) | ||
| 160 | { | ||
| 161 | /* From (n1 >= d1) /\ (the most significant bit of d1 is set), | ||
| 162 | conclude (the most significant bit of n1 is set) /\ (the | ||
| 163 | quotient digit q0 = 0 or 1). | ||
| 164 | |||
| 165 | This special case is necessary, not an optimization. */ | ||
| 166 | |||
| 167 | /* The condition on the next line takes advantage of that | ||
| 168 | n1 >= d1 (true due to program flow). */ | ||
| 169 | if (n1 > d1 || n0 >= d0) | ||
| 170 | { | ||
| 171 | q0 = 1; | ||
| 172 | sub_ddmmss (n1, n0, n1, n0, d1, d0); | ||
| 173 | } | ||
| 174 | else | ||
| 175 | q0 = 0; | ||
| 176 | |||
| 177 | q1 = 0; | ||
| 178 | |||
| 179 | if (rp != 0) | ||
| 180 | { | ||
| 181 | rr.s.low = n0; | ||
| 182 | rr.s.high = n1; | ||
| 183 | *rp = rr.ll; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | else | ||
| 187 | { | ||
| 188 | USItype m1, m0; | ||
| 189 | /* Normalize. */ | ||
| 190 | |||
| 191 | b = SI_TYPE_SIZE - bm; | ||
| 192 | |||
| 193 | d1 = (d1 << bm) | (d0 >> b); | ||
| 194 | d0 = d0 << bm; | ||
| 195 | n2 = n1 >> b; | ||
| 196 | n1 = (n1 << bm) | (n0 >> b); | ||
| 197 | n0 = n0 << bm; | ||
| 198 | |||
| 199 | udiv_qrnnd (q0, n1, n2, n1, d1); | ||
| 200 | umul_ppmm (m1, m0, q0, d0); | ||
| 201 | |||
| 202 | if (m1 > n1 || (m1 == n1 && m0 > n0)) | ||
| 203 | { | ||
| 204 | q0--; | ||
| 205 | sub_ddmmss (m1, m0, m1, m0, d1, d0); | ||
| 206 | } | ||
| 207 | |||
| 208 | q1 = 0; | ||
| 209 | |||
| 210 | /* Remainder in (n1n0 - m1m0) >> bm. */ | ||
| 211 | if (rp != 0) | ||
| 212 | { | ||
| 213 | sub_ddmmss (n1, n0, n1, n0, m1, m0); | ||
| 214 | rr.s.low = (n1 << b) | (n0 >> bm); | ||
| 215 | rr.s.high = n1 >> bm; | ||
| 216 | *rp = rr.ll; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | ww.s.low = q0; | ||
| 223 | ww.s.high = q1; | ||
| 224 | return ww.ll; | ||
| 225 | } | ||
| 226 | |||
| 227 | UDItype | ||
| 228 | __udivdi3 (UDItype n, UDItype d) | ||
| 229 | { | ||
| 230 | return __udivmoddi4 (n, d, (UDItype *) 0); | ||
| 231 | } | ||
| 232 | |||
| 233 | UDItype | ||
| 234 | __umoddi3 (UDItype u, UDItype v) | ||
| 235 | { | ||
| 236 | UDItype w; | ||
| 237 | |||
| 238 | (void) __udivmoddi4 (u ,v, &w); | ||
| 239 | |||
| 240 | return w; | ||
| 241 | } | ||
| 242 | |||
