diff options
Diffstat (limited to 'arch/ppc/lib')
-rw-r--r-- | arch/ppc/lib/Makefile | 5 | ||||
-rw-r--r-- | arch/ppc/lib/checksum.S | 225 | ||||
-rw-r--r-- | arch/ppc/lib/div64.S | 58 | ||||
-rw-r--r-- | arch/ppc/lib/locks.c | 189 | ||||
-rw-r--r-- | arch/ppc/lib/string.S | 732 |
5 files changed, 0 insertions, 1209 deletions
diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile deleted file mode 100644 index 095e661e79dd..000000000000 --- a/arch/ppc/lib/Makefile +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | # | ||
2 | # Makefile for ppc-specific library files.. | ||
3 | # | ||
4 | |||
5 | obj-y := checksum.o string.o div64.o | ||
diff --git a/arch/ppc/lib/checksum.S b/arch/ppc/lib/checksum.S deleted file mode 100644 index 7874e8a80455..000000000000 --- a/arch/ppc/lib/checksum.S +++ /dev/null | |||
@@ -1,225 +0,0 @@ | |||
1 | /* | ||
2 | * This file contains assembly-language implementations | ||
3 | * of IP-style 1's complement checksum routines. | ||
4 | * | ||
5 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au). | ||
13 | */ | ||
14 | |||
15 | #include <linux/sys.h> | ||
16 | #include <asm/processor.h> | ||
17 | #include <asm/errno.h> | ||
18 | #include <asm/ppc_asm.h> | ||
19 | |||
20 | .text | ||
21 | |||
22 | /* | ||
23 | * ip_fast_csum(buf, len) -- Optimized for IP header | ||
24 | * len is in words and is always >= 5. | ||
25 | */ | ||
26 | _GLOBAL(ip_fast_csum) | ||
27 | lwz r0,0(r3) | ||
28 | lwzu r5,4(r3) | ||
29 | addic. r4,r4,-2 | ||
30 | addc r0,r0,r5 | ||
31 | mtctr r4 | ||
32 | blelr- | ||
33 | 1: lwzu r4,4(r3) | ||
34 | adde r0,r0,r4 | ||
35 | bdnz 1b | ||
36 | addze r0,r0 /* add in final carry */ | ||
37 | rlwinm r3,r0,16,0,31 /* fold two halves together */ | ||
38 | add r3,r0,r3 | ||
39 | not r3,r3 | ||
40 | srwi r3,r3,16 | ||
41 | blr | ||
42 | |||
43 | /* | ||
44 | * Compute checksum of TCP or UDP pseudo-header: | ||
45 | * csum_tcpudp_magic(saddr, daddr, len, proto, sum) | ||
46 | */ | ||
47 | _GLOBAL(csum_tcpudp_magic) | ||
48 | rlwimi r5,r6,16,0,15 /* put proto in upper half of len */ | ||
49 | addc r0,r3,r4 /* add 4 32-bit words together */ | ||
50 | adde r0,r0,r5 | ||
51 | adde r0,r0,r7 | ||
52 | addze r0,r0 /* add in final carry */ | ||
53 | rlwinm r3,r0,16,0,31 /* fold two halves together */ | ||
54 | add r3,r0,r3 | ||
55 | not r3,r3 | ||
56 | srwi r3,r3,16 | ||
57 | blr | ||
58 | |||
59 | /* | ||
60 | * computes the checksum of a memory block at buff, length len, | ||
61 | * and adds in "sum" (32-bit) | ||
62 | * | ||
63 | * csum_partial(buff, len, sum) | ||
64 | */ | ||
65 | _GLOBAL(csum_partial) | ||
66 | addic r0,r5,0 | ||
67 | subi r3,r3,4 | ||
68 | srwi. r6,r4,2 | ||
69 | beq 3f /* if we're doing < 4 bytes */ | ||
70 | andi. r5,r3,2 /* Align buffer to longword boundary */ | ||
71 | beq+ 1f | ||
72 | lhz r5,4(r3) /* do 2 bytes to get aligned */ | ||
73 | addi r3,r3,2 | ||
74 | subi r4,r4,2 | ||
75 | addc r0,r0,r5 | ||
76 | srwi. r6,r4,2 /* # words to do */ | ||
77 | beq 3f | ||
78 | 1: mtctr r6 | ||
79 | 2: lwzu r5,4(r3) /* the bdnz has zero overhead, so it should */ | ||
80 | adde r0,r0,r5 /* be unnecessary to unroll this loop */ | ||
81 | bdnz 2b | ||
82 | andi. r4,r4,3 | ||
83 | 3: cmpwi 0,r4,2 | ||
84 | blt+ 4f | ||
85 | lhz r5,4(r3) | ||
86 | addi r3,r3,2 | ||
87 | subi r4,r4,2 | ||
88 | adde r0,r0,r5 | ||
89 | 4: cmpwi 0,r4,1 | ||
90 | bne+ 5f | ||
91 | lbz r5,4(r3) | ||
92 | slwi r5,r5,8 /* Upper byte of word */ | ||
93 | adde r0,r0,r5 | ||
94 | 5: addze r3,r0 /* add in final carry */ | ||
95 | blr | ||
96 | |||
97 | /* | ||
98 | * Computes the checksum of a memory block at src, length len, | ||
99 | * and adds in "sum" (32-bit), while copying the block to dst. | ||
100 | * If an access exception occurs on src or dst, it stores -EFAULT | ||
101 | * to *src_err or *dst_err respectively, and (for an error on | ||
102 | * src) zeroes the rest of dst. | ||
103 | * | ||
104 | * csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err) | ||
105 | */ | ||
106 | _GLOBAL(csum_partial_copy_generic) | ||
107 | addic r0,r6,0 | ||
108 | subi r3,r3,4 | ||
109 | subi r4,r4,4 | ||
110 | srwi. r6,r5,2 | ||
111 | beq 3f /* if we're doing < 4 bytes */ | ||
112 | andi. r9,r4,2 /* Align dst to longword boundary */ | ||
113 | beq+ 1f | ||
114 | 81: lhz r6,4(r3) /* do 2 bytes to get aligned */ | ||
115 | addi r3,r3,2 | ||
116 | subi r5,r5,2 | ||
117 | 91: sth r6,4(r4) | ||
118 | addi r4,r4,2 | ||
119 | addc r0,r0,r6 | ||
120 | srwi. r6,r5,2 /* # words to do */ | ||
121 | beq 3f | ||
122 | 1: srwi. r6,r5,4 /* # groups of 4 words to do */ | ||
123 | beq 10f | ||
124 | mtctr r6 | ||
125 | 71: lwz r6,4(r3) | ||
126 | 72: lwz r9,8(r3) | ||
127 | 73: lwz r10,12(r3) | ||
128 | 74: lwzu r11,16(r3) | ||
129 | adde r0,r0,r6 | ||
130 | 75: stw r6,4(r4) | ||
131 | adde r0,r0,r9 | ||
132 | 76: stw r9,8(r4) | ||
133 | adde r0,r0,r10 | ||
134 | 77: stw r10,12(r4) | ||
135 | adde r0,r0,r11 | ||
136 | 78: stwu r11,16(r4) | ||
137 | bdnz 71b | ||
138 | 10: rlwinm. r6,r5,30,30,31 /* # words left to do */ | ||
139 | beq 13f | ||
140 | mtctr r6 | ||
141 | 82: lwzu r9,4(r3) | ||
142 | 92: stwu r9,4(r4) | ||
143 | adde r0,r0,r9 | ||
144 | bdnz 82b | ||
145 | 13: andi. r5,r5,3 | ||
146 | 3: cmpwi 0,r5,2 | ||
147 | blt+ 4f | ||
148 | 83: lhz r6,4(r3) | ||
149 | addi r3,r3,2 | ||
150 | subi r5,r5,2 | ||
151 | 93: sth r6,4(r4) | ||
152 | addi r4,r4,2 | ||
153 | adde r0,r0,r6 | ||
154 | 4: cmpwi 0,r5,1 | ||
155 | bne+ 5f | ||
156 | 84: lbz r6,4(r3) | ||
157 | 94: stb r6,4(r4) | ||
158 | slwi r6,r6,8 /* Upper byte of word */ | ||
159 | adde r0,r0,r6 | ||
160 | 5: addze r3,r0 /* add in final carry */ | ||
161 | blr | ||
162 | |||
163 | /* These shouldn't go in the fixup section, since that would | ||
164 | cause the ex_table addresses to get out of order. */ | ||
165 | |||
166 | src_error_4: | ||
167 | mfctr r6 /* update # bytes remaining from ctr */ | ||
168 | rlwimi r5,r6,4,0,27 | ||
169 | b 79f | ||
170 | src_error_1: | ||
171 | li r6,0 | ||
172 | subi r5,r5,2 | ||
173 | 95: sth r6,4(r4) | ||
174 | addi r4,r4,2 | ||
175 | 79: srwi. r6,r5,2 | ||
176 | beq 3f | ||
177 | mtctr r6 | ||
178 | src_error_2: | ||
179 | li r6,0 | ||
180 | 96: stwu r6,4(r4) | ||
181 | bdnz 96b | ||
182 | 3: andi. r5,r5,3 | ||
183 | beq src_error | ||
184 | src_error_3: | ||
185 | li r6,0 | ||
186 | mtctr r5 | ||
187 | addi r4,r4,3 | ||
188 | 97: stbu r6,1(r4) | ||
189 | bdnz 97b | ||
190 | src_error: | ||
191 | cmpwi 0,r7,0 | ||
192 | beq 1f | ||
193 | li r6,-EFAULT | ||
194 | stw r6,0(r7) | ||
195 | 1: addze r3,r0 | ||
196 | blr | ||
197 | |||
198 | dst_error: | ||
199 | cmpwi 0,r8,0 | ||
200 | beq 1f | ||
201 | li r6,-EFAULT | ||
202 | stw r6,0(r8) | ||
203 | 1: addze r3,r0 | ||
204 | blr | ||
205 | |||
206 | .section __ex_table,"a" | ||
207 | .long 81b,src_error_1 | ||
208 | .long 91b,dst_error | ||
209 | .long 71b,src_error_4 | ||
210 | .long 72b,src_error_4 | ||
211 | .long 73b,src_error_4 | ||
212 | .long 74b,src_error_4 | ||
213 | .long 75b,dst_error | ||
214 | .long 76b,dst_error | ||
215 | .long 77b,dst_error | ||
216 | .long 78b,dst_error | ||
217 | .long 82b,src_error_2 | ||
218 | .long 92b,dst_error | ||
219 | .long 83b,src_error_3 | ||
220 | .long 93b,dst_error | ||
221 | .long 84b,src_error_3 | ||
222 | .long 94b,dst_error | ||
223 | .long 95b,dst_error | ||
224 | .long 96b,dst_error | ||
225 | .long 97b,dst_error | ||
diff --git a/arch/ppc/lib/div64.S b/arch/ppc/lib/div64.S deleted file mode 100644 index 3527569e9926..000000000000 --- a/arch/ppc/lib/div64.S +++ /dev/null | |||
@@ -1,58 +0,0 @@ | |||
1 | /* | ||
2 | * Divide a 64-bit unsigned number by a 32-bit unsigned number. | ||
3 | * This routine assumes that the top 32 bits of the dividend are | ||
4 | * non-zero to start with. | ||
5 | * On entry, r3 points to the dividend, which get overwritten with | ||
6 | * the 64-bit quotient, and r4 contains the divisor. | ||
7 | * On exit, r3 contains the remainder. | ||
8 | * | ||
9 | * Copyright (C) 2002 Paul Mackerras, IBM Corp. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version | ||
14 | * 2 of the License, or (at your option) any later version. | ||
15 | */ | ||
16 | #include <asm/ppc_asm.h> | ||
17 | #include <asm/processor.h> | ||
18 | |||
19 | _GLOBAL(__div64_32) | ||
20 | lwz r5,0(r3) # get the dividend into r5/r6 | ||
21 | lwz r6,4(r3) | ||
22 | cmplw r5,r4 | ||
23 | li r7,0 | ||
24 | li r8,0 | ||
25 | blt 1f | ||
26 | divwu r7,r5,r4 # if dividend.hi >= divisor, | ||
27 | mullw r0,r7,r4 # quotient.hi = dividend.hi / divisor | ||
28 | subf. r5,r0,r5 # dividend.hi %= divisor | ||
29 | beq 3f | ||
30 | 1: mr r11,r5 # here dividend.hi != 0 | ||
31 | andis. r0,r5,0xc000 | ||
32 | bne 2f | ||
33 | cntlzw r0,r5 # we are shifting the dividend right | ||
34 | li r10,-1 # to make it < 2^32, and shifting | ||
35 | srw r10,r10,r0 # the divisor right the same amount, | ||
36 | add r9,r4,r10 # rounding up (so the estimate cannot | ||
37 | andc r11,r6,r10 # ever be too large, only too small) | ||
38 | andc r9,r9,r10 | ||
39 | or r11,r5,r11 | ||
40 | rotlw r9,r9,r0 | ||
41 | rotlw r11,r11,r0 | ||
42 | divwu r11,r11,r9 # then we divide the shifted quantities | ||
43 | 2: mullw r10,r11,r4 # to get an estimate of the quotient, | ||
44 | mulhwu r9,r11,r4 # multiply the estimate by the divisor, | ||
45 | subfc r6,r10,r6 # take the product from the divisor, | ||
46 | add r8,r8,r11 # and add the estimate to the accumulated | ||
47 | subfe. r5,r9,r5 # quotient | ||
48 | bne 1b | ||
49 | 3: cmplw r6,r4 | ||
50 | blt 4f | ||
51 | divwu r0,r6,r4 # perform the remaining 32-bit division | ||
52 | mullw r10,r0,r4 # and get the remainder | ||
53 | add r8,r8,r0 | ||
54 | subf r6,r10,r6 | ||
55 | 4: stw r7,0(r3) # return the quotient in *r3 | ||
56 | stw r8,4(r3) | ||
57 | mr r3,r6 # return the remainder in r3 | ||
58 | blr | ||
diff --git a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c deleted file mode 100644 index ea4aee6b20e6..000000000000 --- a/arch/ppc/lib/locks.c +++ /dev/null | |||
@@ -1,189 +0,0 @@ | |||
1 | /* | ||
2 | * Locks for smp ppc | ||
3 | * | ||
4 | * Written by Cort Dougan (cort@cs.nmt.edu) | ||
5 | */ | ||
6 | |||
7 | #include <linux/sched.h> | ||
8 | #include <linux/spinlock.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <asm/ppc_asm.h> | ||
11 | #include <asm/smp.h> | ||
12 | |||
13 | #ifdef CONFIG_DEBUG_SPINLOCK | ||
14 | |||
15 | #undef INIT_STUCK | ||
16 | #define INIT_STUCK 200000000 /*0xffffffff*/ | ||
17 | |||
18 | /* | ||
19 | * Try to acquire a spinlock. | ||
20 | * Only does the stwcx. if the load returned 0 - the Programming | ||
21 | * Environments Manual suggests not doing unnecessary stcwx.'s | ||
22 | * since they may inhibit forward progress by other CPUs in getting | ||
23 | * a lock. | ||
24 | */ | ||
25 | static inline unsigned long __spin_trylock(volatile unsigned long *lock) | ||
26 | { | ||
27 | unsigned long ret; | ||
28 | |||
29 | __asm__ __volatile__ ("\n\ | ||
30 | 1: lwarx %0,0,%1\n\ | ||
31 | cmpwi 0,%0,0\n\ | ||
32 | bne 2f\n" | ||
33 | PPC405_ERR77(0,%1) | ||
34 | " stwcx. %2,0,%1\n\ | ||
35 | bne- 1b\n\ | ||
36 | isync\n\ | ||
37 | 2:" | ||
38 | : "=&r"(ret) | ||
39 | : "r"(lock), "r"(1) | ||
40 | : "cr0", "memory"); | ||
41 | |||
42 | return ret; | ||
43 | } | ||
44 | |||
45 | void _raw_spin_lock(spinlock_t *lock) | ||
46 | { | ||
47 | int cpu = smp_processor_id(); | ||
48 | unsigned int stuck = INIT_STUCK; | ||
49 | while (__spin_trylock(&lock->lock)) { | ||
50 | while ((unsigned volatile long)lock->lock != 0) { | ||
51 | if (!--stuck) { | ||
52 | printk("_spin_lock(%p) CPU#%d NIP %p" | ||
53 | " holder: cpu %ld pc %08lX\n", | ||
54 | lock, cpu, __builtin_return_address(0), | ||
55 | lock->owner_cpu,lock->owner_pc); | ||
56 | stuck = INIT_STUCK; | ||
57 | /* steal the lock */ | ||
58 | /*xchg_u32((void *)&lock->lock,0);*/ | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | lock->owner_pc = (unsigned long)__builtin_return_address(0); | ||
63 | lock->owner_cpu = cpu; | ||
64 | } | ||
65 | EXPORT_SYMBOL(_raw_spin_lock); | ||
66 | |||
67 | int _raw_spin_trylock(spinlock_t *lock) | ||
68 | { | ||
69 | if (__spin_trylock(&lock->lock)) | ||
70 | return 0; | ||
71 | lock->owner_cpu = smp_processor_id(); | ||
72 | lock->owner_pc = (unsigned long)__builtin_return_address(0); | ||
73 | return 1; | ||
74 | } | ||
75 | EXPORT_SYMBOL(_raw_spin_trylock); | ||
76 | |||
77 | void _raw_spin_unlock(spinlock_t *lp) | ||
78 | { | ||
79 | if ( !lp->lock ) | ||
80 | printk("_spin_unlock(%p): no lock cpu %d curr PC %p %s/%d\n", | ||
81 | lp, smp_processor_id(), __builtin_return_address(0), | ||
82 | current->comm, current->pid); | ||
83 | if ( lp->owner_cpu != smp_processor_id() ) | ||
84 | printk("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n", | ||
85 | lp, smp_processor_id(), (int)lp->owner_cpu, | ||
86 | lp->owner_pc,lp->lock); | ||
87 | lp->owner_pc = lp->owner_cpu = 0; | ||
88 | wmb(); | ||
89 | lp->lock = 0; | ||
90 | } | ||
91 | EXPORT_SYMBOL(_raw_spin_unlock); | ||
92 | |||
93 | /* | ||
94 | * For rwlocks, zero is unlocked, -1 is write-locked, | ||
95 | * positive is read-locked. | ||
96 | */ | ||
97 | static __inline__ int __read_trylock(rwlock_t *rw) | ||
98 | { | ||
99 | signed int tmp; | ||
100 | |||
101 | __asm__ __volatile__( | ||
102 | "2: lwarx %0,0,%1 # __read_trylock\n\ | ||
103 | addic. %0,%0,1\n\ | ||
104 | ble- 1f\n" | ||
105 | PPC405_ERR77(0,%1) | ||
106 | " stwcx. %0,0,%1\n\ | ||
107 | bne- 2b\n\ | ||
108 | isync\n\ | ||
109 | 1:" | ||
110 | : "=&r"(tmp) | ||
111 | : "r"(&rw->lock) | ||
112 | : "cr0", "memory"); | ||
113 | |||
114 | return tmp; | ||
115 | } | ||
116 | |||
117 | int _raw_read_trylock(rwlock_t *rw) | ||
118 | { | ||
119 | return __read_trylock(rw) > 0; | ||
120 | } | ||
121 | EXPORT_SYMBOL(_raw_read_trylock); | ||
122 | |||
123 | void _raw_read_lock(rwlock_t *rw) | ||
124 | { | ||
125 | unsigned int stuck; | ||
126 | |||
127 | while (__read_trylock(rw) <= 0) { | ||
128 | stuck = INIT_STUCK; | ||
129 | while (!read_can_lock(rw)) { | ||
130 | if (--stuck == 0) { | ||
131 | printk("_read_lock(%p) CPU#%d lock %d\n", | ||
132 | rw, raw_smp_processor_id(), rw->lock); | ||
133 | stuck = INIT_STUCK; | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | EXPORT_SYMBOL(_raw_read_lock); | ||
139 | |||
140 | void _raw_read_unlock(rwlock_t *rw) | ||
141 | { | ||
142 | if ( rw->lock == 0 ) | ||
143 | printk("_read_unlock(): %s/%d (nip %08lX) lock %d\n", | ||
144 | current->comm,current->pid,current->thread.regs->nip, | ||
145 | rw->lock); | ||
146 | wmb(); | ||
147 | atomic_dec((atomic_t *) &(rw)->lock); | ||
148 | } | ||
149 | EXPORT_SYMBOL(_raw_read_unlock); | ||
150 | |||
151 | void _raw_write_lock(rwlock_t *rw) | ||
152 | { | ||
153 | unsigned int stuck; | ||
154 | |||
155 | while (cmpxchg(&rw->lock, 0, -1) != 0) { | ||
156 | stuck = INIT_STUCK; | ||
157 | while (!write_can_lock(rw)) { | ||
158 | if (--stuck == 0) { | ||
159 | printk("write_lock(%p) CPU#%d lock %d)\n", | ||
160 | rw, raw_smp_processor_id(), rw->lock); | ||
161 | stuck = INIT_STUCK; | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | wmb(); | ||
166 | } | ||
167 | EXPORT_SYMBOL(_raw_write_lock); | ||
168 | |||
169 | int _raw_write_trylock(rwlock_t *rw) | ||
170 | { | ||
171 | if (cmpxchg(&rw->lock, 0, -1) != 0) | ||
172 | return 0; | ||
173 | wmb(); | ||
174 | return 1; | ||
175 | } | ||
176 | EXPORT_SYMBOL(_raw_write_trylock); | ||
177 | |||
178 | void _raw_write_unlock(rwlock_t *rw) | ||
179 | { | ||
180 | if (rw->lock >= 0) | ||
181 | printk("_write_lock(): %s/%d (nip %08lX) lock %d\n", | ||
182 | current->comm,current->pid,current->thread.regs->nip, | ||
183 | rw->lock); | ||
184 | wmb(); | ||
185 | rw->lock = 0; | ||
186 | } | ||
187 | EXPORT_SYMBOL(_raw_write_unlock); | ||
188 | |||
189 | #endif | ||
diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S deleted file mode 100644 index 927253bfc826..000000000000 --- a/arch/ppc/lib/string.S +++ /dev/null | |||
@@ -1,732 +0,0 @@ | |||
1 | /* | ||
2 | * String handling functions for PowerPC. | ||
3 | * | ||
4 | * Copyright (C) 1996 Paul Mackerras. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | #include <asm/processor.h> | ||
12 | #include <asm/cache.h> | ||
13 | #include <asm/errno.h> | ||
14 | #include <asm/ppc_asm.h> | ||
15 | |||
16 | #define COPY_16_BYTES \ | ||
17 | lwz r7,4(r4); \ | ||
18 | lwz r8,8(r4); \ | ||
19 | lwz r9,12(r4); \ | ||
20 | lwzu r10,16(r4); \ | ||
21 | stw r7,4(r6); \ | ||
22 | stw r8,8(r6); \ | ||
23 | stw r9,12(r6); \ | ||
24 | stwu r10,16(r6) | ||
25 | |||
26 | #define COPY_16_BYTES_WITHEX(n) \ | ||
27 | 8 ## n ## 0: \ | ||
28 | lwz r7,4(r4); \ | ||
29 | 8 ## n ## 1: \ | ||
30 | lwz r8,8(r4); \ | ||
31 | 8 ## n ## 2: \ | ||
32 | lwz r9,12(r4); \ | ||
33 | 8 ## n ## 3: \ | ||
34 | lwzu r10,16(r4); \ | ||
35 | 8 ## n ## 4: \ | ||
36 | stw r7,4(r6); \ | ||
37 | 8 ## n ## 5: \ | ||
38 | stw r8,8(r6); \ | ||
39 | 8 ## n ## 6: \ | ||
40 | stw r9,12(r6); \ | ||
41 | 8 ## n ## 7: \ | ||
42 | stwu r10,16(r6) | ||
43 | |||
44 | #define COPY_16_BYTES_EXCODE(n) \ | ||
45 | 9 ## n ## 0: \ | ||
46 | addi r5,r5,-(16 * n); \ | ||
47 | b 104f; \ | ||
48 | 9 ## n ## 1: \ | ||
49 | addi r5,r5,-(16 * n); \ | ||
50 | b 105f; \ | ||
51 | .section __ex_table,"a"; \ | ||
52 | .align 2; \ | ||
53 | .long 8 ## n ## 0b,9 ## n ## 0b; \ | ||
54 | .long 8 ## n ## 1b,9 ## n ## 0b; \ | ||
55 | .long 8 ## n ## 2b,9 ## n ## 0b; \ | ||
56 | .long 8 ## n ## 3b,9 ## n ## 0b; \ | ||
57 | .long 8 ## n ## 4b,9 ## n ## 1b; \ | ||
58 | .long 8 ## n ## 5b,9 ## n ## 1b; \ | ||
59 | .long 8 ## n ## 6b,9 ## n ## 1b; \ | ||
60 | .long 8 ## n ## 7b,9 ## n ## 1b; \ | ||
61 | .text | ||
62 | |||
63 | .text | ||
64 | .stabs "arch/ppc/lib/",N_SO,0,0,0f | ||
65 | .stabs "string.S",N_SO,0,0,0f | ||
66 | |||
67 | CACHELINE_BYTES = L1_CACHE_BYTES | ||
68 | LG_CACHELINE_BYTES = L1_CACHE_SHIFT | ||
69 | CACHELINE_MASK = (L1_CACHE_BYTES-1) | ||
70 | |||
71 | _GLOBAL(strcpy) | ||
72 | addi r5,r3,-1 | ||
73 | addi r4,r4,-1 | ||
74 | 1: lbzu r0,1(r4) | ||
75 | cmpwi 0,r0,0 | ||
76 | stbu r0,1(r5) | ||
77 | bne 1b | ||
78 | blr | ||
79 | |||
80 | /* This clears out any unused part of the destination buffer, | ||
81 | just as the libc version does. -- paulus */ | ||
82 | _GLOBAL(strncpy) | ||
83 | cmpwi 0,r5,0 | ||
84 | beqlr | ||
85 | mtctr r5 | ||
86 | addi r6,r3,-1 | ||
87 | addi r4,r4,-1 | ||
88 | 1: lbzu r0,1(r4) | ||
89 | cmpwi 0,r0,0 | ||
90 | stbu r0,1(r6) | ||
91 | bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ | ||
92 | bnelr /* if we didn't hit a null char, we're done */ | ||
93 | mfctr r5 | ||
94 | cmpwi 0,r5,0 /* any space left in destination buffer? */ | ||
95 | beqlr /* we know r0 == 0 here */ | ||
96 | 2: stbu r0,1(r6) /* clear it out if so */ | ||
97 | bdnz 2b | ||
98 | blr | ||
99 | |||
100 | _GLOBAL(strcat) | ||
101 | addi r5,r3,-1 | ||
102 | addi r4,r4,-1 | ||
103 | 1: lbzu r0,1(r5) | ||
104 | cmpwi 0,r0,0 | ||
105 | bne 1b | ||
106 | addi r5,r5,-1 | ||
107 | 1: lbzu r0,1(r4) | ||
108 | cmpwi 0,r0,0 | ||
109 | stbu r0,1(r5) | ||
110 | bne 1b | ||
111 | blr | ||
112 | |||
113 | _GLOBAL(strcmp) | ||
114 | addi r5,r3,-1 | ||
115 | addi r4,r4,-1 | ||
116 | 1: lbzu r3,1(r5) | ||
117 | cmpwi 1,r3,0 | ||
118 | lbzu r0,1(r4) | ||
119 | subf. r3,r0,r3 | ||
120 | beqlr 1 | ||
121 | beq 1b | ||
122 | blr | ||
123 | |||
124 | _GLOBAL(strncmp) | ||
125 | PPC_LCMPI r5,0 | ||
126 | beqlr | ||
127 | mtctr r5 | ||
128 | addi r5,r3,-1 | ||
129 | addi r4,r4,-1 | ||
130 | 1: lbzu r3,1(r5) | ||
131 | cmpwi 1,r3,0 | ||
132 | lbzu r0,1(r4) | ||
133 | subf. r3,r0,r3 | ||
134 | beqlr 1 | ||
135 | bdnzt eq,1b | ||
136 | blr | ||
137 | |||
138 | _GLOBAL(strlen) | ||
139 | addi r4,r3,-1 | ||
140 | 1: lbzu r0,1(r4) | ||
141 | cmpwi 0,r0,0 | ||
142 | bne 1b | ||
143 | subf r3,r3,r4 | ||
144 | blr | ||
145 | |||
146 | /* | ||
147 | * Use dcbz on the complete cache lines in the destination | ||
148 | * to set them to zero. This requires that the destination | ||
149 | * area is cacheable. -- paulus | ||
150 | */ | ||
151 | _GLOBAL(cacheable_memzero) | ||
152 | mr r5,r4 | ||
153 | li r4,0 | ||
154 | addi r6,r3,-4 | ||
155 | cmplwi 0,r5,4 | ||
156 | blt 7f | ||
157 | stwu r4,4(r6) | ||
158 | beqlr | ||
159 | andi. r0,r6,3 | ||
160 | add r5,r0,r5 | ||
161 | subf r6,r0,r6 | ||
162 | clrlwi r7,r6,32-LG_CACHELINE_BYTES | ||
163 | add r8,r7,r5 | ||
164 | srwi r9,r8,LG_CACHELINE_BYTES | ||
165 | addic. r9,r9,-1 /* total number of complete cachelines */ | ||
166 | ble 2f | ||
167 | xori r0,r7,CACHELINE_MASK & ~3 | ||
168 | srwi. r0,r0,2 | ||
169 | beq 3f | ||
170 | mtctr r0 | ||
171 | 4: stwu r4,4(r6) | ||
172 | bdnz 4b | ||
173 | 3: mtctr r9 | ||
174 | li r7,4 | ||
175 | #if !defined(CONFIG_8xx) | ||
176 | 10: dcbz r7,r6 | ||
177 | #else | ||
178 | 10: stw r4, 4(r6) | ||
179 | stw r4, 8(r6) | ||
180 | stw r4, 12(r6) | ||
181 | stw r4, 16(r6) | ||
182 | #if CACHE_LINE_SIZE >= 32 | ||
183 | stw r4, 20(r6) | ||
184 | stw r4, 24(r6) | ||
185 | stw r4, 28(r6) | ||
186 | stw r4, 32(r6) | ||
187 | #endif /* CACHE_LINE_SIZE */ | ||
188 | #endif | ||
189 | addi r6,r6,CACHELINE_BYTES | ||
190 | bdnz 10b | ||
191 | clrlwi r5,r8,32-LG_CACHELINE_BYTES | ||
192 | addi r5,r5,4 | ||
193 | 2: srwi r0,r5,2 | ||
194 | mtctr r0 | ||
195 | bdz 6f | ||
196 | 1: stwu r4,4(r6) | ||
197 | bdnz 1b | ||
198 | 6: andi. r5,r5,3 | ||
199 | 7: cmpwi 0,r5,0 | ||
200 | beqlr | ||
201 | mtctr r5 | ||
202 | addi r6,r6,3 | ||
203 | 8: stbu r4,1(r6) | ||
204 | bdnz 8b | ||
205 | blr | ||
206 | |||
207 | _GLOBAL(memset) | ||
208 | rlwimi r4,r4,8,16,23 | ||
209 | rlwimi r4,r4,16,0,15 | ||
210 | addi r6,r3,-4 | ||
211 | cmplwi 0,r5,4 | ||
212 | blt 7f | ||
213 | stwu r4,4(r6) | ||
214 | beqlr | ||
215 | andi. r0,r6,3 | ||
216 | add r5,r0,r5 | ||
217 | subf r6,r0,r6 | ||
218 | srwi r0,r5,2 | ||
219 | mtctr r0 | ||
220 | bdz 6f | ||
221 | 1: stwu r4,4(r6) | ||
222 | bdnz 1b | ||
223 | 6: andi. r5,r5,3 | ||
224 | 7: cmpwi 0,r5,0 | ||
225 | beqlr | ||
226 | mtctr r5 | ||
227 | addi r6,r6,3 | ||
228 | 8: stbu r4,1(r6) | ||
229 | bdnz 8b | ||
230 | blr | ||
231 | |||
232 | /* | ||
233 | * This version uses dcbz on the complete cache lines in the | ||
234 | * destination area to reduce memory traffic. This requires that | ||
235 | * the destination area is cacheable. | ||
236 | * We only use this version if the source and dest don't overlap. | ||
237 | * -- paulus. | ||
238 | */ | ||
239 | _GLOBAL(cacheable_memcpy) | ||
240 | add r7,r3,r5 /* test if the src & dst overlap */ | ||
241 | add r8,r4,r5 | ||
242 | cmplw 0,r4,r7 | ||
243 | cmplw 1,r3,r8 | ||
244 | crand 0,0,4 /* cr0.lt &= cr1.lt */ | ||
245 | blt memcpy /* if regions overlap */ | ||
246 | |||
247 | addi r4,r4,-4 | ||
248 | addi r6,r3,-4 | ||
249 | neg r0,r3 | ||
250 | andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ | ||
251 | beq 58f | ||
252 | |||
253 | cmplw 0,r5,r0 /* is this more than total to do? */ | ||
254 | blt 63f /* if not much to do */ | ||
255 | andi. r8,r0,3 /* get it word-aligned first */ | ||
256 | subf r5,r0,r5 | ||
257 | mtctr r8 | ||
258 | beq+ 61f | ||
259 | 70: lbz r9,4(r4) /* do some bytes */ | ||
260 | stb r9,4(r6) | ||
261 | addi r4,r4,1 | ||
262 | addi r6,r6,1 | ||
263 | bdnz 70b | ||
264 | 61: srwi. r0,r0,2 | ||
265 | mtctr r0 | ||
266 | beq 58f | ||
267 | 72: lwzu r9,4(r4) /* do some words */ | ||
268 | stwu r9,4(r6) | ||
269 | bdnz 72b | ||
270 | |||
271 | 58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ | ||
272 | clrlwi r5,r5,32-LG_CACHELINE_BYTES | ||
273 | li r11,4 | ||
274 | mtctr r0 | ||
275 | beq 63f | ||
276 | 53: | ||
277 | #if !defined(CONFIG_8xx) | ||
278 | dcbz r11,r6 | ||
279 | #endif | ||
280 | COPY_16_BYTES | ||
281 | #if L1_CACHE_BYTES >= 32 | ||
282 | COPY_16_BYTES | ||
283 | #if L1_CACHE_BYTES >= 64 | ||
284 | COPY_16_BYTES | ||
285 | COPY_16_BYTES | ||
286 | #if L1_CACHE_BYTES >= 128 | ||
287 | COPY_16_BYTES | ||
288 | COPY_16_BYTES | ||
289 | COPY_16_BYTES | ||
290 | COPY_16_BYTES | ||
291 | #endif | ||
292 | #endif | ||
293 | #endif | ||
294 | bdnz 53b | ||
295 | |||
296 | 63: srwi. r0,r5,2 | ||
297 | mtctr r0 | ||
298 | beq 64f | ||
299 | 30: lwzu r0,4(r4) | ||
300 | stwu r0,4(r6) | ||
301 | bdnz 30b | ||
302 | |||
303 | 64: andi. r0,r5,3 | ||
304 | mtctr r0 | ||
305 | beq+ 65f | ||
306 | 40: lbz r0,4(r4) | ||
307 | stb r0,4(r6) | ||
308 | addi r4,r4,1 | ||
309 | addi r6,r6,1 | ||
310 | bdnz 40b | ||
311 | 65: blr | ||
312 | |||
313 | _GLOBAL(memmove) | ||
314 | cmplw 0,r3,r4 | ||
315 | bgt backwards_memcpy | ||
316 | /* fall through */ | ||
317 | |||
318 | _GLOBAL(memcpy) | ||
319 | srwi. r7,r5,3 | ||
320 | addi r6,r3,-4 | ||
321 | addi r4,r4,-4 | ||
322 | beq 2f /* if less than 8 bytes to do */ | ||
323 | andi. r0,r6,3 /* get dest word aligned */ | ||
324 | mtctr r7 | ||
325 | bne 5f | ||
326 | 1: lwz r7,4(r4) | ||
327 | lwzu r8,8(r4) | ||
328 | stw r7,4(r6) | ||
329 | stwu r8,8(r6) | ||
330 | bdnz 1b | ||
331 | andi. r5,r5,7 | ||
332 | 2: cmplwi 0,r5,4 | ||
333 | blt 3f | ||
334 | lwzu r0,4(r4) | ||
335 | addi r5,r5,-4 | ||
336 | stwu r0,4(r6) | ||
337 | 3: cmpwi 0,r5,0 | ||
338 | beqlr | ||
339 | mtctr r5 | ||
340 | addi r4,r4,3 | ||
341 | addi r6,r6,3 | ||
342 | 4: lbzu r0,1(r4) | ||
343 | stbu r0,1(r6) | ||
344 | bdnz 4b | ||
345 | blr | ||
346 | 5: subfic r0,r0,4 | ||
347 | mtctr r0 | ||
348 | 6: lbz r7,4(r4) | ||
349 | addi r4,r4,1 | ||
350 | stb r7,4(r6) | ||
351 | addi r6,r6,1 | ||
352 | bdnz 6b | ||
353 | subf r5,r0,r5 | ||
354 | rlwinm. r7,r5,32-3,3,31 | ||
355 | beq 2b | ||
356 | mtctr r7 | ||
357 | b 1b | ||
358 | |||
359 | _GLOBAL(backwards_memcpy) | ||
360 | rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ | ||
361 | add r6,r3,r5 | ||
362 | add r4,r4,r5 | ||
363 | beq 2f | ||
364 | andi. r0,r6,3 | ||
365 | mtctr r7 | ||
366 | bne 5f | ||
367 | 1: lwz r7,-4(r4) | ||
368 | lwzu r8,-8(r4) | ||
369 | stw r7,-4(r6) | ||
370 | stwu r8,-8(r6) | ||
371 | bdnz 1b | ||
372 | andi. r5,r5,7 | ||
373 | 2: cmplwi 0,r5,4 | ||
374 | blt 3f | ||
375 | lwzu r0,-4(r4) | ||
376 | subi r5,r5,4 | ||
377 | stwu r0,-4(r6) | ||
378 | 3: cmpwi 0,r5,0 | ||
379 | beqlr | ||
380 | mtctr r5 | ||
381 | 4: lbzu r0,-1(r4) | ||
382 | stbu r0,-1(r6) | ||
383 | bdnz 4b | ||
384 | blr | ||
385 | 5: mtctr r0 | ||
386 | 6: lbzu r7,-1(r4) | ||
387 | stbu r7,-1(r6) | ||
388 | bdnz 6b | ||
389 | subf r5,r0,r5 | ||
390 | rlwinm. r7,r5,32-3,3,31 | ||
391 | beq 2b | ||
392 | mtctr r7 | ||
393 | b 1b | ||
394 | |||
395 | _GLOBAL(memcmp) | ||
396 | cmpwi 0,r5,0 | ||
397 | ble- 2f | ||
398 | mtctr r5 | ||
399 | addi r6,r3,-1 | ||
400 | addi r4,r4,-1 | ||
401 | 1: lbzu r3,1(r6) | ||
402 | lbzu r0,1(r4) | ||
403 | subf. r3,r0,r3 | ||
404 | bdnzt 2,1b | ||
405 | blr | ||
406 | 2: li r3,0 | ||
407 | blr | ||
408 | |||
409 | _GLOBAL(memchr) | ||
410 | cmpwi 0,r5,0 | ||
411 | ble- 2f | ||
412 | mtctr r5 | ||
413 | addi r3,r3,-1 | ||
414 | 1: lbzu r0,1(r3) | ||
415 | cmpw 0,r0,r4 | ||
416 | bdnzf 2,1b | ||
417 | beqlr | ||
418 | 2: li r3,0 | ||
419 | blr | ||
420 | |||
421 | _GLOBAL(__copy_tofrom_user) | ||
422 | addi r4,r4,-4 | ||
423 | addi r6,r3,-4 | ||
424 | neg r0,r3 | ||
425 | andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ | ||
426 | beq 58f | ||
427 | |||
428 | cmplw 0,r5,r0 /* is this more than total to do? */ | ||
429 | blt 63f /* if not much to do */ | ||
430 | andi. r8,r0,3 /* get it word-aligned first */ | ||
431 | mtctr r8 | ||
432 | beq+ 61f | ||
433 | 70: lbz r9,4(r4) /* do some bytes */ | ||
434 | 71: stb r9,4(r6) | ||
435 | addi r4,r4,1 | ||
436 | addi r6,r6,1 | ||
437 | bdnz 70b | ||
438 | 61: subf r5,r0,r5 | ||
439 | srwi. r0,r0,2 | ||
440 | mtctr r0 | ||
441 | beq 58f | ||
442 | 72: lwzu r9,4(r4) /* do some words */ | ||
443 | 73: stwu r9,4(r6) | ||
444 | bdnz 72b | ||
445 | |||
446 | .section __ex_table,"a" | ||
447 | .align 2 | ||
448 | .long 70b,100f | ||
449 | .long 71b,101f | ||
450 | .long 72b,102f | ||
451 | .long 73b,103f | ||
452 | .text | ||
453 | |||
454 | 58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ | ||
455 | clrlwi r5,r5,32-LG_CACHELINE_BYTES | ||
456 | li r11,4 | ||
457 | beq 63f | ||
458 | |||
459 | #ifdef CONFIG_8xx | ||
460 | /* Don't use prefetch on 8xx */ | ||
461 | mtctr r0 | ||
462 | li r0,0 | ||
463 | 53: COPY_16_BYTES_WITHEX(0) | ||
464 | bdnz 53b | ||
465 | |||
466 | #else /* not CONFIG_8xx */ | ||
467 | /* Here we decide how far ahead to prefetch the source */ | ||
468 | li r3,4 | ||
469 | cmpwi r0,1 | ||
470 | li r7,0 | ||
471 | ble 114f | ||
472 | li r7,1 | ||
473 | #if MAX_COPY_PREFETCH > 1 | ||
474 | /* Heuristically, for large transfers we prefetch | ||
475 | MAX_COPY_PREFETCH cachelines ahead. For small transfers | ||
476 | we prefetch 1 cacheline ahead. */ | ||
477 | cmpwi r0,MAX_COPY_PREFETCH | ||
478 | ble 112f | ||
479 | li r7,MAX_COPY_PREFETCH | ||
480 | 112: mtctr r7 | ||
481 | 111: dcbt r3,r4 | ||
482 | addi r3,r3,CACHELINE_BYTES | ||
483 | bdnz 111b | ||
484 | #else | ||
485 | dcbt r3,r4 | ||
486 | addi r3,r3,CACHELINE_BYTES | ||
487 | #endif /* MAX_COPY_PREFETCH > 1 */ | ||
488 | |||
489 | 114: subf r8,r7,r0 | ||
490 | mr r0,r7 | ||
491 | mtctr r8 | ||
492 | |||
493 | 53: dcbt r3,r4 | ||
494 | 54: dcbz r11,r6 | ||
495 | .section __ex_table,"a" | ||
496 | .align 2 | ||
497 | .long 54b,105f | ||
498 | .text | ||
499 | /* the main body of the cacheline loop */ | ||
500 | COPY_16_BYTES_WITHEX(0) | ||
501 | #if L1_CACHE_BYTES >= 32 | ||
502 | COPY_16_BYTES_WITHEX(1) | ||
503 | #if L1_CACHE_BYTES >= 64 | ||
504 | COPY_16_BYTES_WITHEX(2) | ||
505 | COPY_16_BYTES_WITHEX(3) | ||
506 | #if L1_CACHE_BYTES >= 128 | ||
507 | COPY_16_BYTES_WITHEX(4) | ||
508 | COPY_16_BYTES_WITHEX(5) | ||
509 | COPY_16_BYTES_WITHEX(6) | ||
510 | COPY_16_BYTES_WITHEX(7) | ||
511 | #endif | ||
512 | #endif | ||
513 | #endif | ||
514 | bdnz 53b | ||
515 | cmpwi r0,0 | ||
516 | li r3,4 | ||
517 | li r7,0 | ||
518 | bne 114b | ||
519 | #endif /* CONFIG_8xx */ | ||
520 | |||
521 | 63: srwi. r0,r5,2 | ||
522 | mtctr r0 | ||
523 | beq 64f | ||
524 | 30: lwzu r0,4(r4) | ||
525 | 31: stwu r0,4(r6) | ||
526 | bdnz 30b | ||
527 | |||
528 | 64: andi. r0,r5,3 | ||
529 | mtctr r0 | ||
530 | beq+ 65f | ||
531 | 40: lbz r0,4(r4) | ||
532 | 41: stb r0,4(r6) | ||
533 | addi r4,r4,1 | ||
534 | addi r6,r6,1 | ||
535 | bdnz 40b | ||
536 | 65: li r3,0 | ||
537 | blr | ||
538 | |||
539 | /* read fault, initial single-byte copy */ | ||
540 | 100: li r9,0 | ||
541 | b 90f | ||
542 | /* write fault, initial single-byte copy */ | ||
543 | 101: li r9,1 | ||
544 | 90: subf r5,r8,r5 | ||
545 | li r3,0 | ||
546 | b 99f | ||
547 | /* read fault, initial word copy */ | ||
548 | 102: li r9,0 | ||
549 | b 91f | ||
550 | /* write fault, initial word copy */ | ||
551 | 103: li r9,1 | ||
552 | 91: li r3,2 | ||
553 | b 99f | ||
554 | |||
555 | /* | ||
556 | * this stuff handles faults in the cacheline loop and branches to either | ||
557 | * 104f (if in read part) or 105f (if in write part), after updating r5 | ||
558 | */ | ||
559 | COPY_16_BYTES_EXCODE(0) | ||
560 | #if L1_CACHE_BYTES >= 32 | ||
561 | COPY_16_BYTES_EXCODE(1) | ||
562 | #if L1_CACHE_BYTES >= 64 | ||
563 | COPY_16_BYTES_EXCODE(2) | ||
564 | COPY_16_BYTES_EXCODE(3) | ||
565 | #if L1_CACHE_BYTES >= 128 | ||
566 | COPY_16_BYTES_EXCODE(4) | ||
567 | COPY_16_BYTES_EXCODE(5) | ||
568 | COPY_16_BYTES_EXCODE(6) | ||
569 | COPY_16_BYTES_EXCODE(7) | ||
570 | #endif | ||
571 | #endif | ||
572 | #endif | ||
573 | |||
574 | /* read fault in cacheline loop */ | ||
575 | 104: li r9,0 | ||
576 | b 92f | ||
577 | /* fault on dcbz (effectively a write fault) */ | ||
578 | /* or write fault in cacheline loop */ | ||
579 | 105: li r9,1 | ||
580 | 92: li r3,LG_CACHELINE_BYTES | ||
581 | mfctr r8 | ||
582 | add r0,r0,r8 | ||
583 | b 106f | ||
584 | /* read fault in final word loop */ | ||
585 | 108: li r9,0 | ||
586 | b 93f | ||
587 | /* write fault in final word loop */ | ||
588 | 109: li r9,1 | ||
589 | 93: andi. r5,r5,3 | ||
590 | li r3,2 | ||
591 | b 99f | ||
592 | /* read fault in final byte loop */ | ||
593 | 110: li r9,0 | ||
594 | b 94f | ||
595 | /* write fault in final byte loop */ | ||
596 | 111: li r9,1 | ||
597 | 94: li r5,0 | ||
598 | li r3,0 | ||
599 | /* | ||
600 | * At this stage the number of bytes not copied is | ||
601 | * r5 + (ctr << r3), and r9 is 0 for read or 1 for write. | ||
602 | */ | ||
603 | 99: mfctr r0 | ||
604 | 106: slw r3,r0,r3 | ||
605 | add. r3,r3,r5 | ||
606 | beq 120f /* shouldn't happen */ | ||
607 | cmpwi 0,r9,0 | ||
608 | bne 120f | ||
609 | /* for a read fault, first try to continue the copy one byte at a time */ | ||
610 | mtctr r3 | ||
611 | 130: lbz r0,4(r4) | ||
612 | 131: stb r0,4(r6) | ||
613 | addi r4,r4,1 | ||
614 | addi r6,r6,1 | ||
615 | bdnz 130b | ||
616 | /* then clear out the destination: r3 bytes starting at 4(r6) */ | ||
617 | 132: mfctr r3 | ||
618 | srwi. r0,r3,2 | ||
619 | li r9,0 | ||
620 | mtctr r0 | ||
621 | beq 113f | ||
622 | 112: stwu r9,4(r6) | ||
623 | bdnz 112b | ||
624 | 113: andi. r0,r3,3 | ||
625 | mtctr r0 | ||
626 | beq 120f | ||
627 | 114: stb r9,4(r6) | ||
628 | addi r6,r6,1 | ||
629 | bdnz 114b | ||
630 | 120: blr | ||
631 | |||
632 | .section __ex_table,"a" | ||
633 | .align 2 | ||
634 | .long 30b,108b | ||
635 | .long 31b,109b | ||
636 | .long 40b,110b | ||
637 | .long 41b,111b | ||
638 | .long 130b,132b | ||
639 | .long 131b,120b | ||
640 | .long 112b,120b | ||
641 | .long 114b,120b | ||
642 | .text | ||
643 | |||
644 | _GLOBAL(__clear_user) | ||
645 | addi r6,r3,-4 | ||
646 | li r3,0 | ||
647 | li r5,0 | ||
648 | cmplwi 0,r4,4 | ||
649 | blt 7f | ||
650 | /* clear a single word */ | ||
651 | 11: stwu r5,4(r6) | ||
652 | beqlr | ||
653 | /* clear word sized chunks */ | ||
654 | andi. r0,r6,3 | ||
655 | add r4,r0,r4 | ||
656 | subf r6,r0,r6 | ||
657 | srwi r0,r4,2 | ||
658 | andi. r4,r4,3 | ||
659 | mtctr r0 | ||
660 | bdz 7f | ||
661 | 1: stwu r5,4(r6) | ||
662 | bdnz 1b | ||
663 | /* clear byte sized chunks */ | ||
664 | 7: cmpwi 0,r4,0 | ||
665 | beqlr | ||
666 | mtctr r4 | ||
667 | addi r6,r6,3 | ||
668 | 8: stbu r5,1(r6) | ||
669 | bdnz 8b | ||
670 | blr | ||
671 | 90: mr r3,r4 | ||
672 | blr | ||
673 | 91: mfctr r3 | ||
674 | slwi r3,r3,2 | ||
675 | add r3,r3,r4 | ||
676 | blr | ||
677 | 92: mfctr r3 | ||
678 | blr | ||
679 | |||
680 | .section __ex_table,"a" | ||
681 | .align 2 | ||
682 | .long 11b,90b | ||
683 | .long 1b,91b | ||
684 | .long 8b,92b | ||
685 | .text | ||
686 | |||
687 | _GLOBAL(__strncpy_from_user) | ||
688 | addi r6,r3,-1 | ||
689 | addi r4,r4,-1 | ||
690 | cmpwi 0,r5,0 | ||
691 | beq 2f | ||
692 | mtctr r5 | ||
693 | 1: lbzu r0,1(r4) | ||
694 | cmpwi 0,r0,0 | ||
695 | stbu r0,1(r6) | ||
696 | bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ | ||
697 | beq 3f | ||
698 | 2: addi r6,r6,1 | ||
699 | 3: subf r3,r3,r6 | ||
700 | blr | ||
701 | 99: li r3,-EFAULT | ||
702 | blr | ||
703 | |||
704 | .section __ex_table,"a" | ||
705 | .align 2 | ||
706 | .long 1b,99b | ||
707 | .text | ||
708 | |||
709 | /* r3 = str, r4 = len (> 0), r5 = top (highest addr) */ | ||
710 | _GLOBAL(__strnlen_user) | ||
711 | addi r7,r3,-1 | ||
712 | subf r6,r7,r5 /* top+1 - str */ | ||
713 | cmplw 0,r4,r6 | ||
714 | bge 0f | ||
715 | mr r6,r4 | ||
716 | 0: mtctr r6 /* ctr = min(len, top - str) */ | ||
717 | 1: lbzu r0,1(r7) /* get next byte */ | ||
718 | cmpwi 0,r0,0 | ||
719 | bdnzf 2,1b /* loop if --ctr != 0 && byte != 0 */ | ||
720 | addi r7,r7,1 | ||
721 | subf r3,r3,r7 /* number of bytes we have looked at */ | ||
722 | beqlr /* return if we found a 0 byte */ | ||
723 | cmpw 0,r3,r4 /* did we look at all len bytes? */ | ||
724 | blt 99f /* if not, must have hit top */ | ||
725 | addi r3,r4,1 /* return len + 1 to indicate no null found */ | ||
726 | blr | ||
727 | 99: li r3,0 /* bad address, return 0 */ | ||
728 | blr | ||
729 | |||
730 | .section __ex_table,"a" | ||
731 | .align 2 | ||
732 | .long 1b,99b | ||