aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/misc.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/kernel/misc.S')
-rw-r--r--arch/ppc/kernel/misc.S868
1 files changed, 0 insertions, 868 deletions
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
deleted file mode 100644
index d5e0dfc9ffec..000000000000
--- a/arch/ppc/kernel/misc.S
+++ /dev/null
@@ -1,868 +0,0 @@
1/*
2 * This file contains miscellaneous low-level functions.
3 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
4 *
5 * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
6 * and Paul Mackerras.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 */
14
15#include <linux/sys.h>
16#include <asm/unistd.h>
17#include <asm/errno.h>
18#include <asm/processor.h>
19#include <asm/page.h>
20#include <asm/cache.h>
21#include <asm/cputable.h>
22#include <asm/mmu.h>
23#include <asm/ppc_asm.h>
24#include <asm/thread_info.h>
25#include <asm/asm-offsets.h>
26
27#ifdef CONFIG_8xx
28#define ISYNC_8xx isync
29#else
30#define ISYNC_8xx
31#endif
32 .text
33
34 .align 5
35_GLOBAL(__delay)
36 cmpwi 0,r3,0
37 mtctr r3
38 beqlr
391: bdnz 1b
40 blr
41
42/*
43 * Returns (address we're running at) - (address we were linked at)
44 * for use before the text and data are mapped to KERNELBASE.
45 */
46_GLOBAL(reloc_offset)
47 mflr r0
48 bl 1f
491: mflr r3
50 lis r4,1b@ha
51 addi r4,r4,1b@l
52 subf r3,r4,r3
53 mtlr r0
54 blr
55
56/*
57 * add_reloc_offset(x) returns x + reloc_offset().
58 */
59_GLOBAL(add_reloc_offset)
60 mflr r0
61 bl 1f
621: mflr r5
63 lis r4,1b@ha
64 addi r4,r4,1b@l
65 subf r5,r4,r5
66 add r3,r3,r5
67 mtlr r0
68 blr
69
70/*
71 * sub_reloc_offset(x) returns x - reloc_offset().
72 */
73_GLOBAL(sub_reloc_offset)
74 mflr r0
75 bl 1f
761: mflr r5
77 lis r4,1b@ha
78 addi r4,r4,1b@l
79 subf r5,r4,r5
80 subf r3,r5,r3
81 mtlr r0
82 blr
83
84/*
85 * reloc_got2 runs through the .got2 section adding an offset
86 * to each entry.
87 */
88_GLOBAL(reloc_got2)
89 mflr r11
90 lis r7,__got2_start@ha
91 addi r7,r7,__got2_start@l
92 lis r8,__got2_end@ha
93 addi r8,r8,__got2_end@l
94 subf r8,r7,r8
95 srwi. r8,r8,2
96 beqlr
97 mtctr r8
98 bl 1f
991: mflr r0
100 lis r4,1b@ha
101 addi r4,r4,1b@l
102 subf r0,r4,r0
103 add r7,r0,r7
1042: lwz r0,0(r7)
105 add r0,r0,r3
106 stw r0,0(r7)
107 addi r7,r7,4
108 bdnz 2b
109 mtlr r11
110 blr
111
112/*
113 * call_setup_cpu - call the setup_cpu function for this cpu
114 * r3 = data offset, r24 = cpu number
115 *
116 * Setup function is called with:
117 * r3 = data offset
118 * r4 = ptr to CPU spec (relocated)
119 */
120_GLOBAL(call_setup_cpu)
121 addis r4,r3,cur_cpu_spec@ha
122 addi r4,r4,cur_cpu_spec@l
123 lwz r4,0(r4)
124 add r4,r4,r3
125 lwz r5,CPU_SPEC_SETUP(r4)
126 cmpi 0,r5,0
127 add r5,r5,r3
128 beqlr
129 mtctr r5
130 bctr
131
132/*
133 * complement mask on the msr then "or" some values on.
134 * _nmask_and_or_msr(nmask, value_to_or)
135 */
136_GLOBAL(_nmask_and_or_msr)
137 mfmsr r0 /* Get current msr */
138 andc r0,r0,r3 /* And off the bits set in r3 (first parm) */
139 or r0,r0,r4 /* Or on the bits in r4 (second parm) */
140 SYNC /* Some chip revs have problems here... */
141 mtmsr r0 /* Update machine state */
142 isync
143 blr /* Done */
144
145
146/*
147 * Flush MMU TLB
148 */
149_GLOBAL(_tlbia)
150#if defined(CONFIG_40x)
151 sync /* Flush to memory before changing mapping */
152 tlbia
153 isync /* Flush shadow TLB */
154#elif defined(CONFIG_44x)
155 li r3,0
156 sync
157
158 /* Load high watermark */
159 lis r4,tlb_44x_hwater@ha
160 lwz r5,tlb_44x_hwater@l(r4)
161
1621: tlbwe r3,r3,PPC44x_TLB_PAGEID
163 addi r3,r3,1
164 cmpw 0,r3,r5
165 ble 1b
166
167 isync
168#else /* !(CONFIG_40x || CONFIG_44x) */
169#if defined(CONFIG_SMP)
170 rlwinm r8,r1,0,0,18
171 lwz r8,TI_CPU(r8)
172 oris r8,r8,10
173 mfmsr r10
174 SYNC
175 rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */
176 rlwinm r0,r0,0,28,26 /* clear DR */
177 mtmsr r0
178 SYNC_601
179 isync
180 lis r9,mmu_hash_lock@h
181 ori r9,r9,mmu_hash_lock@l
182 tophys(r9,r9)
18310: lwarx r7,0,r9
184 cmpwi 0,r7,0
185 bne- 10b
186 stwcx. r8,0,r9
187 bne- 10b
188 sync
189 tlbia
190 sync
191 TLBSYNC
192 li r0,0
193 stw r0,0(r9) /* clear mmu_hash_lock */
194 mtmsr r10
195 SYNC_601
196 isync
197#else /* CONFIG_SMP */
198 sync
199 tlbia
200 sync
201#endif /* CONFIG_SMP */
202#endif /* ! defined(CONFIG_40x) */
203 blr
204
205/*
206 * Flush MMU TLB for a particular address
207 */
208_GLOBAL(_tlbie)
209#if defined(CONFIG_40x)
210 /* We run the search with interrupts disabled because we have to change
211 * the PID and I don't want to preempt when that happens.
212 */
213 mfmsr r5
214 mfspr r6,SPRN_PID
215 wrteei 0
216 mtspr SPRN_PID,r4
217 tlbsx. r3, 0, r3
218 mtspr SPRN_PID,r6
219 wrtee r5
220 bne 10f
221 sync
222 /* There are only 64 TLB entries, so r3 < 64, which means bit 25 is clear.
223 * Since 25 is the V bit in the TLB_TAG, loading this value will invalidate
224 * the TLB entry. */
225 tlbwe r3, r3, TLB_TAG
226 isync
22710:
228#elif defined(CONFIG_44x)
229 mfspr r5,SPRN_MMUCR
230 rlwimi r5,r4,0,24,31 /* Set TID */
231
232 /* We have to run the search with interrupts disabled, even critical
233 * and debug interrupts (in fact the only critical exceptions we have
234 * are debug and machine check). Otherwise an interrupt which causes
235 * a TLB miss can clobber the MMUCR between the mtspr and the tlbsx. */
236 mfmsr r4
237 lis r6,(MSR_EE|MSR_CE|MSR_ME|MSR_DE)@ha
238 addi r6,r6,(MSR_EE|MSR_CE|MSR_ME|MSR_DE)@l
239 andc r6,r4,r6
240 mtmsr r6
241 mtspr SPRN_MMUCR,r5
242 tlbsx. r3, 0, r3
243 mtmsr r4
244 bne 10f
245 sync
246 /* There are only 64 TLB entries, so r3 < 64,
247 * which means bit 22, is clear. Since 22 is
248 * the V bit in the TLB_PAGEID, loading this
249 * value will invalidate the TLB entry.
250 */
251 tlbwe r3, r3, PPC44x_TLB_PAGEID
252 isync
25310:
254#else /* !(CONFIG_40x || CONFIG_44x) */
255#if defined(CONFIG_SMP)
256 rlwinm r8,r1,0,0,18
257 lwz r8,TI_CPU(r8)
258 oris r8,r8,11
259 mfmsr r10
260 SYNC
261 rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */
262 rlwinm r0,r0,0,28,26 /* clear DR */
263 mtmsr r0
264 SYNC_601
265 isync
266 lis r9,mmu_hash_lock@h
267 ori r9,r9,mmu_hash_lock@l
268 tophys(r9,r9)
26910: lwarx r7,0,r9
270 cmpwi 0,r7,0
271 bne- 10b
272 stwcx. r8,0,r9
273 bne- 10b
274 eieio
275 tlbie r3
276 sync
277 TLBSYNC
278 li r0,0
279 stw r0,0(r9) /* clear mmu_hash_lock */
280 mtmsr r10
281 SYNC_601
282 isync
283#else /* CONFIG_SMP */
284 tlbie r3
285 sync
286#endif /* CONFIG_SMP */
287#endif /* ! CONFIG_40x */
288 blr
289
290/*
291 * Flush instruction cache.
292 * This is a no-op on the 601.
293 */
294_GLOBAL(flush_instruction_cache)
295#if defined(CONFIG_8xx)
296 isync
297 lis r5, IDC_INVALL@h
298 mtspr SPRN_IC_CST, r5
299#elif defined(CONFIG_4xx)
300#ifdef CONFIG_403GCX
301 li r3, 512
302 mtctr r3
303 lis r4, KERNELBASE@h
3041: iccci 0, r4
305 addi r4, r4, 16
306 bdnz 1b
307#else
308 lis r3, KERNELBASE@h
309 iccci 0,r3
310#endif
311#else
312 mfspr r3,SPRN_PVR
313 rlwinm r3,r3,16,16,31
314 cmpwi 0,r3,1
315 beqlr /* for 601, do nothing */
316 /* 603/604 processor - use invalidate-all bit in HID0 */
317 mfspr r3,SPRN_HID0
318 ori r3,r3,HID0_ICFI
319 mtspr SPRN_HID0,r3
320#endif /* CONFIG_8xx/4xx */
321 isync
322 blr
323
324/*
325 * Write any modified data cache blocks out to memory
326 * and invalidate the corresponding instruction cache blocks.
327 * This is a no-op on the 601.
328 *
329 * __flush_icache_range(unsigned long start, unsigned long stop)
330 */
331_GLOBAL(__flush_icache_range)
332BEGIN_FTR_SECTION
333 blr /* for 601, do nothing */
334END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
335 li r5,L1_CACHE_BYTES-1
336 andc r3,r3,r5
337 subf r4,r3,r4
338 add r4,r4,r5
339 srwi. r4,r4,L1_CACHE_SHIFT
340 beqlr
341 mtctr r4
342 mr r6,r3
3431: dcbst 0,r3
344 addi r3,r3,L1_CACHE_BYTES
345 bdnz 1b
346 sync /* wait for dcbst's to get to ram */
347 mtctr r4
3482: icbi 0,r6
349 addi r6,r6,L1_CACHE_BYTES
350 bdnz 2b
351 sync /* additional sync needed on g4 */
352 isync
353 blr
354/*
355 * Write any modified data cache blocks out to memory.
356 * Does not invalidate the corresponding cache lines (especially for
357 * any corresponding instruction cache).
358 *
359 * clean_dcache_range(unsigned long start, unsigned long stop)
360 */
361_GLOBAL(clean_dcache_range)
362 li r5,L1_CACHE_BYTES-1
363 andc r3,r3,r5
364 subf r4,r3,r4
365 add r4,r4,r5
366 srwi. r4,r4,L1_CACHE_SHIFT
367 beqlr
368 mtctr r4
369
3701: dcbst 0,r3
371 addi r3,r3,L1_CACHE_BYTES
372 bdnz 1b
373 sync /* wait for dcbst's to get to ram */
374 blr
375
376/*
377 * Write any modified data cache blocks out to memory and invalidate them.
378 * Does not invalidate the corresponding instruction cache blocks.
379 *
380 * flush_dcache_range(unsigned long start, unsigned long stop)
381 */
382_GLOBAL(flush_dcache_range)
383 li r5,L1_CACHE_BYTES-1
384 andc r3,r3,r5
385 subf r4,r3,r4
386 add r4,r4,r5
387 srwi. r4,r4,L1_CACHE_SHIFT
388 beqlr
389 mtctr r4
390
3911: dcbf 0,r3
392 addi r3,r3,L1_CACHE_BYTES
393 bdnz 1b
394 sync /* wait for dcbst's to get to ram */
395 blr
396
397/*
398 * Like above, but invalidate the D-cache. This is used by the 8xx
399 * to invalidate the cache so the PPC core doesn't get stale data
400 * from the CPM (no cache snooping here :-).
401 *
402 * invalidate_dcache_range(unsigned long start, unsigned long stop)
403 */
404_GLOBAL(invalidate_dcache_range)
405 li r5,L1_CACHE_BYTES-1
406 andc r3,r3,r5
407 subf r4,r3,r4
408 add r4,r4,r5
409 srwi. r4,r4,L1_CACHE_SHIFT
410 beqlr
411 mtctr r4
412
4131: dcbi 0,r3
414 addi r3,r3,L1_CACHE_BYTES
415 bdnz 1b
416 sync /* wait for dcbi's to get to ram */
417 blr
418
419#ifdef CONFIG_NOT_COHERENT_CACHE
420/*
421 * 40x cores have 8K or 16K dcache and 32 byte line size.
422 * 44x has a 32K dcache and 32 byte line size.
423 * 8xx has 1, 2, 4, 8K variants.
424 * For now, cover the worst case of the 44x.
425 * Must be called with external interrupts disabled.
426 */
427#define CACHE_NWAYS 64
428#define CACHE_NLINES 16
429
430_GLOBAL(flush_dcache_all)
431 li r4, (2 * CACHE_NWAYS * CACHE_NLINES)
432 mtctr r4
433 lis r5, KERNELBASE@h
4341: lwz r3, 0(r5) /* Load one word from every line */
435 addi r5, r5, L1_CACHE_BYTES
436 bdnz 1b
437 blr
438#endif /* CONFIG_NOT_COHERENT_CACHE */
439
440/*
441 * Flush a particular page from the data cache to RAM.
442 * Note: this is necessary because the instruction cache does *not*
443 * snoop from the data cache.
444 * This is a no-op on the 601 which has a unified cache.
445 *
446 * void __flush_dcache_icache(void *page)
447 */
448_GLOBAL(__flush_dcache_icache)
449BEGIN_FTR_SECTION
450 blr /* for 601, do nothing */
451END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
452 rlwinm r3,r3,0,0,19 /* Get page base address */
453 li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */
454 mtctr r4
455 mr r6,r3
4560: dcbst 0,r3 /* Write line to ram */
457 addi r3,r3,L1_CACHE_BYTES
458 bdnz 0b
459 sync
460#ifndef CONFIG_44x
461 /* We don't flush the icache on 44x. Those have a virtual icache
462 * and we don't have access to the virtual address here (it's
463 * not the page vaddr but where it's mapped in user space). The
464 * flushing of the icache on these is handled elsewhere, when
465 * a change in the address space occurs, before returning to
466 * user space
467 */
468 mtctr r4
4691: icbi 0,r6
470 addi r6,r6,L1_CACHE_BYTES
471 bdnz 1b
472 sync
473 isync
474#endif /* CONFIG_44x */
475 blr
476
477/*
478 * Flush a particular page from the data cache to RAM, identified
479 * by its physical address. We turn off the MMU so we can just use
480 * the physical address (this may be a highmem page without a kernel
481 * mapping).
482 *
483 * void __flush_dcache_icache_phys(unsigned long physaddr)
484 */
485_GLOBAL(__flush_dcache_icache_phys)
486BEGIN_FTR_SECTION
487 blr /* for 601, do nothing */
488END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
489 mfmsr r10
490 rlwinm r0,r10,0,28,26 /* clear DR */
491 mtmsr r0
492 isync
493 rlwinm r3,r3,0,0,19 /* Get page base address */
494 li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */
495 mtctr r4
496 mr r6,r3
4970: dcbst 0,r3 /* Write line to ram */
498 addi r3,r3,L1_CACHE_BYTES
499 bdnz 0b
500 sync
501 mtctr r4
5021: icbi 0,r6
503 addi r6,r6,L1_CACHE_BYTES
504 bdnz 1b
505 sync
506 mtmsr r10 /* restore DR */
507 isync
508 blr
509
510/*
511 * Clear pages using the dcbz instruction, which doesn't cause any
512 * memory traffic (except to write out any cache lines which get
513 * displaced). This only works on cacheable memory.
514 *
515 * void clear_pages(void *page, int order) ;
516 */
517_GLOBAL(clear_pages)
518 li r0,4096/L1_CACHE_BYTES
519 slw r0,r0,r4
520 mtctr r0
521#ifdef CONFIG_8xx
522 li r4, 0
5231: stw r4, 0(r3)
524 stw r4, 4(r3)
525 stw r4, 8(r3)
526 stw r4, 12(r3)
527#else
5281: dcbz 0,r3
529#endif
530 addi r3,r3,L1_CACHE_BYTES
531 bdnz 1b
532 blr
533
534/*
535 * Copy a whole page. We use the dcbz instruction on the destination
536 * to reduce memory traffic (it eliminates the unnecessary reads of
537 * the destination into cache). This requires that the destination
538 * is cacheable.
539 */
540#define COPY_16_BYTES \
541 lwz r6,4(r4); \
542 lwz r7,8(r4); \
543 lwz r8,12(r4); \
544 lwzu r9,16(r4); \
545 stw r6,4(r3); \
546 stw r7,8(r3); \
547 stw r8,12(r3); \
548 stwu r9,16(r3)
549
550_GLOBAL(copy_page)
551 addi r3,r3,-4
552 addi r4,r4,-4
553
554#ifdef CONFIG_8xx
555 /* don't use prefetch on 8xx */
556 li r0,4096/L1_CACHE_BYTES
557 mtctr r0
5581: COPY_16_BYTES
559 bdnz 1b
560 blr
561
562#else /* not 8xx, we can prefetch */
563 li r5,4
564
565#if MAX_COPY_PREFETCH > 1
566 li r0,MAX_COPY_PREFETCH
567 li r11,4
568 mtctr r0
56911: dcbt r11,r4
570 addi r11,r11,L1_CACHE_BYTES
571 bdnz 11b
572#else /* MAX_COPY_PREFETCH == 1 */
573 dcbt r5,r4
574 li r11,L1_CACHE_BYTES+4
575#endif /* MAX_COPY_PREFETCH */
576 li r0,4096/L1_CACHE_BYTES - MAX_COPY_PREFETCH
577 crclr 4*cr0+eq
5782:
579 mtctr r0
5801:
581 dcbt r11,r4
582 dcbz r5,r3
583 COPY_16_BYTES
584#if L1_CACHE_BYTES >= 32
585 COPY_16_BYTES
586#if L1_CACHE_BYTES >= 64
587 COPY_16_BYTES
588 COPY_16_BYTES
589#if L1_CACHE_BYTES >= 128
590 COPY_16_BYTES
591 COPY_16_BYTES
592 COPY_16_BYTES
593 COPY_16_BYTES
594#endif
595#endif
596#endif
597 bdnz 1b
598 beqlr
599 crnot 4*cr0+eq,4*cr0+eq
600 li r0,MAX_COPY_PREFETCH
601 li r11,4
602 b 2b
603#endif /* CONFIG_8xx */
604
605/*
606 * void atomic_clear_mask(atomic_t mask, atomic_t *addr)
607 * void atomic_set_mask(atomic_t mask, atomic_t *addr);
608 */
609_GLOBAL(atomic_clear_mask)
61010: lwarx r5,0,r4
611 andc r5,r5,r3
612 PPC405_ERR77(0,r4)
613 stwcx. r5,0,r4
614 bne- 10b
615 blr
616_GLOBAL(atomic_set_mask)
61710: lwarx r5,0,r4
618 or r5,r5,r3
619 PPC405_ERR77(0,r4)
620 stwcx. r5,0,r4
621 bne- 10b
622 blr
623
624/*
625 * I/O string operations
626 *
627 * insb(port, buf, len)
628 * outsb(port, buf, len)
629 * insw(port, buf, len)
630 * outsw(port, buf, len)
631 * insl(port, buf, len)
632 * outsl(port, buf, len)
633 * insw_ns(port, buf, len)
634 * outsw_ns(port, buf, len)
635 * insl_ns(port, buf, len)
636 * outsl_ns(port, buf, len)
637 *
638 * The *_ns versions don't do byte-swapping.
639 */
640_GLOBAL(_insb)
641 cmpwi 0,r5,0
642 mtctr r5
643 subi r4,r4,1
644 blelr-
64500: lbz r5,0(r3)
64601: eieio
64702: stbu r5,1(r4)
648 ISYNC_8xx
649 .section .fixup,"ax"
65003: blr
651 .text
652 .section __ex_table, "a"
653 .align 2
654 .long 00b, 03b
655 .long 01b, 03b
656 .long 02b, 03b
657 .text
658 bdnz 00b
659 blr
660
661_GLOBAL(_outsb)
662 cmpwi 0,r5,0
663 mtctr r5
664 subi r4,r4,1
665 blelr-
66600: lbzu r5,1(r4)
66701: stb r5,0(r3)
66802: eieio
669 ISYNC_8xx
670 .section .fixup,"ax"
67103: blr
672 .text
673 .section __ex_table, "a"
674 .align 2
675 .long 00b, 03b
676 .long 01b, 03b
677 .long 02b, 03b
678 .text
679 bdnz 00b
680 blr
681
682_GLOBAL(_insw_ns)
683 cmpwi 0,r5,0
684 mtctr r5
685 subi r4,r4,2
686 blelr-
68700: lhz r5,0(r3)
68801: eieio
68902: sthu r5,2(r4)
690 ISYNC_8xx
691 .section .fixup,"ax"
69203: blr
693 .text
694 .section __ex_table, "a"
695 .align 2
696 .long 00b, 03b
697 .long 01b, 03b
698 .long 02b, 03b
699 .text
700 bdnz 00b
701 blr
702
703_GLOBAL(_outsw_ns)
704 cmpwi 0,r5,0
705 mtctr r5
706 subi r4,r4,2
707 blelr-
70800: lhzu r5,2(r4)
70901: sth r5,0(r3)
71002: eieio
711 ISYNC_8xx
712 .section .fixup,"ax"
71303: blr
714 .text
715 .section __ex_table, "a"
716 .align 2
717 .long 00b, 03b
718 .long 01b, 03b
719 .long 02b, 03b
720 .text
721 bdnz 00b
722 blr
723
724_GLOBAL(_insl_ns)
725 cmpwi 0,r5,0
726 mtctr r5
727 subi r4,r4,4
728 blelr-
72900: lwz r5,0(r3)
73001: eieio
73102: stwu r5,4(r4)
732 ISYNC_8xx
733 .section .fixup,"ax"
73403: blr
735 .text
736 .section __ex_table, "a"
737 .align 2
738 .long 00b, 03b
739 .long 01b, 03b
740 .long 02b, 03b
741 .text
742 bdnz 00b
743 blr
744
745_GLOBAL(_outsl_ns)
746 cmpwi 0,r5,0
747 mtctr r5
748 subi r4,r4,4
749 blelr-
75000: lwzu r5,4(r4)
75101: stw r5,0(r3)
75202: eieio
753 ISYNC_8xx
754 .section .fixup,"ax"
75503: blr
756 .text
757 .section __ex_table, "a"
758 .align 2
759 .long 00b, 03b
760 .long 01b, 03b
761 .long 02b, 03b
762 .text
763 bdnz 00b
764 blr
765
766/*
767 * Extended precision shifts.
768 *
769 * Updated to be valid for shift counts from 0 to 63 inclusive.
770 * -- Gabriel
771 *
772 * R3/R4 has 64 bit value
773 * R5 has shift count
774 * result in R3/R4
775 *
776 * ashrdi3: arithmetic right shift (sign propagation)
777 * lshrdi3: logical right shift
778 * ashldi3: left shift
779 */
780_GLOBAL(__ashrdi3)
781 subfic r6,r5,32
782 srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count
783 addi r7,r5,32 # could be xori, or addi with -32
784 slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count)
785 rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0
786 sraw r7,r3,r7 # t2 = MSW >> (count-32)
787 or r4,r4,r6 # LSW |= t1
788 slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2
789 sraw r3,r3,r5 # MSW = MSW >> count
790 or r4,r4,r7 # LSW |= t2
791 blr
792
793_GLOBAL(__ashldi3)
794 subfic r6,r5,32
795 slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count
796 addi r7,r5,32 # could be xori, or addi with -32
797 srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count)
798 slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32)
799 or r3,r3,r6 # MSW |= t1
800 slw r4,r4,r5 # LSW = LSW << count
801 or r3,r3,r7 # MSW |= t2
802 blr
803
804_GLOBAL(__lshrdi3)
805 subfic r6,r5,32
806 srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count
807 addi r7,r5,32 # could be xori, or addi with -32
808 slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count)
809 srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32)
810 or r4,r4,r6 # LSW |= t1
811 srw r3,r3,r5 # MSW = MSW >> count
812 or r4,r4,r7 # LSW |= t2
813 blr
814
815_GLOBAL(abs)
816 srawi r4,r3,31
817 xor r3,r3,r4
818 sub r3,r3,r4
819 blr
820
821_GLOBAL(_get_SP)
822 mr r3,r1 /* Close enough */
823 blr
824
825/*
826 * Create a kernel thread
827 * kernel_thread(fn, arg, flags)
828 */
829_GLOBAL(kernel_thread)
830 stwu r1,-16(r1)
831 stw r30,8(r1)
832 stw r31,12(r1)
833 mr r30,r3 /* function */
834 mr r31,r4 /* argument */
835 ori r3,r5,CLONE_VM /* flags */
836 oris r3,r3,CLONE_UNTRACED>>16
837 li r4,0 /* new sp (unused) */
838 li r0,__NR_clone
839 sc
840 cmpwi 0,r3,0 /* parent or child? */
841 bne 1f /* return if parent */
842 li r0,0 /* make top-level stack frame */
843 stwu r0,-16(r1)
844 mtlr r30 /* fn addr in lr */
845 mr r3,r31 /* load arg and call fn */
846 PPC440EP_ERR42
847 blrl
848 li r0,__NR_exit /* exit if function returns */
849 li r3,0
850 sc
8511: lwz r30,8(r1)
852 lwz r31,12(r1)
853 addi r1,r1,16
854 blr
855
856_GLOBAL(kernel_execve)
857 li r0,__NR_execve
858 sc
859 bnslr
860 neg r3,r3
861 blr
862
863/*
864 * This routine is just here to keep GCC happy - sigh...
865 */
866_GLOBAL(__main)
867 blr
868