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/arm26/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/arm26/lib')
45 files changed, 4979 insertions, 0 deletions
diff --git a/arch/arm26/lib/Makefile b/arch/arm26/lib/Makefile new file mode 100644 index 000000000000..6df2b793d367 --- /dev/null +++ b/arch/arm26/lib/Makefile | |||
@@ -0,0 +1,26 @@ | |||
1 | # | ||
2 | # linux/arch/arm26/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 \ | ||
11 | strchr.o strrchr.o testchangebit.o \ | ||
12 | testclearbit.o testsetbit.o getuser.o \ | ||
13 | putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ | ||
14 | ucmpdi2.o udivdi3.o lib1funcs.o ecard.o io-acorn.o \ | ||
15 | floppydma.o io-readsb.o io-writesb.o io-writesl.o \ | ||
16 | uaccess-kernel.o uaccess-user.o io-readsw.o \ | ||
17 | io-writesw.o io-readsl.o ecard.o io-acorn.o \ | ||
18 | floppydma.o | ||
19 | |||
20 | lib-n := | ||
21 | |||
22 | lib-$(CONFIG_VT)+= kbd.o | ||
23 | |||
24 | csumpartialcopy.o: csumpartialcopygeneric.S | ||
25 | csumpartialcopyuser.o: csumpartialcopygeneric.S | ||
26 | |||
diff --git a/arch/arm26/lib/ashldi3.c b/arch/arm26/lib/ashldi3.c new file mode 100644 index 000000000000..130f5a839669 --- /dev/null +++ b/arch/arm26/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/arm26/lib/ashrdi3.c b/arch/arm26/lib/ashrdi3.c new file mode 100644 index 000000000000..71625d218f8d --- /dev/null +++ b/arch/arm26/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/arm26/lib/backtrace.S b/arch/arm26/lib/backtrace.S new file mode 100644 index 000000000000..d793fe4339fc --- /dev/null +++ b/arch/arm26/lib/backtrace.S | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | #include <linux/config.h> | ||
11 | #include <linux/linkage.h> | ||
12 | #include <asm/assembler.h> | ||
13 | .text | ||
14 | |||
15 | @ fp is 0 or stack frame | ||
16 | |||
17 | #define frame r4 | ||
18 | #define next r5 | ||
19 | #define save r6 | ||
20 | #define mask r7 | ||
21 | #define offset r8 | ||
22 | |||
23 | ENTRY(__backtrace) | ||
24 | mov r1, #0x10 | ||
25 | mov r0, fp | ||
26 | |||
27 | ENTRY(c_backtrace) | ||
28 | |||
29 | #ifdef CONFIG_NO_FRAME_POINTER | ||
30 | mov pc, lr | ||
31 | #else | ||
32 | |||
33 | stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... | ||
34 | mov mask, #0xfc000003 | ||
35 | tst mask, r0 | ||
36 | movne r0, #0 | ||
37 | movs frame, r0 | ||
38 | 1: moveq r0, #-2 | ||
39 | LOADREGS(eqfd, sp!, {r4 - r8, pc}) | ||
40 | |||
41 | 2: stmfd sp!, {pc} @ calculate offset of PC in STMIA instruction | ||
42 | ldr r0, [sp], #4 | ||
43 | adr r1, 2b - 4 | ||
44 | sub offset, r0, r1 | ||
45 | |||
46 | 3: tst frame, mask @ Check for address exceptions... | ||
47 | bne 1b | ||
48 | |||
49 | 1001: ldr next, [frame, #-12] @ get fp | ||
50 | 1002: ldr r2, [frame, #-4] @ get lr | ||
51 | 1003: ldr r3, [frame, #0] @ get pc | ||
52 | sub save, r3, offset @ Correct PC for prefetching | ||
53 | bic save, save, mask | ||
54 | 1004: ldr r1, [save, #0] @ get instruction at function | ||
55 | mov r1, r1, lsr #10 | ||
56 | ldr r3, .Ldsi+4 | ||
57 | teq r1, r3 | ||
58 | subeq save, save, #4 | ||
59 | adr r0, .Lfe | ||
60 | mov r1, save | ||
61 | bic r2, r2, mask | ||
62 | bl printk @ print pc and link register | ||
63 | |||
64 | ldr r0, [frame, #-8] @ get sp | ||
65 | sub r0, r0, #4 | ||
66 | 1005: ldr r1, [save, #4] @ get instruction at function+4 | ||
67 | mov r3, r1, lsr #10 | ||
68 | ldr r2, .Ldsi+4 | ||
69 | teq r3, r2 @ Check for stmia sp!, {args} | ||
70 | addeq save, save, #4 @ next instruction | ||
71 | bleq .Ldumpstm | ||
72 | |||
73 | sub r0, frame, #16 | ||
74 | 1006: ldr r1, [save, #4] @ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction | ||
75 | mov r3, r1, lsr #10 | ||
76 | ldr r2, .Ldsi | ||
77 | teq r3, r2 | ||
78 | bleq .Ldumpstm | ||
79 | |||
80 | teq frame, next | ||
81 | movne frame, next | ||
82 | teqne frame, #0 | ||
83 | bne 3b | ||
84 | LOADREGS(fd, sp!, {r4 - r8, pc}) | ||
85 | |||
86 | /* | ||
87 | * Fixup for LDMDB | ||
88 | */ | ||
89 | .section .fixup,"ax" | ||
90 | .align 0 | ||
91 | 1007: ldr r0, =.Lbad | ||
92 | mov r1, frame | ||
93 | bl printk | ||
94 | LOADREGS(fd, sp!, {r4 - r8, pc}) | ||
95 | .ltorg | ||
96 | .previous | ||
97 | |||
98 | .section __ex_table,"a" | ||
99 | .align 3 | ||
100 | .long 1001b, 1007b | ||
101 | .long 1002b, 1007b | ||
102 | .long 1003b, 1007b | ||
103 | .long 1004b, 1007b | ||
104 | .long 1005b, 1007b | ||
105 | .long 1006b, 1007b | ||
106 | .previous | ||
107 | |||
108 | #define instr r4 | ||
109 | #define reg r5 | ||
110 | #define stack r6 | ||
111 | |||
112 | .Ldumpstm: stmfd sp!, {instr, reg, stack, r7, lr} | ||
113 | mov stack, r0 | ||
114 | mov instr, r1 | ||
115 | mov reg, #9 | ||
116 | mov r7, #0 | ||
117 | 1: mov r3, #1 | ||
118 | tst instr, r3, lsl reg | ||
119 | beq 2f | ||
120 | add r7, r7, #1 | ||
121 | teq r7, #4 | ||
122 | moveq r7, #0 | ||
123 | moveq r3, #'\n' | ||
124 | movne r3, #' ' | ||
125 | ldr r2, [stack], #-4 | ||
126 | mov r1, reg | ||
127 | adr r0, .Lfp | ||
128 | bl printk | ||
129 | 2: subs reg, reg, #1 | ||
130 | bpl 1b | ||
131 | teq r7, #0 | ||
132 | adrne r0, .Lcr | ||
133 | blne printk | ||
134 | mov r0, stack | ||
135 | LOADREGS(fd, sp!, {instr, reg, stack, r7, pc}) | ||
136 | |||
137 | .Lfe: .asciz "Function entered at [<%p>] from [<%p>]\n" | ||
138 | .Lfp: .asciz " r%d = %08X%c" | ||
139 | .Lcr: .asciz "\n" | ||
140 | .Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" | ||
141 | .align | ||
142 | .Ldsi: .word 0x00e92dd8 >> 2 | ||
143 | .word 0x00e92d00 >> 2 | ||
144 | |||
145 | #endif | ||
diff --git a/arch/arm26/lib/changebit.S b/arch/arm26/lib/changebit.S new file mode 100644 index 000000000000..1b6a077be5a6 --- /dev/null +++ b/arch/arm26/lib/changebit.S | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/clearbit.S b/arch/arm26/lib/clearbit.S new file mode 100644 index 000000000000..0a895b0c759f --- /dev/null +++ b/arch/arm26/lib/clearbit.S | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/copy_page.S b/arch/arm26/lib/copy_page.S new file mode 100644 index 000000000000..2d79ee12ea1f --- /dev/null +++ b/arch/arm26/lib/copy_page.S | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/asm_offsets.h> | ||
15 | |||
16 | .text | ||
17 | .align 5 | ||
18 | /* | ||
19 | * ARMv3 optimised copy_user_page | ||
20 | * | ||
21 | * FIXME: rmk do we need to handle cache stuff... | ||
22 | * FIXME: im is this right on ARM26? | ||
23 | */ | ||
24 | ENTRY(__copy_user_page) | ||
25 | stmfd sp!, {r4, lr} @ 2 | ||
26 | mov r2, #PAGE_SZ/64 @ 1 | ||
27 | ldmia r1!, {r3, r4, ip, lr} @ 4+1 | ||
28 | 1: stmia r0!, {r3, r4, ip, lr} @ 4 | ||
29 | ldmia r1!, {r3, r4, ip, lr} @ 4+1 | ||
30 | stmia r0!, {r3, r4, ip, lr} @ 4 | ||
31 | ldmia r1!, {r3, r4, ip, lr} @ 4+1 | ||
32 | stmia r0!, {r3, r4, ip, lr} @ 4 | ||
33 | ldmia r1!, {r3, r4, ip, lr} @ 4 | ||
34 | subs r2, r2, #1 @ 1 | ||
35 | stmia r0!, {r3, r4, ip, lr} @ 4 | ||
36 | ldmneia r1!, {r3, r4, ip, lr} @ 4 | ||
37 | bne 1b @ 1 | ||
38 | LOADREGS(fd, sp!, {r4, pc}) @ 3 | ||
39 | |||
40 | .align 5 | ||
41 | /* | ||
42 | * ARMv3 optimised clear_user_page | ||
43 | * | ||
44 | * FIXME: rmk do we need to handle cache stuff... | ||
45 | */ | ||
46 | ENTRY(__clear_user_page) | ||
47 | str lr, [sp, #-4]! | ||
48 | mov r1, #PAGE_SZ/64 @ 1 | ||
49 | mov r2, #0 @ 1 | ||
50 | mov r3, #0 @ 1 | ||
51 | mov ip, #0 @ 1 | ||
52 | mov lr, #0 @ 1 | ||
53 | 1: stmia r0!, {r2, r3, ip, lr} @ 4 | ||
54 | stmia r0!, {r2, r3, ip, lr} @ 4 | ||
55 | stmia r0!, {r2, r3, ip, lr} @ 4 | ||
56 | stmia r0!, {r2, r3, ip, lr} @ 4 | ||
57 | subs r1, r1, #1 @ 1 | ||
58 | bne 1b @ 1 | ||
59 | ldr pc, [sp], #4 | ||
60 | |||
61 | .section ".init.text", #alloc, #execinstr | ||
62 | |||
diff --git a/arch/arm26/lib/csumipv6.S b/arch/arm26/lib/csumipv6.S new file mode 100644 index 000000000000..62831155acde --- /dev/null +++ b/arch/arm26/lib/csumipv6.S | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/csumpartial.S b/arch/arm26/lib/csumpartial.S new file mode 100644 index 000000000000..e53e7109e623 --- /dev/null +++ b/arch/arm26/lib/csumpartial.S | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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, lsl #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 | orr td0, td0, td3, lsl #8 | ||
60 | #endif | ||
61 | adcs sum, sum, td0 | ||
62 | tst len, #6 | ||
63 | bne .less8_wordlp | ||
64 | |||
65 | .less8_byte: tst len, #1 @ odd number of bytes | ||
66 | ldrneb td0, [buf], #1 @ include last byte | ||
67 | adcnes sum, sum, td0, lsl #byte(0) @ update checksum | ||
68 | |||
69 | .done: adc r0, sum, #0 @ collect up the last carry | ||
70 | ldr td0, [sp], #4 | ||
71 | tst td0, #1 @ check buffer alignment | ||
72 | movne td0, r0, lsl #8 @ rotate checksum by 8 bits | ||
73 | orrne r0, td0, r0, lsr #24 | ||
74 | ldr pc, [sp], #4 @ return | ||
75 | |||
76 | .not_aligned: tst buf, #1 @ odd address | ||
77 | ldrneb td0, [buf], #1 @ make even | ||
78 | subne len, len, #1 | ||
79 | adcnes sum, sum, td0, lsl #byte(1) @ update checksum | ||
80 | |||
81 | tst buf, #2 @ 32-bit aligned? | ||
82 | #if __LINUX_ARM_ARCH__ >= 4 | ||
83 | ldrneh td0, [buf], #2 @ make 32-bit aligned | ||
84 | subne len, len, #2 | ||
85 | #else | ||
86 | ldrneb td0, [buf], #1 | ||
87 | ldrneb ip, [buf], #1 | ||
88 | subne len, len, #2 | ||
89 | orrne td0, td0, ip, lsl #8 | ||
90 | #endif | ||
91 | adcnes sum, sum, td0 @ update checksum | ||
92 | mov pc, lr | ||
93 | |||
94 | ENTRY(csum_partial) | ||
95 | stmfd sp!, {buf, lr} | ||
96 | cmp len, #8 @ Ensure that we have at least | ||
97 | blo .less8 @ 8 bytes to copy. | ||
98 | |||
99 | adds sum, sum, #0 @ C = 0 | ||
100 | tst buf, #3 @ Test destination alignment | ||
101 | blne .not_aligned @ aligh destination, return here | ||
102 | |||
103 | 1: bics ip, len, #31 | ||
104 | beq 3f | ||
105 | |||
106 | stmfd sp!, {r4 - r5} | ||
107 | 2: ldmia buf!, {td0, td1, td2, td3} | ||
108 | adcs sum, sum, td0 | ||
109 | adcs sum, sum, td1 | ||
110 | adcs sum, sum, td2 | ||
111 | adcs sum, sum, td3 | ||
112 | ldmia buf!, {td0, td1, td2, td3} | ||
113 | adcs sum, sum, td0 | ||
114 | adcs sum, sum, td1 | ||
115 | adcs sum, sum, td2 | ||
116 | adcs sum, sum, td3 | ||
117 | sub ip, ip, #32 | ||
118 | teq ip, #0 | ||
119 | bne 2b | ||
120 | ldmfd sp!, {r4 - r5} | ||
121 | |||
122 | 3: tst len, #0x1c @ should not change C | ||
123 | beq .less4 | ||
124 | |||
125 | 4: ldr td0, [buf], #4 | ||
126 | sub len, len, #4 | ||
127 | adcs sum, sum, td0 | ||
128 | tst len, #0x1c | ||
129 | bne 4b | ||
130 | b .less4 | ||
diff --git a/arch/arm26/lib/csumpartialcopy.S b/arch/arm26/lib/csumpartialcopy.S new file mode 100644 index 000000000000..a1c4b5fdd498 --- /dev/null +++ b/arch/arm26/lib/csumpartialcopy.S | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/csumpartialcopygeneric.S b/arch/arm26/lib/csumpartialcopygeneric.S new file mode 100644 index 000000000000..5249c3ad11db --- /dev/null +++ b/arch/arm26/lib/csumpartialcopygeneric.S | |||
@@ -0,0 +1,352 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | * JMA 01/06/03 Commented out some shl0s; probobly irrelevant to arm26 | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * unsigned int | ||
16 | * csum_partial_copy_xxx(const char *src, char *dst, int len, int sum, ) | ||
17 | * r0 = src, r1 = dst, r2 = len, r3 = sum | ||
18 | * Returns : r0 = checksum | ||
19 | * | ||
20 | * Note that 'tst' and 'teq' preserve the carry flag. | ||
21 | */ | ||
22 | |||
23 | /* Quick hack */ | ||
24 | .macro save_regs | ||
25 | stmfd sp!, {r1, r4 - r8, fp, ip, lr, pc} | ||
26 | .endm | ||
27 | |||
28 | /* end Quick Hack */ | ||
29 | |||
30 | src .req r0 | ||
31 | dst .req r1 | ||
32 | len .req r2 | ||
33 | sum .req r3 | ||
34 | |||
35 | .zero: mov r0, sum | ||
36 | load_regs ea | ||
37 | |||
38 | /* | ||
39 | * Align an unaligned destination pointer. We know that | ||
40 | * we have >= 8 bytes here, so we don't need to check | ||
41 | * the length. Note that the source pointer hasn't been | ||
42 | * aligned yet. | ||
43 | */ | ||
44 | .dst_unaligned: tst dst, #1 | ||
45 | beq .dst_16bit | ||
46 | |||
47 | load1b ip | ||
48 | sub len, len, #1 | ||
49 | adcs sum, sum, ip, lsl #byte(1) @ update checksum | ||
50 | strb ip, [dst], #1 | ||
51 | tst dst, #2 | ||
52 | moveq pc, lr @ dst is now 32bit aligned | ||
53 | |||
54 | .dst_16bit: load2b r8, ip | ||
55 | sub len, len, #2 | ||
56 | adcs sum, sum, r8, lsl #byte(0) | ||
57 | strb r8, [dst], #1 | ||
58 | adcs sum, sum, ip, lsl #byte(1) | ||
59 | strb ip, [dst], #1 | ||
60 | mov pc, lr @ dst is now 32bit aligned | ||
61 | |||
62 | /* | ||
63 | * Handle 0 to 7 bytes, with any alignment of source and | ||
64 | * destination pointers. Note that when we get here, C = 0 | ||
65 | */ | ||
66 | .less8: teq len, #0 @ check for zero count | ||
67 | beq .zero | ||
68 | |||
69 | /* we must have at least one byte. */ | ||
70 | tst dst, #1 @ dst 16-bit aligned | ||
71 | beq .less8_aligned | ||
72 | |||
73 | /* Align dst */ | ||
74 | load1b ip | ||
75 | sub len, len, #1 | ||
76 | adcs sum, sum, ip, lsl #byte(1) @ update checksum | ||
77 | strb ip, [dst], #1 | ||
78 | tst len, #6 | ||
79 | beq .less8_byteonly | ||
80 | |||
81 | 1: load2b r8, ip | ||
82 | sub len, len, #2 | ||
83 | adcs sum, sum, r8, lsl #byte(0) | ||
84 | strb r8, [dst], #1 | ||
85 | adcs sum, sum, ip, lsl #byte(1) | ||
86 | strb ip, [dst], #1 | ||
87 | .less8_aligned: tst len, #6 | ||
88 | bne 1b | ||
89 | .less8_byteonly: | ||
90 | tst len, #1 | ||
91 | beq .done | ||
92 | load1b r8 | ||
93 | adcs sum, sum, r8, lsl #byte(0) @ update checksum | ||
94 | strb r8, [dst], #1 | ||
95 | b .done | ||
96 | |||
97 | FN_ENTRY | ||
98 | mov ip, sp | ||
99 | save_regs | ||
100 | sub fp, ip, #4 | ||
101 | |||
102 | cmp len, #8 @ Ensure that we have at least | ||
103 | blo .less8 @ 8 bytes to copy. | ||
104 | |||
105 | adds sum, sum, #0 @ C = 0 | ||
106 | tst dst, #3 @ Test destination alignment | ||
107 | blne .dst_unaligned @ align destination, return here | ||
108 | |||
109 | /* | ||
110 | * Ok, the dst pointer is now 32bit aligned, and we know | ||
111 | * that we must have more than 4 bytes to copy. Note | ||
112 | * that C contains the carry from the dst alignment above. | ||
113 | */ | ||
114 | |||
115 | tst src, #3 @ Test source alignment | ||
116 | bne .src_not_aligned | ||
117 | |||
118 | /* Routine for src & dst aligned */ | ||
119 | |||
120 | bics ip, len, #15 | ||
121 | beq 2f | ||
122 | |||
123 | 1: load4l r4, r5, r6, r7 | ||
124 | stmia dst!, {r4, r5, r6, r7} | ||
125 | adcs sum, sum, r4 | ||
126 | adcs sum, sum, r5 | ||
127 | adcs sum, sum, r6 | ||
128 | adcs sum, sum, r7 | ||
129 | sub ip, ip, #16 | ||
130 | teq ip, #0 | ||
131 | bne 1b | ||
132 | |||
133 | 2: ands ip, len, #12 | ||
134 | beq 4f | ||
135 | tst ip, #8 | ||
136 | beq 3f | ||
137 | load2l r4, r5 | ||
138 | stmia dst!, {r4, r5} | ||
139 | adcs sum, sum, r4 | ||
140 | adcs sum, sum, r5 | ||
141 | tst ip, #4 | ||
142 | beq 4f | ||
143 | |||
144 | 3: load1l r4 | ||
145 | str r4, [dst], #4 | ||
146 | adcs sum, sum, r4 | ||
147 | |||
148 | 4: ands len, len, #3 | ||
149 | beq .done | ||
150 | load1l r4 | ||
151 | tst len, #2 | ||
152 | /* mov r5, r4, lsr #byte(0) | ||
153 | FIXME? 0 Shift anyhow! | ||
154 | */ | ||
155 | beq .exit | ||
156 | adcs sum, sum, r4, push #16 | ||
157 | strb r5, [dst], #1 | ||
158 | mov r5, r4, lsr #byte(1) | ||
159 | strb r5, [dst], #1 | ||
160 | mov r5, r4, lsr #byte(2) | ||
161 | .exit: tst len, #1 | ||
162 | strneb r5, [dst], #1 | ||
163 | andne r5, r5, #255 | ||
164 | adcnes sum, sum, r5, lsl #byte(0) | ||
165 | |||
166 | /* | ||
167 | * If the dst pointer was not 16-bit aligned, we | ||
168 | * need to rotate the checksum here to get around | ||
169 | * the inefficient byte manipulations in the | ||
170 | * architecture independent code. | ||
171 | */ | ||
172 | .done: adc r0, sum, #0 | ||
173 | ldr sum, [sp, #0] @ dst | ||
174 | tst sum, #1 | ||
175 | movne sum, r0, lsl #8 | ||
176 | orrne r0, sum, r0, lsr #24 | ||
177 | load_regs ea | ||
178 | |||
179 | .src_not_aligned: | ||
180 | adc sum, sum, #0 @ include C from dst alignment | ||
181 | and ip, src, #3 | ||
182 | bic src, src, #3 | ||
183 | load1l r5 | ||
184 | cmp ip, #2 | ||
185 | beq .src2_aligned | ||
186 | bhi .src3_aligned | ||
187 | mov r4, r5, pull #8 @ C = 0 | ||
188 | bics ip, len, #15 | ||
189 | beq 2f | ||
190 | 1: load4l r5, r6, r7, r8 | ||
191 | orr r4, r4, r5, push #24 | ||
192 | mov r5, r5, pull #8 | ||
193 | orr r5, r5, r6, push #24 | ||
194 | mov r6, r6, pull #8 | ||
195 | orr r6, r6, r7, push #24 | ||
196 | mov r7, r7, pull #8 | ||
197 | orr r7, r7, r8, push #24 | ||
198 | stmia dst!, {r4, r5, r6, r7} | ||
199 | adcs sum, sum, r4 | ||
200 | adcs sum, sum, r5 | ||
201 | adcs sum, sum, r6 | ||
202 | adcs sum, sum, r7 | ||
203 | mov r4, r8, pull #8 | ||
204 | sub ip, ip, #16 | ||
205 | teq ip, #0 | ||
206 | bne 1b | ||
207 | 2: ands ip, len, #12 | ||
208 | beq 4f | ||
209 | tst ip, #8 | ||
210 | beq 3f | ||
211 | load2l r5, r6 | ||
212 | orr r4, r4, r5, push #24 | ||
213 | mov r5, r5, pull #8 | ||
214 | orr r5, r5, r6, push #24 | ||
215 | stmia dst!, {r4, r5} | ||
216 | adcs sum, sum, r4 | ||
217 | adcs sum, sum, r5 | ||
218 | mov r4, r6, pull #8 | ||
219 | tst ip, #4 | ||
220 | beq 4f | ||
221 | 3: load1l r5 | ||
222 | orr r4, r4, r5, push #24 | ||
223 | str r4, [dst], #4 | ||
224 | adcs sum, sum, r4 | ||
225 | mov r4, r5, pull #8 | ||
226 | 4: ands len, len, #3 | ||
227 | beq .done | ||
228 | /* mov r5, r4, lsr #byte(0) | ||
229 | FIXME? 0 Shift anyhow | ||
230 | */ | ||
231 | tst len, #2 | ||
232 | beq .exit | ||
233 | adcs sum, sum, r4, push #16 | ||
234 | strb r5, [dst], #1 | ||
235 | mov r5, r4, lsr #byte(1) | ||
236 | strb r5, [dst], #1 | ||
237 | mov r5, r4, lsr #byte(2) | ||
238 | b .exit | ||
239 | |||
240 | .src2_aligned: mov r4, r5, pull #16 | ||
241 | adds sum, sum, #0 | ||
242 | bics ip, len, #15 | ||
243 | beq 2f | ||
244 | 1: load4l r5, r6, r7, r8 | ||
245 | orr r4, r4, r5, push #16 | ||
246 | mov r5, r5, pull #16 | ||
247 | orr r5, r5, r6, push #16 | ||
248 | mov r6, r6, pull #16 | ||
249 | orr r6, r6, r7, push #16 | ||
250 | mov r7, r7, pull #16 | ||
251 | orr r7, r7, r8, push #16 | ||
252 | stmia dst!, {r4, r5, r6, r7} | ||
253 | adcs sum, sum, r4 | ||
254 | adcs sum, sum, r5 | ||
255 | adcs sum, sum, r6 | ||
256 | adcs sum, sum, r7 | ||
257 | mov r4, r8, pull #16 | ||
258 | sub ip, ip, #16 | ||
259 | teq ip, #0 | ||
260 | bne 1b | ||
261 | 2: ands ip, len, #12 | ||
262 | beq 4f | ||
263 | tst ip, #8 | ||
264 | beq 3f | ||
265 | load2l r5, r6 | ||
266 | orr r4, r4, r5, push #16 | ||
267 | mov r5, r5, pull #16 | ||
268 | orr r5, r5, r6, push #16 | ||
269 | stmia dst!, {r4, r5} | ||
270 | adcs sum, sum, r4 | ||
271 | adcs sum, sum, r5 | ||
272 | mov r4, r6, pull #16 | ||
273 | tst ip, #4 | ||
274 | beq 4f | ||
275 | 3: load1l r5 | ||
276 | orr r4, r4, r5, push #16 | ||
277 | str r4, [dst], #4 | ||
278 | adcs sum, sum, r4 | ||
279 | mov r4, r5, pull #16 | ||
280 | 4: ands len, len, #3 | ||
281 | beq .done | ||
282 | /* mov r5, r4, lsr #byte(0) | ||
283 | FIXME? 0 Shift anyhow | ||
284 | */ | ||
285 | tst len, #2 | ||
286 | beq .exit | ||
287 | adcs sum, sum, r4 | ||
288 | strb r5, [dst], #1 | ||
289 | mov r5, r4, lsr #byte(1) | ||
290 | strb r5, [dst], #1 | ||
291 | tst len, #1 | ||
292 | beq .done | ||
293 | load1b r5 | ||
294 | b .exit | ||
295 | |||
296 | .src3_aligned: mov r4, r5, pull #24 | ||
297 | adds sum, sum, #0 | ||
298 | bics ip, len, #15 | ||
299 | beq 2f | ||
300 | 1: load4l r5, r6, r7, r8 | ||
301 | orr r4, r4, r5, push #8 | ||
302 | mov r5, r5, pull #24 | ||
303 | orr r5, r5, r6, push #8 | ||
304 | mov r6, r6, pull #24 | ||
305 | orr r6, r6, r7, push #8 | ||
306 | mov r7, r7, pull #24 | ||
307 | orr r7, r7, r8, push #8 | ||
308 | stmia dst!, {r4, r5, r6, r7} | ||
309 | adcs sum, sum, r4 | ||
310 | adcs sum, sum, r5 | ||
311 | adcs sum, sum, r6 | ||
312 | adcs sum, sum, r7 | ||
313 | mov r4, r8, pull #24 | ||
314 | sub ip, ip, #16 | ||
315 | teq ip, #0 | ||
316 | bne 1b | ||
317 | 2: ands ip, len, #12 | ||
318 | beq 4f | ||
319 | tst ip, #8 | ||
320 | beq 3f | ||
321 | load2l r5, r6 | ||
322 | orr r4, r4, r5, push #8 | ||
323 | mov r5, r5, pull #24 | ||
324 | orr r5, r5, r6, push #8 | ||
325 | stmia dst!, {r4, r5} | ||
326 | adcs sum, sum, r4 | ||
327 | adcs sum, sum, r5 | ||
328 | mov r4, r6, pull #24 | ||
329 | tst ip, #4 | ||
330 | beq 4f | ||
331 | 3: load1l r5 | ||
332 | orr r4, r4, r5, push #8 | ||
333 | str r4, [dst], #4 | ||
334 | adcs sum, sum, r4 | ||
335 | mov r4, r5, pull #24 | ||
336 | 4: ands len, len, #3 | ||
337 | beq .done | ||
338 | /* mov r5, r4, lsr #byte(0) | ||
339 | FIXME? 0 Shift anyhow | ||
340 | */ | ||
341 | tst len, #2 | ||
342 | beq .exit | ||
343 | strb r5, [dst], #1 | ||
344 | adcs sum, sum, r4 | ||
345 | load1l r4 | ||
346 | /* mov r5, r4, lsr #byte(0) | ||
347 | FIXME? 0 Shift anyhow | ||
348 | */ | ||
349 | strb r5, [dst], #1 | ||
350 | adcs sum, sum, r4, push #24 | ||
351 | mov r5, r4, lsr #byte(1) | ||
352 | b .exit | ||
diff --git a/arch/arm26/lib/csumpartialcopyuser.S b/arch/arm26/lib/csumpartialcopyuser.S new file mode 100644 index 000000000000..5b821188e479 --- /dev/null +++ b/arch/arm26/lib/csumpartialcopyuser.S | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | #include <linux/config.h> | ||
11 | #include <linux/linkage.h> | ||
12 | #include <asm/assembler.h> | ||
13 | #include <asm/errno.h> | ||
14 | #include <asm/asm_offsets.h> | ||
15 | |||
16 | .text | ||
17 | |||
18 | .macro save_regs | ||
19 | stmfd sp!, {r1 - r2, r4 - r9, fp, ip, lr, pc} | ||
20 | mov r9, sp, lsr #13 | ||
21 | mov r9, r9, lsl #13 | ||
22 | ldr r9, [r9, #TSK_ADDR_LIMIT] | ||
23 | mov r9, r9, lsr #24 | ||
24 | .endm | ||
25 | |||
26 | .macro load_regs,flags | ||
27 | ldm\flags fp, {r1, r2, r4-r9, fp, sp, pc}^ | ||
28 | .endm | ||
29 | |||
30 | .macro load1b, reg1 | ||
31 | tst r9, #0x01 | ||
32 | 9999: ldreqbt \reg1, [r0], #1 | ||
33 | ldrneb \reg1, [r0], #1 | ||
34 | .section __ex_table, "a" | ||
35 | .align 3 | ||
36 | .long 9999b, 6001f | ||
37 | .previous | ||
38 | .endm | ||
39 | |||
40 | .macro load2b, reg1, reg2 | ||
41 | tst r9, #0x01 | ||
42 | 9999: ldreqbt \reg1, [r0], #1 | ||
43 | ldrneb \reg1, [r0], #1 | ||
44 | 9998: ldreqbt \reg2, [r0], #1 | ||
45 | ldrneb \reg2, [r0], #1 | ||
46 | .section __ex_table, "a" | ||
47 | .long 9999b, 6001f | ||
48 | .long 9998b, 6001f | ||
49 | .previous | ||
50 | .endm | ||
51 | |||
52 | .macro load1l, reg1 | ||
53 | tst r9, #0x01 | ||
54 | 9999: ldreqt \reg1, [r0], #4 | ||
55 | ldrne \reg1, [r0], #4 | ||
56 | .section __ex_table, "a" | ||
57 | .align 3 | ||
58 | .long 9999b, 6001f | ||
59 | .previous | ||
60 | .endm | ||
61 | |||
62 | .macro load2l, reg1, reg2 | ||
63 | tst r9, #0x01 | ||
64 | ldmneia r0!, {\reg1, \reg2} | ||
65 | 9999: ldreqt \reg1, [r0], #4 | ||
66 | 9998: ldreqt \reg2, [r0], #4 | ||
67 | .section __ex_table, "a" | ||
68 | .long 9999b, 6001f | ||
69 | .long 9998b, 6001f | ||
70 | .previous | ||
71 | .endm | ||
72 | |||
73 | .macro load4l, reg1, reg2, reg3, reg4 | ||
74 | tst r9, #0x01 | ||
75 | ldmneia r0!, {\reg1, \reg2, \reg3, \reg4} | ||
76 | 9999: ldreqt \reg1, [r0], #4 | ||
77 | 9998: ldreqt \reg2, [r0], #4 | ||
78 | 9997: ldreqt \reg3, [r0], #4 | ||
79 | 9996: ldreqt \reg4, [r0], #4 | ||
80 | .section __ex_table, "a" | ||
81 | .long 9999b, 6001f | ||
82 | .long 9998b, 6001f | ||
83 | .long 9997b, 6001f | ||
84 | .long 9996b, 6001f | ||
85 | .previous | ||
86 | .endm | ||
87 | |||
88 | /* | ||
89 | * unsigned int | ||
90 | * csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *err_ptr) | ||
91 | * r0 = src, r1 = dst, r2 = len, r3 = sum, [sp] = *err_ptr | ||
92 | * Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT | ||
93 | */ | ||
94 | |||
95 | #define FN_ENTRY ENTRY(csum_partial_copy_from_user) | ||
96 | |||
97 | #include "csumpartialcopygeneric.S" | ||
98 | |||
99 | /* | ||
100 | * FIXME: minor buglet here | ||
101 | * We don't return the checksum for the data present in the buffer. To do | ||
102 | * so properly, we would have to add in whatever registers were loaded before | ||
103 | * the fault, which, with the current asm above is not predictable. | ||
104 | */ | ||
105 | .align 4 | ||
106 | 6001: mov r4, #-EFAULT | ||
107 | ldr r5, [fp, #4] @ *err_ptr | ||
108 | str r4, [r5] | ||
109 | ldmia sp, {r1, r2} @ retrieve dst, len | ||
110 | add r2, r2, r1 | ||
111 | mov r0, #0 @ zero the buffer | ||
112 | 6002: teq r2, r1 | ||
113 | strneb r0, [r1], #1 | ||
114 | bne 6002b | ||
115 | load_regs ea | ||
diff --git a/arch/arm26/lib/delay.S b/arch/arm26/lib/delay.S new file mode 100644 index 000000000000..66f2b68e1b13 --- /dev/null +++ b/arch/arm26/lib/delay.S | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 r1, r0, r2 | ||
23 | ldr r2, LC0 | ||
24 | ldr r2, [r2] | ||
25 | mov r1, r1, lsr #11 | ||
26 | mov r2, r2, lsr #11 | ||
27 | mul r0, r1, r2 | ||
28 | movs r0, r0, lsr #6 | ||
29 | RETINSTR(moveq,pc,lr) | ||
30 | |||
31 | /* | ||
32 | * loops = (r0 * 0x10c6 * 100 * loops_per_jiffy) / 2^32 | ||
33 | * | ||
34 | * Oh, if only we had a cycle counter... | ||
35 | */ | ||
36 | |||
37 | @ Delay routine | ||
38 | ENTRY(__delay) | ||
39 | subs r0, r0, #1 | ||
40 | #if 0 | ||
41 | RETINSTR(movls,pc,lr) | ||
42 | subs r0, r0, #1 | ||
43 | RETINSTR(movls,pc,lr) | ||
44 | subs r0, r0, #1 | ||
45 | RETINSTR(movls,pc,lr) | ||
46 | subs r0, r0, #1 | ||
47 | RETINSTR(movls,pc,lr) | ||
48 | subs r0, r0, #1 | ||
49 | RETINSTR(movls,pc,lr) | ||
50 | subs r0, r0, #1 | ||
51 | RETINSTR(movls,pc,lr) | ||
52 | subs r0, r0, #1 | ||
53 | RETINSTR(movls,pc,lr) | ||
54 | subs r0, r0, #1 | ||
55 | #endif | ||
56 | bhi __delay | ||
57 | RETINSTR(mov,pc,lr) | ||
diff --git a/arch/arm26/lib/ecard.S b/arch/arm26/lib/ecard.S new file mode 100644 index 000000000000..b4633150f01c --- /dev/null +++ b/arch/arm26/lib/ecard.S | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | #include <linux/config.h> /* for CONFIG_CPU_nn */ | ||
11 | #include <linux/linkage.h> | ||
12 | #include <asm/assembler.h> | ||
13 | #include <asm/hardware.h> | ||
14 | |||
15 | #define CPSR2SPSR(rt) | ||
16 | |||
17 | @ Purpose: call an expansion card loader to read bytes. | ||
18 | @ Proto : char read_loader(int offset, char *card_base, char *loader); | ||
19 | @ Returns: byte read | ||
20 | |||
21 | ENTRY(ecard_loader_read) | ||
22 | stmfd sp!, {r4 - r12, lr} | ||
23 | mov r11, r1 | ||
24 | mov r1, r0 | ||
25 | CPSR2SPSR(r0) | ||
26 | mov lr, pc | ||
27 | mov pc, r2 | ||
28 | LOADREGS(fd, sp!, {r4 - r12, pc}) | ||
29 | |||
30 | @ Purpose: call an expansion card loader to reset the card | ||
31 | @ Proto : void read_loader(int card_base, char *loader); | ||
32 | @ Returns: byte read | ||
33 | |||
34 | ENTRY(ecard_loader_reset) | ||
35 | stmfd sp!, {r4 - r12, lr} | ||
36 | mov r11, r0 | ||
37 | CPSR2SPSR(r0) | ||
38 | mov lr, pc | ||
39 | add pc, r1, #8 | ||
40 | LOADREGS(fd, sp!, {r4 - r12, pc}) | ||
41 | |||
diff --git a/arch/arm26/lib/findbit.S b/arch/arm26/lib/findbit.S new file mode 100644 index 000000000000..26f67cccc37c --- /dev/null +++ b/arch/arm26/lib/findbit.S | |||
@@ -0,0 +1,67 @@ | |||
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 2b | ||
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 | * One or more bits in the LSB of r3 are assumed to be set. | ||
56 | */ | ||
57 | .found: tst r3, #0x0f | ||
58 | addeq r2, r2, #4 | ||
59 | movne r3, r3, lsl #4 | ||
60 | tst r3, #0x30 | ||
61 | addeq r2, r2, #2 | ||
62 | movne r3, r3, lsl #2 | ||
63 | tst r3, #0x40 | ||
64 | addeq r2, r2, #1 | ||
65 | mov r0, r2 | ||
66 | RETINSTR(mov,pc,lr) | ||
67 | |||
diff --git a/arch/arm26/lib/floppydma.S b/arch/arm26/lib/floppydma.S new file mode 100644 index 000000000000..e99ebbb20353 --- /dev/null +++ b/arch/arm26/lib/floppydma.S | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/gcclib.h b/arch/arm26/lib/gcclib.h new file mode 100644 index 000000000000..9895e78904b5 --- /dev/null +++ b/arch/arm26/lib/gcclib.h | |||
@@ -0,0 +1,21 @@ | |||
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 | struct DIstruct {SItype low, high;}; | ||
15 | |||
16 | typedef union | ||
17 | { | ||
18 | struct DIstruct s; | ||
19 | DItype ll; | ||
20 | } DIunion; | ||
21 | |||
diff --git a/arch/arm26/lib/getuser.S b/arch/arm26/lib/getuser.S new file mode 100644 index 000000000000..e6d59b334851 --- /dev/null +++ b/arch/arm26/lib/getuser.S | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | * r1, r2 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/asm_offsets.h> | ||
30 | #include <asm/thread_info.h> | ||
31 | #include <asm/errno.h> | ||
32 | |||
33 | .global __get_user_1 | ||
34 | __get_user_1: | ||
35 | bic r1, sp, #0x1f00 | ||
36 | bic r1, r1, #0x00ff | ||
37 | str lr, [sp, #-4]! | ||
38 | ldr r1, [r1, #TI_ADDR_LIMIT] | ||
39 | sub r1, r1, #1 | ||
40 | cmp r0, r1 | ||
41 | bge __get_user_bad | ||
42 | cmp r0, #0x02000000 | ||
43 | 1: ldrlsbt r1, [r0] | ||
44 | ldrgeb r1, [r0] | ||
45 | mov r0, #0 | ||
46 | ldmfd sp!, {pc}^ | ||
47 | |||
48 | .global __get_user_2 | ||
49 | __get_user_2: | ||
50 | bic r2, sp, #0x1f00 | ||
51 | bic r2, r2, #0x00ff | ||
52 | str lr, [sp, #-4]! | ||
53 | ldr r2, [r2, #TI_ADDR_LIMIT] | ||
54 | sub r2, r2, #2 | ||
55 | cmp r0, r2 | ||
56 | bge __get_user_bad | ||
57 | cmp r0, #0x02000000 | ||
58 | 2: ldrlsbt r1, [r0], #1 | ||
59 | 3: ldrlsbt r2, [r0] | ||
60 | ldrgeb r1, [r0], #1 | ||
61 | ldrgeb r2, [r0] | ||
62 | orr r1, r1, r2, lsl #8 | ||
63 | mov r0, #0 | ||
64 | ldmfd sp!, {pc}^ | ||
65 | |||
66 | .global __get_user_4 | ||
67 | __get_user_4: | ||
68 | bic r1, sp, #0x1f00 | ||
69 | bic r1, r1, #0x00ff | ||
70 | str lr, [sp, #-4]! | ||
71 | ldr r1, [r1, #TI_ADDR_LIMIT] | ||
72 | sub r1, r1, #4 | ||
73 | cmp r0, r1 | ||
74 | bge __get_user_bad | ||
75 | cmp r0, #0x02000000 | ||
76 | 4: ldrlst r1, [r0] | ||
77 | ldrge r1, [r0] | ||
78 | mov r0, #0 | ||
79 | ldmfd sp!, {pc}^ | ||
80 | |||
81 | .global __get_user_8 | ||
82 | __get_user_8: | ||
83 | bic r2, sp, #0x1f00 | ||
84 | bic r2, r2, #0x00ff | ||
85 | str lr, [sp, #-4]! | ||
86 | ldr r2, [r2, #TI_ADDR_LIMIT] | ||
87 | sub r2, r2, #8 | ||
88 | cmp r0, r2 | ||
89 | bge __get_user_bad_8 | ||
90 | cmp r0, #0x02000000 | ||
91 | 5: ldrlst r1, [r0], #4 | ||
92 | 6: ldrlst r2, [r0] | ||
93 | ldrge r1, [r0], #4 | ||
94 | ldrge r2, [r0] | ||
95 | mov r0, #0 | ||
96 | ldmfd sp!, {pc}^ | ||
97 | |||
98 | __get_user_bad_8: | ||
99 | mov r2, #0 | ||
100 | __get_user_bad: | ||
101 | mov r1, #0 | ||
102 | mov r0, #-EFAULT | ||
103 | ldmfd sp!, {pc}^ | ||
104 | |||
105 | .section __ex_table, "a" | ||
106 | .long 1b, __get_user_bad | ||
107 | .long 2b, __get_user_bad | ||
108 | .long 3b, __get_user_bad | ||
109 | .long 4b, __get_user_bad | ||
110 | .long 5b, __get_user_bad_8 | ||
111 | .long 6b, __get_user_bad_8 | ||
112 | .previous | ||
diff --git a/arch/arm26/lib/io-acorn.S b/arch/arm26/lib/io-acorn.S new file mode 100644 index 000000000000..f6c3e30b1b4f --- /dev/null +++ b/arch/arm26/lib/io-acorn.S | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | #include <linux/config.h> /* for CONFIG_CPU_nn */ | ||
11 | #include <linux/linkage.h> | ||
12 | #include <asm/assembler.h> | ||
13 | #include <asm/hardware.h> | ||
14 | |||
15 | .text | ||
16 | .align | ||
17 | |||
18 | .equ diff_pcio_base, PCIO_BASE - IO_BASE | ||
19 | |||
20 | .macro outw2 rd | ||
21 | mov r8, \rd, lsl #16 | ||
22 | orr r8, r8, r8, lsr #16 | ||
23 | str r8, [r3, r0, lsl #2] | ||
24 | mov r8, \rd, lsr #16 | ||
25 | orr r8, r8, r8, lsl #16 | ||
26 | str r8, [r3, r0, lsl #2] | ||
27 | .endm | ||
28 | |||
29 | .macro inw2 rd, mask, temp | ||
30 | ldr \rd, [r0] | ||
31 | and \rd, \rd, \mask | ||
32 | ldr \temp, [r0] | ||
33 | orr \rd, \rd, \temp, lsl #16 | ||
34 | .endm | ||
35 | |||
36 | .macro addr rd | ||
37 | tst \rd, #0x80000000 | ||
38 | mov \rd, \rd, lsl #2 | ||
39 | add \rd, \rd, #IO_BASE | ||
40 | addeq \rd, \rd, #diff_pcio_base | ||
41 | .endm | ||
42 | |||
43 | .iosl_warning: | ||
44 | .ascii "<4>insl/outsl not implemented, called from %08lX\0" | ||
45 | .align | ||
46 | |||
47 | /* | ||
48 | * These make no sense on Acorn machines. | ||
49 | * Print a warning message. | ||
50 | */ | ||
51 | ENTRY(insl) | ||
52 | ENTRY(outsl) | ||
53 | adr r0, .iosl_warning | ||
54 | mov r1, lr | ||
55 | b printk | ||
56 | |||
57 | @ Purpose: write a memc register | ||
58 | @ Proto : void memc_write(int register, int value); | ||
59 | @ Returns: nothing | ||
60 | |||
61 | ENTRY(memc_write) | ||
62 | cmp r0, #7 | ||
63 | RETINSTR(movgt,pc,lr) | ||
64 | mov r0, r0, lsl #17 | ||
65 | mov r1, r1, lsl #15 | ||
66 | mov r1, r1, lsr #17 | ||
67 | orr r0, r0, r1, lsl #2 | ||
68 | add r0, r0, #0x03600000 | ||
69 | strb r0, [r0] | ||
70 | RETINSTR(mov,pc,lr) | ||
71 | |||
diff --git a/arch/arm26/lib/io-readsb.S b/arch/arm26/lib/io-readsb.S new file mode 100644 index 000000000000..4c4d99c05856 --- /dev/null +++ b/arch/arm26/lib/io-readsb.S | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | #include <asm/hardware.h> | ||
13 | |||
14 | .insb_align: rsb ip, ip, #4 | ||
15 | cmp ip, r2 | ||
16 | movgt ip, r2 | ||
17 | cmp ip, #2 | ||
18 | ldrb r3, [r0] | ||
19 | strb r3, [r1], #1 | ||
20 | ldrgeb r3, [r0] | ||
21 | strgeb r3, [r1], #1 | ||
22 | ldrgtb r3, [r0] | ||
23 | strgtb r3, [r1], #1 | ||
24 | subs r2, r2, ip | ||
25 | bne .insb_aligned | ||
26 | |||
27 | ENTRY(__raw_readsb) | ||
28 | teq r2, #0 @ do we have to check for the zero len? | ||
29 | moveq pc, lr | ||
30 | ands ip, r1, #3 | ||
31 | bne .insb_align | ||
32 | |||
33 | .insb_aligned: stmfd sp!, {r4 - r6, lr} | ||
34 | |||
35 | subs r2, r2, #16 | ||
36 | bmi .insb_no_16 | ||
37 | |||
38 | .insb_16_lp: ldrb r3, [r0] | ||
39 | ldrb r4, [r0] | ||
40 | orr r3, r3, r4, lsl #8 | ||
41 | ldrb r4, [r0] | ||
42 | orr r3, r3, r4, lsl #16 | ||
43 | ldrb r4, [r0] | ||
44 | orr r3, r3, r4, lsl #24 | ||
45 | ldrb r4, [r0] | ||
46 | ldrb r5, [r0] | ||
47 | orr r4, r4, r5, lsl #8 | ||
48 | ldrb r5, [r0] | ||
49 | orr r4, r4, r5, lsl #16 | ||
50 | ldrb r5, [r0] | ||
51 | orr r4, r4, r5, lsl #24 | ||
52 | ldrb r5, [r0] | ||
53 | ldrb r6, [r0] | ||
54 | orr r5, r5, r6, lsl #8 | ||
55 | ldrb r6, [r0] | ||
56 | orr r5, r5, r6, lsl #16 | ||
57 | ldrb r6, [r0] | ||
58 | orr r5, r5, r6, lsl #24 | ||
59 | ldrb r6, [r0] | ||
60 | ldrb ip, [r0] | ||
61 | orr r6, r6, ip, lsl #8 | ||
62 | ldrb ip, [r0] | ||
63 | orr r6, r6, ip, lsl #16 | ||
64 | ldrb ip, [r0] | ||
65 | orr r6, r6, ip, lsl #24 | ||
66 | stmia r1!, {r3 - r6} | ||
67 | |||
68 | subs r2, r2, #16 | ||
69 | bpl .insb_16_lp | ||
70 | |||
71 | tst r2, #15 | ||
72 | LOADREGS(eqfd, sp!, {r4 - r6, pc}) | ||
73 | |||
74 | .insb_no_16: tst r2, #8 | ||
75 | beq .insb_no_8 | ||
76 | |||
77 | ldrb r3, [r0] | ||
78 | ldrb r4, [r0] | ||
79 | orr r3, r3, r4, lsl #8 | ||
80 | ldrb r4, [r0] | ||
81 | orr r3, r3, r4, lsl #16 | ||
82 | ldrb r4, [r0] | ||
83 | orr r3, r3, r4, lsl #24 | ||
84 | ldrb r4, [r0] | ||
85 | ldrb r5, [r0] | ||
86 | orr r4, r4, r5, lsl #8 | ||
87 | ldrb r5, [r0] | ||
88 | orr r4, r4, r5, lsl #16 | ||
89 | ldrb r5, [r0] | ||
90 | orr r4, r4, r5, lsl #24 | ||
91 | stmia r1!, {r3, r4} | ||
92 | |||
93 | .insb_no_8: tst r2, #4 | ||
94 | beq .insb_no_4 | ||
95 | |||
96 | ldrb r3, [r0] | ||
97 | ldrb r4, [r0] | ||
98 | orr r3, r3, r4, lsl #8 | ||
99 | ldrb r4, [r0] | ||
100 | orr r3, r3, r4, lsl #16 | ||
101 | ldrb r4, [r0] | ||
102 | orr r3, r3, r4, lsl #24 | ||
103 | str r3, [r1], #4 | ||
104 | |||
105 | .insb_no_4: ands r2, r2, #3 | ||
106 | LOADREGS(eqfd, sp!, {r4 - r6, pc}) | ||
107 | |||
108 | cmp r2, #2 | ||
109 | ldrb r3, [r0] | ||
110 | strb r3, [r1], #1 | ||
111 | ldrgeb r3, [r0] | ||
112 | strgeb r3, [r1], #1 | ||
113 | ldrgtb r3, [r0] | ||
114 | strgtb r3, [r1] | ||
115 | |||
116 | LOADREGS(fd, sp!, {r4 - r6, pc}) | ||
diff --git a/arch/arm26/lib/io-readsl.S b/arch/arm26/lib/io-readsl.S new file mode 100644 index 000000000000..7be208bd23c6 --- /dev/null +++ b/arch/arm26/lib/io-readsl.S | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | #include <asm/hardware.h> | ||
13 | |||
14 | /* | ||
15 | * Note that some reads can be aligned on half-word boundaries. | ||
16 | */ | ||
17 | ENTRY(__raw_readsl) | ||
18 | teq r2, #0 @ do we have to check for the zero len? | ||
19 | moveq pc, lr | ||
20 | ands ip, r1, #3 | ||
21 | bne 2f | ||
22 | |||
23 | 1: ldr r3, [r0] | ||
24 | str r3, [r1], #4 | ||
25 | subs r2, r2, #1 | ||
26 | bne 1b | ||
27 | mov pc, lr | ||
28 | |||
29 | 2: cmp ip, #2 | ||
30 | ldr ip, [r0] | ||
31 | blt 4f | ||
32 | bgt 6f | ||
33 | |||
34 | strb ip, [r1], #1 | ||
35 | mov ip, ip, lsr #8 | ||
36 | strb ip, [r1], #1 | ||
37 | mov ip, ip, lsr #8 | ||
38 | 3: subs r2, r2, #1 | ||
39 | ldrne r3, [r0] | ||
40 | orrne ip, ip, r3, lsl #16 | ||
41 | strne ip, [r1], #4 | ||
42 | movne ip, r3, lsr #16 | ||
43 | bne 3b | ||
44 | strb ip, [r1], #1 | ||
45 | mov ip, ip, lsr #8 | ||
46 | strb ip, [r1], #1 | ||
47 | mov pc, lr | ||
48 | |||
49 | 4: strb ip, [r1], #1 | ||
50 | mov ip, ip, lsr #8 | ||
51 | strb ip, [r1], #1 | ||
52 | mov ip, ip, lsr #8 | ||
53 | strb ip, [r1], #1 | ||
54 | mov ip, ip, lsr #8 | ||
55 | 5: subs r2, r2, #1 | ||
56 | ldrne r3, [r0] | ||
57 | orrne ip, ip, r3, lsl #8 | ||
58 | strne ip, [r1], #4 | ||
59 | movne ip, r3, lsr #24 | ||
60 | bne 5b | ||
61 | strb ip, [r1], #1 | ||
62 | mov pc, lr | ||
63 | |||
64 | 6: strb ip, [r1], #1 | ||
65 | mov ip, ip, lsr #8 | ||
66 | 7: subs r2, r2, #1 | ||
67 | ldrne r3, [r0] | ||
68 | orrne ip, ip, r3, lsl #24 | ||
69 | strne ip, [r1], #4 | ||
70 | movne ip, r3, lsr #8 | ||
71 | bne 7b | ||
72 | strb ip, [r1], #1 | ||
73 | mov ip, ip, lsr #8 | ||
74 | strb ip, [r1], #1 | ||
75 | mov ip, ip, lsr #8 | ||
76 | strb ip, [r1], #1 | ||
77 | mov pc, lr | ||
78 | |||
diff --git a/arch/arm26/lib/io-readsw.S b/arch/arm26/lib/io-readsw.S new file mode 100644 index 000000000000..c65c1f28fcff --- /dev/null +++ b/arch/arm26/lib/io-readsw.S | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/lib/io-readsw.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/arm26/lib/io-writesb.S b/arch/arm26/lib/io-writesb.S new file mode 100644 index 000000000000..16251b4d5101 --- /dev/null +++ b/arch/arm26/lib/io-writesb.S | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | #include <asm/hardware.h> | ||
13 | |||
14 | .outsb_align: rsb ip, ip, #4 | ||
15 | cmp ip, r2 | ||
16 | movgt ip, r2 | ||
17 | cmp ip, #2 | ||
18 | ldrb r3, [r1], #1 | ||
19 | strb r3, [r0] | ||
20 | ldrgeb r3, [r1], #1 | ||
21 | strgeb r3, [r0] | ||
22 | ldrgtb r3, [r1], #1 | ||
23 | strgtb r3, [r0] | ||
24 | subs r2, r2, ip | ||
25 | bne .outsb_aligned | ||
26 | |||
27 | ENTRY(__raw_writesb) | ||
28 | teq r2, #0 @ do we have to check for the zero len? | ||
29 | moveq pc, lr | ||
30 | ands ip, r1, #3 | ||
31 | bne .outsb_align | ||
32 | |||
33 | .outsb_aligned: stmfd sp!, {r4 - r6, lr} | ||
34 | |||
35 | subs r2, r2, #16 | ||
36 | bmi .outsb_no_16 | ||
37 | |||
38 | .outsb_16_lp: ldmia r1!, {r3 - r6} | ||
39 | |||
40 | strb r3, [r0] | ||
41 | mov r3, r3, lsr #8 | ||
42 | strb r3, [r0] | ||
43 | mov r3, r3, lsr #8 | ||
44 | strb r3, [r0] | ||
45 | mov r3, r3, lsr #8 | ||
46 | strb r3, [r0] | ||
47 | |||
48 | strb r4, [r0] | ||
49 | mov r4, r4, lsr #8 | ||
50 | strb r4, [r0] | ||
51 | mov r4, r4, lsr #8 | ||
52 | strb r4, [r0] | ||
53 | mov r4, r4, lsr #8 | ||
54 | strb r4, [r0] | ||
55 | |||
56 | strb r5, [r0] | ||
57 | mov r5, r5, lsr #8 | ||
58 | strb r5, [r0] | ||
59 | mov r5, r5, lsr #8 | ||
60 | strb r5, [r0] | ||
61 | mov r5, r5, lsr #8 | ||
62 | strb r5, [r0] | ||
63 | |||
64 | strb r6, [r0] | ||
65 | mov r6, r6, lsr #8 | ||
66 | strb r6, [r0] | ||
67 | mov r6, r6, lsr #8 | ||
68 | strb r6, [r0] | ||
69 | mov r6, r6, lsr #8 | ||
70 | strb r6, [r0] | ||
71 | |||
72 | subs r2, r2, #16 | ||
73 | bpl .outsb_16_lp | ||
74 | |||
75 | tst r2, #15 | ||
76 | LOADREGS(eqfd, sp!, {r4 - r6, pc}) | ||
77 | |||
78 | .outsb_no_16: tst r2, #8 | ||
79 | beq .outsb_no_8 | ||
80 | |||
81 | ldmia r1!, {r3, r4} | ||
82 | |||
83 | strb r3, [r0] | ||
84 | mov r3, r3, lsr #8 | ||
85 | strb r3, [r0] | ||
86 | mov r3, r3, lsr #8 | ||
87 | strb r3, [r0] | ||
88 | mov r3, r3, lsr #8 | ||
89 | strb r3, [r0] | ||
90 | |||
91 | strb r4, [r0] | ||
92 | mov r4, r4, lsr #8 | ||
93 | strb r4, [r0] | ||
94 | mov r4, r4, lsr #8 | ||
95 | strb r4, [r0] | ||
96 | mov r4, r4, lsr #8 | ||
97 | strb r4, [r0] | ||
98 | |||
99 | .outsb_no_8: tst r2, #4 | ||
100 | beq .outsb_no_4 | ||
101 | |||
102 | ldr r3, [r1], #4 | ||
103 | strb r3, [r0] | ||
104 | mov r3, r3, lsr #8 | ||
105 | strb r3, [r0] | ||
106 | mov r3, r3, lsr #8 | ||
107 | strb r3, [r0] | ||
108 | mov r3, r3, lsr #8 | ||
109 | strb r3, [r0] | ||
110 | |||
111 | .outsb_no_4: ands r2, r2, #3 | ||
112 | LOADREGS(eqfd, sp!, {r4 - r6, pc}) | ||
113 | |||
114 | cmp r2, #2 | ||
115 | ldrb r3, [r1], #1 | ||
116 | strb r3, [r0] | ||
117 | ldrgeb r3, [r1], #1 | ||
118 | strgeb r3, [r0] | ||
119 | ldrgtb r3, [r1] | ||
120 | strgtb r3, [r0] | ||
121 | |||
122 | LOADREGS(fd, sp!, {r4 - r6, pc}) | ||
diff --git a/arch/arm26/lib/io-writesl.S b/arch/arm26/lib/io-writesl.S new file mode 100644 index 000000000000..4d6049b16e71 --- /dev/null +++ b/arch/arm26/lib/io-writesl.S | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | #include <asm/hardware.h> | ||
13 | |||
14 | ENTRY(__raw_writesl) | ||
15 | teq r2, #0 @ do we have to check for the zero len? | ||
16 | moveq pc, lr | ||
17 | ands ip, r1, #3 | ||
18 | bne 2f | ||
19 | |||
20 | 1: ldr r3, [r1], #4 | ||
21 | str r3, [r0] | ||
22 | subs r2, r2, #1 | ||
23 | bne 1b | ||
24 | mov pc, lr | ||
25 | |||
26 | 2: bic r1, r1, #3 | ||
27 | cmp ip, #2 | ||
28 | ldr r3, [r1], #4 | ||
29 | bgt 4f | ||
30 | blt 5f | ||
31 | |||
32 | 3: mov ip, r3, lsr #16 | ||
33 | ldr r3, [r1], #4 | ||
34 | orr ip, ip, r3, lsl #16 | ||
35 | str ip, [r0] | ||
36 | subs r2, r2, #1 | ||
37 | bne 3b | ||
38 | mov pc, lr | ||
39 | |||
40 | 4: mov ip, r3, lsr #24 | ||
41 | ldr r3, [r1], #4 | ||
42 | orr ip, ip, r3, lsl #8 | ||
43 | str ip, [r0] | ||
44 | subs r2, r2, #1 | ||
45 | bne 4b | ||
46 | mov pc, lr | ||
47 | |||
48 | 5: mov ip, r3, lsr #8 | ||
49 | ldr r3, [r1], #4 | ||
50 | orr ip, ip, r3, lsl #24 | ||
51 | str ip, [r0] | ||
52 | subs r2, r2, #1 | ||
53 | bne 5b | ||
54 | mov pc, lr | ||
55 | |||
56 | |||
diff --git a/arch/arm26/lib/io-writesw.S b/arch/arm26/lib/io-writesw.S new file mode 100644 index 000000000000..a24f891f6b1c --- /dev/null +++ b/arch/arm26/lib/io-writesw.S | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/lib/io-writesw.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/arm26/lib/kbd.c b/arch/arm26/lib/kbd.c new file mode 100644 index 000000000000..22d2c93aaf1a --- /dev/null +++ b/arch/arm26/lib/kbd.c | |||
@@ -0,0 +1,279 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include <linux/kd.h> | ||
3 | //#include <linux/kbd_ll.h> | ||
4 | #include <linux/kbd_kern.h> | ||
5 | |||
6 | /* | ||
7 | * Translation of escaped scancodes to keycodes. | ||
8 | * This is now user-settable. | ||
9 | * The keycodes 1-88,96-111,119 are fairly standard, and | ||
10 | * should probably not be changed - changing might confuse X. | ||
11 | * X also interprets scancode 0x5d (KEY_Begin). | ||
12 | * | ||
13 | * For 1-88 keycode equals scancode. | ||
14 | */ | ||
15 | |||
16 | #define E0_KPENTER 96 | ||
17 | #define E0_RCTRL 97 | ||
18 | #define E0_KPSLASH 98 | ||
19 | #define E0_PRSCR 99 | ||
20 | #define E0_RALT 100 | ||
21 | #define E0_BREAK 101 /* (control-pause) */ | ||
22 | #define E0_HOME 102 | ||
23 | #define E0_UP 103 | ||
24 | #define E0_PGUP 104 | ||
25 | #define E0_LEFT 105 | ||
26 | #define E0_RIGHT 106 | ||
27 | #define E0_END 107 | ||
28 | #define E0_DOWN 108 | ||
29 | #define E0_PGDN 109 | ||
30 | #define E0_INS 110 | ||
31 | #define E0_DEL 111 | ||
32 | |||
33 | /* for USB 106 keyboard */ | ||
34 | #define E0_YEN 124 | ||
35 | #define E0_BACKSLASH 89 | ||
36 | |||
37 | |||
38 | #define E1_PAUSE 119 | ||
39 | |||
40 | /* | ||
41 | * The keycodes below are randomly located in 89-95,112-118,120-127. | ||
42 | * They could be thrown away (and all occurrences below replaced by 0), | ||
43 | * but that would force many users to use the `setkeycodes' utility, where | ||
44 | * they needed not before. It does not matter that there are duplicates, as | ||
45 | * long as no duplication occurs for any single keyboard. | ||
46 | */ | ||
47 | #define SC_LIM 89 | ||
48 | |||
49 | #define FOCUS_PF1 85 /* actual code! */ | ||
50 | #define FOCUS_PF2 89 | ||
51 | #define FOCUS_PF3 90 | ||
52 | #define FOCUS_PF4 91 | ||
53 | #define FOCUS_PF5 92 | ||
54 | #define FOCUS_PF6 93 | ||
55 | #define FOCUS_PF7 94 | ||
56 | #define FOCUS_PF8 95 | ||
57 | #define FOCUS_PF9 120 | ||
58 | #define FOCUS_PF10 121 | ||
59 | #define FOCUS_PF11 122 | ||
60 | #define FOCUS_PF12 123 | ||
61 | |||
62 | #define JAP_86 124 | ||
63 | /* tfj@olivia.ping.dk: | ||
64 | * The four keys are located over the numeric keypad, and are | ||
65 | * labelled A1-A4. It's an rc930 keyboard, from | ||
66 | * Regnecentralen/RC International, Now ICL. | ||
67 | * Scancodes: 59, 5a, 5b, 5c. | ||
68 | */ | ||
69 | #define RGN1 124 | ||
70 | #define RGN2 125 | ||
71 | #define RGN3 126 | ||
72 | #define RGN4 127 | ||
73 | |||
74 | static unsigned char high_keys[128 - SC_LIM] = { | ||
75 | RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ | ||
76 | 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ | ||
77 | 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ | ||
78 | 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ | ||
79 | FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ | ||
80 | FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ | ||
81 | }; | ||
82 | |||
83 | /* BTC */ | ||
84 | #define E0_MACRO 112 | ||
85 | /* LK450 */ | ||
86 | #define E0_F13 113 | ||
87 | #define E0_F14 114 | ||
88 | #define E0_HELP 115 | ||
89 | #define E0_DO 116 | ||
90 | #define E0_F17 117 | ||
91 | #define E0_KPMINPLUS 118 | ||
92 | /* | ||
93 | * My OmniKey generates e0 4c for the "OMNI" key and the | ||
94 | * right alt key does nada. [kkoller@nyx10.cs.du.edu] | ||
95 | */ | ||
96 | #define E0_OK 124 | ||
97 | /* | ||
98 | * New microsoft keyboard is rumoured to have | ||
99 | * e0 5b (left window button), e0 5c (right window button), | ||
100 | * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] | ||
101 | * [or: Windows_L, Windows_R, TaskMan] | ||
102 | */ | ||
103 | #define E0_MSLW 125 | ||
104 | #define E0_MSRW 126 | ||
105 | #define E0_MSTM 127 | ||
106 | |||
107 | static unsigned char e0_keys[128] = { | ||
108 | 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ | ||
109 | 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ | ||
110 | 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ | ||
111 | 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ | ||
112 | 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ | ||
113 | 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ | ||
114 | 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ | ||
115 | E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ | ||
116 | E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ | ||
117 | E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END, /* 0x48-0x4f */ | ||
118 | E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ | ||
119 | 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ | ||
120 | 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ | ||
121 | 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ | ||
122 | //0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ | ||
123 | 0, 0, 0, 0, 0, E0_BACKSLASH, 0, 0, /* 0x70-0x77 */ | ||
124 | 0, 0, 0, E0_YEN, 0, 0, 0, 0 /* 0x78-0x7f */ | ||
125 | }; | ||
126 | |||
127 | static int gen_setkeycode(unsigned int scancode, unsigned int keycode) | ||
128 | { | ||
129 | if (scancode < SC_LIM || scancode > 255 || keycode > 127) | ||
130 | return -EINVAL; | ||
131 | if (scancode < 128) | ||
132 | high_keys[scancode - SC_LIM] = keycode; | ||
133 | else | ||
134 | e0_keys[scancode - 128] = keycode; | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int gen_getkeycode(unsigned int scancode) | ||
139 | { | ||
140 | return | ||
141 | (scancode < SC_LIM || scancode > 255) ? -EINVAL : | ||
142 | (scancode < | ||
143 | 128) ? high_keys[scancode - SC_LIM] : e0_keys[scancode - 128]; | ||
144 | } | ||
145 | |||
146 | static int | ||
147 | gen_translate(unsigned char scancode, unsigned char *keycode, char raw_mode) | ||
148 | { | ||
149 | static int prev_scancode; | ||
150 | |||
151 | /* special prefix scancodes.. */ | ||
152 | if (scancode == 0xe0 || scancode == 0xe1) { | ||
153 | prev_scancode = scancode; | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ | ||
158 | if (scancode == 0x00 || scancode == 0xff) { | ||
159 | prev_scancode = 0; | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | scancode &= 0x7f; | ||
164 | |||
165 | if (prev_scancode) { | ||
166 | /* | ||
167 | * usually it will be 0xe0, but a Pause key generates | ||
168 | * e1 1d 45 e1 9d c5 when pressed, and nothing when released | ||
169 | */ | ||
170 | if (prev_scancode != 0xe0) { | ||
171 | if (prev_scancode == 0xe1 && scancode == 0x1d) { | ||
172 | prev_scancode = 0x100; | ||
173 | return 0; | ||
174 | } | ||
175 | else if (prev_scancode == 0x100 | ||
176 | && scancode == 0x45) { | ||
177 | *keycode = E1_PAUSE; | ||
178 | prev_scancode = 0; | ||
179 | } else { | ||
180 | #ifdef KBD_REPORT_UNKN | ||
181 | if (!raw_mode) | ||
182 | printk(KERN_INFO | ||
183 | "keyboard: unknown e1 escape sequence\n"); | ||
184 | #endif | ||
185 | prev_scancode = 0; | ||
186 | return 0; | ||
187 | } | ||
188 | } else { | ||
189 | prev_scancode = 0; | ||
190 | /* | ||
191 | * The keyboard maintains its own internal caps lock and | ||
192 | * num lock statuses. In caps lock mode E0 AA precedes make | ||
193 | * code and E0 2A follows break code. In num lock mode, | ||
194 | * E0 2A precedes make code and E0 AA follows break code. | ||
195 | * We do our own book-keeping, so we will just ignore these. | ||
196 | */ | ||
197 | /* | ||
198 | * For my keyboard there is no caps lock mode, but there are | ||
199 | * both Shift-L and Shift-R modes. The former mode generates | ||
200 | * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. | ||
201 | * So, we should also ignore the latter. - aeb@cwi.nl | ||
202 | */ | ||
203 | if (scancode == 0x2a || scancode == 0x36) | ||
204 | return 0; | ||
205 | |||
206 | if (e0_keys[scancode]) | ||
207 | *keycode = e0_keys[scancode]; | ||
208 | else { | ||
209 | #ifdef KBD_REPORT_UNKN | ||
210 | if (!raw_mode) | ||
211 | printk(KERN_INFO | ||
212 | "keyboard: unknown scancode e0 %02x\n", | ||
213 | scancode); | ||
214 | #endif | ||
215 | return 0; | ||
216 | } | ||
217 | } | ||
218 | } else if (scancode >= SC_LIM) { | ||
219 | /* This happens with the FOCUS 9000 keyboard | ||
220 | Its keys PF1..PF12 are reported to generate | ||
221 | 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f | ||
222 | Moreover, unless repeated, they do not generate | ||
223 | key-down events, so we have to zero up_flag below */ | ||
224 | /* Also, Japanese 86/106 keyboards are reported to | ||
225 | generate 0x73 and 0x7d for \ - and \ | respectively. */ | ||
226 | /* Also, some Brazilian keyboard is reported to produce | ||
227 | 0x73 and 0x7e for \ ? and KP-dot, respectively. */ | ||
228 | |||
229 | *keycode = high_keys[scancode - SC_LIM]; | ||
230 | |||
231 | if (!*keycode) { | ||
232 | if (!raw_mode) { | ||
233 | #ifdef KBD_REPORT_UNKN | ||
234 | printk(KERN_INFO | ||
235 | "keyboard: unrecognized scancode (%02x)" | ||
236 | " - ignored\n", scancode); | ||
237 | #endif | ||
238 | } | ||
239 | return 0; | ||
240 | } | ||
241 | } else | ||
242 | *keycode = scancode; | ||
243 | return 1; | ||
244 | } | ||
245 | |||
246 | static char gen_unexpected_up(unsigned char keycode) | ||
247 | { | ||
248 | /* unexpected, but this can happen: maybe this was a key release for a | ||
249 | FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */ | ||
250 | if (keycode >= SC_LIM || keycode == 85) | ||
251 | return 0; | ||
252 | else | ||
253 | return 0200; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * These are the default mappings | ||
258 | */ | ||
259 | int (*k_setkeycode)(unsigned int, unsigned int) = gen_setkeycode; | ||
260 | int (*k_getkeycode)(unsigned int) = gen_getkeycode; | ||
261 | int (*k_translate)(unsigned char, unsigned char *, char) = gen_translate; | ||
262 | char (*k_unexpected_up)(unsigned char) = gen_unexpected_up; | ||
263 | void (*k_leds)(unsigned char); | ||
264 | |||
265 | /* Simple translation table for the SysRq keys */ | ||
266 | |||
267 | #ifdef CONFIG_MAGIC_SYSRQ | ||
268 | static unsigned char gen_sysrq_xlate[128] = | ||
269 | "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ | ||
270 | "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ | ||
271 | "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ | ||
272 | "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ | ||
273 | "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ | ||
274 | "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ | ||
275 | "\r\000/"; /* 0x60 - 0x6f */ | ||
276 | |||
277 | unsigned char *k_sysrq_xlate = gen_sysrq_xlate; | ||
278 | int k_sysrq_key = 0x54; | ||
279 | #endif | ||
diff --git a/arch/arm26/lib/lib1funcs.S b/arch/arm26/lib/lib1funcs.S new file mode 100644 index 000000000000..b8f9518db871 --- /dev/null +++ b/arch/arm26/lib/lib1funcs.S | |||
@@ -0,0 +1,314 @@ | |||
1 | @ libgcc1 routines for ARM cpu. | ||
2 | @ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) | ||
3 | |||
4 | /* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. | ||
5 | |||
6 | This file is free software; you can redistribute it and/or modify it | ||
7 | under the terms of the GNU General Public License as published by the | ||
8 | Free Software Foundation; either version 2, or (at your option) any | ||
9 | later version. | ||
10 | |||
11 | In addition to the permissions in the GNU General Public License, the | ||
12 | Free Software Foundation gives you unlimited permission to link the | ||
13 | compiled version of this file with other programs, and to distribute | ||
14 | those programs without any restriction coming from the use of this | ||
15 | file. (The General Public License restrictions do apply in other | ||
16 | respects; for example, they cover modification of the file, and | ||
17 | distribution when not linked into another program.) | ||
18 | |||
19 | This file is distributed in the hope that it will be useful, but | ||
20 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | General Public License for more details. | ||
23 | |||
24 | You should have received a copy of the GNU General Public License | ||
25 | along with this program; see the file COPYING. If not, write to | ||
26 | the Free Software Foundation, 59 Temple Place - Suite 330, | ||
27 | Boston, MA 02111-1307, USA. */ | ||
28 | |||
29 | /* As a special exception, if you link this library with other files, | ||
30 | some of which are compiled with GCC, to produce an executable, | ||
31 | this library does not by itself cause the resulting executable | ||
32 | to be covered by the GNU General Public License. | ||
33 | This exception does not however invalidate any other reasons why | ||
34 | the executable file might be covered by the GNU General Public License. | ||
35 | */ | ||
36 | /* This code is derived from gcc 2.95.3 */ | ||
37 | /* I Molton 29/07/01 */ | ||
38 | |||
39 | #include <linux/linkage.h> | ||
40 | #include <asm/assembler.h> | ||
41 | #include <asm/hardware.h> | ||
42 | #include <linux/config.h> | ||
43 | |||
44 | #define RET movs | ||
45 | #define RETc(x) mov##x##s | ||
46 | #define RETCOND ^ | ||
47 | |||
48 | dividend .req r0 | ||
49 | divisor .req r1 | ||
50 | result .req r2 | ||
51 | overdone .req r2 | ||
52 | curbit .req r3 | ||
53 | ip .req r12 | ||
54 | sp .req r13 | ||
55 | lr .req r14 | ||
56 | pc .req r15 | ||
57 | |||
58 | ENTRY(__udivsi3) | ||
59 | cmp divisor, #0 | ||
60 | beq Ldiv0 | ||
61 | mov curbit, #1 | ||
62 | mov result, #0 | ||
63 | cmp dividend, divisor | ||
64 | bcc Lgot_result_udivsi3 | ||
65 | 1: | ||
66 | @ Unless the divisor is very big, shift it up in multiples of | ||
67 | @ four bits, since this is the amount of unwinding in the main | ||
68 | @ division loop. Continue shifting until the divisor is | ||
69 | @ larger than the dividend. | ||
70 | cmp divisor, #0x10000000 | ||
71 | cmpcc divisor, dividend | ||
72 | movcc divisor, divisor, lsl #4 | ||
73 | movcc curbit, curbit, lsl #4 | ||
74 | bcc 1b | ||
75 | |||
76 | 2: | ||
77 | @ For very big divisors, we must shift it a bit at a time, or | ||
78 | @ we will be in danger of overflowing. | ||
79 | cmp divisor, #0x80000000 | ||
80 | cmpcc divisor, dividend | ||
81 | movcc divisor, divisor, lsl #1 | ||
82 | movcc curbit, curbit, lsl #1 | ||
83 | bcc 2b | ||
84 | |||
85 | 3: | ||
86 | @ Test for possible subtractions, and note which bits | ||
87 | @ are done in the result. On the final pass, this may subtract | ||
88 | @ too much from the dividend, but the result will be ok, since the | ||
89 | @ "bit" will have been shifted out at the bottom. | ||
90 | cmp dividend, divisor | ||
91 | subcs dividend, dividend, divisor | ||
92 | orrcs result, result, curbit | ||
93 | cmp dividend, divisor, lsr #1 | ||
94 | subcs dividend, dividend, divisor, lsr #1 | ||
95 | orrcs result, result, curbit, lsr #1 | ||
96 | cmp dividend, divisor, lsr #2 | ||
97 | subcs dividend, dividend, divisor, lsr #2 | ||
98 | orrcs result, result, curbit, lsr #2 | ||
99 | cmp dividend, divisor, lsr #3 | ||
100 | subcs dividend, dividend, divisor, lsr #3 | ||
101 | orrcs result, result, curbit, lsr #3 | ||
102 | cmp dividend, #0 @ Early termination? | ||
103 | movnes curbit, curbit, lsr #4 @ No, any more bits to do? | ||
104 | movne divisor, divisor, lsr #4 | ||
105 | bne 3b | ||
106 | Lgot_result_udivsi3: | ||
107 | mov r0, result | ||
108 | RET pc, lr | ||
109 | |||
110 | Ldiv0: | ||
111 | str lr, [sp, #-4]! | ||
112 | bl __div0 | ||
113 | mov r0, #0 @ about as wrong as it could be | ||
114 | ldmia sp!, {pc}RETCOND | ||
115 | |||
116 | /* __umodsi3 ----------------------- */ | ||
117 | |||
118 | ENTRY(__umodsi3) | ||
119 | cmp divisor, #0 | ||
120 | beq Ldiv0 | ||
121 | mov curbit, #1 | ||
122 | cmp dividend, divisor | ||
123 | RETc(cc) pc, lr | ||
124 | 1: | ||
125 | @ Unless the divisor is very big, shift it up in multiples of | ||
126 | @ four bits, since this is the amount of unwinding in the main | ||
127 | @ division loop. Continue shifting until the divisor is | ||
128 | @ larger than the dividend. | ||
129 | cmp divisor, #0x10000000 | ||
130 | cmpcc divisor, dividend | ||
131 | movcc divisor, divisor, lsl #4 | ||
132 | movcc curbit, curbit, lsl #4 | ||
133 | bcc 1b | ||
134 | |||
135 | 2: | ||
136 | @ For very big divisors, we must shift it a bit at a time, or | ||
137 | @ we will be in danger of overflowing. | ||
138 | cmp divisor, #0x80000000 | ||
139 | cmpcc divisor, dividend | ||
140 | movcc divisor, divisor, lsl #1 | ||
141 | movcc curbit, curbit, lsl #1 | ||
142 | bcc 2b | ||
143 | |||
144 | 3: | ||
145 | @ Test for possible subtractions. On the final pass, this may | ||
146 | @ subtract too much from the dividend, so keep track of which | ||
147 | @ subtractions are done, we can fix them up afterwards... | ||
148 | mov overdone, #0 | ||
149 | cmp dividend, divisor | ||
150 | subcs dividend, dividend, divisor | ||
151 | cmp dividend, divisor, lsr #1 | ||
152 | subcs dividend, dividend, divisor, lsr #1 | ||
153 | orrcs overdone, overdone, curbit, ror #1 | ||
154 | cmp dividend, divisor, lsr #2 | ||
155 | subcs dividend, dividend, divisor, lsr #2 | ||
156 | orrcs overdone, overdone, curbit, ror #2 | ||
157 | cmp dividend, divisor, lsr #3 | ||
158 | subcs dividend, dividend, divisor, lsr #3 | ||
159 | orrcs overdone, overdone, curbit, ror #3 | ||
160 | mov ip, curbit | ||
161 | cmp dividend, #0 @ Early termination? | ||
162 | movnes curbit, curbit, lsr #4 @ No, any more bits to do? | ||
163 | movne divisor, divisor, lsr #4 | ||
164 | bne 3b | ||
165 | |||
166 | @ Any subtractions that we should not have done will be recorded in | ||
167 | @ the top three bits of "overdone". Exactly which were not needed | ||
168 | @ are governed by the position of the bit, stored in ip. | ||
169 | @ If we terminated early, because dividend became zero, | ||
170 | @ then none of the below will match, since the bit in ip will not be | ||
171 | @ in the bottom nibble. | ||
172 | ands overdone, overdone, #0xe0000000 | ||
173 | RETc(eq) pc, lr @ No fixups needed | ||
174 | tst overdone, ip, ror #3 | ||
175 | addne dividend, dividend, divisor, lsr #3 | ||
176 | tst overdone, ip, ror #2 | ||
177 | addne dividend, dividend, divisor, lsr #2 | ||
178 | tst overdone, ip, ror #1 | ||
179 | addne dividend, dividend, divisor, lsr #1 | ||
180 | RET pc, lr | ||
181 | |||
182 | ENTRY(__divsi3) | ||
183 | eor ip, dividend, divisor @ Save the sign of the result. | ||
184 | mov curbit, #1 | ||
185 | mov result, #0 | ||
186 | cmp divisor, #0 | ||
187 | rsbmi divisor, divisor, #0 @ Loops below use unsigned. | ||
188 | beq Ldiv0 | ||
189 | cmp dividend, #0 | ||
190 | rsbmi dividend, dividend, #0 | ||
191 | cmp dividend, divisor | ||
192 | bcc Lgot_result_divsi3 | ||
193 | |||
194 | 1: | ||
195 | @ Unless the divisor is very big, shift it up in multiples of | ||
196 | @ four bits, since this is the amount of unwinding in the main | ||
197 | @ division loop. Continue shifting until the divisor is | ||
198 | @ larger than the dividend. | ||
199 | cmp divisor, #0x10000000 | ||
200 | cmpcc divisor, dividend | ||
201 | movcc divisor, divisor, lsl #4 | ||
202 | movcc curbit, curbit, lsl #4 | ||
203 | bcc 1b | ||
204 | |||
205 | 2: | ||
206 | @ For very big divisors, we must shift it a bit at a time, or | ||
207 | @ we will be in danger of overflowing. | ||
208 | cmp divisor, #0x80000000 | ||
209 | cmpcc divisor, dividend | ||
210 | movcc divisor, divisor, lsl #1 | ||
211 | movcc curbit, curbit, lsl #1 | ||
212 | bcc 2b | ||
213 | |||
214 | 3: | ||
215 | @ Test for possible subtractions, and note which bits | ||
216 | @ are done in the result. On the final pass, this may subtract | ||
217 | @ too much from the dividend, but the result will be ok, since the | ||
218 | @ "bit" will have been shifted out at the bottom. | ||
219 | cmp dividend, divisor | ||
220 | subcs dividend, dividend, divisor | ||
221 | orrcs result, result, curbit | ||
222 | cmp dividend, divisor, lsr #1 | ||
223 | subcs dividend, dividend, divisor, lsr #1 | ||
224 | orrcs result, result, curbit, lsr #1 | ||
225 | cmp dividend, divisor, lsr #2 | ||
226 | subcs dividend, dividend, divisor, lsr #2 | ||
227 | orrcs result, result, curbit, lsr #2 | ||
228 | cmp dividend, divisor, lsr #3 | ||
229 | subcs dividend, dividend, divisor, lsr #3 | ||
230 | orrcs result, result, curbit, lsr #3 | ||
231 | cmp dividend, #0 @ Early termination? | ||
232 | movnes curbit, curbit, lsr #4 @ No, any more bits to do? | ||
233 | movne divisor, divisor, lsr #4 | ||
234 | bne 3b | ||
235 | Lgot_result_divsi3: | ||
236 | mov r0, result | ||
237 | cmp ip, #0 | ||
238 | rsbmi r0, r0, #0 | ||
239 | RET pc, lr | ||
240 | |||
241 | ENTRY(__modsi3) | ||
242 | mov curbit, #1 | ||
243 | cmp divisor, #0 | ||
244 | rsbmi divisor, divisor, #0 @ Loops below use unsigned. | ||
245 | beq Ldiv0 | ||
246 | @ Need to save the sign of the dividend, unfortunately, we need | ||
247 | @ ip later on; this is faster than pushing lr and using that. | ||
248 | str dividend, [sp, #-4]! | ||
249 | cmp dividend, #0 | ||
250 | rsbmi dividend, dividend, #0 | ||
251 | cmp dividend, divisor | ||
252 | bcc Lgot_result_modsi3 | ||
253 | |||
254 | 1: | ||
255 | @ Unless the divisor is very big, shift it up in multiples of | ||
256 | @ four bits, since this is the amount of unwinding in the main | ||
257 | @ division loop. Continue shifting until the divisor is | ||
258 | @ larger than the dividend. | ||
259 | cmp divisor, #0x10000000 | ||
260 | cmpcc divisor, dividend | ||
261 | movcc divisor, divisor, lsl #4 | ||
262 | movcc curbit, curbit, lsl #4 | ||
263 | bcc 1b | ||
264 | |||
265 | 2: | ||
266 | @ For very big divisors, we must shift it a bit at a time, or | ||
267 | @ we will be in danger of overflowing. | ||
268 | cmp divisor, #0x80000000 | ||
269 | cmpcc divisor, dividend | ||
270 | movcc divisor, divisor, lsl #1 | ||
271 | movcc curbit, curbit, lsl #1 | ||
272 | bcc 2b | ||
273 | |||
274 | 3: | ||
275 | @ Test for possible subtractions. On the final pass, this may | ||
276 | @ subtract too much from the dividend, so keep track of which | ||
277 | @ subtractions are done, we can fix them up afterwards... | ||
278 | mov overdone, #0 | ||
279 | cmp dividend, divisor | ||
280 | subcs dividend, dividend, divisor | ||
281 | cmp dividend, divisor, lsr #1 | ||
282 | subcs dividend, dividend, divisor, lsr #1 | ||
283 | orrcs overdone, overdone, curbit, ror #1 | ||
284 | cmp dividend, divisor, lsr #2 | ||
285 | subcs dividend, dividend, divisor, lsr #2 | ||
286 | orrcs overdone, overdone, curbit, ror #2 | ||
287 | cmp dividend, divisor, lsr #3 | ||
288 | subcs dividend, dividend, divisor, lsr #3 | ||
289 | orrcs overdone, overdone, curbit, ror #3 | ||
290 | mov ip, curbit | ||
291 | cmp dividend, #0 @ Early termination? | ||
292 | movnes curbit, curbit, lsr #4 @ No, any more bits to do? | ||
293 | movne divisor, divisor, lsr #4 | ||
294 | bne 3b | ||
295 | |||
296 | @ Any subtractions that we should not have done will be recorded in | ||
297 | @ the top three bits of "overdone". Exactly which were not needed | ||
298 | @ are governed by the position of the bit, stored in ip. | ||
299 | @ If we terminated early, because dividend became zero, | ||
300 | @ then none of the below will match, since the bit in ip will not be | ||
301 | @ in the bottom nibble. | ||
302 | ands overdone, overdone, #0xe0000000 | ||
303 | beq Lgot_result_modsi3 | ||
304 | tst overdone, ip, ror #3 | ||
305 | addne dividend, dividend, divisor, lsr #3 | ||
306 | tst overdone, ip, ror #2 | ||
307 | addne dividend, dividend, divisor, lsr #2 | ||
308 | tst overdone, ip, ror #1 | ||
309 | addne dividend, dividend, divisor, lsr #1 | ||
310 | Lgot_result_modsi3: | ||
311 | ldr ip, [sp], #4 | ||
312 | cmp ip, #0 | ||
313 | rsbmi dividend, dividend, #0 | ||
314 | RET pc, lr | ||
diff --git a/arch/arm26/lib/longlong.h b/arch/arm26/lib/longlong.h new file mode 100644 index 000000000000..05ec1abd6a2c --- /dev/null +++ b/arch/arm26/lib/longlong.h | |||
@@ -0,0 +1,184 @@ | |||
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 | extern const UQItype __clz_tab[]; | ||
165 | #define count_leading_zeros(count, x) \ | ||
166 | do { \ | ||
167 | USItype __xr = (x); \ | ||
168 | USItype __a; \ | ||
169 | \ | ||
170 | if (SI_TYPE_SIZE <= 32) \ | ||
171 | { \ | ||
172 | __a = __xr < ((USItype)1<<2*__BITS4) \ | ||
173 | ? (__xr < ((USItype)1<<__BITS4) ? 0 : __BITS4) \ | ||
174 | : (__xr < ((USItype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ | ||
175 | } \ | ||
176 | else \ | ||
177 | { \ | ||
178 | for (__a = SI_TYPE_SIZE - 8; __a > 0; __a -= 8) \ | ||
179 | if (((__xr >> __a) & 0xff) != 0) \ | ||
180 | break; \ | ||
181 | } \ | ||
182 | \ | ||
183 | (count) = SI_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ | ||
184 | } while (0) | ||
diff --git a/arch/arm26/lib/lshrdi3.c b/arch/arm26/lib/lshrdi3.c new file mode 100644 index 000000000000..b666f1bad451 --- /dev/null +++ b/arch/arm26/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/arm26/lib/memchr.S b/arch/arm26/lib/memchr.S new file mode 100644 index 000000000000..34e7c14c08ad --- /dev/null +++ b/arch/arm26/lib/memchr.S | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/memcpy.S b/arch/arm26/lib/memcpy.S new file mode 100644 index 000000000000..3f719e412069 --- /dev/null +++ b/arch/arm26/lib/memcpy.S | |||
@@ -0,0 +1,318 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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!,{r4-r9,fp,ip,lr,pc} ;\ | ||
20 | sub fp,ip,#4 | ||
21 | |||
22 | #define EXIT \ | ||
23 | LOADREGS(ea, fp, {r4 - r9, fp, sp, pc}) | ||
24 | |||
25 | #define EXITEQ \ | ||
26 | LOADREGS(eqea, fp, {r4 - r9, fp, sp, pc}) | ||
27 | |||
28 | /* | ||
29 | * Prototype: void memcpy(void *to,const void *from,unsigned long n); | ||
30 | * ARM3: cant use memcopy here!!! | ||
31 | */ | ||
32 | ENTRY(memcpy) | ||
33 | ENTRY(memmove) | ||
34 | ENTER | ||
35 | cmp r1, r0 | ||
36 | bcc 19f | ||
37 | subs r2, r2, #4 | ||
38 | blt 6f | ||
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, #0x14 | ||
47 | blt 3f | ||
48 | 2: ldmia r1!,{r3 - r9, ip} | ||
49 | stmia r0!,{r3 - r9, ip} | ||
50 | subs r2, r2, #32 | ||
51 | bge 2b | ||
52 | cmn r2, #16 | ||
53 | ldmgeia r1!, {r3 - r6} | ||
54 | stmgeia r0!, {r3 - r6} | ||
55 | subge r2, r2, #0x10 | ||
56 | 3: adds r2, r2, #0x14 | ||
57 | 4: ldmgeia r1!, {r3 - r5} | ||
58 | stmgeia r0!, {r3 - r5} | ||
59 | subges r2, r2, #12 | ||
60 | bge 4b | ||
61 | 5: adds r2, r2, #8 | ||
62 | blt 6f | ||
63 | subs r2, r2, #4 | ||
64 | ldrlt r3, [r1], #4 | ||
65 | ldmgeia r1!, {r4, r5} | ||
66 | strlt r3, [r0], #4 | ||
67 | stmgeia r0!, {r4, r5} | ||
68 | subge r2, r2, #4 | ||
69 | |||
70 | 6: adds r2, r2, #4 | ||
71 | EXITEQ | ||
72 | cmp r2, #2 | ||
73 | ldrb r3, [r1], #1 | ||
74 | ldrgeb r4, [r1], #1 | ||
75 | ldrgtb r5, [r1], #1 | ||
76 | strb r3, [r0], #1 | ||
77 | strgeb r4, [r0], #1 | ||
78 | strgtb r5, [r0], #1 | ||
79 | EXIT | ||
80 | |||
81 | 7: rsb ip, ip, #4 | ||
82 | cmp ip, #2 | ||
83 | ldrb r3, [r1], #1 | ||
84 | ldrgeb r4, [r1], #1 | ||
85 | ldrgtb r5, [r1], #1 | ||
86 | strb r3, [r0], #1 | ||
87 | strgeb r4, [r0], #1 | ||
88 | strgtb r5, [r0], #1 | ||
89 | subs r2, r2, ip | ||
90 | blt 6b | ||
91 | ands ip, r1, #3 | ||
92 | beq 1b | ||
93 | |||
94 | 8: bic r1, r1, #3 | ||
95 | ldr r7, [r1], #4 | ||
96 | cmp ip, #2 | ||
97 | bgt 15f | ||
98 | beq 11f | ||
99 | cmp r2, #12 | ||
100 | blt 10f | ||
101 | sub r2, r2, #12 | ||
102 | 9: mov r3, r7, pull #8 | ||
103 | ldmia r1!, {r4 - r7} | ||
104 | orr r3, r3, r4, push #24 | ||
105 | mov r4, r4, pull #8 | ||
106 | orr r4, r4, r5, push #24 | ||
107 | mov r5, r5, pull #8 | ||
108 | orr r5, r5, r6, push #24 | ||
109 | mov r6, r6, pull #8 | ||
110 | orr r6, r6, r7, push #24 | ||
111 | stmia r0!, {r3 - r6} | ||
112 | subs r2, r2, #16 | ||
113 | bge 9b | ||
114 | adds r2, r2, #12 | ||
115 | blt 100f | ||
116 | 10: mov r3, r7, pull #8 | ||
117 | ldr r7, [r1], #4 | ||
118 | subs r2, r2, #4 | ||
119 | orr r3, r3, r7, push #24 | ||
120 | str r3, [r0], #4 | ||
121 | bge 10b | ||
122 | 100: sub r1, r1, #3 | ||
123 | b 6b | ||
124 | |||
125 | 11: cmp r2, #12 | ||
126 | blt 13f /* */ | ||
127 | sub r2, r2, #12 | ||
128 | 12: mov r3, r7, pull #16 | ||
129 | ldmia r1!, {r4 - r7} | ||
130 | orr r3, r3, r4, push #16 | ||
131 | mov r4, r4, pull #16 | ||
132 | orr r4, r4, r5, push #16 | ||
133 | mov r5, r5, pull #16 | ||
134 | orr r5, r5, r6, push #16 | ||
135 | mov r6, r6, pull #16 | ||
136 | orr r6, r6, r7, push #16 | ||
137 | stmia r0!, {r3 - r6} | ||
138 | subs r2, r2, #16 | ||
139 | bge 12b | ||
140 | adds r2, r2, #12 | ||
141 | blt 14f | ||
142 | 13: mov r3, r7, pull #16 | ||
143 | ldr r7, [r1], #4 | ||
144 | subs r2, r2, #4 | ||
145 | orr r3, r3, r7, push #16 | ||
146 | str r3, [r0], #4 | ||
147 | bge 13b | ||
148 | 14: sub r1, r1, #2 | ||
149 | b 6b | ||
150 | |||
151 | 15: cmp r2, #12 | ||
152 | blt 17f | ||
153 | sub r2, r2, #12 | ||
154 | 16: mov r3, r7, pull #24 | ||
155 | ldmia r1!, {r4 - r7} | ||
156 | orr r3, r3, r4, push #8 | ||
157 | mov r4, r4, pull #24 | ||
158 | orr r4, r4, r5, push #8 | ||
159 | mov r5, r5, pull #24 | ||
160 | orr r5, r5, r6, push #8 | ||
161 | mov r6, r6, pull #24 | ||
162 | orr r6, r6, r7, push #8 | ||
163 | stmia r0!, {r3 - r6} | ||
164 | subs r2, r2, #16 | ||
165 | bge 16b | ||
166 | adds r2, r2, #12 | ||
167 | blt 18f | ||
168 | 17: mov r3, r7, pull #24 | ||
169 | ldr r7, [r1], #4 | ||
170 | subs r2, r2, #4 | ||
171 | orr r3, r3, r7, push #8 | ||
172 | str r3, [r0], #4 | ||
173 | bge 17b | ||
174 | 18: sub r1, r1, #1 | ||
175 | b 6b | ||
176 | |||
177 | |||
178 | 19: add r1, r1, r2 | ||
179 | add r0, r0, r2 | ||
180 | subs r2, r2, #4 | ||
181 | blt 24f | ||
182 | ands ip, r0, #3 | ||
183 | bne 25f | ||
184 | ands ip, r1, #3 | ||
185 | bne 26f | ||
186 | |||
187 | 20: subs r2, r2, #8 | ||
188 | blt 23f | ||
189 | subs r2, r2, #0x14 | ||
190 | blt 22f | ||
191 | 21: ldmdb r1!, {r3 - r9, ip} | ||
192 | stmdb r0!, {r3 - r9, ip} | ||
193 | subs r2, r2, #32 | ||
194 | bge 21b | ||
195 | 22: cmn r2, #16 | ||
196 | ldmgedb r1!, {r3 - r6} | ||
197 | stmgedb r0!, {r3 - r6} | ||
198 | subge r2, r2, #16 | ||
199 | adds r2, r2, #20 | ||
200 | ldmgedb r1!, {r3 - r5} | ||
201 | stmgedb r0!, {r3 - r5} | ||
202 | subge r2, r2, #12 | ||
203 | 23: adds r2, r2, #8 | ||
204 | blt 24f | ||
205 | subs r2, r2, #4 | ||
206 | ldrlt r3, [r1, #-4]! | ||
207 | ldmgedb r1!, {r4, r5} | ||
208 | strlt r3, [r0, #-4]! | ||
209 | stmgedb r0!, {r4, r5} | ||
210 | subge r2, r2, #4 | ||
211 | |||
212 | 24: adds r2, r2, #4 | ||
213 | EXITEQ | ||
214 | cmp r2, #2 | ||
215 | ldrb r3, [r1, #-1]! | ||
216 | ldrgeb r4, [r1, #-1]! | ||
217 | ldrgtb r5, [r1, #-1]! | ||
218 | strb r3, [r0, #-1]! | ||
219 | strgeb r4, [r0, #-1]! | ||
220 | strgtb r5, [r0, #-1]! | ||
221 | EXIT | ||
222 | |||
223 | 25: cmp ip, #2 | ||
224 | ldrb r3, [r1, #-1]! | ||
225 | ldrgeb r4, [r1, #-1]! | ||
226 | ldrgtb r5, [r1, #-1]! | ||
227 | strb r3, [r0, #-1]! | ||
228 | strgeb r4, [r0, #-1]! | ||
229 | strgtb r5, [r0, #-1]! | ||
230 | subs r2, r2, ip | ||
231 | blt 24b | ||
232 | ands ip, r1, #3 | ||
233 | beq 20b | ||
234 | |||
235 | 26: bic r1, r1, #3 | ||
236 | ldr r3, [r1], #0 | ||
237 | cmp ip, #2 | ||
238 | blt 34f | ||
239 | beq 30f | ||
240 | cmp r2, #12 | ||
241 | blt 28f | ||
242 | sub r2, r2, #12 | ||
243 | 27: mov r7, r3, push #8 | ||
244 | ldmdb r1!, {r3, r4, r5, r6} | ||
245 | orr r7, r7, r6, pull #24 | ||
246 | mov r6, r6, push #8 | ||
247 | orr r6, r6, r5, pull #24 | ||
248 | mov r5, r5, push #8 | ||
249 | orr r5, r5, r4, pull #24 | ||
250 | mov r4, r4, push #8 | ||
251 | orr r4, r4, r3, pull #24 | ||
252 | stmdb r0!, {r4, r5, r6, r7} | ||
253 | subs r2, r2, #16 | ||
254 | bge 27b | ||
255 | adds r2, r2, #12 | ||
256 | blt 29f | ||
257 | 28: mov ip, r3, push #8 | ||
258 | ldr r3, [r1, #-4]! | ||
259 | subs r2, r2, #4 | ||
260 | orr ip, ip, r3, pull #24 | ||
261 | str ip, [r0, #-4]! | ||
262 | bge 28b | ||
263 | 29: add r1, r1, #3 | ||
264 | b 24b | ||
265 | |||
266 | 30: cmp r2, #12 | ||
267 | blt 32f | ||
268 | sub r2, r2, #12 | ||
269 | 31: mov r7, r3, push #16 | ||
270 | ldmdb r1!, {r3, r4, r5, r6} | ||
271 | orr r7, r7, r6, pull #16 | ||
272 | mov r6, r6, push #16 | ||
273 | orr r6, r6, r5, pull #16 | ||
274 | mov r5, r5, push #16 | ||
275 | orr r5, r5, r4, pull #16 | ||
276 | mov r4, r4, push #16 | ||
277 | orr r4, r4, r3, pull #16 | ||
278 | stmdb r0!, {r4, r5, r6, r7} | ||
279 | subs r2, r2, #16 | ||
280 | bge 31b | ||
281 | adds r2, r2, #12 | ||
282 | blt 33f | ||
283 | 32: mov ip, r3, push #16 | ||
284 | ldr r3, [r1, #-4]! | ||
285 | subs r2, r2, #4 | ||
286 | orr ip, ip, r3, pull #16 | ||
287 | str ip, [r0, #-4]! | ||
288 | bge 32b | ||
289 | 33: add r1, r1, #2 | ||
290 | b 24b | ||
291 | |||
292 | 34: cmp r2, #12 | ||
293 | blt 36f | ||
294 | sub r2, r2, #12 | ||
295 | 35: mov r7, r3, push #24 | ||
296 | ldmdb r1!, {r3, r4, r5, r6} | ||
297 | orr r7, r7, r6, pull #8 | ||
298 | mov r6, r6, push #24 | ||
299 | orr r6, r6, r5, pull #8 | ||
300 | mov r5, r5, push #24 | ||
301 | orr r5, r5, r4, pull #8 | ||
302 | mov r4, r4, push #24 | ||
303 | orr r4, r4, r3, pull #8 | ||
304 | stmdb r0!, {r4, r5, r6, r7} | ||
305 | subs r2, r2, #16 | ||
306 | bge 35b | ||
307 | adds r2, r2, #12 | ||
308 | blt 37f | ||
309 | 36: mov ip, r3, push #24 | ||
310 | ldr r3, [r1, #-4]! | ||
311 | subs r2, r2, #4 | ||
312 | orr ip, ip, r3, pull #8 | ||
313 | str ip, [r0, #-4]! | ||
314 | bge 36b | ||
315 | 37: add r1, r1, #1 | ||
316 | b 24b | ||
317 | |||
318 | .align | ||
diff --git a/arch/arm26/lib/memset.S b/arch/arm26/lib/memset.S new file mode 100644 index 000000000000..aedec10b58f5 --- /dev/null +++ b/arch/arm26/lib/memset.S | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/memzero.S b/arch/arm26/lib/memzero.S new file mode 100644 index 000000000000..cc5bf6860061 --- /dev/null +++ b/arch/arm26/lib/memzero.S | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/muldi3.c b/arch/arm26/lib/muldi3.c new file mode 100644 index 000000000000..44d611b1cfdb --- /dev/null +++ b/arch/arm26/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/arm26/lib/putuser.S b/arch/arm26/lib/putuser.S new file mode 100644 index 000000000000..87588cbe46ae --- /dev/null +++ b/arch/arm26/lib/putuser.S | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | * r1, r2 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/asm_offsets.h> | ||
30 | #include <asm/thread_info.h> | ||
31 | #include <asm/errno.h> | ||
32 | |||
33 | .global __put_user_1 | ||
34 | __put_user_1: | ||
35 | bic r2, sp, #0x1f00 | ||
36 | bic r2, r2, #0x00ff | ||
37 | str lr, [sp, #-4]! | ||
38 | ldr r2, [r2, #TI_ADDR_LIMIT] | ||
39 | sub r2, r2, #1 | ||
40 | cmp r0, r2 | ||
41 | bge __put_user_bad | ||
42 | 1: cmp r0, #0x02000000 | ||
43 | strlsbt r1, [r0] | ||
44 | strgeb r1, [r0] | ||
45 | mov r0, #0 | ||
46 | ldmfd sp!, {pc}^ | ||
47 | |||
48 | .global __put_user_2 | ||
49 | __put_user_2: | ||
50 | bic r2, sp, #0x1f00 | ||
51 | bic r2, r2, #0x00ff | ||
52 | str lr, [sp, #-4]! | ||
53 | ldr r2, [r2, #TI_ADDR_LIMIT] | ||
54 | sub r2, r2, #2 | ||
55 | cmp r0, r2 | ||
56 | bge __put_user_bad | ||
57 | 2: cmp r0, #0x02000000 | ||
58 | strlsbt r1, [r0], #1 | ||
59 | strgeb r1, [r0], #1 | ||
60 | mov r1, r1, lsr #8 | ||
61 | 3: strlsbt r1, [r0] | ||
62 | strgeb r1, [r0] | ||
63 | mov r0, #0 | ||
64 | ldmfd sp!, {pc}^ | ||
65 | |||
66 | .global __put_user_4 | ||
67 | __put_user_4: | ||
68 | bic r2, sp, #0x1f00 | ||
69 | bic r2, r2, #0x00ff | ||
70 | str lr, [sp, #-4]! | ||
71 | ldr r2, [r2, #TI_ADDR_LIMIT] | ||
72 | sub r2, r2, #4 | ||
73 | cmp r0, r2 | ||
74 | 4: bge __put_user_bad | ||
75 | cmp r0, #0x02000000 | ||
76 | strlst r1, [r0] | ||
77 | strge r1, [r0] | ||
78 | mov r0, #0 | ||
79 | ldmfd sp!, {pc}^ | ||
80 | |||
81 | .global __put_user_8 | ||
82 | __put_user_8: | ||
83 | bic ip, sp, #0x1f00 | ||
84 | bic ip, ip, #0x00ff | ||
85 | str lr, [sp, #-4]! | ||
86 | ldr ip, [ip, #TI_ADDR_LIMIT] | ||
87 | sub ip, ip, #8 | ||
88 | cmp r0, ip | ||
89 | bge __put_user_bad | ||
90 | cmp r0, #0x02000000 | ||
91 | 5: strlst r1, [r0], #4 | ||
92 | 6: strlst r2, [r0] | ||
93 | strge r1, [r0], #4 | ||
94 | strge r2, [r0] | ||
95 | mov r0, #0 | ||
96 | ldmfd sp!, {pc}^ | ||
97 | |||
98 | __put_user_bad: | ||
99 | mov r0, #-EFAULT | ||
100 | mov pc, lr | ||
101 | |||
102 | .section __ex_table, "a" | ||
103 | .long 1b, __put_user_bad | ||
104 | .long 2b, __put_user_bad | ||
105 | .long 3b, __put_user_bad | ||
106 | .long 4b, __put_user_bad | ||
107 | .long 5b, __put_user_bad | ||
108 | .long 6b, __put_user_bad | ||
109 | .previous | ||
diff --git a/arch/arm26/lib/setbit.S b/arch/arm26/lib/setbit.S new file mode 100644 index 000000000000..e180c1a1b2f1 --- /dev/null +++ b/arch/arm26/lib/setbit.S | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/strchr.S b/arch/arm26/lib/strchr.S new file mode 100644 index 000000000000..ecfff21aa7c7 --- /dev/null +++ b/arch/arm26/lib/strchr.S | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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 | 1: ldrb r2, [r0], #1 | ||
19 | teq r2, r1 | ||
20 | teqne r2, #0 | ||
21 | bne 1b | ||
22 | teq r2, #0 | ||
23 | moveq r0, #0 | ||
24 | subne r0, r0, #1 | ||
25 | RETINSTR(mov,pc,lr) | ||
diff --git a/arch/arm26/lib/strrchr.S b/arch/arm26/lib/strrchr.S new file mode 100644 index 000000000000..db43b28e78dc --- /dev/null +++ b/arch/arm26/lib/strrchr.S | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/testchangebit.S b/arch/arm26/lib/testchangebit.S new file mode 100644 index 000000000000..17049a2d93a4 --- /dev/null +++ b/arch/arm26/lib/testchangebit.S | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/testclearbit.S b/arch/arm26/lib/testclearbit.S new file mode 100644 index 000000000000..2506bd743ab4 --- /dev/null +++ b/arch/arm26/lib/testclearbit.S | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/testsetbit.S b/arch/arm26/lib/testsetbit.S new file mode 100644 index 000000000000..f827de64b22d --- /dev/null +++ b/arch/arm26/lib/testsetbit.S | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/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/arm26/lib/uaccess-kernel.S b/arch/arm26/lib/uaccess-kernel.S new file mode 100644 index 000000000000..3950a1f6bc99 --- /dev/null +++ b/arch/arm26/lib/uaccess-kernel.S | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/lib/uaccess-kernel.S | ||
3 | * | ||
4 | * Copyright (C) 1998 Russell King | ||
5 | * | ||
6 | * Note! Some code fragments found in here have a special calling | ||
7 | * convention - they are not APCS compliant! | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/assembler.h> | ||
15 | |||
16 | .text | ||
17 | |||
18 | //FIXME - surely this can be done in C not asm, removing the problem of keeping C and asm in sync? (this is a struct uaccess_t) | ||
19 | |||
20 | .globl uaccess_kernel | ||
21 | uaccess_kernel: | ||
22 | .word uaccess_kernel_put_byte | ||
23 | .word uaccess_kernel_get_byte | ||
24 | .word uaccess_kernel_put_half | ||
25 | .word uaccess_kernel_get_half | ||
26 | .word uaccess_kernel_put_word | ||
27 | .word uaccess_kernel_get_word | ||
28 | .word uaccess_kernel_put_dword | ||
29 | .word uaccess_kernel_copy | ||
30 | .word uaccess_kernel_copy | ||
31 | .word uaccess_kernel_clear | ||
32 | .word uaccess_kernel_strncpy | ||
33 | .word uaccess_kernel_strnlen | ||
34 | |||
35 | @ In : r0 = x, r1 = addr, r2 = error | ||
36 | @ Out: r2 = error | ||
37 | uaccess_kernel_put_byte: | ||
38 | stmfd sp!, {lr} | ||
39 | strb r0, [r1] | ||
40 | ldmfd sp!, {pc}^ | ||
41 | |||
42 | @ In : r0 = x, r1 = addr, r2 = error | ||
43 | @ Out: r2 = error | ||
44 | uaccess_kernel_put_half: | ||
45 | stmfd sp!, {lr} | ||
46 | strb r0, [r1] | ||
47 | mov r0, r0, lsr #8 | ||
48 | strb r0, [r1, #1] | ||
49 | ldmfd sp!, {pc}^ | ||
50 | |||
51 | @ In : r0 = x, r1 = addr, r2 = error | ||
52 | @ Out: r2 = error | ||
53 | uaccess_kernel_put_word: | ||
54 | stmfd sp!, {lr} | ||
55 | str r0, [r1] | ||
56 | ldmfd sp!, {pc}^ | ||
57 | |||
58 | @ In : r0 = x, r1 = addr, r2 = error | ||
59 | @ Out: r2 = error | ||
60 | uaccess_kernel_put_dword: | ||
61 | stmfd sp!, {lr} | ||
62 | str r0, [r1], #4 | ||
63 | str r0, [r1], #0 | ||
64 | ldmfd sp!, {pc}^ | ||
65 | |||
66 | @ In : r0 = addr, r1 = error | ||
67 | @ Out: r0 = x, r1 = error | ||
68 | uaccess_kernel_get_byte: | ||
69 | stmfd sp!, {lr} | ||
70 | ldrb r0, [r0] | ||
71 | ldmfd sp!, {pc}^ | ||
72 | |||
73 | @ In : r0 = addr, r1 = error | ||
74 | @ Out: r0 = x, r1 = error | ||
75 | uaccess_kernel_get_half: | ||
76 | stmfd sp!, {lr} | ||
77 | ldr r0, [r0] | ||
78 | mov r0, r0, lsl #16 | ||
79 | mov r0, r0, lsr #16 | ||
80 | ldmfd sp!, {pc}^ | ||
81 | |||
82 | @ In : r0 = addr, r1 = error | ||
83 | @ Out: r0 = x, r1 = error | ||
84 | uaccess_kernel_get_word: | ||
85 | stmfd sp!, {lr} | ||
86 | ldr r0, [r0] | ||
87 | ldmfd sp!, {pc}^ | ||
88 | |||
89 | |||
90 | /* Prototype: int uaccess_kernel_copy(void *to, const char *from, size_t n) | ||
91 | * Purpose : copy a block to kernel memory from kernel memory | ||
92 | * Params : to - kernel memory | ||
93 | * : from - kernel memory | ||
94 | * : n - number of bytes to copy | ||
95 | * Returns : Number of bytes NOT copied. | ||
96 | */ | ||
97 | uaccess_kernel_copy: | ||
98 | stmfd sp!, {lr} | ||
99 | bl memcpy | ||
100 | mov r0, #0 | ||
101 | ldmfd sp!, {pc}^ | ||
102 | |||
103 | /* Prototype: int uaccess_kernel_clear(void *addr, size_t sz) | ||
104 | * Purpose : clear some kernel memory | ||
105 | * Params : addr - kernel memory address to clear | ||
106 | * : sz - number of bytes to clear | ||
107 | * Returns : number of bytes NOT cleared | ||
108 | */ | ||
109 | uaccess_kernel_clear: | ||
110 | stmfd sp!, {lr} | ||
111 | mov r2, #0 | ||
112 | cmp r1, #4 | ||
113 | blt 2f | ||
114 | ands ip, r0, #3 | ||
115 | beq 1f | ||
116 | cmp ip, #1 | ||
117 | strb r2, [r0], #1 | ||
118 | strleb r2, [r0], #1 | ||
119 | strltb r2, [r0], #1 | ||
120 | rsb ip, ip, #4 | ||
121 | sub r1, r1, ip @ 7 6 5 4 3 2 1 | ||
122 | 1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 | ||
123 | bmi 2f | ||
124 | str r2, [r0], #4 | ||
125 | str r2, [r0], #4 | ||
126 | b 1b | ||
127 | 2: adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 | ||
128 | strpl r2, [r0], #4 | ||
129 | tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x | ||
130 | strneb r2, [r0], #1 | ||
131 | strneb r2, [r0], #1 | ||
132 | tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 | ||
133 | strneb r2, [r0], #1 | ||
134 | mov r0, #0 | ||
135 | ldmfd sp!, {pc}^ | ||
136 | |||
137 | /* Prototype: size_t uaccess_kernel_strncpy(char *dst, char *src, size_t len) | ||
138 | * Purpose : copy a string from kernel memory to kernel memory | ||
139 | * Params : dst - kernel memory destination | ||
140 | * : src - kernel memory source | ||
141 | * : len - maximum length of string | ||
142 | * Returns : number of characters copied | ||
143 | */ | ||
144 | uaccess_kernel_strncpy: | ||
145 | stmfd sp!, {lr} | ||
146 | mov ip, r2 | ||
147 | 1: subs r2, r2, #1 | ||
148 | bmi 2f | ||
149 | ldrb r3, [r1], #1 | ||
150 | strb r3, [r0], #1 | ||
151 | teq r3, #0 | ||
152 | bne 1b | ||
153 | 2: subs r0, ip, r2 | ||
154 | ldmfd sp!, {pc}^ | ||
155 | |||
156 | /* Prototype: int uaccess_kernel_strlen(char *str, long n) | ||
157 | * Purpose : get length of a string in kernel memory | ||
158 | * Params : str - address of string in kernel memory | ||
159 | * Returns : length of string *including terminator*, | ||
160 | * or zero on exception, or n + 1 if too long | ||
161 | */ | ||
162 | uaccess_kernel_strnlen: | ||
163 | stmfd sp!, {lr} | ||
164 | mov r2, r0 | ||
165 | 1: ldrb r1, [r0], #1 | ||
166 | teq r1, #0 | ||
167 | beq 2f | ||
168 | subs r1, r1, #1 | ||
169 | bne 1b | ||
170 | add r0, r0, #1 | ||
171 | 2: sub r0, r0, r2 | ||
172 | ldmfd sp!, {pc}^ | ||
173 | |||
diff --git a/arch/arm26/lib/uaccess-user.S b/arch/arm26/lib/uaccess-user.S new file mode 100644 index 000000000000..130b8f28610a --- /dev/null +++ b/arch/arm26/lib/uaccess-user.S | |||
@@ -0,0 +1,718 @@ | |||
1 | /* | ||
2 | * linux/arch/arm26/lib/uaccess-user.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 | #include <asm/page.h> | ||
18 | |||
19 | .text | ||
20 | |||
21 | //FIXME - surely this can be done in C not asm, removing the problem of keeping C and asm in sync? (this is a struct uaccess_t) | ||
22 | .globl uaccess_user | ||
23 | uaccess_user: | ||
24 | .word uaccess_user_put_byte | ||
25 | .word uaccess_user_get_byte | ||
26 | .word uaccess_user_put_half | ||
27 | .word uaccess_user_get_half | ||
28 | .word uaccess_user_put_word | ||
29 | .word uaccess_user_get_word | ||
30 | .word uaccess_user_put_dword | ||
31 | .word uaccess_user_copy_from_user | ||
32 | .word uaccess_user_copy_to_user | ||
33 | .word uaccess_user_clear_user | ||
34 | .word uaccess_user_strncpy_from_user | ||
35 | .word uaccess_user_strnlen_user | ||
36 | |||
37 | |||
38 | @ In : r0 = x, r1 = addr, r2 = error | ||
39 | @ Out: r2 = error | ||
40 | uaccess_user_put_byte: | ||
41 | stmfd sp!, {lr} | ||
42 | USER( strbt r0, [r1]) | ||
43 | ldmfd sp!, {pc}^ | ||
44 | |||
45 | @ In : r0 = x, r1 = addr, r2 = error | ||
46 | @ Out: r2 = error | ||
47 | uaccess_user_put_half: | ||
48 | stmfd sp!, {lr} | ||
49 | USER( strbt r0, [r1], #1) | ||
50 | mov r0, r0, lsr #8 | ||
51 | USER( strbt r0, [r1]) | ||
52 | ldmfd sp!, {pc}^ | ||
53 | |||
54 | @ In : r0 = x, r1 = addr, r2 = error | ||
55 | @ Out: r2 = error | ||
56 | uaccess_user_put_word: | ||
57 | stmfd sp!, {lr} | ||
58 | USER( strt r0, [r1]) | ||
59 | ldmfd sp!, {pc}^ | ||
60 | |||
61 | @ In : r0 = x, r1 = addr, r2 = error | ||
62 | @ Out: r2 = error | ||
63 | uaccess_user_put_dword: | ||
64 | stmfd sp!, {lr} | ||
65 | USER( strt r0, [r1], #4) | ||
66 | USER( strt r0, [r1], #0) | ||
67 | ldmfd sp!, {pc}^ | ||
68 | |||
69 | 9001: mov r2, #-EFAULT | ||
70 | ldmfd sp!, {pc}^ | ||
71 | |||
72 | |||
73 | @ In : r0 = addr, r1 = error | ||
74 | @ Out: r0 = x, r1 = error | ||
75 | uaccess_user_get_byte: | ||
76 | stmfd sp!, {lr} | ||
77 | USER( ldrbt r0, [r0]) | ||
78 | ldmfd sp!, {pc}^ | ||
79 | |||
80 | @ In : r0 = addr, r1 = error | ||
81 | @ Out: r0 = x, r1 = error | ||
82 | uaccess_user_get_half: | ||
83 | stmfd sp!, {lr} | ||
84 | USER( ldrt r0, [r0]) | ||
85 | mov r0, r0, lsl #16 | ||
86 | mov r0, r0, lsr #16 | ||
87 | ldmfd sp!, {pc}^ | ||
88 | |||
89 | @ In : r0 = addr, r1 = error | ||
90 | @ Out: r0 = x, r1 = error | ||
91 | uaccess_user_get_word: | ||
92 | stmfd sp!, {lr} | ||
93 | USER( ldrt r0, [r0]) | ||
94 | ldmfd sp!, {pc}^ | ||
95 | |||
96 | 9001: mov r1, #-EFAULT | ||
97 | ldmfd sp!, {pc}^ | ||
98 | |||
99 | /* Prototype: int uaccess_user_copy_to_user(void *to, const char *from, size_t n) | ||
100 | * Purpose : copy a block to user memory from kernel memory | ||
101 | * Params : to - user memory | ||
102 | * : from - kernel memory | ||
103 | * : n - number of bytes to copy | ||
104 | * Returns : Number of bytes NOT copied. | ||
105 | */ | ||
106 | |||
107 | .c2u_dest_not_aligned: | ||
108 | rsb ip, ip, #4 | ||
109 | 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 | sub r2, r2, ip | ||
117 | b .c2u_dest_aligned | ||
118 | |||
119 | ENTRY(uaccess_user_copy_to_user) | ||
120 | stmfd sp!, {r2, r4 - r7, lr} | ||
121 | cmp r2, #4 | ||
122 | blt .c2u_not_enough | ||
123 | ands ip, r0, #3 | ||
124 | bne .c2u_dest_not_aligned | ||
125 | .c2u_dest_aligned: | ||
126 | |||
127 | ands ip, r1, #3 | ||
128 | bne .c2u_src_not_aligned | ||
129 | /* | ||
130 | * Seeing as there has to be at least 8 bytes to copy, we can | ||
131 | * copy one word, and force a user-mode page fault... | ||
132 | */ | ||
133 | |||
134 | .c2u_0fupi: subs r2, r2, #4 | ||
135 | addmi ip, r2, #4 | ||
136 | bmi .c2u_0nowords | ||
137 | ldr r3, [r1], #4 | ||
138 | USER( strt r3, [r0], #4) @ May fault | ||
139 | mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction | ||
140 | rsb ip, ip, #0 | ||
141 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
142 | beq .c2u_0fupi | ||
143 | /* | ||
144 | * ip = max no. of bytes to copy before needing another "strt" insn | ||
145 | */ | ||
146 | cmp r2, ip | ||
147 | movlt ip, r2 | ||
148 | sub r2, r2, ip | ||
149 | subs ip, ip, #32 | ||
150 | blt .c2u_0rem8lp | ||
151 | |||
152 | .c2u_0cpy8lp: ldmia r1!, {r3 - r6} | ||
153 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
154 | ldmia r1!, {r3 - r6} | ||
155 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
156 | subs ip, ip, #32 | ||
157 | bpl .c2u_0cpy8lp | ||
158 | .c2u_0rem8lp: cmn ip, #16 | ||
159 | ldmgeia r1!, {r3 - r6} | ||
160 | stmgeia r0!, {r3 - r6} @ Shouldnt fault | ||
161 | tst ip, #8 | ||
162 | ldmneia r1!, {r3 - r4} | ||
163 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
164 | tst ip, #4 | ||
165 | ldrne r3, [r1], #4 | ||
166 | strnet r3, [r0], #4 @ Shouldnt fault | ||
167 | ands ip, ip, #3 | ||
168 | beq .c2u_0fupi | ||
169 | .c2u_0nowords: teq ip, #0 | ||
170 | beq .c2u_finished | ||
171 | .c2u_nowords: cmp ip, #2 | ||
172 | ldrb r3, [r1], #1 | ||
173 | USER( strbt r3, [r0], #1) @ May fault | ||
174 | ldrgeb r3, [r1], #1 | ||
175 | USER( strgebt r3, [r0], #1) @ May fault | ||
176 | ldrgtb r3, [r1], #1 | ||
177 | USER( strgtbt r3, [r0], #1) @ May fault | ||
178 | b .c2u_finished | ||
179 | |||
180 | .c2u_not_enough: | ||
181 | movs ip, r2 | ||
182 | bne .c2u_nowords | ||
183 | .c2u_finished: mov r0, #0 | ||
184 | LOADREGS(fd,sp!,{r2, r4 - r7, pc}) | ||
185 | |||
186 | .c2u_src_not_aligned: | ||
187 | bic r1, r1, #3 | ||
188 | ldr r7, [r1], #4 | ||
189 | cmp ip, #2 | ||
190 | bgt .c2u_3fupi | ||
191 | beq .c2u_2fupi | ||
192 | .c2u_1fupi: subs r2, r2, #4 | ||
193 | addmi ip, r2, #4 | ||
194 | bmi .c2u_1nowords | ||
195 | mov r3, r7, pull #8 | ||
196 | ldr r7, [r1], #4 | ||
197 | orr r3, r3, r7, push #24 | ||
198 | USER( strt r3, [r0], #4) @ May fault | ||
199 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
200 | rsb ip, ip, #0 | ||
201 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
202 | beq .c2u_1fupi | ||
203 | cmp r2, ip | ||
204 | movlt ip, r2 | ||
205 | sub r2, r2, ip | ||
206 | subs ip, ip, #16 | ||
207 | blt .c2u_1rem8lp | ||
208 | |||
209 | .c2u_1cpy8lp: mov r3, r7, pull #8 | ||
210 | ldmia r1!, {r4 - r7} | ||
211 | orr r3, r3, r4, push #24 | ||
212 | mov r4, r4, pull #8 | ||
213 | orr r4, r4, r5, push #24 | ||
214 | mov r5, r5, pull #8 | ||
215 | orr r5, r5, r6, push #24 | ||
216 | mov r6, r6, pull #8 | ||
217 | orr r6, r6, r7, push #24 | ||
218 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
219 | subs ip, ip, #16 | ||
220 | bpl .c2u_1cpy8lp | ||
221 | .c2u_1rem8lp: tst ip, #8 | ||
222 | movne r3, r7, pull #8 | ||
223 | ldmneia r1!, {r4, r7} | ||
224 | orrne r3, r3, r4, push #24 | ||
225 | movne r4, r4, pull #8 | ||
226 | orrne r4, r4, r7, push #24 | ||
227 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
228 | tst ip, #4 | ||
229 | movne r3, r7, pull #8 | ||
230 | ldrne r7, [r1], #4 | ||
231 | orrne r3, r3, r7, push #24 | ||
232 | strnet r3, [r0], #4 @ Shouldnt fault | ||
233 | ands ip, ip, #3 | ||
234 | beq .c2u_1fupi | ||
235 | .c2u_1nowords: mov r3, r7, lsr #byte(1) | ||
236 | teq ip, #0 | ||
237 | beq .c2u_finished | ||
238 | cmp ip, #2 | ||
239 | USER( strbt r3, [r0], #1) @ May fault | ||
240 | movge r3, r7, lsr #byte(2) | ||
241 | USER( strgebt r3, [r0], #1) @ May fault | ||
242 | movgt r3, r7, lsr #byte(3) | ||
243 | USER( strgtbt r3, [r0], #1) @ May fault | ||
244 | b .c2u_finished | ||
245 | |||
246 | .c2u_2fupi: subs r2, r2, #4 | ||
247 | addmi ip, r2, #4 | ||
248 | bmi .c2u_2nowords | ||
249 | mov r3, r7, pull #16 | ||
250 | ldr r7, [r1], #4 | ||
251 | orr r3, r3, r7, push #16 | ||
252 | USER( strt r3, [r0], #4) @ May fault | ||
253 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
254 | rsb ip, ip, #0 | ||
255 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
256 | beq .c2u_2fupi | ||
257 | cmp r2, ip | ||
258 | movlt ip, r2 | ||
259 | sub r2, r2, ip | ||
260 | subs ip, ip, #16 | ||
261 | blt .c2u_2rem8lp | ||
262 | |||
263 | .c2u_2cpy8lp: mov r3, r7, pull #16 | ||
264 | ldmia r1!, {r4 - r7} | ||
265 | orr r3, r3, r4, push #16 | ||
266 | mov r4, r4, pull #16 | ||
267 | orr r4, r4, r5, push #16 | ||
268 | mov r5, r5, pull #16 | ||
269 | orr r5, r5, r6, push #16 | ||
270 | mov r6, r6, pull #16 | ||
271 | orr r6, r6, r7, push #16 | ||
272 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
273 | subs ip, ip, #16 | ||
274 | bpl .c2u_2cpy8lp | ||
275 | .c2u_2rem8lp: tst ip, #8 | ||
276 | movne r3, r7, pull #16 | ||
277 | ldmneia r1!, {r4, r7} | ||
278 | orrne r3, r3, r4, push #16 | ||
279 | movne r4, r4, pull #16 | ||
280 | orrne r4, r4, r7, push #16 | ||
281 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
282 | tst ip, #4 | ||
283 | movne r3, r7, pull #16 | ||
284 | ldrne r7, [r1], #4 | ||
285 | orrne r3, r3, r7, push #16 | ||
286 | strnet r3, [r0], #4 @ Shouldnt fault | ||
287 | ands ip, ip, #3 | ||
288 | beq .c2u_2fupi | ||
289 | .c2u_2nowords: mov r3, r7, lsr #byte(2) | ||
290 | teq ip, #0 | ||
291 | beq .c2u_finished | ||
292 | cmp ip, #2 | ||
293 | USER( strbt r3, [r0], #1) @ May fault | ||
294 | movge r3, r7, lsr #byte(3) | ||
295 | USER( strgebt r3, [r0], #1) @ May fault | ||
296 | ldrgtb r3, [r1], #0 | ||
297 | USER( strgtbt r3, [r0], #1) @ May fault | ||
298 | b .c2u_finished | ||
299 | |||
300 | .c2u_3fupi: subs r2, r2, #4 | ||
301 | addmi ip, r2, #4 | ||
302 | bmi .c2u_3nowords | ||
303 | mov r3, r7, pull #24 | ||
304 | ldr r7, [r1], #4 | ||
305 | orr r3, r3, r7, push #8 | ||
306 | USER( strt r3, [r0], #4) @ May fault | ||
307 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
308 | rsb ip, ip, #0 | ||
309 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
310 | beq .c2u_3fupi | ||
311 | cmp r2, ip | ||
312 | movlt ip, r2 | ||
313 | sub r2, r2, ip | ||
314 | subs ip, ip, #16 | ||
315 | blt .c2u_3rem8lp | ||
316 | |||
317 | .c2u_3cpy8lp: mov r3, r7, pull #24 | ||
318 | ldmia r1!, {r4 - r7} | ||
319 | orr r3, r3, r4, push #8 | ||
320 | mov r4, r4, pull #24 | ||
321 | orr r4, r4, r5, push #8 | ||
322 | mov r5, r5, pull #24 | ||
323 | orr r5, r5, r6, push #8 | ||
324 | mov r6, r6, pull #24 | ||
325 | orr r6, r6, r7, push #8 | ||
326 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
327 | subs ip, ip, #16 | ||
328 | bpl .c2u_3cpy8lp | ||
329 | .c2u_3rem8lp: tst ip, #8 | ||
330 | movne r3, r7, pull #24 | ||
331 | ldmneia r1!, {r4, r7} | ||
332 | orrne r3, r3, r4, push #8 | ||
333 | movne r4, r4, pull #24 | ||
334 | orrne r4, r4, r7, push #8 | ||
335 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
336 | tst ip, #4 | ||
337 | movne r3, r7, pull #24 | ||
338 | ldrne r7, [r1], #4 | ||
339 | orrne r3, r3, r7, push #8 | ||
340 | strnet r3, [r0], #4 @ Shouldnt fault | ||
341 | ands ip, ip, #3 | ||
342 | beq .c2u_3fupi | ||
343 | .c2u_3nowords: mov r3, r7, lsr #byte(3) | ||
344 | teq ip, #0 | ||
345 | beq .c2u_finished | ||
346 | cmp ip, #2 | ||
347 | USER( strbt r3, [r0], #1) @ May fault | ||
348 | ldrgeb r3, [r1], #1 | ||
349 | USER( strgebt r3, [r0], #1) @ May fault | ||
350 | ldrgtb r3, [r1], #0 | ||
351 | USER( strgtbt r3, [r0], #1) @ May fault | ||
352 | b .c2u_finished | ||
353 | |||
354 | .section .fixup,"ax" | ||
355 | .align 0 | ||
356 | 9001: LOADREGS(fd,sp!, {r0, r4 - r7, pc}) | ||
357 | .previous | ||
358 | |||
359 | /* Prototype: unsigned long uaccess_user_copy_from_user(void *to,const void *from,unsigned long n); | ||
360 | * Purpose : copy a block from user memory to kernel memory | ||
361 | * Params : to - kernel memory | ||
362 | * : from - user memory | ||
363 | * : n - number of bytes to copy | ||
364 | * Returns : Number of bytes NOT copied. | ||
365 | */ | ||
366 | .cfu_dest_not_aligned: | ||
367 | rsb ip, ip, #4 | ||
368 | cmp ip, #2 | ||
369 | USER( ldrbt r3, [r1], #1) @ May fault | ||
370 | strb r3, [r0], #1 | ||
371 | USER( ldrgebt r3, [r1], #1) @ May fault | ||
372 | strgeb r3, [r0], #1 | ||
373 | USER( ldrgtbt r3, [r1], #1) @ May fault | ||
374 | strgtb r3, [r0], #1 | ||
375 | sub r2, r2, ip | ||
376 | b .cfu_dest_aligned | ||
377 | |||
378 | ENTRY(uaccess_user_copy_from_user) | ||
379 | stmfd sp!, {r0, r2, r4 - r7, lr} | ||
380 | cmp r2, #4 | ||
381 | blt .cfu_not_enough | ||
382 | ands ip, r0, #3 | ||
383 | bne .cfu_dest_not_aligned | ||
384 | .cfu_dest_aligned: | ||
385 | ands ip, r1, #3 | ||
386 | bne .cfu_src_not_aligned | ||
387 | /* | ||
388 | * Seeing as there has to be at least 8 bytes to copy, we can | ||
389 | * copy one word, and force a user-mode page fault... | ||
390 | */ | ||
391 | |||
392 | .cfu_0fupi: subs r2, r2, #4 | ||
393 | addmi ip, r2, #4 | ||
394 | bmi .cfu_0nowords | ||
395 | USER( ldrt r3, [r1], #4) | ||
396 | str r3, [r0], #4 | ||
397 | mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction | ||
398 | rsb ip, ip, #0 | ||
399 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
400 | beq .cfu_0fupi | ||
401 | /* | ||
402 | * ip = max no. of bytes to copy before needing another "strt" insn | ||
403 | */ | ||
404 | cmp r2, ip | ||
405 | movlt ip, r2 | ||
406 | sub r2, r2, ip | ||
407 | subs ip, ip, #32 | ||
408 | blt .cfu_0rem8lp | ||
409 | |||
410 | .cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault | ||
411 | stmia r0!, {r3 - r6} | ||
412 | ldmia r1!, {r3 - r6} @ Shouldnt fault | ||
413 | stmia r0!, {r3 - r6} | ||
414 | subs ip, ip, #32 | ||
415 | bpl .cfu_0cpy8lp | ||
416 | .cfu_0rem8lp: cmn ip, #16 | ||
417 | ldmgeia r1!, {r3 - r6} @ Shouldnt fault | ||
418 | stmgeia r0!, {r3 - r6} | ||
419 | tst ip, #8 | ||
420 | ldmneia r1!, {r3 - r4} @ Shouldnt fault | ||
421 | stmneia r0!, {r3 - r4} | ||
422 | tst ip, #4 | ||
423 | ldrnet r3, [r1], #4 @ Shouldnt fault | ||
424 | strne r3, [r0], #4 | ||
425 | ands ip, ip, #3 | ||
426 | beq .cfu_0fupi | ||
427 | .cfu_0nowords: teq ip, #0 | ||
428 | beq .cfu_finished | ||
429 | .cfu_nowords: cmp ip, #2 | ||
430 | USER( ldrbt r3, [r1], #1) @ May fault | ||
431 | strb r3, [r0], #1 | ||
432 | USER( ldrgebt r3, [r1], #1) @ May fault | ||
433 | strgeb r3, [r0], #1 | ||
434 | USER( ldrgtbt r3, [r1], #1) @ May fault | ||
435 | strgtb r3, [r0], #1 | ||
436 | b .cfu_finished | ||
437 | |||
438 | .cfu_not_enough: | ||
439 | movs ip, r2 | ||
440 | bne .cfu_nowords | ||
441 | .cfu_finished: mov r0, #0 | ||
442 | add sp, sp, #8 | ||
443 | LOADREGS(fd,sp!,{r4 - r7, pc}) | ||
444 | |||
445 | .cfu_src_not_aligned: | ||
446 | bic r1, r1, #3 | ||
447 | USER( ldrt r7, [r1], #4) @ May fault | ||
448 | cmp ip, #2 | ||
449 | bgt .cfu_3fupi | ||
450 | beq .cfu_2fupi | ||
451 | .cfu_1fupi: subs r2, r2, #4 | ||
452 | addmi ip, r2, #4 | ||
453 | bmi .cfu_1nowords | ||
454 | mov r3, r7, pull #8 | ||
455 | USER( ldrt r7, [r1], #4) @ May fault | ||
456 | orr r3, r3, r7, push #24 | ||
457 | str r3, [r0], #4 | ||
458 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
459 | rsb ip, ip, #0 | ||
460 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
461 | beq .cfu_1fupi | ||
462 | cmp r2, ip | ||
463 | movlt ip, r2 | ||
464 | sub r2, r2, ip | ||
465 | subs ip, ip, #16 | ||
466 | blt .cfu_1rem8lp | ||
467 | |||
468 | .cfu_1cpy8lp: mov r3, r7, pull #8 | ||
469 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
470 | orr r3, r3, r4, push #24 | ||
471 | mov r4, r4, pull #8 | ||
472 | orr r4, r4, r5, push #24 | ||
473 | mov r5, r5, pull #8 | ||
474 | orr r5, r5, r6, push #24 | ||
475 | mov r6, r6, pull #8 | ||
476 | orr r6, r6, r7, push #24 | ||
477 | stmia r0!, {r3 - r6} | ||
478 | subs ip, ip, #16 | ||
479 | bpl .cfu_1cpy8lp | ||
480 | .cfu_1rem8lp: tst ip, #8 | ||
481 | movne r3, r7, pull #8 | ||
482 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
483 | orrne r3, r3, r4, push #24 | ||
484 | movne r4, r4, pull #8 | ||
485 | orrne r4, r4, r7, push #24 | ||
486 | stmneia r0!, {r3 - r4} | ||
487 | tst ip, #4 | ||
488 | movne r3, r7, pull #8 | ||
489 | USER( ldrnet r7, [r1], #4) @ May fault | ||
490 | orrne r3, r3, r7, push #24 | ||
491 | strne r3, [r0], #4 | ||
492 | ands ip, ip, #3 | ||
493 | beq .cfu_1fupi | ||
494 | .cfu_1nowords: mov r3, r7, lsr #byte(1) | ||
495 | teq ip, #0 | ||
496 | beq .cfu_finished | ||
497 | cmp ip, #2 | ||
498 | strb r3, [r0], #1 | ||
499 | movge r3, r7, lsr #byte(2) | ||
500 | strgeb r3, [r0], #1 | ||
501 | movgt r3, r7, lsr #byte(3) | ||
502 | strgtb r3, [r0], #1 | ||
503 | b .cfu_finished | ||
504 | |||
505 | .cfu_2fupi: subs r2, r2, #4 | ||
506 | addmi ip, r2, #4 | ||
507 | bmi .cfu_2nowords | ||
508 | mov r3, r7, pull #16 | ||
509 | USER( ldrt r7, [r1], #4) @ May fault | ||
510 | orr r3, r3, r7, push #16 | ||
511 | str r3, [r0], #4 | ||
512 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
513 | rsb ip, ip, #0 | ||
514 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
515 | beq .cfu_2fupi | ||
516 | cmp r2, ip | ||
517 | movlt ip, r2 | ||
518 | sub r2, r2, ip | ||
519 | subs ip, ip, #16 | ||
520 | blt .cfu_2rem8lp | ||
521 | |||
522 | .cfu_2cpy8lp: mov r3, r7, pull #16 | ||
523 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
524 | orr r3, r3, r4, push #16 | ||
525 | mov r4, r4, pull #16 | ||
526 | orr r4, r4, r5, push #16 | ||
527 | mov r5, r5, pull #16 | ||
528 | orr r5, r5, r6, push #16 | ||
529 | mov r6, r6, pull #16 | ||
530 | orr r6, r6, r7, push #16 | ||
531 | stmia r0!, {r3 - r6} | ||
532 | subs ip, ip, #16 | ||
533 | bpl .cfu_2cpy8lp | ||
534 | .cfu_2rem8lp: tst ip, #8 | ||
535 | movne r3, r7, pull #16 | ||
536 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
537 | orrne r3, r3, r4, push #16 | ||
538 | movne r4, r4, pull #16 | ||
539 | orrne r4, r4, r7, push #16 | ||
540 | stmneia r0!, {r3 - r4} | ||
541 | tst ip, #4 | ||
542 | movne r3, r7, pull #16 | ||
543 | USER( ldrnet r7, [r1], #4) @ May fault | ||
544 | orrne r3, r3, r7, push #16 | ||
545 | strne r3, [r0], #4 | ||
546 | ands ip, ip, #3 | ||
547 | beq .cfu_2fupi | ||
548 | .cfu_2nowords: mov r3, r7, lsr #byte(2) | ||
549 | teq ip, #0 | ||
550 | beq .cfu_finished | ||
551 | cmp ip, #2 | ||
552 | strb r3, [r0], #1 | ||
553 | movge r3, r7, lsr #byte(3) | ||
554 | strgeb r3, [r0], #1 | ||
555 | USER( ldrgtbt r3, [r1], #0) @ May fault | ||
556 | strgtb r3, [r0], #1 | ||
557 | b .cfu_finished | ||
558 | |||
559 | .cfu_3fupi: subs r2, r2, #4 | ||
560 | addmi ip, r2, #4 | ||
561 | bmi .cfu_3nowords | ||
562 | mov r3, r7, pull #24 | ||
563 | USER( ldrt r7, [r1], #4) @ May fault | ||
564 | orr r3, r3, r7, push #8 | ||
565 | str r3, [r0], #4 | ||
566 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
567 | rsb ip, ip, #0 | ||
568 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
569 | beq .cfu_3fupi | ||
570 | cmp r2, ip | ||
571 | movlt ip, r2 | ||
572 | sub r2, r2, ip | ||
573 | subs ip, ip, #16 | ||
574 | blt .cfu_3rem8lp | ||
575 | |||
576 | .cfu_3cpy8lp: mov r3, r7, pull #24 | ||
577 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
578 | orr r3, r3, r4, push #8 | ||
579 | mov r4, r4, pull #24 | ||
580 | orr r4, r4, r5, push #8 | ||
581 | mov r5, r5, pull #24 | ||
582 | orr r5, r5, r6, push #8 | ||
583 | mov r6, r6, pull #24 | ||
584 | orr r6, r6, r7, push #8 | ||
585 | stmia r0!, {r3 - r6} | ||
586 | subs ip, ip, #16 | ||
587 | bpl .cfu_3cpy8lp | ||
588 | .cfu_3rem8lp: tst ip, #8 | ||
589 | movne r3, r7, pull #24 | ||
590 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
591 | orrne r3, r3, r4, push #8 | ||
592 | movne r4, r4, pull #24 | ||
593 | orrne r4, r4, r7, push #8 | ||
594 | stmneia r0!, {r3 - r4} | ||
595 | tst ip, #4 | ||
596 | movne r3, r7, pull #24 | ||
597 | USER( ldrnet r7, [r1], #4) @ May fault | ||
598 | orrne r3, r3, r7, push #8 | ||
599 | strne r3, [r0], #4 | ||
600 | ands ip, ip, #3 | ||
601 | beq .cfu_3fupi | ||
602 | .cfu_3nowords: mov r3, r7, lsr #byte(3) | ||
603 | teq ip, #0 | ||
604 | beq .cfu_finished | ||
605 | cmp ip, #2 | ||
606 | strb r3, [r0], #1 | ||
607 | USER( ldrgebt r3, [r1], #1) @ May fault | ||
608 | strgeb r3, [r0], #1 | ||
609 | USER( ldrgtbt r3, [r1], #1) @ May fault | ||
610 | strgtb r3, [r0], #1 | ||
611 | b .cfu_finished | ||
612 | |||
613 | .section .fixup,"ax" | ||
614 | .align 0 | ||
615 | /* | ||
616 | * We took an exception. r0 contains a pointer to | ||
617 | * the byte not copied. | ||
618 | */ | ||
619 | 9001: ldr r2, [sp], #4 @ void *to | ||
620 | sub r2, r0, r2 @ bytes copied | ||
621 | ldr r1, [sp], #4 @ unsigned long count | ||
622 | subs r4, r1, r2 @ bytes left to copy | ||
623 | movne r1, r4 | ||
624 | blne __memzero | ||
625 | mov r0, r4 | ||
626 | LOADREGS(fd,sp!, {r4 - r7, pc}) | ||
627 | .previous | ||
628 | |||
629 | /* Prototype: int uaccess_user_clear_user(void *addr, size_t sz) | ||
630 | * Purpose : clear some user memory | ||
631 | * Params : addr - user memory address to clear | ||
632 | * : sz - number of bytes to clear | ||
633 | * Returns : number of bytes NOT cleared | ||
634 | */ | ||
635 | ENTRY(uaccess_user_clear_user) | ||
636 | stmfd sp!, {r1, lr} | ||
637 | mov r2, #0 | ||
638 | cmp r1, #4 | ||
639 | blt 2f | ||
640 | ands ip, r0, #3 | ||
641 | beq 1f | ||
642 | cmp ip, #2 | ||
643 | USER( strbt r2, [r0], #1) | ||
644 | USER( strlebt r2, [r0], #1) | ||
645 | USER( strltbt r2, [r0], #1) | ||
646 | rsb ip, ip, #4 | ||
647 | sub r1, r1, ip @ 7 6 5 4 3 2 1 | ||
648 | 1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 | ||
649 | USER( strplt r2, [r0], #4) | ||
650 | USER( strplt r2, [r0], #4) | ||
651 | bpl 1b | ||
652 | adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 | ||
653 | USER( strplt r2, [r0], #4) | ||
654 | 2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x | ||
655 | USER( strnebt r2, [r0], #1) | ||
656 | USER( strnebt r2, [r0], #1) | ||
657 | tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 | ||
658 | USER( strnebt r2, [r0], #1) | ||
659 | mov r0, #0 | ||
660 | LOADREGS(fd,sp!, {r1, pc}) | ||
661 | |||
662 | .section .fixup,"ax" | ||
663 | .align 0 | ||
664 | 9001: LOADREGS(fd,sp!, {r0, pc}) | ||
665 | .previous | ||
666 | |||
667 | /* | ||
668 | * Copy a string from user space to kernel space. | ||
669 | * r0 = dst, r1 = src, r2 = byte length | ||
670 | * returns the number of characters copied (strlen of copied string), | ||
671 | * -EFAULT on exception, or "len" if we fill the whole buffer | ||
672 | */ | ||
673 | ENTRY(uaccess_user_strncpy_from_user) | ||
674 | save_lr | ||
675 | mov ip, r1 | ||
676 | 1: subs r2, r2, #1 | ||
677 | USER( ldrplbt r3, [r1], #1) | ||
678 | bmi 2f | ||
679 | strb r3, [r0], #1 | ||
680 | teq r3, #0 | ||
681 | bne 1b | ||
682 | sub r1, r1, #1 @ take NUL character out of count | ||
683 | 2: sub r0, r1, ip | ||
684 | restore_pc | ||
685 | |||
686 | .section .fixup,"ax" | ||
687 | .align 0 | ||
688 | 9001: mov r3, #0 | ||
689 | strb r3, [r0, #0] @ null terminate | ||
690 | mov r0, #-EFAULT | ||
691 | restore_pc | ||
692 | .previous | ||
693 | |||
694 | /* Prototype: unsigned long uaccess_user_strnlen_user(const char *str, long n) | ||
695 | * Purpose : get length of a string in user memory | ||
696 | * Params : str - address of string in user memory | ||
697 | * Returns : length of string *including terminator* | ||
698 | * or zero on exception, or n + 1 if too long | ||
699 | */ | ||
700 | ENTRY(uaccess_user_strnlen_user) | ||
701 | save_lr | ||
702 | mov r2, r0 | ||
703 | 1: | ||
704 | USER( ldrbt r3, [r0], #1) | ||
705 | teq r3, #0 | ||
706 | beq 2f | ||
707 | subs r1, r1, #1 | ||
708 | bne 1b | ||
709 | add r0, r0, #1 | ||
710 | 2: sub r0, r0, r2 | ||
711 | restore_pc | ||
712 | |||
713 | .section .fixup,"ax" | ||
714 | .align 0 | ||
715 | 9001: mov r0, #0 | ||
716 | restore_pc | ||
717 | .previous | ||
718 | |||
diff --git a/arch/arm26/lib/ucmpdi2.c b/arch/arm26/lib/ucmpdi2.c new file mode 100644 index 000000000000..6c6ae63efa02 --- /dev/null +++ b/arch/arm26/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/arm26/lib/udivdi3.c b/arch/arm26/lib/udivdi3.c new file mode 100644 index 000000000000..d25195f673f4 --- /dev/null +++ b/arch/arm26/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 | |||