2 * arch/ppc64/kernel/misc.S
6 * This file contains miscellaneous low-level functions.
7 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
9 * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
11 * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
12 * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version
17 * 2 of the License, or (at your option) any later version.
21 #include <linux/config.h>
22 #include <linux/sys.h>
23 #include <asm/unistd.h>
24 #include <asm/errno.h>
25 #include <asm/processor.h>
27 #include <asm/cache.h>
28 #include <asm/cputable.h>
34 * Returns (address we're running at) - (address we were linked at)
35 * for use before the text and data are mapped to KERNELBASE.
67 #ifdef CONFIG_PPC_ISERIES
68 /* unsigned long __no_use_save_flags(void) */
69 _GLOBAL(__no_use_save_flags)
71 lbz r3,PACAPROCENABLED(r4)
72 /* shift into position of MSR.EE */
76 /* void __no_use_restore_flags(unsigned long flags) */
77 _GLOBAL(__no_use_restore_flags)
78 /* shift from position of MSR.EE */
81 lbz r5,PACAPROCENABLED(r6)
82 /* Check if things are setup the way we want _already_. */
85 /* are we enabling interrupts? */
87 stb r3,PACAPROCENABLED(r6)
89 /* Check pending interrupts */
94 * Handle pending interrupts in interrupt context
100 _GLOBAL(__no_use_cli)
102 lbz r3,PACAPROCENABLED(r5)
104 stb r4,PACAPROCENABLED(r5)
105 /* shift into position of MSR.EE */
109 _GLOBAL(__no_use_sti)
112 stb r3,PACAPROCENABLED(r6)
114 /* Check for pending interrupts
115 * A decrementer, IPI or PMC interrupt may have occurred
116 * while we were in the hypervisor (which enables)
122 * Handle pending interrupts in interrupt context
129 * Flush instruction cache.
131 _GLOBAL(flush_instruction_cache)
134 * This is called by kgdb code
135 * and should probably go away
136 * to be replaced by invalidating
137 * the cache lines that are actually
140 /* use invalidate-all bit in HID0
141 * - is this consistent across all 64-bit cpus? -- paulus */
150 * Write any modified data cache blocks out to memory
151 * and invalidate the corresponding instruction cache blocks.
153 * flush_icache_range(unsigned long start, unsigned long stop)
155 * flush all bytes from start through stop-1 inclusive
158 _GLOBAL(flush_icache_range)
161 * Flush the data cache to memory
163 * Different systems have different cache line sizes
164 * and in some cases i-cache and d-cache line sizes differ from
167 LOADADDR(r10,naca) /* Get Naca address */
169 LOADADDR(r11,systemcfg) /* Get systemcfg address */
171 lwz r7,DCACHEL1LINESIZE(r11) /* Get cache line size */
173 andc r6,r3,r5 /* round low to line bdy */
174 subf r8,r6,r4 /* compute length */
175 add r8,r8,r5 /* ensure we get enough */
176 lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of cache line size */
177 srw. r8,r8,r9 /* compute line count */
178 beqlr /* nothing to do? */
185 /* Now invalidate the instruction cache */
187 lwz r7,ICACHEL1LINESIZE(r11) /* Get Icache line size */
189 andc r6,r3,r5 /* round low to line bdy */
190 subf r8,r6,r4 /* compute length */
192 lwz r9,ICACHEL1LOGLINESIZE(r10) /* Get log-2 of Icache line size */
193 srw. r8,r8,r9 /* compute line count */
194 beqlr /* nothing to do? */
203 * Like above, but only do the D-cache.
205 * flush_dcache_range(unsigned long start, unsigned long stop)
207 * flush all bytes from start to stop-1 inclusive
209 _GLOBAL(flush_dcache_range)
212 * Flush the data cache to memory
214 * Different systems have different cache line sizes
216 LOADADDR(r10,naca) /* Get Naca address */
218 LOADADDR(r11,systemcfg) /* Get systemcfg address */
220 lwz r7,DCACHEL1LINESIZE(r11) /* Get dcache line size */
222 andc r6,r3,r5 /* round low to line bdy */
223 subf r8,r6,r4 /* compute length */
224 add r8,r8,r5 /* ensure we get enough */
225 lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */
226 srw. r8,r8,r9 /* compute line count */
227 beqlr /* nothing to do? */
236 * Flush a particular page from the data cache to RAM.
237 * Note: this is necessary because the instruction cache does *not*
238 * snoop from the data cache.
240 * void __flush_dcache_icache(void *page)
242 _GLOBAL(__flush_dcache_icache)
244 * Flush the data cache to memory
246 * Different systems have different cache line sizes
249 /* Flush the dcache */
252 LOADADDR(r8,systemcfg) /* Get systemcfg address */
254 clrrdi r3,r3,12 /* Page align */
255 lwz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */
256 lwz r5,DCACHEL1LINESIZE(r8) /* Get dcache line size */
264 /* Now invalidate the icache */
266 lwz r4,ICACHEL1LINESPERPAGE(r7) /* Get # icache lines per page */
267 lwz r5,ICACHEL1LINESIZE(r8) /* Get icache line size */
276 * I/O string operations
278 * insb(port, buf, len)
279 * outsb(port, buf, len)
280 * insw(port, buf, len)
281 * outsw(port, buf, len)
282 * insl(port, buf, len)
283 * outsl(port, buf, len)
284 * insw_ns(port, buf, len)
285 * outsw_ns(port, buf, len)
286 * insl_ns(port, buf, len)
287 * outsl_ns(port, buf, len)
289 * The *_ns versions don't do byte-swapping.
402 * Extended precision shifts
404 * R3/R4 has 64 bit value
408 * ashrdi3: XXXYYY/ZZZAAA -> SSSXXX/YYYZZZ
409 * ashldi3: XXXYYY/ZZZAAA -> YYYZZZ/AAA000
410 * lshrdi3: XXXYYY/ZZZAAA -> 000XXX/YYYZZZ
412 /* MIKEC: These may no longer be needed...what does gcc expect ? */
417 slw r7,r3,r6 /* isolate YYY */
418 srw r4,r4,r5 /* isolate ZZZ */
419 or r4,r4,r7 /* YYYZZZ */
420 sraw r3,r3,r5 /* SSSXXX */
426 srw r7,r4,r6 /* isolate ZZZ */
427 slw r4,r4,r5 /* AAA000 */
428 slw r3,r3,r5 /* YYY--- */
429 or r3,r3,r7 /* YYYZZZ */
435 slw r7,r3,r6 /* isolate YYY */
436 srw r4,r4,r5 /* isolate ZZZ */
437 or r4,r4,r7 /* YYYZZZ */
438 srw r3,r3,r5 /* 000XXX */
448 mr r3,r1 /* Close enough */
464 lfd 0,0(r5) /* load up fpscr value */
468 mffs 0 /* save new fpscr value */
473 lfd 0,0(r5) /* load up fpscr value */
477 mffs 0 /* save new fpscr value */
483 * In: r3 = base of the cpu_specs array
484 * r4 = address of cur_cpu_spec
485 * r5 = relocation offset
487 _GLOBAL(identify_cpu)
490 lwz r8,CPU_SPEC_PVR_MASK(r3)
492 lwz r9,CPU_SPEC_PVR_VALUE(r3)
495 addi r3,r3,CPU_SPEC_ENTRY_SIZE
503 * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
504 * and writes nop's over sections of code that don't apply for this cpu.
505 * r3 = data offset (not changed)
507 _GLOBAL(do_cpu_ftr_fixups)
508 /* Dummy feature section to make sure section exists */
511 /* Get CPU 0 features */
512 LOADADDR(r6,cur_cpu_spec)
516 ld r4,CPU_SPEC_FEATURES(r4)
517 /* Get the fixup table */
518 LOADADDR(r6,__start___ftr_fixup)
520 LOADADDR(r7,__stop___ftr_fixup)
526 ld r8,-32(r6) /* mask */
528 ld r9,-24(r6) /* value */
531 ld r8,-16(r6) /* section begin */
532 ld r9,-8(r6) /* section end */
535 /* write nops over the section of code */
536 /* todo: if large section, add a branch at the start of it */
540 lis r0,0x60000000@h /* nop */
542 andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l
544 dcbst 0,r8 /* suboptimal, but simpler */
549 sync /* additional sync needed on g4 */
554 * call_setup_cpu - call the setup_cpu function for this cpu
557 * Setup function is called with:
559 * r4 = ptr to CPU spec (relocated)
561 _GLOBAL(call_setup_cpu)
562 LOADADDR(r4, cur_cpu_spec)
564 lwz r4,0(r4) # load pointer to cpu_spec
565 sub r4,r4,r3 # relocate
566 lwz r6,CPU_SPEC_SETUP(r4) # load function pointer
572 * Create a kernel thread
573 * arch_kernel_thread(fn, arg, flags)
575 _GLOBAL(arch_kernel_thread)
576 mr r6,r3 /* function */
577 ori r3,r5,CLONE_VM /* flags */
580 cmpi 0,r3,0 /* parent or child? */
581 bnelr /* return if parent */
583 li r0,0 /* clear out p->thread.regs */
584 ld r7,PACACURRENT(r13)
585 std r0,THREAD+PT_REGS(r7) /* since we don't have user ctx */
586 li r0,RUN_FLAG /* Run light on */
587 std r0,THREAD+THREAD_FLAGS(r7)
591 mtlr r6 /* fn addr in lr */
592 mr r3,r4 /* load arg and call fn */
594 li r0,__NR_exit /* exit after child exits */
598 #ifdef CONFIG_BINFMT_ELF32
599 /* Why isn't this a) automatic, b) written in 'C'? */
601 _GLOBAL(sys_call_table32)
602 .llong .sys_ni_syscall /* 0 - old "setup()" system call */
607 .llong .sys32_open /* 5 */
609 .llong .sys32_waitpid
612 .llong .sys_unlink /* 10 */
617 .llong .sys_chmod /* 15 */
619 .llong .sys_ni_syscall /* old break syscall holder */
622 .llong .sys_getpid /* 20 */
624 .llong .sys_oldumount
627 .llong .ppc64_sys32_stime /* 25 */
632 .llong .sys32_utime /* 30 */
633 .llong .sys_ni_syscall /* old stty syscall holder */
634 .llong .sys_ni_syscall /* old gtty syscall holder */
637 .llong .sys_ni_syscall /* 35 */ /* old ftime syscall holder */
642 .llong .sys_rmdir /* 40 */
646 .llong .sys_ni_syscall /* old prof syscall holder */
647 .llong .sys_brk /* 45 */
652 .llong .sys_getegid /* 50 */
654 .llong .sys32_umount /* recycled never used phys() */
655 .llong .sys_ni_syscall /* old lock syscall holder */
657 .llong .sys32_fcntl /* 55 */
658 .llong .sys_ni_syscall /* old mpx syscall holder */
659 .llong .sys32_setpgid
660 .llong .sys_ni_syscall /* old ulimit syscall holder */
662 .llong .sys32_umask /* 60 */
667 .llong .sys_getpgrp /* 65 */
669 .llong .sys32_sigaction
671 .llong .sys32_ssetmask
672 .llong .sys_setreuid /* 70 */
674 .llong .sys_sigsuspend
675 .llong .sys32_sigpending
676 .llong .sys32_sethostname
677 .llong .sys32_setrlimit /* 75 */
678 .llong .sys32_old_getrlimit
679 .llong .sys32_getrusage
680 .llong .sys32_gettimeofday
681 .llong .sys32_settimeofday
682 .llong .sys32_getgroups /* 80 */
683 .llong .sys32_setgroups
684 .llong .sys_ni_syscall /* old select syscall */
687 .llong .sys32_readlink /* 85 */
691 .llong .old32_readdir
692 .llong .sys32_mmap /* 90 */
695 .llong .sys_ftruncate
697 .llong .sys_fchown /* 95 */
698 .llong .sys32_getpriority
699 .llong .sys32_setpriority
700 .llong .sys_ni_syscall /* old profil syscall holder */
702 .llong .sys32_fstatfs /* 100 */
704 .llong .sys32_socketcall
706 .llong .sys32_setitimer
707 .llong .sys32_getitimer /* 105 */
708 .llong .sys32_newstat
709 .llong .sys32_newlstat
710 .llong .sys32_newfstat
712 .llong .sys_ni_syscall /* 110 old iopl syscall */
714 .llong .sys_ni_syscall /* old 'idle' syscall */
715 .llong .sys_ni_syscall /* old vm86 syscall */
717 .llong .sys_swapoff /* 115 */
718 .llong .sys32_sysinfo
721 .llong .ppc32_sigreturn
722 .llong .sys32_clone /* 120 */
723 .llong .sys32_setdomainname
724 .llong .ppc64_newuname
725 .llong .sys_ni_syscall /* old modify_ldt syscall */
726 .llong .sys32_adjtimex
727 .llong .sys_mprotect /* 125 */
728 .llong .sys32_sigprocmask
729 .llong .sys32_create_module
730 .llong .sys32_init_module
731 .llong .sys32_delete_module
732 .llong .sys32_get_kernel_syms /* 130 */
733 .llong .sys32_quotactl
734 .llong .sys32_getpgid
736 .llong .sys32_bdflush
737 .llong .sys32_sysfs /* 135 */
738 .llong .sys32_personality
739 .llong .sys_ni_syscall /* for afs_syscall */
742 .llong .sys_llseek /* 140 */
743 .llong .sys32_getdents
747 .llong .sys32_readv /* 145 */
750 .llong .sys_fdatasync
752 .llong .sys_mlock /* 150 */
754 .llong .sys32_mlockall
755 .llong .sys_munlockall
756 .llong .sys32_sched_setparam
757 .llong .sys32_sched_getparam /* 155 */
758 .llong .sys32_sched_setscheduler
759 .llong .sys32_sched_getscheduler
760 .llong .sys_sched_yield
761 .llong .sys32_sched_get_priority_max
762 .llong .sys32_sched_get_priority_min /* 160 */
763 .llong .sys32_sched_rr_get_interval
764 .llong .sys32_nanosleep
766 .llong .sys_setresuid
767 .llong .sys_getresuid /* 165 */
768 .llong .sys32_query_module
770 .llong .sys32_nfsservctl
771 .llong .sys_setresgid
772 .llong .sys_getresgid /* 170 */
774 .llong .ppc32_rt_sigreturn
775 .llong .sys32_rt_sigaction
776 .llong .sys32_rt_sigprocmask
777 .llong .sys32_rt_sigpending /* 175 */
778 .llong .sys32_rt_sigtimedwait
779 .llong .sys32_rt_sigqueueinfo
780 .llong .sys32_rt_sigsuspend
782 .llong .sys32_pwrite /* 180 */
787 .llong .sys32_sigaltstack /* 185 */
788 .llong .sys32_sendfile
789 .llong .sys_ni_syscall /* streams1 */
790 .llong .sys_ni_syscall /* streams2 */
792 .llong .sys32_getrlimit /* 190 */
793 .llong .sys32_readahead
795 .llong .sys32_truncate64 /* 193 - truncate64 */
796 .llong .sys32_ftruncate64 /* 194 - ftruncate64 */
797 .llong .sys_stat64 /* 195 - stat64 */
798 .llong .sys_lstat64 /* 196 - lstat64 */
799 .llong .sys_fstat64 /* 197 - fstat64 */
800 .llong .sys32_pciconfig_read /* 198 */
801 .llong .sys32_pciconfig_write /* 199 */
802 .llong .sys_pciconfig_iobase /* 200 */
803 .llong .sys_ni_syscall /* 201 - reserved - MacOnLinux - new */
804 .llong .sys_getdents64 /* 202 */
805 .llong .sys_pivot_root /* 203 */
806 .llong .sys32_fcntl64 /* 204 */
807 .llong .sys_madvise /* 205 */
808 .llong .sys_mincore /* 206 */
809 .llong .sys_gettid /* 207 */
810 #if 0 /* Reserved syscalls */
811 .llong .sys_tkill /* 208 */
813 .llong .sys_lsetxattr /* 210 */
814 .llong .sys_fsetxattr
816 .llong .sys_lgetxattr
817 .llong .sys_fgetxattr
818 .llong .sys_listxattr /* 215 */
819 .llong .sys_llistxattr
820 .llong .sys_flistxattr
821 .llong .sys_removexattr
822 .llong .sys_lremovexattr
823 .llong .sys_fremovexattr /* 220 */
826 .llong .sys_perfmonctl /* Put this here for now ... */
827 .rept NR_syscalls-222
828 .llong .sys_ni_syscall
832 _GLOBAL(sys_call_table)
833 .llong .sys_ni_syscall /* 0 - old "setup()" system call */
838 .llong .sys_open /* 5 */
843 .llong .sys_unlink /* 10 */
848 .llong .sys_chmod /* 15 */
850 .llong .sys_ni_syscall /* old break syscall holder */
853 .llong .sys_getpid /* 20 */
855 .llong .sys_ni_syscall /* old umount syscall */
858 .llong .ppc64_sys_stime /* 25 */
863 .llong .sys_utime /* 30 */
864 .llong .sys_ni_syscall /* old stty syscall holder */
865 .llong .sys_ni_syscall /* old gtty syscall holder */
868 .llong .sys_ni_syscall /* 35 */ /* old ftime syscall holder */
873 .llong .sys_rmdir /* 40 */
877 .llong .sys_ni_syscall /* old prof syscall holder */
878 .llong .sys_brk /* 45 */
883 .llong .sys_getegid /* 50 */
885 .llong .sys_umount /* recycled never used phys() */
886 .llong .sys_ni_syscall /* old lock syscall holder */
888 .llong .sys_fcntl /* 55 */
889 .llong .sys_ni_syscall /* old mpx syscall holder */
891 .llong .sys_ni_syscall /* old ulimit syscall holder */
892 .llong .sys_ni_syscall /* old uname syscall */
893 .llong .sys_umask /* 60 */
898 .llong .sys_getpgrp /* 65 */
900 .llong .sys_sigaction
903 .llong .sys_setreuid /* 70 */
905 .llong .sys_sigsuspend
906 .llong .sys_sigpending
907 .llong .sys_sethostname
908 .llong .sys_setrlimit /* 75 */
909 .llong .sys_ni_syscall /* old getrlimit syscall */
910 .llong .sys_getrusage
911 .llong .sys_gettimeofday
912 .llong .sys_settimeofday
913 .llong .sys_getgroups /* 80 */
914 .llong .sys_setgroups
915 .llong .sys_ni_syscall /* old select syscall */
918 .llong .sys_readlink /* 85 */
922 .llong .sys_ni_syscall /* old readdir syscall */
923 .llong .sys_mmap /* 90 */
926 .llong .sys_ftruncate
928 .llong .sys_fchown /* 95 */
929 .llong .sys_getpriority
930 .llong .sys_setpriority
931 .llong .sys_ni_syscall /* old profil syscall holder */
933 .llong .sys_fstatfs /* 100 */
935 .llong .sys_socketcall
937 .llong .sys_setitimer
938 .llong .sys_getitimer /* 105 */
943 .llong .sys_ni_syscall /* 110 old iopl syscall */
945 .llong .sys_ni_syscall /* old 'idle' syscall */
946 .llong .sys_ni_syscall /* old vm86 syscall */
948 .llong .sys_swapoff /* 115 */
952 .llong .ppc64_sigreturn
953 .llong .sys_clone /* 120 */
954 .llong .sys_setdomainname
955 .llong .ppc64_newuname
956 .llong .sys_ni_syscall /* old modify_ldt syscall */
958 .llong .sys_mprotect /* 125 */
959 .llong .sys_sigprocmask
960 .llong .sys_create_module
961 .llong .sys_init_module
962 .llong .sys_delete_module
963 .llong .sys_get_kernel_syms /* 130 */
968 .llong .sys_sysfs /* 135 */
969 .llong .sys_personality
970 .llong .sys_ni_syscall /* for afs_syscall */
973 .llong .sys_llseek /* 140 */
978 .llong .sys_readv /* 145 */
981 .llong .sys_fdatasync
983 .llong .sys_mlock /* 150 */
986 .llong .sys_munlockall
987 .llong .sys_sched_setparam
988 .llong .sys_sched_getparam /* 155 */
989 .llong .sys_sched_setscheduler
990 .llong .sys_sched_getscheduler
991 .llong .sys_sched_yield
992 .llong .sys_sched_get_priority_max
993 .llong .sys_sched_get_priority_min /* 160 */
994 .llong .sys_sched_rr_get_interval
995 .llong .sys_nanosleep
997 .llong .sys_setresuid
998 .llong .sys_getresuid /* 165 */
999 .llong .sys_query_module
1001 .llong .sys_nfsservctl
1002 .llong .sys_setresgid
1003 .llong .sys_getresgid /* 170 */
1005 .llong .ppc64_rt_sigreturn
1006 .llong .sys_rt_sigaction
1007 .llong .sys_rt_sigprocmask
1008 .llong .sys_rt_sigpending /* 175 */
1009 .llong .sys_rt_sigtimedwait
1010 .llong .sys_rt_sigqueueinfo
1011 .llong .sys_rt_sigsuspend
1013 .llong .sys_pwrite /* 180 */
1018 .llong .sys_sigaltstack /* 185 */
1019 .llong .sys_sendfile
1020 .llong .sys_ni_syscall /* streams1 */
1021 .llong .sys_ni_syscall /* streams2 */
1023 .llong .sys_getrlimit /* 190 */
1024 .llong .sys_readahead
1025 .llong .sys_ni_syscall /* 192 - reserved - mmap2 */
1026 .llong .sys_ni_syscall /* 193 - reserved - truncate64 */
1027 .llong .sys_ni_syscall /* 194 - reserved - ftruncate64 */
1028 .llong .sys_ni_syscall /* 195 - reserved - stat64 */
1029 .llong .sys_ni_syscall /* 196 - reserved - lstat64 */
1030 .llong .sys_ni_syscall /* 197 - reserved - fstat64 */
1031 .llong .sys_pciconfig_read /* 198 */
1032 .llong .sys_pciconfig_write /* 199 */
1033 .llong .sys_pciconfig_iobase /* 200 */
1034 .llong .sys_ni_syscall /* 201 - reserved - MacOnLinux - new */
1035 .llong .sys_getdents64 /* 202 */
1036 .llong .sys_pivot_root /* 203 */
1037 .llong .sys_ni_syscall /* 204 */
1038 .llong .sys_madvise /* 205 */
1039 .llong .sys_mincore /* 206 */
1040 .llong .sys_gettid /* 207 */
1041 #if 0 /* Reserved syscalls */
1042 .llong .sys_tkill /* 208 */
1043 .llong .sys_setxattr
1044 .llong .sys_lsetxattr /* 210 */
1045 .llong .sys_fsetxattr
1046 .llong .sys_getxattr
1047 .llong .sys_lgetxattr
1048 .llong .sys_fgetxattr
1049 .llong .sys_listxattr /* 215 */
1050 .llong .sys_llistxattr
1051 .llong .sys_flistxattr
1052 .llong .sys_removexattr
1053 .llong .sys_lremovexattr
1054 .llong .sys_fremovexattr /* 220 */
1057 .llong .sys_perfmonctl /* Put this here for now ... */
1058 .rept NR_syscalls-222
1059 .llong .sys_ni_syscall