2 * Linux/PA-RISC Project (http://www.parisc-linux.org/)
4 * kernel entry points (interruptions, system call wrappers)
5 * Copyright (C) 1999,2000 Philipp Rumpf
6 * Copyright (C) 1999 SuSE GmbH Nuernberg
7 * Copyright (C) 2000 Hewlett-Packard (John Marvin)
8 * Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <linux/config.h>
26 #include <asm/offsets.h>
28 /* we have the following possibilities to act on an interruption:
29 * - handle in assembly and use shadowed registers only
30 * - save registers to kernel stack and handle in assembly or C */
33 #include <asm/assembly.h> /* for LDREG/STREG defines */
34 #include <asm/pgtable.h>
36 #include <asm/signal.h>
37 #include <asm/unistd.h>
38 #include <asm/thread_info.h>
52 .import pa_dbit_lock,data
54 /* space_to_prot macro creates a prot id from a space id */
56 #if (SPACEID_SHIFT) == 0
57 .macro space_to_prot spc prot
58 depd,z \spc,62,31,\prot
61 .macro space_to_prot spc prot
62 extrd,u \spc,(64 - (SPACEID_SHIFT)),32,\prot
66 /* Switch to virtual mapping, trashing only %r1 */
71 or,= %r0,%r1,%r0 /* Only save sr7 in sr3 if sr7 != 0 */
77 ldil L%KERNEL_PSW, %r1
78 ldo R%KERNEL_PSW(%r1), %r1
93 * The "get_stack" macros are responsible for determining the
98 * Already using a kernel stack, so call the
99 * get_stack_use_r30 macro to push a pt_regs structure
100 * on the stack, and store registers there.
102 * Need to set up a kernel stack, so call the
103 * get_stack_use_cr30 macro to set up a pointer
104 * to the pt_regs structure contained within the
105 * task pointer pointed to by cr30. Set the stack
106 * pointer to point to the end of the task structure.
110 * Already using a kernel stack, check to see if r30
111 * is already pointing to the per processor interrupt
112 * stack. If it is, call the get_stack_use_r30 macro
113 * to push a pt_regs structure on the stack, and store
114 * registers there. Otherwise, call get_stack_use_cr31
115 * to get a pointer to the base of the interrupt stack
116 * and push a pt_regs structure on that stack.
118 * Need to set up a kernel stack, so call the
119 * get_stack_use_cr30 macro to set up a pointer
120 * to the pt_regs structure contained within the
121 * task pointer pointed to by cr30. Set the stack
122 * pointer to point to the end of the task structure.
123 * N.B: We don't use the interrupt stack for the
124 * first interrupt from userland, because signals/
125 * resched's are processed when returning to userland,
126 * and we can sleep in those cases.
128 * Note that we use shadowed registers for temps until
129 * we can save %r26 and %r29. %r26 is used to preserve
130 * %r8 (a shadowed register) which temporarily contained
131 * either the fault type ("code") or the eirr. We need
132 * to use a non-shadowed register to carry the value over
133 * the rfir in virt_map. We use %r26 since this value winds
134 * up being passed as the argument to either do_cpu_irq_mask
135 * or handle_interruption. %r29 is used to hold a pointer
136 * the register save area, and once again, it needs to
137 * be a non-shadowed register so that it survives the rfir.
139 * N.B. TASK_SZ_ALGN and PT_SZ_ALGN include space for a stack frame.
142 .macro get_stack_use_cr30
144 /* we save the registers in the task struct */
148 LDREG TI_TASK(%r9), %r1 /* thread_info -> task_struct */
150 ldo TASK_REGS(%r9),%r9
151 STREG %r30, PT_GR30(%r9)
152 STREG %r29,PT_GR29(%r9)
153 STREG %r26,PT_GR26(%r9)
156 ldo THREAD_SZ_ALGN(%r1), %r30
159 .macro get_stack_use_r30
161 /* we put a struct pt_regs on the stack and save the registers there */
164 STREG %r30,PT_GR30(%r9)
165 ldo PT_SZ_ALGN(%r30),%r30
166 STREG %r29,PT_GR29(%r9)
167 STREG %r26,PT_GR26(%r9)
172 LDREG PT_GR1(%r29), %r1
173 LDREG PT_GR30(%r29),%r30
174 LDREG PT_GR29(%r29),%r29
177 /* default interruption handler
178 * (calls traps.c:handle_interruption) */
185 /* Interrupt interruption handler
186 * (calls irq.c:do_cpu_irq_mask) */
193 .import os_hpmc, code
197 nop /* must be a NOP, will be patched later */
198 ldil L%PA(os_hpmc), %r3
199 ldo R%PA(os_hpmc)(%r3), %r3
202 .word 0 /* checksum (will be patched) */
203 .word PA(os_hpmc) /* address of handler */
204 .word 0 /* length of handler */
208 * Performance Note: Instructions will be moved up into
209 * this part of the code later on, once we are sure
210 * that the tlb miss handlers are close to final form.
213 /* Register definitions for tlb miss handler macros */
215 va = r8 /* virtual address for which the trap occured */
216 spc = r24 /* space for which the trap occured */
221 * itlb miss interruption handler (parisc 1.1 - 32 bit)
235 * itlb miss interruption handler (parisc 2.0)
252 * naitlb miss interruption handler (parisc 1.1 - 32 bit)
254 * Note: naitlb misses will be treated
255 * as an ordinary itlb miss for now.
256 * However, note that naitlb misses
257 * have the faulting address in the
261 .macro naitlb_11 code
266 /* FIXME: If user causes a naitlb miss, the priv level may not be in
267 * lower bits of va, where the itlb miss handler is expecting them
275 * naitlb miss interruption handler (parisc 2.0)
277 * Note: naitlb misses will be treated
278 * as an ordinary itlb miss for now.
279 * However, note that naitlb misses
280 * have the faulting address in the
284 .macro naitlb_20 code
293 /* FIXME: If user causes a naitlb miss, the priv level may not be in
294 * lower bits of va, where the itlb miss handler is expecting them
302 * dtlb miss interruption handler (parisc 1.1 - 32 bit)
316 * dtlb miss interruption handler (parisc 2.0)
333 /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) */
335 .macro nadtlb_11 code
345 /* nadtlb miss interruption handler (parisc 2.0) */
347 .macro nadtlb_20 code
362 * dirty bit trap interruption handler (parisc 1.1 - 32 bit)
376 * dirty bit trap interruption handler (parisc 2.0)
393 * Align fault_vector_20 on 4K boundary so that both
394 * fault_vector_11 and fault_vector_20 are on the
395 * same page. This is only necessary as long as we
396 * write protect the kernel text, which we may stop
397 * doing once we use large page translations to cover
398 * the static part of the kernel address space.
401 .export fault_vector_20
408 /* First vector is invalid (0) */
409 .ascii "cows can fly"
451 .export fault_vector_11
456 /* First vector is invalid (0) */
457 .ascii "cows can fly"
499 .import handle_interruption,code
500 .import do_cpu_irq_mask,code
503 * r26 = function to be called
504 * r25 = argument to pass in
505 * r24 = flags for do_fork()
507 * Kernel threads don't ever return, so they don't need
508 * a true register context. We just save away the arguments
509 * for copy_thread/ret_ to properly set up the child.
512 #define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */
513 #define CLONE_UNTRACED 0x00800000
515 .export __kernel_thread, code
518 STREG %r2, -RP_OFFSET(%r30)
521 ldo PT_SZ_ALGN(%r30),%r30
523 /* Yo, function pointers in wide mode are little structs... -PB */
525 STREG %r2, PT_GR27(%r1) /* Store childs %dp */
528 STREG %r22, PT_GR22(%r1) /* save r22 (arg5) */
529 copy %r0, %r22 /* user_tid */
531 STREG %r26, PT_GR26(%r1) /* Store function & argument for child */
532 STREG %r25, PT_GR25(%r1)
533 ldil L%CLONE_UNTRACED, %r26
534 ldo CLONE_VM(%r26), %r26 /* Force CLONE_VM since only init_mm */
535 or %r26, %r24, %r26 /* will have kernel mappings. */
536 copy %r0, %r25 /* stack_start */
537 stw %r0, -52(%r30) /* user_tid */
539 ldo -16(%r30),%r29 /* Reference param save area */
542 copy %r1, %r24 /* pt_regs */
544 /* Parent Returns here */
546 LDREG -PT_SZ_ALGN-RP_OFFSET(%r30), %r2
547 ldo -PT_SZ_ALGN(%r30), %r30
549 ldw TASK_PID(%r28), %r28
554 * copy_thread moved args from temp save area set up above
555 * into task save area.
558 .export ret_from_kernel_thread
559 ret_from_kernel_thread:
561 #if CONFIG_PREEMPT || CONFIG_SMP
562 /* Call schedule_tail first though */
563 bl schedule_tail, %r2
567 LDREG TI_TASK-THREAD_SZ_ALGN(%r30), %r1
568 LDREG TASK_PT_GR25(%r1), %r26
570 LDREG TASK_PT_GR27(%r1), %r27
571 LDREG TASK_PT_GR22(%r1), %r22
573 LDREG TASK_PT_GR26(%r1), %r1
578 ldo -16(%r30),%r29 /* Reference param save area */
579 loadgp /* Thread could have been in a module */
584 .import sys_execve, code
585 .export __execve, code
589 ldo PT_SZ_ALGN(%r30), %r30
590 STREG %r26, PT_GR26(%r16)
591 STREG %r25, PT_GR25(%r16)
592 STREG %r24, PT_GR24(%r16)
594 ldo -16(%r30),%r29 /* Reference param save area */
599 cmpib,=,n 0,%r28,intr_return /* forward */
601 /* yes, this will trap and die. */
610 * struct task_struct *_switch_to(struct task_struct *prev,
611 * struct task_struct *next)
613 * switch kernel stacks and return prev */
614 .export _switch_to, code
616 STREG %r2, -RP_OFFSET(%r30)
620 ldil L%_switch_to_ret, %r2
621 ldo R%_switch_to_ret(%r2), %r2
623 STREG %r2, TASK_PT_KPC(%r26)
624 LDREG TASK_PT_KPC(%r25), %r2
626 STREG %r30, TASK_PT_KSP(%r26)
627 LDREG TASK_PT_KSP(%r25), %r30
628 LDREG TASK_THREAD_INFO(%r25), %r25
633 mtctl %r0, %cr0 /* Needed for single stepping */
636 LDREG -RP_OFFSET(%r30), %r2
641 * Common rfi return path for interruptions, kernel execve, and
642 * sys_rt_sigreturn (sometimes). The sys_rt_sigreturn syscall will
643 * return via this path if the signal was received when the process
644 * was running; if the process was blocked on a syscall then the
645 * normal syscall_exit path is used. All syscalls for traced
646 * proceses exit via intr_restore.
648 * XXX If any syscalls that change a processes space id ever exit
649 * this way, then we will need to copy %sr3 in to PT_SR[3..7], and
652 * Note that the following code uses a "relied upon translation".
653 * See the parisc ACD for details. The ssm is necessary due to a
659 .export syscall_exit_rfi
662 LDREG TI_TASK(%r16), %r16 /* thread_info -> task_struct */
663 ldo TASK_REGS(%r16),%r16
664 /* Force iaoq to userspace, as the user has had access to our current
665 * context via sigcontext. Also Filter the PSW for the same reason.
667 LDREG PT_IAOQ0(%r16),%r19
669 STREG %r19,PT_IAOQ0(%r16)
670 LDREG PT_IAOQ1(%r16),%r19
672 STREG %r19,PT_IAOQ1(%r16)
673 LDREG PT_PSW(%r16),%r19
674 ldil L%USER_PSW_MASK,%r1
675 ldo R%USER_PSW_MASK(%r1),%r1
677 ldil L%USER_PSW_HI_MASK,%r20
678 ldo R%USER_PSW_HI_MASK(%r20),%r20
681 and %r19,%r1,%r19 /* Mask out bits that user shouldn't play with */
683 ldo R%USER_PSW(%r1),%r1
684 or %r19,%r1,%r19 /* Make sure default USER_PSW bits are set */
685 STREG %r19,PT_PSW(%r16)
688 * If we aren't being traced, we never saved space registers
689 * (we don't store them in the sigcontext), so set them
690 * to "proper" values now (otherwise we'll wind up restoring
691 * whatever was last stored in the task structure, which might
692 * be inconsistant if an interrupt occured while on the gateway
693 * page) Note that we may be "trashing" values the user put in
694 * them, but we don't support the the user changing them.
697 STREG %r0,PT_SR2(%r16)
699 STREG %r19,PT_SR0(%r16)
700 STREG %r19,PT_SR1(%r16)
701 STREG %r19,PT_SR3(%r16)
702 STREG %r19,PT_SR4(%r16)
703 STREG %r19,PT_SR5(%r16)
704 STREG %r19,PT_SR6(%r16)
705 STREG %r19,PT_SR7(%r16)
710 /* Check for software interrupts */
712 .import irq_stat,data
715 ldo R%irq_stat(%r19),%r19
718 ldw TI_CPU(%r1),%r1 /* get cpu # - int */
719 /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
720 ** irq_stat[] is defined using ____cacheline_aligned.
727 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
728 #endif /* CONFIG_SMP */
730 LDREG IRQSTAT_SIRQ_PEND(%r19),%r20 /* hardirq.h: unsigned long */
731 cmpib,<>,n 0,%r20,intr_do_softirq /* forward */
735 /* check for reschedule */
737 LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */
738 bb,<,n %r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */
743 LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_SIGPENDING */
744 bb,<,n %r19, 31-TIF_SIGPENDING, intr_do_signal /* forward */
748 ldo PT_FR31(%r29),%r1
760 rsm (PSW_SM_Q|PSW_SM_P|PSW_SM_D|PSW_SM_I),%r0
773 .import do_softirq,code
777 ldo -16(%r30),%r29 /* Reference param save area */
784 .import schedule,code
786 /* Only do reschedule if we are returning to user space */
787 LDREG PT_IASQ0(%r16), %r20
788 CMPIB= 0,%r20,intr_restore /* backward */
790 LDREG PT_IASQ1(%r16), %r20
791 CMPIB= 0,%r20,intr_restore /* backward */
795 ldo -16(%r30),%r29 /* Reference param save area */
798 ldil L%intr_check_sig, %r2
800 ldo R%intr_check_sig(%r2), %r2
803 .import do_signal,code
805 /* Only do signals if we are returning to user space */
806 LDREG PT_IASQ0(%r16), %r20
807 CMPIB= 0,%r20,intr_restore /* backward */
809 LDREG PT_IASQ1(%r16), %r20
810 CMPIB= 0,%r20,intr_restore /* backward */
813 copy %r0, %r24 /* unsigned long in_syscall */
814 copy %r16, %r25 /* struct pt_regs *regs */
816 ldo -16(%r30),%r29 /* Reference param save area */
820 copy %r0, %r26 /* sigset_t *oldset = NULL */
826 * External interrupts.
835 #if 0 /* Interrupt Stack support not working yet! */
838 /* FIXME! depi below has hardcoded idea of interrupt stack size (32k)*/
856 ldo PT_FR0(%r29), %r24
861 copy %r29, %r26 /* arg0 is pt_regs */
862 copy %r29, %r16 /* save pt_regs */
864 ldil L%intr_return, %r2
867 ldo -16(%r30),%r29 /* Reference param save area */
871 ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */
874 /* Generic interruptions (illegal insn, unaligned, page fault, etc) */
876 .export intr_save, code /* for os_hpmc */
892 /* If this trap is a itlb miss, skip saving/adjusting isr/ior */
895 * FIXME: 1) Use a #define for the hardwired "6" below (and in
897 * 2) Once we start executing code above 4 Gb, we need
898 * to adjust iasq/iaoq here in the same way we
899 * adjust isr/ior below.
902 CMPIB=,n 6,%r26,skip_save_ior
904 /* save_specials left ipsw value in r8 for us to test */
906 mfctl %cr20, %r16 /* isr */
907 mfctl %cr21, %r17 /* ior */
911 * If the interrupted code was running with W bit off (32 bit),
912 * clear the b bits (bits 0 & 1) in the ior.
914 extrd,u,*<> %r8,PSW_W_BIT,1,%r0
918 * FIXME: This code has hardwired assumptions about the split
919 * between space bits and offset bits. This will change
920 * when we allow alternate page sizes.
923 /* adjust isr/ior. */
925 extrd,u %r16,63,7,%r1 /* get high bits from isr for ior */
926 depd %r1,31,7,%r17 /* deposit them into ior */
927 depdi 0,63,7,%r16 /* clear them from isr */
929 STREG %r16, PT_ISR(%r29)
930 STREG %r17, PT_IOR(%r29)
937 ldo PT_FR0(%r29), %r25
942 copy %r29, %r25 /* arg1 is pt_regs */
944 ldo -16(%r30),%r29 /* Reference param save area */
947 ldil L%intr_check_sig, %r2
948 copy %r25, %r16 /* save pt_regs */
950 b handle_interruption
951 ldo R%intr_check_sig(%r2), %r2
955 * Note for all tlb miss handlers:
957 * cr24 contains a pointer to the kernel address space
960 * cr25 contains a pointer to the current user address
961 * space page directory.
963 * sr3 will contain the space id of the user address space
964 * of the current running thread while that thread is
965 * running in the kernel.
969 * register number allocations. Note that these are all
970 * in the shadowed registers
973 t0 = r1 /* temporary register 0 */
974 va = r8 /* virtual address for which the trap occured */
975 t1 = r9 /* temporary register 1 */
976 pte = r16 /* pte/phys page # */
977 prot = r17 /* prot bits */
978 spc = r24 /* space for which the trap occured */
979 ptp = r25 /* page directory/page table pointer */
984 extrd,u spc,63,7,t1 /* adjust va */
985 depd t1,31,7,va /* adjust va */
986 depdi 0,63,7,spc /* adjust space */
987 mfctl %cr25,ptp /* Assume user space miss */
988 or,*<> %r0,spc,%r0 /* If it is user space, nullify */
989 mfctl %cr24,ptp /* Load kernel pgd instead */
990 extrd,u va,33,9,t1 /* Get pgd index */
992 mfsp %sr7,t0 /* Get current space */
993 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
994 cmpb,*<>,n t0,spc,dtlb_fault /* forward */
996 /* First level page table lookup */
999 extrd,u va,42,9,t0 /* get second-level index */
1000 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
1001 depdi 0,63,12,ptp /* clear prot bits */
1003 /* Second level page table lookup */
1006 extrd,u va,51,9,t0 /* get third-level index */
1007 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
1008 depdi 0,63,12,ptp /* clear prot bits */
1010 /* Third level page table lookup */
1013 ldi _PAGE_ACCESSED,t1
1015 bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
1017 /* Check whether the "accessed" bit was set, otherwise do so */
1019 or t1,pte,t0 /* t0 has R bit set */
1020 and,*<> t1,pte,%r0 /* test and nullify if already set */
1021 std t0,0(ptp) /* write back pte */
1023 space_to_prot spc prot /* create prot id from space */
1024 depd pte,8,7,prot /* add in prot bits from pte */
1026 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1027 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1028 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1029 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1031 /* Get rid of prot bits and convert to page addr for idtlbt */
1034 extrd,u pte,56,52,pte
1040 dtlb_check_alias_20w:
1042 /* Check to see if fault is in the temporary alias region */
1044 cmpib,*<>,n 0,spc,dtlb_fault /* forward */
1045 ldil L%(TMPALIAS_MAP_START),t0
1048 cmpb,*<>,n t0,t1,dtlb_fault /* forward */
1049 ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
1050 depd,z prot,8,7,prot
1053 * OK, it is in the temp alias region, check whether "from" or "to".
1054 * Check "subtle" note in pacache.S re: r23/r26.
1057 extrd,u,*= va,41,1,r0
1058 or,*tr %r23,%r0,pte /* If "from" use "from" page */
1059 or,* %r26,%r0,pte /* else "to", use "to" page */
1067 extrd,u spc,63,7,t1 /* adjust va */
1068 depd t1,31,7,va /* adjust va */
1069 depdi 0,63,7,spc /* adjust space */
1070 mfctl %cr25,ptp /* Assume user space miss */
1071 or,*<> %r0,spc,%r0 /* If it is user space, nullify */
1072 mfctl %cr24,ptp /* Load kernel pgd instead */
1073 extrd,u va,33,9,t1 /* Get pgd index */
1075 mfsp %sr7,t0 /* Get current space */
1076 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
1077 cmpb,*<>,n t0,spc,nadtlb_fault /* forward */
1079 /* First level page table lookup */
1082 extrd,u va,42,9,t0 /* get second-level index */
1083 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1084 depdi 0,63,12,ptp /* clear prot bits */
1086 /* Second level page table lookup */
1089 extrd,u va,51,9,t0 /* get third-level index */
1090 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1091 depdi 0,63,12,ptp /* clear prot bits */
1093 /* Third level page table lookup */
1096 ldi _PAGE_ACCESSED,t1
1098 bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20w
1100 space_to_prot spc prot /* create prot id from space */
1101 depd pte,8,7,prot /* add in prot bits from pte */
1103 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1104 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1105 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1106 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1108 /* Get rid of prot bits and convert to page addr for idtlbt */
1111 extrd,u pte,56,52,pte
1117 nadtlb_check_flush_20w:
1118 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1120 /* Insert a "flush only" translation */
1125 /* Get rid of prot bits and convert to page addr for idtlbt */
1128 extrd,u pte,56,52,pte
1137 mfctl %cr25,ptp /* Assume user space miss */
1138 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1139 mfctl %cr24,ptp /* Load kernel pgd instead */
1140 extru va,9,10,t1 /* Get pgd index */
1142 mfsp %sr7,t0 /* Get current space */
1143 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1144 cmpb,<>,n t0,spc,dtlb_fault /* forward */
1146 /* First level page table lookup */
1149 extru va,19,10,t0 /* get second-level index */
1150 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_11
1151 depi 0,31,12,ptp /* clear prot bits */
1153 /* Second level page table lookup */
1156 ldi _PAGE_ACCESSED,t1
1158 bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_11
1160 /* Check whether the "accessed" bit was set, otherwise do so */
1162 or t1,pte,t0 /* t0 has R bit set */
1163 and,<> t1,pte,%r0 /* test and nullify if already set */
1164 stw t0,0(ptp) /* write back pte */
1166 zdep spc,30,15,prot /* create prot id from space */
1167 dep pte,8,7,prot /* add in prot bits from pte */
1169 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1171 extru,= pte,_PAGE_USER_BIT,1,r0
1172 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1173 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1174 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1176 /* Get rid of prot bits and convert to page addr for idtlba */
1181 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1184 idtlba pte,(%sr1,va)
1185 idtlbp prot,(%sr1,va)
1187 mtsp t0, %sr1 /* Restore sr1 */
1192 dtlb_check_alias_11:
1194 /* Check to see if fault is in the temporary alias region */
1196 cmpib,<>,n 0,spc,dtlb_fault /* forward */
1197 ldil L%(TMPALIAS_MAP_START),t0
1200 cmpb,<>,n t0,t1,dtlb_fault /* forward */
1201 ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
1202 depw,z prot,8,7,prot
1205 * OK, it is in the temp alias region, check whether "from" or "to".
1206 * Check "subtle" note in pacache.S re: r23/r26.
1210 or,tr %r23,%r0,pte /* If "from" use "from" page */
1211 or %r26,%r0,pte /* else "to", use "to" page */
1220 mfctl %cr25,ptp /* Assume user space miss */
1221 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1222 mfctl %cr24,ptp /* Load kernel pgd instead */
1223 extru va,9,10,t1 /* Get pgd index */
1225 mfsp %sr7,t0 /* Get current space */
1226 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1227 cmpb,<>,n t0,spc,nadtlb_fault /* forward */
1229 /* First level page table lookup */
1232 extru va,19,10,t0 /* get second-level index */
1233 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1234 depi 0,31,12,ptp /* clear prot bits */
1236 /* Second level page table lookup */
1239 ldi _PAGE_ACCESSED,t1
1241 bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_11
1243 zdep spc,30,15,prot /* create prot id from space */
1244 dep pte,8,7,prot /* add in prot bits from pte */
1246 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1248 extru,= pte,_PAGE_USER_BIT,1,r0
1249 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1250 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1251 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1253 /* Get rid of prot bits and convert to page addr for idtlba */
1258 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1261 idtlba pte,(%sr1,va)
1262 idtlbp prot,(%sr1,va)
1264 mtsp t0, %sr1 /* Restore sr1 */
1269 nadtlb_check_flush_11:
1270 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1272 /* Insert a "flush only" translation */
1277 /* Get rid of prot bits and convert to page addr for idtlba */
1282 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1285 idtlba pte,(%sr1,va)
1286 idtlbp prot,(%sr1,va)
1288 mtsp t0, %sr1 /* Restore sr1 */
1294 mfctl %cr25,ptp /* Assume user space miss */
1295 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1296 mfctl %cr24,ptp /* Load kernel pgd instead */
1297 extru va,9,10,t1 /* Get pgd index */
1299 mfsp %sr7,t0 /* Get current space */
1300 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1301 cmpb,<>,n t0,spc,dtlb_fault /* forward */
1303 /* First level page table lookup */
1306 extru va,19,10,t0 /* get second-level index */
1307 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20
1308 depi 0,31,12,ptp /* clear prot bits */
1310 /* Second level page table lookup */
1313 ldi _PAGE_ACCESSED,t1
1315 bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20
1317 /* Check whether the "accessed" bit was set, otherwise do so */
1319 or t1,pte,t0 /* t0 has R bit set */
1320 and,<> t1,pte,%r0 /* test and nullify if already set */
1321 stw t0,0(ptp) /* write back pte */
1323 space_to_prot spc prot /* create prot id from space */
1324 depd pte,8,7,prot /* add in prot bits from pte */
1326 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1327 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1328 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1329 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1331 /* Get rid of prot bits and convert to page addr for idtlbt */
1334 depdi 0,63,12,pte /* clear lower 12 bits */
1336 extrd,u,*tr pte,56,25,pte
1337 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1343 dtlb_check_alias_20:
1345 /* Check to see if fault is in the temporary alias region */
1347 cmpib,<>,n 0,spc,dtlb_fault /* forward */
1348 ldil L%(TMPALIAS_MAP_START),t0
1351 cmpb,<>,n t0,t1,dtlb_fault /* forward */
1352 ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
1353 depd,z prot,8,7,prot
1356 * OK, it is in the temp alias region, check whether "from" or "to".
1357 * Check "subtle" note in pacache.S re: r23/r26.
1361 or,tr %r23,%r0,pte /* If "from" use "from" page */
1362 or %r26,%r0,pte /* else "to", use "to" page */
1370 mfctl %cr25,ptp /* Assume user space miss */
1371 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1372 mfctl %cr24,ptp /* Load kernel pgd instead */
1373 extru va,9,10,t1 /* Get pgd index */
1375 mfsp %sr7,t0 /* Get current space */
1376 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1377 cmpb,<>,n t0,spc,nadtlb_fault /* forward */
1379 /* First level page table lookup */
1382 extru va,19,10,t0 /* get second-level index */
1383 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1384 depi 0,31,12,ptp /* clear prot bits */
1386 /* Second level page table lookup */
1389 ldi _PAGE_ACCESSED,t1
1391 bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20
1393 space_to_prot spc prot /* create prot id from space */
1394 depd pte,8,7,prot /* add in prot bits from pte */
1396 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1397 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1398 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1399 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1401 /* Get rid of prot bits and convert to page addr for idtlbt */
1404 depdi 0,63,12,pte /* clear lower 12 bits */
1406 extrd,u,*tr pte,56,25,pte
1407 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1413 nadtlb_check_flush_20:
1414 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1416 /* Insert a "flush only" translation */
1421 /* Get rid of prot bits and convert to page addr for idtlbt */
1424 extrd,u pte,56,32,pte
1434 * Non access misses can be caused by fdc,fic,pdc,lpa,probe and
1435 * probei instructions. We don't want to fault for these
1436 * instructions (not only does it not make sense, it can cause
1437 * deadlocks, since some flushes are done with the mmap
1438 * semaphore held). If the translation doesn't exist, we can't
1439 * insert a translation, so have to emulate the side effects
1440 * of the instruction. Since we don't insert a translation
1441 * we can get a lot of faults during a flush loop, so it makes
1442 * sense to try to do it here with minimum overhead. We only
1443 * emulate fdc,fic & pdc instructions whose base and index
1444 * registers are not shadowed. We defer everything else to the
1448 mfctl %cr19,%r9 /* Get iir */
1451 cmpb,<>,n %r16,%r17,nadtlb_fault /* Not fdc,fic,pdc */
1452 bb,>=,n %r9,26,nadtlb_nullify /* m bit not set, just nullify */
1453 b,l get_register,%r25
1454 extrw,u %r9,15,5,%r8 /* Get index register # */
1455 CMPIB=,n -1,%r1,nadtlb_fault /* have to use slow path */
1457 b,l get_register,%r25
1458 extrw,u %r9,10,5,%r8 /* Get base register # */
1459 CMPIB=,n -1,%r1,nadtlb_fault /* have to use slow path */
1460 b,l set_register,%r25
1461 add,l %r1,%r24,%r1 /* doesn't affect c/b bits */
1464 mfctl %cr22,%r8 /* Get ipsw */
1466 or %r8,%r9,%r8 /* Set PSW_N */
1476 * I miss is a little different, since we allow users to fault
1477 * on the gateway page which is in the kernel address space.
1480 extrd,u spc,63,7,t1 /* adjust va */
1481 depd t1,31,7,va /* adjust va */
1482 depdi 0,63,7,spc /* adjust space */
1483 cmpib,*= 0,spc,itlb_miss_kernel_20w
1484 extrd,u va,33,9,t1 /* Get pgd index */
1486 mfctl %cr25,ptp /* load user pgd */
1488 mfsp %sr7,t0 /* Get current space */
1489 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
1490 cmpb,*<>,n t0,spc,itlb_fault /* forward */
1492 /* First level page table lookup */
1494 itlb_miss_common_20w:
1496 extrd,u va,42,9,t0 /* get second-level index */
1497 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1498 depdi 0,63,12,ptp /* clear prot bits */
1500 /* Second level page table lookup */
1503 extrd,u va,51,9,t0 /* get third-level index */
1504 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1505 depdi 0,63,12,ptp /* clear prot bits */
1507 /* Third level page table lookup */
1510 ldi _PAGE_ACCESSED,t1
1512 bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
1514 /* Check whether the "accessed" bit was set, otherwise do so */
1516 or t1,pte,t0 /* t0 has R bit set */
1517 and,*<> t1,pte,%r0 /* test and nullify if already set */
1518 std t0,0(ptp) /* write back pte */
1520 space_to_prot spc prot /* create prot id from space */
1521 depd pte,8,7,prot /* add in prot bits from pte */
1523 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1524 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1525 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1526 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1528 /* Get rid of prot bits and convert to page addr for iitlbt */
1531 extrd,u pte,56,32,pte
1537 itlb_miss_kernel_20w:
1538 b itlb_miss_common_20w
1539 mfctl %cr24,ptp /* Load kernel pgd */
1545 * I miss is a little different, since we allow users to fault
1546 * on the gateway page which is in the kernel address space.
1549 cmpib,= 0,spc,itlb_miss_kernel_11
1550 extru va,9,10,t1 /* Get pgd index */
1552 mfctl %cr25,ptp /* load user pgd */
1554 mfsp %sr7,t0 /* Get current space */
1555 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1556 cmpb,<>,n t0,spc,itlb_fault /* forward */
1558 /* First level page table lookup */
1560 itlb_miss_common_11:
1562 extru va,19,10,t0 /* get second-level index */
1563 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1564 depi 0,31,12,ptp /* clear prot bits */
1566 /* Second level page table lookup */
1569 ldi _PAGE_ACCESSED,t1
1571 bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
1573 /* Check whether the "accessed" bit was set, otherwise do so */
1575 or t1,pte,t0 /* t0 has R bit set */
1576 and,<> t1,pte,%r0 /* test and nullify if already set */
1577 stw t0,0(ptp) /* write back pte */
1579 zdep spc,30,15,prot /* create prot id from space */
1580 dep pte,8,7,prot /* add in prot bits from pte */
1582 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1584 extru,= pte,_PAGE_USER_BIT,1,r0
1585 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1586 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1587 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1589 /* Get rid of prot bits and convert to page addr for iitlba */
1594 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1597 iitlba pte,(%sr1,va)
1598 iitlbp prot,(%sr1,va)
1600 mtsp t0, %sr1 /* Restore sr1 */
1605 itlb_miss_kernel_11:
1606 b itlb_miss_common_11
1607 mfctl %cr24,ptp /* Load kernel pgd */
1612 * I miss is a little different, since we allow users to fault
1613 * on the gateway page which is in the kernel address space.
1616 cmpib,= 0,spc,itlb_miss_kernel_20
1617 extru va,9,10,t1 /* Get pgd index */
1619 mfctl %cr25,ptp /* load user pgd */
1621 mfsp %sr7,t0 /* Get current space */
1622 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1623 cmpb,<>,n t0,spc,itlb_fault /* forward */
1625 /* First level page table lookup */
1627 itlb_miss_common_20:
1629 extru va,19,10,t0 /* get second-level index */
1630 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1631 depi 0,31,12,ptp /* clear prot bits */
1633 /* Second level page table lookup */
1636 ldi _PAGE_ACCESSED,t1
1638 bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
1640 /* Check whether the "accessed" bit was set, otherwise do so */
1642 or t1,pte,t0 /* t0 has R bit set */
1643 and,<> t1,pte,%r0 /* test and nullify if already set */
1644 stw t0,0(ptp) /* write back pte */
1646 space_to_prot spc prot /* create prot id from space */
1647 depd pte,8,7,prot /* add in prot bits from pte */
1649 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1650 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1651 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1652 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1654 /* Get rid of prot bits and convert to page addr for iitlbt */
1657 depdi 0,63,12,pte /* clear lower 12 bits */
1659 extrd,u,*tr pte,56,25,pte
1660 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1667 itlb_miss_kernel_20:
1668 b itlb_miss_common_20
1669 mfctl %cr24,ptp /* Load kernel pgd */
1675 extrd,u spc,63,7,t1 /* adjust va */
1676 depd t1,31,7,va /* adjust va */
1677 depdi 0,1,2,va /* adjust va */
1678 depdi 0,63,7,spc /* adjust space */
1679 mfctl %cr25,ptp /* Assume user space miss */
1680 or,*<> %r0,spc,%r0 /* If it is user space, nullify */
1681 mfctl %cr24,ptp /* Load kernel pgd instead */
1682 extrd,u va,33,9,t1 /* Get pgd index */
1684 mfsp %sr7,t0 /* Get current space */
1685 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
1686 cmpb,*<>,n t0,spc,dbit_fault /* forward */
1688 /* First level page table lookup */
1691 extrd,u va,42,9,t0 /* get second-level index */
1692 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1693 depdi 0,63,12,ptp /* clear prot bits */
1695 /* Second level page table lookup */
1698 extrd,u va,51,9,t0 /* get third-level index */
1699 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1700 depdi 0,63,12,ptp /* clear prot bits */
1702 /* Third level page table lookup */
1706 CMPIB=,n 0,spc,dbit_nolock_20w
1707 ldil L%PA(pa_dbit_lock),t0
1708 ldo R%PA(pa_dbit_lock)(t0),t0
1712 cmpib,= 0,t1,dbit_spin_20w
1717 ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
1719 bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
1721 /* Set Accessed and Dirty bits in the pte */
1724 std pte,0(ptp) /* write back pte */
1726 space_to_prot spc prot /* create prot id from space */
1727 depd pte,8,7,prot /* add in prot bits from pte */
1729 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1730 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1731 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1732 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1734 /* Get rid of prot bits and convert to page addr for idtlbt */
1737 extrd,u pte,56,52,pte
1740 CMPIB=,n 0,spc,dbit_nounlock_20w
1752 mfctl %cr25,ptp /* Assume user space trap */
1753 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1754 mfctl %cr24,ptp /* Load kernel pgd instead */
1755 extru va,9,10,t1 /* Get pgd index */
1757 mfsp %sr7,t0 /* Get current space */
1758 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1759 cmpb,<>,n t0,spc,dbit_fault /* forward */
1761 /* First level page table lookup */
1764 extru va,19,10,t0 /* get second-level index */
1765 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1766 depi 0,31,12,ptp /* clear prot bits */
1768 /* Second level page table lookup */
1772 CMPIB=,n 0,spc,dbit_nolock_11
1773 ldil L%PA(pa_dbit_lock),t0
1774 ldo R%PA(pa_dbit_lock)(t0),t0
1778 cmpib,= 0,t1,dbit_spin_11
1783 ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
1785 bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
1787 /* Set Accessed and Dirty bits in the pte */
1790 stw pte,0(ptp) /* write back pte */
1792 zdep spc,30,15,prot /* create prot id from space */
1793 dep pte,8,7,prot /* add in prot bits from pte */
1795 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1797 extru,= pte,_PAGE_USER_BIT,1,r0
1798 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1799 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1800 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1802 /* Get rid of prot bits and convert to page addr for idtlba */
1807 mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
1810 idtlba pte,(%sr1,va)
1811 idtlbp prot,(%sr1,va)
1813 mtsp t1, %sr1 /* Restore sr1 */
1815 CMPIB=,n 0,spc,dbit_nounlock_11
1826 mfctl %cr25,ptp /* Assume user space trap */
1827 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1828 mfctl %cr24,ptp /* Load kernel pgd instead */
1829 extru va,9,10,t1 /* Get pgd index */
1831 mfsp %sr7,t0 /* Get current space */
1832 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1833 cmpb,<>,n t0,spc,dbit_fault /* forward */
1835 /* First level page table lookup */
1838 extru va,19,10,t0 /* get second-level index */
1839 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1840 depi 0,31,12,ptp /* clear prot bits */
1842 /* Second level page table lookup */
1846 CMPIB=,n 0,spc,dbit_nolock_20
1847 ldil L%PA(pa_dbit_lock),t0
1848 ldo R%PA(pa_dbit_lock)(t0),t0
1852 cmpib,= 0,t1,dbit_spin_20
1857 ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
1859 bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
1861 /* Set Accessed and Dirty bits in the pte */
1864 stw pte,0(ptp) /* write back pte */
1866 space_to_prot spc prot /* create prot id from space */
1867 depd pte,8,7,prot /* add in prot bits from pte */
1869 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1870 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1871 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1872 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1875 depdi 0,63,12,pte /* clear lower 12 bits */
1877 extrd,u,*tr pte,56,25,pte
1878 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1882 CMPIB=,n 0,spc,dbit_nounlock_20
1893 .import handle_interruption,code
1897 ldi 31,%r8 /* Use an unused code */
1915 /* Register saving semantics for system calls:
1917 %r1 clobbered by system call macro in userspace
1918 %r2 saved in PT_REGS by gateway page
1919 %r3 - %r18 preserved by C code (saved by signal code)
1920 %r19 - %r20 saved in PT_REGS by gateway page
1921 %r21 - %r22 non-standard syscall args
1922 stored in kernel stack by gateway page
1923 %r23 - %r26 arg3-arg0, saved in PT_REGS by gateway page
1924 %r27 - %r30 saved in PT_REGS by gateway page
1925 %r31 syscall return pointer
1928 /* Floating point registers (FIXME: what do we do with these?)
1930 %fr0 - %fr3 status/exception, not preserved
1931 %fr4 - %fr7 arguments
1932 %fr8 - %fr11 not preserved by C code
1933 %fr12 - %fr21 preserved by C code
1934 %fr22 - %fr31 not preserved by C code
1937 .macro reg_save regs
1938 STREG %r3, PT_GR3(\regs)
1939 STREG %r4, PT_GR4(\regs)
1940 STREG %r5, PT_GR5(\regs)
1941 STREG %r6, PT_GR6(\regs)
1942 STREG %r7, PT_GR7(\regs)
1943 STREG %r8, PT_GR8(\regs)
1944 STREG %r9, PT_GR9(\regs)
1945 STREG %r10,PT_GR10(\regs)
1946 STREG %r11,PT_GR11(\regs)
1947 STREG %r12,PT_GR12(\regs)
1948 STREG %r13,PT_GR13(\regs)
1949 STREG %r14,PT_GR14(\regs)
1950 STREG %r15,PT_GR15(\regs)
1951 STREG %r16,PT_GR16(\regs)
1952 STREG %r17,PT_GR17(\regs)
1953 STREG %r18,PT_GR18(\regs)
1956 .macro reg_restore regs
1957 LDREG PT_GR3(\regs), %r3
1958 LDREG PT_GR4(\regs), %r4
1959 LDREG PT_GR5(\regs), %r5
1960 LDREG PT_GR6(\regs), %r6
1961 LDREG PT_GR7(\regs), %r7
1962 LDREG PT_GR8(\regs), %r8
1963 LDREG PT_GR9(\regs), %r9
1964 LDREG PT_GR10(\regs),%r10
1965 LDREG PT_GR11(\regs),%r11
1966 LDREG PT_GR12(\regs),%r12
1967 LDREG PT_GR13(\regs),%r13
1968 LDREG PT_GR14(\regs),%r14
1969 LDREG PT_GR15(\regs),%r15
1970 LDREG PT_GR16(\regs),%r16
1971 LDREG PT_GR17(\regs),%r17
1972 LDREG PT_GR18(\regs),%r18
1975 .export sys_fork_wrapper
1976 .export child_return
1978 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
1979 ldo TASK_REGS(%r1),%r1
1982 STREG %r3, PT_CR27(%r1)
1984 STREG %r2,-RP_OFFSET(%r30)
1985 ldo FRAME_SIZE(%r30),%r30
1987 ldo -16(%r30),%r29 /* Reference param save area */
1990 /* These are call-clobbered registers and therefore
1991 also syscall-clobbered (we hope). */
1992 STREG %r2,PT_GR19(%r1) /* save for child */
1993 STREG %r30,PT_GR21(%r1)
1995 LDREG PT_GR30(%r1),%r25
2000 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
2002 ldo -FRAME_SIZE(%r30),%r30 /* get the stackframe */
2003 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2004 ldo TASK_REGS(%r1),%r1 /* get pt regs */
2006 LDREG PT_CR27(%r1), %r3
2010 /* strace expects syscall # to be preserved in r20 */
2013 STREG %r20,PT_GR20(%r1)
2015 /* Set the return value for the child */
2017 #if CONFIG_SMP || CONFIG_PREEMPT
2018 bl schedule_tail, %r2
2022 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1
2023 LDREG TASK_PT_GR19(%r1),%r2
2028 .export sys_clone_wrapper
2030 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2031 ldo TASK_REGS(%r1),%r1 /* get pt regs */
2034 STREG %r3, PT_CR27(%r1)
2036 STREG %r2,-RP_OFFSET(%r30)
2037 ldo FRAME_SIZE(%r30),%r30
2039 ldo -16(%r30),%r29 /* Reference param save area */
2042 STREG %r2,PT_GR19(%r1) /* save for child */
2043 STREG %r30,PT_GR21(%r1)
2048 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
2050 .export sys_vfork_wrapper
2052 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2053 ldo TASK_REGS(%r1),%r1 /* get pt regs */
2056 STREG %r3, PT_CR27(%r1)
2058 STREG %r2,-RP_OFFSET(%r30)
2059 ldo FRAME_SIZE(%r30),%r30
2061 ldo -16(%r30),%r29 /* Reference param save area */
2064 STREG %r2,PT_GR19(%r1) /* save for child */
2065 STREG %r30,PT_GR21(%r1)
2071 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
2074 .macro execve_wrapper execve
2075 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2076 ldo TASK_REGS(%r1),%r1 /* get pt regs */
2079 * Do we need to save/restore r3-r18 here?
2080 * I don't think so. why would new thread need old
2081 * threads registers?
2084 /* %arg0 - %arg3 are already saved for us. */
2086 STREG %r2,-RP_OFFSET(%r30)
2087 ldo FRAME_SIZE(%r30),%r30
2089 ldo -16(%r30),%r29 /* Reference param save area */
2094 ldo -FRAME_SIZE(%r30),%r30
2095 LDREG -RP_OFFSET(%r30),%r2
2097 /* If exec succeeded we need to load the args */
2100 cmpb,>>= %r28,%r1,error_\execve
2108 .export sys_execve_wrapper
2112 execve_wrapper sys_execve
2115 .export sys32_execve_wrapper
2116 .import sys32_execve
2118 sys32_execve_wrapper:
2119 execve_wrapper sys32_execve
2122 .export sys_rt_sigreturn_wrapper
2123 sys_rt_sigreturn_wrapper:
2124 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26
2125 ldo TASK_REGS(%r26),%r26 /* get pt regs */
2126 /* Don't save regs, we are going to restore them from sigcontext. */
2127 STREG %r2, -RP_OFFSET(%r30)
2129 ldo FRAME_SIZE(%r30), %r30
2130 bl sys_rt_sigreturn,%r2
2131 ldo -16(%r30),%r29 /* Reference param save area */
2133 bl sys_rt_sigreturn,%r2
2134 ldo FRAME_SIZE(%r30), %r30
2137 ldo -FRAME_SIZE(%r30), %r30
2138 LDREG -RP_OFFSET(%r30), %r2
2140 /* FIXME: I think we need to restore a few more things here. */
2141 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2142 ldo TASK_REGS(%r1),%r1 /* get pt regs */
2145 /* If the signal was received while the process was blocked on a
2146 * syscall, then r2 will take us to syscall_exit; otherwise r2 will
2147 * take us to syscall_exit_rfi and on to intr_return.
2150 LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */
2152 .export sys_sigaltstack_wrapper
2153 sys_sigaltstack_wrapper:
2154 /* Get the user stack pointer */
2155 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2156 ldo TASK_REGS(%r1),%r24 /* get pt regs */
2157 LDREG TASK_PT_GR30(%r24),%r24
2158 STREG %r2, -RP_OFFSET(%r30)
2160 ldo FRAME_SIZE(%r30), %r30
2161 bl do_sigaltstack,%r2
2162 ldo -16(%r30),%r29 /* Reference param save area */
2164 bl do_sigaltstack,%r2
2165 ldo FRAME_SIZE(%r30), %r30
2168 ldo -FRAME_SIZE(%r30), %r30
2169 LDREG -RP_OFFSET(%r30), %r2
2174 .export sys32_sigaltstack_wrapper
2175 sys32_sigaltstack_wrapper:
2176 /* Get the user stack pointer */
2177 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r24
2178 LDREG TASK_PT_GR30(%r24),%r24
2179 STREG %r2, -RP_OFFSET(%r30)
2180 ldo FRAME_SIZE(%r30), %r30
2181 bl do_sigaltstack32,%r2
2182 ldo -16(%r30),%r29 /* Reference param save area */
2184 ldo -FRAME_SIZE(%r30), %r30
2185 LDREG -RP_OFFSET(%r30), %r2
2190 .export sys_rt_sigsuspend_wrapper
2191 sys_rt_sigsuspend_wrapper:
2192 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
2193 ldo TASK_REGS(%r1),%r24
2196 STREG %r2, -RP_OFFSET(%r30)
2198 ldo FRAME_SIZE(%r30), %r30
2199 bl sys_rt_sigsuspend,%r2
2200 ldo -16(%r30),%r29 /* Reference param save area */
2202 bl sys_rt_sigsuspend,%r2
2203 ldo FRAME_SIZE(%r30), %r30
2206 ldo -FRAME_SIZE(%r30), %r30
2207 LDREG -RP_OFFSET(%r30), %r2
2209 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
2210 ldo TASK_REGS(%r1),%r1
2216 .export syscall_exit
2218 /* NOTE: HP-UX syscalls also come through here
2219 after hpux_syscall_exit fixes up return
2221 /* NOTE: Not all syscalls exit this way. rt_sigreturn will exit
2222 * via syscall_exit_rfi if the signal was received while the process
2226 /* save return value now */
2229 LDREG TI_TASK(%r1),%r1
2230 STREG %r28,TASK_PT_GR28(%r1)
2232 /* Save other hpux returns if personality is PER_HPUX */
2234 /* <linux/personality.h> cannot be easily included */
2235 #define PER_HPUX 0x10
2236 LDREG TASK_PERSONALITY(%r1),%r19
2237 #warning the ldo+CMPIB could probably be done better but 0x10 i soutside of range of CMPIB
2238 ldo -PER_HPUX(%r19), %r19
2240 STREG %r22,TASK_PT_GR22(%r1)
2241 STREG %r29,TASK_PT_GR29(%r1)
2244 /* Seems to me that dp could be wrong here, if the syscall involved
2245 * calling a module, and nothing got round to restoring dp on return.
2251 /* Check for software interrupts */
2253 .import irq_stat,data
2255 ldil L%irq_stat,%r19
2256 ldo R%irq_stat(%r19),%r19
2259 /* sched.h: int processor */
2260 /* %r26 is used as scratch register to index into irq_stat[] */
2261 ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
2263 /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
2269 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
2270 #endif /* CONFIG_SMP */
2272 LDREG IRQSTAT_SIRQ_PEND(%r19),%r20 /* hardirq.h: unsigned long */
2273 cmpib,<>,n 0,%r20,syscall_do_softirq /* forward */
2275 syscall_check_resched:
2277 /* check for reschedule */
2279 LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* long */
2280 bb,<,n %r19, 31-TIF_NEED_RESCHED, syscall_do_resched /* forward */
2283 LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* get ti flags */
2284 bb,<,n %r19, 31-TIF_SIGPENDING, syscall_do_signal /* forward */
2287 LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* get ti flags */
2288 bb,< %r19, 31-TIF_SYSCALL_TRACE,syscall_restore_rfi
2289 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* delay slot! */
2290 ldo TASK_PT_FR31(%r1),%r19 /* reload fpregs */
2293 LDREG TASK_PT_SAR(%r1),%r19 /* restore SAR */
2296 LDREG TASK_PT_GR2(%r1),%r2 /* restore user rp */
2297 LDREG TASK_PT_GR19(%r1),%r19
2298 LDREG TASK_PT_GR20(%r1),%r20
2299 LDREG TASK_PT_GR21(%r1),%r21
2300 LDREG TASK_PT_GR22(%r1),%r22
2301 LDREG TASK_PT_GR23(%r1),%r23
2302 LDREG TASK_PT_GR24(%r1),%r24
2303 LDREG TASK_PT_GR25(%r1),%r25
2304 LDREG TASK_PT_GR26(%r1),%r26
2305 LDREG TASK_PT_GR27(%r1),%r27 /* restore user dp */
2306 LDREG TASK_PT_GR28(%r1),%r28 /* syscall return value */
2307 LDREG TASK_PT_GR29(%r1),%r29
2308 LDREG TASK_PT_GR31(%r1),%r31 /* restore syscall rp */
2311 LDREG TASK_PT_GR30(%r1),%r30 /* restore user sp */
2312 mfsp %sr3,%r1 /* Get users space id */
2313 mtsp %r1,%sr7 /* Restore sr7 */
2315 mtsp %r1,%sr4 /* Restore sr4 */
2316 mtsp %r1,%sr5 /* Restore sr5 */
2317 mtsp %r1,%sr6 /* Restore sr6 */
2319 depi 3,31,2,%r31 /* ensure return to user mode. */
2322 /* Since we are returning to a 32 bit user process, we always
2323 * clear the W bit. This means that the be (and mtsp) gets
2324 * executed in narrow mode, but that is OK, since we are
2325 * returning to a 32 bit process. When we support 64 bit processes
2326 * we won't clear the W bit, so the be will run in wide mode.
2329 be 0(%sr3,%r31) /* return to user space */
2332 be,n 0(%sr3,%r31) /* return to user space */
2335 /* We have to return via an RFI, so that PSW T and R bits can be set
2337 * This sets up pt_regs so we can return via intr_restore, which is not
2338 * the most efficient way of doing things, but it works.
2340 syscall_restore_rfi:
2341 LDREG TASK_PTRACE(%r1), %r19
2342 ldo -1(%r0),%r2 /* Set recovery cntr to -1 */
2343 mtctl %r2,%cr0 /* for immediate trap */
2344 LDREG TASK_PT_PSW(%r1),%r2 /* Get old PSW */
2345 ldi 0x0b,%r20 /* Create new PSW */
2346 depi -1,13,1,%r20 /* C, Q, D, and I bits */
2347 bb,>=,n %r19,15,try_tbit /* PT_SINGLESTEP */
2348 depi -1,27,1,%r20 /* R bit */
2350 bb,>=,n %r19,14,psw_setup /* PT_BLOCKSTEP, see ptrace.c */
2351 depi -1,7,1,%r20 /* T bit */
2353 STREG %r20,TASK_PT_PSW(%r1)
2355 /* Always store space registers, since sr3 can be changed (e.g. fork) */
2358 STREG %r25,TASK_PT_SR3(%r1)
2359 STREG %r25,TASK_PT_SR4(%r1)
2360 STREG %r25,TASK_PT_SR5(%r1)
2361 STREG %r25,TASK_PT_SR6(%r1)
2362 STREG %r25,TASK_PT_SR7(%r1)
2363 STREG %r25,TASK_PT_IASQ0(%r1)
2364 STREG %r25,TASK_PT_IASQ1(%r1)
2367 /* Now if old D bit is clear, it means we didn't save all registers
2368 * on syscall entry, so do that now. This only happens on TRACEME
2369 * calls, or if someone attached to us while we were on a syscall.
2370 * We could make this more efficient by not saving r3-r18, but
2371 * then we wouldn't be able to use the common intr_restore path.
2372 * It is only for traced processes anyway, so performance is not
2375 bb,< %r2,30,pt_regs_ok /* Branch if D set */
2376 ldo TASK_REGS(%r1),%r25
2377 reg_save %r25 /* Save r3 to r18 */
2379 STREG %r2,TASK_PT_SR0(%r1)
2381 STREG %r2,TASK_PT_SR1(%r1)
2383 STREG %r2,TASK_PT_SR2(%r1)
2385 LDREG TASK_PT_GR31(%r1),%r2
2386 depi 3,31,2,%r2 /* ensure return to user mode. */
2387 STREG %r2,TASK_PT_IAOQ0(%r1)
2389 STREG %r2,TASK_PT_IAOQ1(%r1)
2394 .import do_softirq,code
2398 b syscall_check_resched
2399 ssm PSW_SM_I, %r0 /* do_softirq returns with I bit off */
2401 .import schedule,code
2405 ldo -16(%r30),%r29 /* Reference param save area */
2409 b syscall_check_bh /* if resched, we start over again */
2412 .import do_signal,code
2414 /* Save callee-save registers (for sigcontext).
2415 FIXME: After this point the process structure should be
2416 consistent with all the relevant state of the process
2417 before the syscall. We need to verify this. */
2418 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2419 ldo TASK_REGS(%r1), %r25 /* struct pt_regs *regs */
2422 ldi 1, %r24 /* unsigned long in_syscall */
2425 ldo -16(%r30),%r29 /* Reference param save area */
2428 copy %r0, %r26 /* sigset_t *oldset = NULL */
2430 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2431 ldo TASK_REGS(%r1), %r20 /* reload pt_regs */
2437 * get_register is used by the non access tlb miss handlers to
2438 * copy the value of the general register specified in r8 into
2439 * r1. This routine can't be used for shadowed registers, since
2440 * the rfir will restore the original value. So, for the shadowed
2441 * registers we put a -1 into r1 to indicate that the register
2442 * should not be used (the register being copied could also have
2443 * a -1 in it, but that is OK, it just means that we will have
2444 * to use the slow path instead).
2450 bv %r0(%r25) /* r0 */
2452 bv %r0(%r25) /* r1 - shadowed */
2454 bv %r0(%r25) /* r2 */
2456 bv %r0(%r25) /* r3 */
2458 bv %r0(%r25) /* r4 */
2460 bv %r0(%r25) /* r5 */
2462 bv %r0(%r25) /* r6 */
2464 bv %r0(%r25) /* r7 */
2466 bv %r0(%r25) /* r8 - shadowed */
2468 bv %r0(%r25) /* r9 - shadowed */
2470 bv %r0(%r25) /* r10 */
2472 bv %r0(%r25) /* r11 */
2474 bv %r0(%r25) /* r12 */
2476 bv %r0(%r25) /* r13 */
2478 bv %r0(%r25) /* r14 */
2480 bv %r0(%r25) /* r15 */
2482 bv %r0(%r25) /* r16 - shadowed */
2484 bv %r0(%r25) /* r17 - shadowed */
2486 bv %r0(%r25) /* r18 */
2488 bv %r0(%r25) /* r19 */
2490 bv %r0(%r25) /* r20 */
2492 bv %r0(%r25) /* r21 */
2494 bv %r0(%r25) /* r22 */
2496 bv %r0(%r25) /* r23 */
2498 bv %r0(%r25) /* r24 - shadowed */
2500 bv %r0(%r25) /* r25 - shadowed */
2502 bv %r0(%r25) /* r26 */
2504 bv %r0(%r25) /* r27 */
2506 bv %r0(%r25) /* r28 */
2508 bv %r0(%r25) /* r29 */
2510 bv %r0(%r25) /* r30 */
2512 bv %r0(%r25) /* r31 */
2516 * set_register is used by the non access tlb miss handlers to
2517 * copy the value of r1 into the general register specified in
2524 bv %r0(%r25) /* r0 (silly, but it is a place holder) */
2526 bv %r0(%r25) /* r1 */
2528 bv %r0(%r25) /* r2 */
2530 bv %r0(%r25) /* r3 */
2532 bv %r0(%r25) /* r4 */
2534 bv %r0(%r25) /* r5 */
2536 bv %r0(%r25) /* r6 */
2538 bv %r0(%r25) /* r7 */
2540 bv %r0(%r25) /* r8 */
2542 bv %r0(%r25) /* r9 */
2544 bv %r0(%r25) /* r10 */
2546 bv %r0(%r25) /* r11 */
2548 bv %r0(%r25) /* r12 */
2550 bv %r0(%r25) /* r13 */
2552 bv %r0(%r25) /* r14 */
2554 bv %r0(%r25) /* r15 */
2556 bv %r0(%r25) /* r16 */
2558 bv %r0(%r25) /* r17 */
2560 bv %r0(%r25) /* r18 */
2562 bv %r0(%r25) /* r19 */
2564 bv %r0(%r25) /* r20 */
2566 bv %r0(%r25) /* r21 */
2568 bv %r0(%r25) /* r22 */
2570 bv %r0(%r25) /* r23 */
2572 bv %r0(%r25) /* r24 */
2574 bv %r0(%r25) /* r25 */
2576 bv %r0(%r25) /* r26 */
2578 bv %r0(%r25) /* r27 */
2580 bv %r0(%r25) /* r28 */
2582 bv %r0(%r25) /* r29 */
2584 bv %r0(%r25) /* r30 */
2586 bv %r0(%r25) /* r31 */