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>
41 #define FRAME_SIZE 128
54 .import pa_dbit_lock,data
56 /* space_to_prot macro creates a prot id from a space id */
58 #if (SPACEID_SHIFT) == 0
59 .macro space_to_prot spc prot
60 depd,z \spc,62,31,\prot
63 .macro space_to_prot spc prot
64 extrd,u \spc,(64 - (SPACEID_SHIFT)),32,\prot
68 /* Switch to virtual mapping, trashing only %r1 */
73 or,= %r0,%r1,%r0 /* Only save sr7 in sr3 if sr7 != 0 */
79 ldil L%KERNEL_PSW, %r1
80 ldo R%KERNEL_PSW(%r1), %r1
95 * The "get_stack" macros are responsible for determining the
100 * Already using a kernel stack, so call the
101 * get_stack_use_r30 macro to push a pt_regs structure
102 * on the stack, and store registers there.
104 * Need to set up a kernel stack, so call the
105 * get_stack_use_cr30 macro to set up a pointer
106 * to the pt_regs structure contained within the
107 * task pointer pointed to by cr30. Set the stack
108 * pointer to point to the end of the task structure.
112 * Already using a kernel stack, check to see if r30
113 * is already pointing to the per processor interrupt
114 * stack. If it is, call the get_stack_use_r30 macro
115 * to push a pt_regs structure on the stack, and store
116 * registers there. Otherwise, call get_stack_use_cr31
117 * to get a pointer to the base of the interrupt stack
118 * and push a pt_regs structure on that stack.
120 * Need to set up a kernel stack, so call the
121 * get_stack_use_cr30 macro to set up a pointer
122 * to the pt_regs structure contained within the
123 * task pointer pointed to by cr30. Set the stack
124 * pointer to point to the end of the task structure.
125 * N.B: We don't use the interrupt stack for the
126 * first interrupt from userland, because signals/
127 * resched's are processed when returning to userland,
128 * and we can sleep in those cases.
130 * Note that we use shadowed registers for temps until
131 * we can save %r26 and %r29. %r26 is used to preserve
132 * %r8 (a shadowed register) which temporarily contained
133 * either the fault type ("code") or the eirr. We need
134 * to use a non-shadowed register to carry the value over
135 * the rfir in virt_map. We use %r26 since this value winds
136 * up being passed as the argument to either do_cpu_irq_mask
137 * or handle_interruption. %r29 is used to hold a pointer
138 * the register save area, and once again, it needs to
139 * be a non-shadowed register so that it survives the rfir.
141 * N.B. TASK_SZ_ALGN and PT_SZ_ALGN include space for a stack frame.
144 .macro get_stack_use_cr30
146 /* we save the registers in the task struct */
150 LDREG 0(%r9), %r1 /* thread_info -> task_struct */
152 ldo TASK_REGS(%r9),%r9
153 STREG %r30, PT_GR30(%r9)
154 STREG %r29,PT_GR29(%r9)
155 STREG %r26,PT_GR26(%r9)
158 ldo THREAD_SZ_ALGN(%r1), %r30
161 .macro get_stack_use_r30
163 /* we put a struct pt_regs on the stack and save the registers there */
166 STREG %r30,PT_GR30(%r9)
167 ldo PT_SZ_ALGN(%r30),%r30
168 STREG %r29,PT_GR29(%r9)
169 STREG %r26,PT_GR26(%r9)
174 LDREG PT_GR1(%r29), %r1
175 LDREG PT_GR30(%r29),%r30
176 LDREG PT_GR29(%r29),%r29
179 /* default interruption handler
180 * (calls traps.c:handle_interruption) */
187 /* Interrupt interruption handler
188 * (calls irq.c:do_cpu_irq_mask) */
195 .import os_hpmc, code
199 nop /* must be a NOP, will be patched later */
200 ldil L%PA(os_hpmc), %r3
201 ldo R%PA(os_hpmc)(%r3), %r3
204 .word 0 /* checksum (will be patched) */
205 .word PA(os_hpmc) /* address of handler */
206 .word 0 /* length of handler */
210 * Performance Note: Instructions will be moved up into
211 * this part of the code later on, once we are sure
212 * that the tlb miss handlers are close to final form.
215 /* Register definitions for tlb miss handler macros */
217 va = r8 /* virtual address for which the trap occured */
218 spc = r24 /* space for which the trap occured */
223 * itlb miss interruption handler (parisc 1.1 - 32 bit)
237 * itlb miss interruption handler (parisc 2.0)
254 * naitlb miss interruption handler (parisc 1.1 - 32 bit)
256 * Note: naitlb misses will be treated
257 * as an ordinary itlb miss for now.
258 * However, note that naitlb misses
259 * have the faulting address in the
263 .macro naitlb_11 code
268 /* FIXME: If user causes a naitlb miss, the priv level may not be in
269 * lower bits of va, where the itlb miss handler is expecting them
277 * naitlb miss interruption handler (parisc 2.0)
279 * Note: naitlb misses will be treated
280 * as an ordinary itlb miss for now.
281 * However, note that naitlb misses
282 * have the faulting address in the
286 .macro naitlb_20 code
295 /* FIXME: If user causes a naitlb miss, the priv level may not be in
296 * lower bits of va, where the itlb miss handler is expecting them
304 * dtlb miss interruption handler (parisc 1.1 - 32 bit)
318 * dtlb miss interruption handler (parisc 2.0)
335 /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) */
337 .macro nadtlb_11 code
347 /* nadtlb miss interruption handler (parisc 2.0) */
349 .macro nadtlb_20 code
364 * dirty bit trap interruption handler (parisc 1.1 - 32 bit)
378 * dirty bit trap interruption handler (parisc 2.0)
395 * Align fault_vector_20 on 4K boundary so that both
396 * fault_vector_11 and fault_vector_20 are on the
397 * same page. This is only necessary as long as we
398 * write protect the kernel text, which we may stop
399 * doing once we use large page translations to cover
400 * the static part of the kernel address space.
403 .export fault_vector_20
410 /* First vector is invalid (0) */
411 .ascii "cows can fly"
453 .export fault_vector_11
458 /* First vector is invalid (0) */
459 .ascii "cows can fly"
501 .import handle_interruption,code
502 .import handle_real_interruption,code
503 .import do_cpu_irq_mask,code
504 .import parisc_stopkernel,code
505 .import cpu_irq_region,data
508 * r26 = function to be called
509 * r25 = argument to pass in
510 * r24 = flags for do_fork()
512 * Kernel threads don't ever return, so they don't need
513 * a true register context. We just save away the arguments
514 * for copy_thread/ret_ to properly set up the child.
517 #define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */
519 .export __kernel_thread, code
522 STREG %r2, -RP_OFFSET(%r30)
525 ldo PT_SZ_ALGN(%r30),%r30
527 /* Yo, function pointers in wide mode are little structs... -PB */
529 STREG %r2, PT_GR27(%r1) /* Store childs %dp */
532 STREG %r26, PT_GR26(%r1) /* Store function & argument for child */
533 STREG %r25, PT_GR25(%r1)
534 ldo CLONE_VM(%r0), %r26 /* Force CLONE_VM since only init_mm */
535 or %r26, %r24, %r26 /* will have kernel mappings. */
538 ldo -16(%r30),%r29 /* Reference param save area */
543 /* Parent Returns here */
545 LDREG -PT_SZ_ALGN-RP_OFFSET(%r30), %r2
547 ldo -PT_SZ_ALGN(%r30), %r30
552 * copy_thread moved args from temp save area set up above
553 * into task save area.
556 .export ret_from_kernel_thread
557 ret_from_kernel_thread:
559 #if CONFIG_PREEMPT || CONFIG_SMP
560 /* Call schedule_tail first though */
561 bl schedule_tail, %r2
565 LDREG -THREAD_SZ_ALGN(%r30), %r1
566 LDREG TASK_PT_GR25(%r1), %r26
568 LDREG TASK_PT_GR27(%r1), %r27
570 LDREG TASK_PT_GR26(%r1), %r1
575 ldo -16(%r30),%r29 /* Reference param save area */
576 loadgp /* Thread could have been in a module */
581 .import sys_execve, code
582 .export __execve, code
586 ldo PT_SZ_ALGN(%r30), %r30
587 STREG %r26, PT_GR26(%r16)
588 STREG %r25, PT_GR25(%r16)
589 STREG %r24, PT_GR24(%r16)
591 ldo -16(%r30),%r29 /* Reference param save area */
596 cmpib,=,n 0,%r28,intr_return /* forward */
598 /* yes, this will trap and die. */
607 * struct task_struct *_switch_to(struct task_struct *prev,
608 * struct task_struct *next)
610 * switch kernel stacks and return prev */
611 .export _switch_to, code
613 STREG %r2, -RP_OFFSET(%r30)
617 ldil L%_switch_to_ret, %r2
618 ldo R%_switch_to_ret(%r2), %r2
620 STREG %r2, TASK_PT_KPC(%r26)
621 LDREG TASK_PT_KPC(%r25), %r2
623 STREG %r30, TASK_PT_KSP(%r26)
624 LDREG TASK_PT_KSP(%r25), %r30
634 mtctl %r0, %cr0 /* Needed for single stepping */
637 LDREG -RP_OFFSET(%r30), %r2
642 * Common rfi return path for interruptions, kernel execve, and
643 * sys_rt_sigreturn (sometimes). The sys_rt_sigreturn syscall will
644 * return via this path if the signal was received when the process
645 * was running; if the process was blocked on a syscall then the
646 * normal syscall_exit path is used. All syscalls for traced
647 * proceses exit via intr_restore.
649 * XXX If any syscalls that change a processes space id ever exit
650 * this way, then we will need to copy %sr3 in to PT_SR[3..7], and
653 * Note that the following code uses a "relied upon translation".
654 * See the parisc ACD for details. The ssm is necessary due to a
660 .export syscall_exit_rfi
663 LDREG 0(%r16), %r16 /* thread_info -> task_struct */
664 ldo TASK_REGS(%r16),%r16
665 /* Force iaoq to userspace, as the user has had access to our current
666 * context via sigcontext. Also Filter the PSW for the same reason.
668 LDREG PT_IAOQ0(%r16),%r19
670 STREG %r19,PT_IAOQ0(%r16)
671 LDREG PT_IAOQ1(%r16),%r19
673 STREG %r19,PT_IAOQ1(%r16)
674 LDREG PT_PSW(%r16),%r19
675 ldil L%USER_PSW_MASK,%r1
676 ldo R%USER_PSW_MASK(%r1),%r1
678 ldil L%USER_PSW_HI_MASK,%r20
679 ldo R%USER_PSW_HI_MASK(%r20),%r20
682 and %r19,%r1,%r19 /* Mask out bits that user shouldn't play with */
684 ldo R%USER_PSW(%r1),%r1
685 or %r19,%r1,%r19 /* Make sure default USER_PSW bits are set */
686 STREG %r19,PT_PSW(%r16)
689 * If we aren't being traced, we never saved space registers
690 * (we don't store them in the sigcontext), so set them
691 * to "proper" values now (otherwise we'll wind up restoring
692 * whatever was last stored in the task structure, which might
693 * be inconsistant if an interrupt occured while on the gateway
694 * page) Note that we may be "trashing" values the user put in
695 * them, but we don't support the the user changing them.
698 STREG %r0,PT_SR2(%r16)
700 STREG %r19,PT_SR0(%r16)
701 STREG %r19,PT_SR1(%r16)
702 STREG %r19,PT_SR3(%r16)
703 STREG %r19,PT_SR4(%r16)
704 STREG %r19,PT_SR5(%r16)
705 STREG %r19,PT_SR6(%r16)
706 STREG %r19,PT_SR7(%r16)
711 /* Check for software interrupts */
713 .import irq_stat,data
716 ldo R%irq_stat(%r19),%r19
719 ldw TI_CPU(%r1),%r1 /* get cpu # - int */
720 /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
721 ** irq_stat[] is defined using ____cacheline_aligned.
728 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
729 #endif /* CONFIG_SMP */
731 LDREG IRQSTAT_SIRQ_PEND(%r19),%r20 /* hardirq.h: unsigned long */
732 cmpib,<>,n 0,%r20,intr_do_softirq /* forward */
736 /* check for reschedule */
738 LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */
739 bb,<,n %r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */
744 LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_SIGPENDING */
745 bb,<,n %r19, 31-TIF_SIGPENDING, intr_do_signal /* forward */
749 ldo PT_FR31(%r29),%r1
761 rsm (PSW_SM_Q|PSW_SM_P|PSW_SM_D|PSW_SM_I),%r0
774 .import do_softirq,code
778 ldo -16(%r30),%r29 /* Reference param save area */
785 .import schedule,code
787 /* Only do reschedule if we are returning to user space */
788 LDREG PT_IASQ0(%r16), %r20
789 CMPIB= 0,%r20,intr_restore /* backward */
791 LDREG PT_IASQ1(%r16), %r20
792 CMPIB= 0,%r20,intr_restore /* backward */
796 ldo -16(%r30),%r29 /* Reference param save area */
799 ldil L%intr_return, %r2
801 ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */
804 .import do_signal,code
806 /* Only do signals if we are returning to user space */
807 LDREG PT_IASQ0(%r16), %r20
808 CMPIB= 0,%r20,intr_restore /* backward */
810 LDREG PT_IASQ1(%r16), %r20
811 CMPIB= 0,%r20,intr_restore /* backward */
814 copy %r0, %r24 /* unsigned long in_syscall */
815 copy %r16, %r25 /* struct pt_regs *regs */
818 ldo -16(%r30),%r29 /* Reference param save area */
820 #warning TAUSQ FIXME, this is wrong
822 copy %r0, %r26 /* sigset_t *oldset = NULL */
828 * External interrupts.
837 #if 0 /* Interrupt Stack support not working yet! */
840 /* FIXME! depi below has hardcoded idea of interrupt stack size (32k)*/
858 ldo PT_FR0(%r29), %r24
863 copy %r29, %r25 /* arg1 is pt_regs */
864 copy %r29, %r16 /* save pt_regs */
867 ldo -16(%r30),%r29 /* Reference param save area */
873 * We need to either load the CPU's ID or IRQ region.
874 * Until we have "per CPU" IRQ regions, this is easy.
876 ldil L%cpu_irq_region, %r26
877 ldil L%intr_return, %r2
878 ldo R%cpu_irq_region(%r26), %r26
881 ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */
883 /* Generic interruptions (illegal insn, unaligned, page fault, etc) */
885 .export intr_save, code /* for os_hpmc */
901 /* If this trap is a itlb miss, skip saving/adjusting isr/ior */
904 * FIXME: 1) Use a #define for the hardwired "6" below (and in
906 * 2) Once we start executing code above 4 Gb, we need
907 * to adjust iasq/iaoq here in the same way we
908 * adjust isr/ior below.
911 CMPIB=,n 6,%r26,skip_save_ior
913 /* save_specials left ipsw value in r8 for us to test */
915 mfctl %cr20, %r16 /* isr */
916 mfctl %cr21, %r17 /* ior */
920 * If the interrupted code was running with W bit off (32 bit),
921 * clear the b bits (bits 0 & 1) in the ior.
923 extrd,u,*<> %r8,PSW_W_BIT,1,%r0
927 * FIXME: This code has hardwired assumptions about the split
928 * between space bits and offset bits. This will change
929 * when we allow alternate page sizes.
932 /* adjust isr/ior. */
934 extrd,u %r16,63,7,%r1 /* get high bits from isr for ior */
935 depd %r1,31,7,%r17 /* deposit them into ior */
936 depdi 0,63,7,%r16 /* clear them from isr */
938 STREG %r16, PT_ISR(%r29)
939 STREG %r17, PT_IOR(%r29)
946 ldo PT_FR0(%r29), %r25
951 copy %r29, %r25 /* arg1 is pt_regs */
953 ldo -16(%r30),%r29 /* Reference param save area */
956 ldil L%intr_return, %r2
957 copy %r25, %r16 /* save pt_regs */
959 b handle_interruption
960 ldo R%intr_return(%r2), %r2 /* return to intr_return */
964 * Note for all tlb miss handlers:
966 * cr24 contains a pointer to the kernel address space
969 * cr25 contains a pointer to the current user address
970 * space page directory.
972 * sr3 will contain the space id of the user address space
973 * of the current running thread while that thread is
974 * running in the kernel.
978 * register number allocations. Note that these are all
979 * in the shadowed registers
982 t0 = r1 /* temporary register 0 */
983 va = r8 /* virtual address for which the trap occured */
984 t1 = r9 /* temporary register 1 */
985 pte = r16 /* pte/phys page # */
986 prot = r17 /* prot bits */
987 spc = r24 /* space for which the trap occured */
988 ptp = r25 /* page directory/page table pointer */
993 extrd,u spc,63,7,t1 /* adjust va */
994 depd t1,31,7,va /* adjust va */
995 depdi 0,63,7,spc /* adjust space */
996 mfctl %cr25,ptp /* Assume user space miss */
997 or,*<> %r0,spc,%r0 /* If it is user space, nullify */
998 mfctl %cr24,ptp /* Load kernel pgd instead */
999 extrd,u va,33,9,t1 /* Get pgd index */
1001 mfsp %sr7,t0 /* Get current space */
1002 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
1003 cmpb,*<>,n t0,spc,dtlb_fault /* forward */
1005 /* First level page table lookup */
1008 extrd,u va,42,9,t0 /* get second-level index */
1009 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
1010 depdi 0,63,12,ptp /* clear prot bits */
1012 /* Second level page table lookup */
1015 extrd,u va,51,9,t0 /* get third-level index */
1016 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
1017 depdi 0,63,12,ptp /* clear prot bits */
1019 /* Third level page table lookup */
1022 ldi _PAGE_ACCESSED,t1
1024 bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
1026 /* Check whether the "accessed" bit was set, otherwise do so */
1028 or t1,pte,t0 /* t0 has R bit set */
1029 and,*<> t1,pte,%r0 /* test and nullify if already set */
1030 std t0,0(ptp) /* write back pte */
1032 space_to_prot spc prot /* create prot id from space */
1033 depd pte,8,7,prot /* add in prot bits from pte */
1035 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1036 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1037 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1038 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1040 /* Get rid of prot bits and convert to page addr for idtlbt */
1043 extrd,u pte,56,52,pte
1049 dtlb_check_alias_20w:
1051 /* Check to see if fault is in the temporary alias region */
1053 cmpib,*<>,n 0,spc,dtlb_fault /* forward */
1054 ldil L%(TMPALIAS_MAP_START),t0
1057 cmpb,*<>,n t0,t1,dtlb_fault /* forward */
1058 ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
1059 depd,z prot,8,7,prot
1062 * OK, it is in the temp alias region, check whether "from" or "to".
1063 * Check "subtle" note in pacache.S re: r23/r26.
1066 extrd,u,*= va,41,1,r0
1067 or,*tr %r23,%r0,pte /* If "from" use "from" page */
1068 or,* %r26,%r0,pte /* else "to", use "to" page */
1076 extrd,u spc,63,7,t1 /* adjust va */
1077 depd t1,31,7,va /* adjust va */
1078 depdi 0,63,7,spc /* adjust space */
1079 mfctl %cr25,ptp /* Assume user space miss */
1080 or,*<> %r0,spc,%r0 /* If it is user space, nullify */
1081 mfctl %cr24,ptp /* Load kernel pgd instead */
1082 extrd,u va,33,9,t1 /* Get pgd index */
1084 mfsp %sr7,t0 /* Get current space */
1085 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
1086 cmpb,*<>,n t0,spc,nadtlb_fault /* forward */
1088 /* First level page table lookup */
1091 extrd,u va,42,9,t0 /* get second-level index */
1092 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1093 depdi 0,63,12,ptp /* clear prot bits */
1095 /* Second level page table lookup */
1098 extrd,u va,51,9,t0 /* get third-level index */
1099 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1100 depdi 0,63,12,ptp /* clear prot bits */
1102 /* Third level page table lookup */
1105 ldi _PAGE_ACCESSED,t1
1107 bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20w
1109 space_to_prot spc prot /* create prot id from space */
1110 depd pte,8,7,prot /* add in prot bits from pte */
1112 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1113 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1114 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1115 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1117 /* Get rid of prot bits and convert to page addr for idtlbt */
1120 extrd,u pte,56,52,pte
1126 nadtlb_check_flush_20w:
1127 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1129 /* Insert a "flush only" translation */
1134 /* Get rid of prot bits and convert to page addr for idtlbt */
1137 extrd,u pte,56,52,pte
1146 mfctl %cr25,ptp /* Assume user space miss */
1147 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1148 mfctl %cr24,ptp /* Load kernel pgd instead */
1149 extru va,9,10,t1 /* Get pgd index */
1151 mfsp %sr7,t0 /* Get current space */
1152 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1153 cmpb,<>,n t0,spc,dtlb_fault /* forward */
1155 /* First level page table lookup */
1158 extru va,19,10,t0 /* get second-level index */
1159 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_11
1160 depi 0,31,12,ptp /* clear prot bits */
1162 /* Second level page table lookup */
1165 ldi _PAGE_ACCESSED,t1
1167 bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_11
1169 /* Check whether the "accessed" bit was set, otherwise do so */
1171 or t1,pte,t0 /* t0 has R bit set */
1172 and,<> t1,pte,%r0 /* test and nullify if already set */
1173 stw t0,0(ptp) /* write back pte */
1175 zdep spc,30,15,prot /* create prot id from space */
1176 dep pte,8,7,prot /* add in prot bits from pte */
1178 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1180 extru,= pte,_PAGE_USER_BIT,1,r0
1181 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1182 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1183 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1185 /* Get rid of prot bits and convert to page addr for idtlba */
1190 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1193 idtlba pte,(%sr1,va)
1194 idtlbp prot,(%sr1,va)
1196 mtsp t0, %sr1 /* Restore sr1 */
1201 dtlb_check_alias_11:
1203 /* Check to see if fault is in the temporary alias region */
1205 cmpib,<>,n 0,spc,dtlb_fault /* forward */
1206 ldil L%(TMPALIAS_MAP_START),t0
1209 cmpb,<>,n t0,t1,dtlb_fault /* forward */
1210 ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
1211 depw,z prot,8,7,prot
1214 * OK, it is in the temp alias region, check whether "from" or "to".
1215 * Check "subtle" note in pacache.S re: r23/r26.
1219 or,tr %r23,%r0,pte /* If "from" use "from" page */
1220 or %r26,%r0,pte /* else "to", use "to" page */
1229 mfctl %cr25,ptp /* Assume user space miss */
1230 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1231 mfctl %cr24,ptp /* Load kernel pgd instead */
1232 extru va,9,10,t1 /* Get pgd index */
1234 mfsp %sr7,t0 /* Get current space */
1235 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1236 cmpb,<>,n t0,spc,nadtlb_fault /* forward */
1238 /* First level page table lookup */
1241 extru va,19,10,t0 /* get second-level index */
1242 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1243 depi 0,31,12,ptp /* clear prot bits */
1245 /* Second level page table lookup */
1248 ldi _PAGE_ACCESSED,t1
1250 bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_11
1252 zdep spc,30,15,prot /* create prot id from space */
1253 dep pte,8,7,prot /* add in prot bits from pte */
1255 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1257 extru,= pte,_PAGE_USER_BIT,1,r0
1258 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1259 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1260 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1262 /* Get rid of prot bits and convert to page addr for idtlba */
1267 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1270 idtlba pte,(%sr1,va)
1271 idtlbp prot,(%sr1,va)
1273 mtsp t0, %sr1 /* Restore sr1 */
1278 nadtlb_check_flush_11:
1279 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1281 /* Insert a "flush only" translation */
1286 /* Get rid of prot bits and convert to page addr for idtlba */
1291 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1294 idtlba pte,(%sr1,va)
1295 idtlbp prot,(%sr1,va)
1297 mtsp t0, %sr1 /* Restore sr1 */
1303 mfctl %cr25,ptp /* Assume user space miss */
1304 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1305 mfctl %cr24,ptp /* Load kernel pgd instead */
1306 extru va,9,10,t1 /* Get pgd index */
1308 mfsp %sr7,t0 /* Get current space */
1309 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1310 cmpb,<>,n t0,spc,dtlb_fault /* forward */
1312 /* First level page table lookup */
1315 extru va,19,10,t0 /* get second-level index */
1316 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20
1317 depi 0,31,12,ptp /* clear prot bits */
1319 /* Second level page table lookup */
1322 ldi _PAGE_ACCESSED,t1
1324 bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20
1326 /* Check whether the "accessed" bit was set, otherwise do so */
1328 or t1,pte,t0 /* t0 has R bit set */
1329 and,<> t1,pte,%r0 /* test and nullify if already set */
1330 stw t0,0(ptp) /* write back pte */
1332 space_to_prot spc prot /* create prot id from space */
1333 depd pte,8,7,prot /* add in prot bits from pte */
1335 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1336 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1337 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1338 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1340 /* Get rid of prot bits and convert to page addr for idtlbt */
1343 depdi 0,63,12,pte /* clear lower 12 bits */
1345 extrd,u,*tr pte,56,25,pte
1346 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1352 dtlb_check_alias_20:
1354 /* Check to see if fault is in the temporary alias region */
1356 cmpib,<>,n 0,spc,dtlb_fault /* forward */
1357 ldil L%(TMPALIAS_MAP_START),t0
1360 cmpb,<>,n t0,t1,dtlb_fault /* forward */
1361 ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
1362 depd,z prot,8,7,prot
1365 * OK, it is in the temp alias region, check whether "from" or "to".
1366 * Check "subtle" note in pacache.S re: r23/r26.
1370 or,tr %r23,%r0,pte /* If "from" use "from" page */
1371 or %r26,%r0,pte /* else "to", use "to" page */
1379 mfctl %cr25,ptp /* Assume user space miss */
1380 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1381 mfctl %cr24,ptp /* Load kernel pgd instead */
1382 extru va,9,10,t1 /* Get pgd index */
1384 mfsp %sr7,t0 /* Get current space */
1385 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1386 cmpb,<>,n t0,spc,nadtlb_fault /* forward */
1388 /* First level page table lookup */
1391 extru va,19,10,t0 /* get second-level index */
1392 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1393 depi 0,31,12,ptp /* clear prot bits */
1395 /* Second level page table lookup */
1398 ldi _PAGE_ACCESSED,t1
1400 bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20
1402 space_to_prot spc prot /* create prot id from space */
1403 depd pte,8,7,prot /* add in prot bits from pte */
1405 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1406 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1407 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1408 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1410 /* Get rid of prot bits and convert to page addr for idtlbt */
1413 depdi 0,63,12,pte /* clear lower 12 bits */
1415 extrd,u,*tr pte,56,25,pte
1416 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1422 nadtlb_check_flush_20:
1423 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1425 /* Insert a "flush only" translation */
1430 /* Get rid of prot bits and convert to page addr for idtlbt */
1433 extrd,u pte,56,32,pte
1443 * Non access misses can be caused by fdc,fic,pdc,lpa,probe and
1444 * probei instructions. We don't want to fault for these
1445 * instructions (not only does it not make sense, it can cause
1446 * deadlocks, since some flushes are done with the mmap
1447 * semaphore held). If the translation doesn't exist, we can't
1448 * insert a translation, so have to emulate the side effects
1449 * of the instruction. Since we don't insert a translation
1450 * we can get a lot of faults during a flush loop, so it makes
1451 * sense to try to do it here with minimum overhead. We only
1452 * emulate fdc,fic & pdc instructions whose base and index
1453 * registers are not shadowed. We defer everything else to the
1457 mfctl %cr19,%r9 /* Get iir */
1460 cmpb,<>,n %r16,%r17,nadtlb_fault /* Not fdc,fic,pdc */
1461 bb,>=,n %r9,26,nadtlb_nullify /* m bit not set, just nullify */
1462 b,l get_register,%r25
1463 extrw,u %r9,15,5,%r8 /* Get index register # */
1464 CMPIB=,n -1,%r1,nadtlb_fault /* have to use slow path */
1466 b,l get_register,%r25
1467 extrw,u %r9,10,5,%r8 /* Get base register # */
1468 CMPIB=,n -1,%r1,nadtlb_fault /* have to use slow path */
1469 b,l set_register,%r25
1470 add,l %r1,%r24,%r1 /* doesn't affect c/b bits */
1473 mfctl %cr22,%r8 /* Get ipsw */
1475 or %r8,%r9,%r8 /* Set PSW_N */
1485 * I miss is a little different, since we allow users to fault
1486 * on the gateway page which is in the kernel address space.
1489 extrd,u spc,63,7,t1 /* adjust va */
1490 depd t1,31,7,va /* adjust va */
1491 depdi 0,63,7,spc /* adjust space */
1492 cmpib,*= 0,spc,itlb_miss_kernel_20w
1493 extrd,u va,33,9,t1 /* Get pgd index */
1495 mfctl %cr25,ptp /* load user pgd */
1497 mfsp %sr7,t0 /* Get current space */
1498 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
1499 cmpb,*<>,n t0,spc,itlb_fault /* forward */
1501 /* First level page table lookup */
1503 itlb_miss_common_20w:
1505 extrd,u va,42,9,t0 /* get second-level index */
1506 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1507 depdi 0,63,12,ptp /* clear prot bits */
1509 /* Second level page table lookup */
1512 extrd,u va,51,9,t0 /* get third-level index */
1513 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1514 depdi 0,63,12,ptp /* clear prot bits */
1516 /* Third level page table lookup */
1519 ldi _PAGE_ACCESSED,t1
1521 bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
1523 /* Check whether the "accessed" bit was set, otherwise do so */
1525 or t1,pte,t0 /* t0 has R bit set */
1526 and,*<> t1,pte,%r0 /* test and nullify if already set */
1527 std t0,0(ptp) /* write back pte */
1529 space_to_prot spc prot /* create prot id from space */
1530 depd pte,8,7,prot /* add in prot bits from pte */
1532 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1533 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1534 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1535 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1537 /* Get rid of prot bits and convert to page addr for iitlbt */
1540 extrd,u pte,56,32,pte
1546 itlb_miss_kernel_20w:
1547 b itlb_miss_common_20w
1548 mfctl %cr24,ptp /* Load kernel pgd */
1554 * I miss is a little different, since we allow users to fault
1555 * on the gateway page which is in the kernel address space.
1558 cmpib,= 0,spc,itlb_miss_kernel_11
1559 extru va,9,10,t1 /* Get pgd index */
1561 mfctl %cr25,ptp /* load user pgd */
1563 mfsp %sr7,t0 /* Get current space */
1564 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1565 cmpb,<>,n t0,spc,itlb_fault /* forward */
1567 /* First level page table lookup */
1569 itlb_miss_common_11:
1571 extru va,19,10,t0 /* get second-level index */
1572 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1573 depi 0,31,12,ptp /* clear prot bits */
1575 /* Second level page table lookup */
1578 ldi _PAGE_ACCESSED,t1
1580 bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
1582 /* Check whether the "accessed" bit was set, otherwise do so */
1584 or t1,pte,t0 /* t0 has R bit set */
1585 and,<> t1,pte,%r0 /* test and nullify if already set */
1586 stw t0,0(ptp) /* write back pte */
1588 zdep spc,30,15,prot /* create prot id from space */
1589 dep pte,8,7,prot /* add in prot bits from pte */
1591 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1593 extru,= pte,_PAGE_USER_BIT,1,r0
1594 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1595 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1596 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1598 /* Get rid of prot bits and convert to page addr for iitlba */
1603 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1606 iitlba pte,(%sr1,va)
1607 iitlbp prot,(%sr1,va)
1609 mtsp t0, %sr1 /* Restore sr1 */
1614 itlb_miss_kernel_11:
1615 b itlb_miss_common_11
1616 mfctl %cr24,ptp /* Load kernel pgd */
1621 * I miss is a little different, since we allow users to fault
1622 * on the gateway page which is in the kernel address space.
1625 cmpib,= 0,spc,itlb_miss_kernel_20
1626 extru va,9,10,t1 /* Get pgd index */
1628 mfctl %cr25,ptp /* load user pgd */
1630 mfsp %sr7,t0 /* Get current space */
1631 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1632 cmpb,<>,n t0,spc,itlb_fault /* forward */
1634 /* First level page table lookup */
1636 itlb_miss_common_20:
1638 extru va,19,10,t0 /* get second-level index */
1639 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1640 depi 0,31,12,ptp /* clear prot bits */
1642 /* Second level page table lookup */
1645 ldi _PAGE_ACCESSED,t1
1647 bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
1649 /* Check whether the "accessed" bit was set, otherwise do so */
1651 or t1,pte,t0 /* t0 has R bit set */
1652 and,<> t1,pte,%r0 /* test and nullify if already set */
1653 stw t0,0(ptp) /* write back pte */
1655 space_to_prot spc prot /* create prot id from space */
1656 depd pte,8,7,prot /* add in prot bits from pte */
1658 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1659 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1660 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1661 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1663 /* Get rid of prot bits and convert to page addr for iitlbt */
1666 depdi 0,63,12,pte /* clear lower 12 bits */
1668 extrd,u,*tr pte,56,25,pte
1669 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1676 itlb_miss_kernel_20:
1677 b itlb_miss_common_20
1678 mfctl %cr24,ptp /* Load kernel pgd */
1684 extrd,u spc,63,7,t1 /* adjust va */
1685 depd t1,31,7,va /* adjust va */
1686 depdi 0,1,2,va /* adjust va */
1687 depdi 0,63,7,spc /* adjust space */
1688 mfctl %cr25,ptp /* Assume user space miss */
1689 or,*<> %r0,spc,%r0 /* If it is user space, nullify */
1690 mfctl %cr24,ptp /* Load kernel pgd instead */
1691 extrd,u va,33,9,t1 /* Get pgd index */
1693 mfsp %sr7,t0 /* Get current space */
1694 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
1695 cmpb,*<>,n t0,spc,dbit_fault /* forward */
1697 /* First level page table lookup */
1700 extrd,u va,42,9,t0 /* get second-level index */
1701 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1702 depdi 0,63,12,ptp /* clear prot bits */
1704 /* Second level page table lookup */
1707 extrd,u va,51,9,t0 /* get third-level index */
1708 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1709 depdi 0,63,12,ptp /* clear prot bits */
1711 /* Third level page table lookup */
1715 CMPIB=,n 0,spc,dbit_nolock_20w
1716 ldil L%PA(pa_dbit_lock),t0
1717 ldo R%PA(pa_dbit_lock)(t0),t0
1721 cmpib,= 0,t1,dbit_spin_20w
1726 ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
1728 bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
1730 /* Set Accessed and Dirty bits in the pte */
1733 std pte,0(ptp) /* write back pte */
1735 space_to_prot spc prot /* create prot id from space */
1736 depd pte,8,7,prot /* add in prot bits from pte */
1738 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1739 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1740 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1741 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1743 /* Get rid of prot bits and convert to page addr for idtlbt */
1746 extrd,u pte,56,52,pte
1749 CMPIB=,n 0,spc,dbit_nounlock_20w
1761 mfctl %cr25,ptp /* Assume user space trap */
1762 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1763 mfctl %cr24,ptp /* Load kernel pgd instead */
1764 extru va,9,10,t1 /* Get pgd index */
1766 mfsp %sr7,t0 /* Get current space */
1767 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1768 cmpb,<>,n t0,spc,dbit_fault /* forward */
1770 /* First level page table lookup */
1773 extru va,19,10,t0 /* get second-level index */
1774 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1775 depi 0,31,12,ptp /* clear prot bits */
1777 /* Second level page table lookup */
1781 CMPIB=,n 0,spc,dbit_nolock_11
1782 ldil L%PA(pa_dbit_lock),t0
1783 ldo R%PA(pa_dbit_lock)(t0),t0
1787 cmpib,= 0,t1,dbit_spin_11
1792 ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
1794 bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
1796 /* Set Accessed and Dirty bits in the pte */
1799 stw pte,0(ptp) /* write back pte */
1801 zdep spc,30,15,prot /* create prot id from space */
1802 dep pte,8,7,prot /* add in prot bits from pte */
1804 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1806 extru,= pte,_PAGE_USER_BIT,1,r0
1807 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1808 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1809 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1811 /* Get rid of prot bits and convert to page addr for idtlba */
1816 mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
1819 idtlba pte,(%sr1,va)
1820 idtlbp prot,(%sr1,va)
1822 mtsp t1, %sr1 /* Restore sr1 */
1824 CMPIB=,n 0,spc,dbit_nounlock_11
1835 mfctl %cr25,ptp /* Assume user space trap */
1836 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1837 mfctl %cr24,ptp /* Load kernel pgd instead */
1838 extru va,9,10,t1 /* Get pgd index */
1840 mfsp %sr7,t0 /* Get current space */
1841 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1842 cmpb,<>,n t0,spc,dbit_fault /* forward */
1844 /* First level page table lookup */
1847 extru va,19,10,t0 /* get second-level index */
1848 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1849 depi 0,31,12,ptp /* clear prot bits */
1851 /* Second level page table lookup */
1855 CMPIB=,n 0,spc,dbit_nolock_20
1856 ldil L%PA(pa_dbit_lock),t0
1857 ldo R%PA(pa_dbit_lock)(t0),t0
1861 cmpib,= 0,t1,dbit_spin_20
1866 ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
1868 bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
1870 /* Set Accessed and Dirty bits in the pte */
1873 stw pte,0(ptp) /* write back pte */
1875 space_to_prot spc prot /* create prot id from space */
1876 depd pte,8,7,prot /* add in prot bits from pte */
1878 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1879 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1880 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1881 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1884 depdi 0,63,12,pte /* clear lower 12 bits */
1886 extrd,u,*tr pte,56,25,pte
1887 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1891 CMPIB=,n 0,spc,dbit_nounlock_20
1902 .import handle_interruption,code
1906 ldi 31,%r8 /* Use an unused code */
1924 /* Register saving semantics for system calls:
1926 %r1 clobbered by system call macro in userspace
1927 %r2 saved in PT_REGS by gateway page
1928 %r3 - %r18 preserved by C code (saved by signal code)
1929 %r19 - %r20 saved in PT_REGS by gateway page
1930 %r21 - %r22 non-standard syscall args
1931 stored in kernel stack by gateway page
1932 %r23 - %r26 arg3-arg0, saved in PT_REGS by gateway page
1933 %r27 - %r30 saved in PT_REGS by gateway page
1934 %r31 syscall return pointer
1937 /* Floating point registers (FIXME: what do we do with these?)
1939 %fr0 - %fr3 status/exception, not preserved
1940 %fr4 - %fr7 arguments
1941 %fr8 - %fr11 not preserved by C code
1942 %fr12 - %fr21 preserved by C code
1943 %fr22 - %fr31 not preserved by C code
1946 .macro reg_save regs
1947 STREG %r3, PT_GR3(\regs)
1948 STREG %r4, PT_GR4(\regs)
1949 STREG %r5, PT_GR5(\regs)
1950 STREG %r6, PT_GR6(\regs)
1951 STREG %r7, PT_GR7(\regs)
1952 STREG %r8, PT_GR8(\regs)
1953 STREG %r9, PT_GR9(\regs)
1954 STREG %r10,PT_GR10(\regs)
1955 STREG %r11,PT_GR11(\regs)
1956 STREG %r12,PT_GR12(\regs)
1957 STREG %r13,PT_GR13(\regs)
1958 STREG %r14,PT_GR14(\regs)
1959 STREG %r15,PT_GR15(\regs)
1960 STREG %r16,PT_GR16(\regs)
1961 STREG %r17,PT_GR17(\regs)
1962 STREG %r18,PT_GR18(\regs)
1965 .macro reg_restore regs
1966 LDREG PT_GR3(\regs), %r3
1967 LDREG PT_GR4(\regs), %r4
1968 LDREG PT_GR5(\regs), %r5
1969 LDREG PT_GR6(\regs), %r6
1970 LDREG PT_GR7(\regs), %r7
1971 LDREG PT_GR8(\regs), %r8
1972 LDREG PT_GR9(\regs), %r9
1973 LDREG PT_GR10(\regs),%r10
1974 LDREG PT_GR11(\regs),%r11
1975 LDREG PT_GR12(\regs),%r12
1976 LDREG PT_GR13(\regs),%r13
1977 LDREG PT_GR14(\regs),%r14
1978 LDREG PT_GR15(\regs),%r15
1979 LDREG PT_GR16(\regs),%r16
1980 LDREG PT_GR17(\regs),%r17
1981 LDREG PT_GR18(\regs),%r18
1984 .export sys_fork_wrapper
1985 .export child_return
1987 mfctl %cr30,%r1 /* get pt regs */
1989 ldo TASK_REGS(%r1),%r1
1992 STREG %r3, PT_CR27(%r1)
1994 STREG %r2,-RP_OFFSET(%r30)
1995 ldo FRAME_SIZE(%r30),%r30
1997 ldo -16(%r30),%r29 /* Reference param save area */
2000 /* These are call-clobbered registers and therefore
2001 also syscall-clobbered (we hope). */
2002 STREG %r2,PT_GR19(%r1) /* save for child */
2003 STREG %r30,PT_GR21(%r1)
2005 LDREG PT_GR30(%r1),%r25
2010 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
2012 ldo -FRAME_SIZE(%r30),%r30 /* get the stackframe */
2013 mfctl %cr30,%r1 /* get pt regs */
2015 ldo TASK_REGS(%r1),%r1
2017 LDREG PT_CR27(%r1), %r3
2021 /* strace expects syscall # to be preserved in r20 */
2024 STREG %r20,PT_GR20(%r1)
2026 /* Set the return value for the child */
2028 #if CONFIG_SMP || CONFIG_PREEMPT
2029 bl schedule_tail, %r2
2035 LDREG TASK_PT_GR19(%r2),%r2
2040 .export sys_clone_wrapper
2042 mfctl %cr30,%r1 /* get pt regs */
2044 ldo TASK_REGS(%r1),%r1
2047 STREG %r3, PT_CR27(%r1)
2049 STREG %r2,-RP_OFFSET(%r30)
2050 ldo FRAME_SIZE(%r30),%r30
2052 ldo -16(%r30),%r29 /* Reference param save area */
2055 STREG %r2,PT_GR19(%r1) /* save for child */
2056 STREG %r30,PT_GR21(%r1)
2061 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
2063 .export sys_vfork_wrapper
2065 mfctl %cr30,%r1 /* get pt regs */
2067 ldo TASK_REGS(%r1),%r1
2070 STREG %r3, PT_CR27(%r1)
2072 STREG %r2,-RP_OFFSET(%r30)
2073 ldo FRAME_SIZE(%r30),%r30
2075 ldo -16(%r30),%r29 /* Reference param save area */
2078 STREG %r2,PT_GR19(%r1) /* save for child */
2079 STREG %r30,PT_GR21(%r1)
2085 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
2088 .macro execve_wrapper execve
2089 mfctl %cr30,%r1 /* get pt regs */
2091 ldo TASK_REGS(%r1),%r1
2094 * Do we need to save/restore r3-r18 here?
2095 * I don't think so. why would new thread need old
2096 * threads registers?
2099 /* %arg0 - %arg3 are already saved for us. */
2101 STREG %r2,-RP_OFFSET(%r30)
2102 ldo FRAME_SIZE(%r30),%r30
2104 ldo -16(%r30),%r29 /* Reference param save area */
2109 ldo -FRAME_SIZE(%r30),%r30
2110 LDREG -RP_OFFSET(%r30),%r2
2112 /* If exec succeeded we need to load the args */
2115 cmpb,>>= %r28,%r1,error_\execve
2123 .export sys_execve_wrapper
2127 execve_wrapper sys_execve
2130 .export sys32_execve_wrapper
2131 .import sys32_execve
2133 sys32_execve_wrapper:
2134 execve_wrapper sys32_execve
2137 .export sys_rt_sigreturn_wrapper
2138 sys_rt_sigreturn_wrapper:
2139 mfctl %cr30,%r26 /* get pt regs */
2141 ldo TASK_REGS(%r26),%r26
2142 /* Don't save regs, we are going to restore them from sigcontext. */
2143 STREG %r2, -RP_OFFSET(%r30)
2145 ldo FRAME_SIZE(%r30), %r30
2146 bl sys_rt_sigreturn,%r2
2147 ldo -16(%r30),%r29 /* Reference param save area */
2149 bl sys_rt_sigreturn,%r2
2150 ldo FRAME_SIZE(%r30), %r30
2153 ldo -FRAME_SIZE(%r30), %r30
2154 LDREG -RP_OFFSET(%r30), %r2
2156 /* FIXME: I think we need to restore a few more things here. */
2157 mfctl %cr30,%r1 /* get pt regs */
2159 ldo TASK_REGS(%r1),%r1
2162 /* If the signal was received while the process was blocked on a
2163 * syscall, then r2 will take us to syscall_exit; otherwise r2 will
2164 * take us to syscall_exit_rfi and on to intr_return.
2167 LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */
2169 .export sys_sigaltstack_wrapper
2170 sys_sigaltstack_wrapper:
2171 /* Get the user stack pointer */
2174 LDREG TASK_PT_GR30(%r24),%r24
2175 STREG %r2, -RP_OFFSET(%r30)
2177 ldo FRAME_SIZE(%r30), %r30
2178 bl do_sigaltstack,%r2
2179 ldo -16(%r30),%r29 /* Reference param save area */
2181 bl do_sigaltstack,%r2
2182 ldo FRAME_SIZE(%r30), %r30
2185 ldo -FRAME_SIZE(%r30), %r30
2186 LDREG -RP_OFFSET(%r30), %r2
2191 .export sys32_sigaltstack_wrapper
2192 sys32_sigaltstack_wrapper:
2193 /* Get the user stack pointer */
2196 LDREG TASK_PT_GR30(%r24),%r24
2197 STREG %r2, -RP_OFFSET(%r30)
2198 ldo FRAME_SIZE(%r30), %r30
2199 bl do_sigaltstack32,%r2
2200 ldo -16(%r30),%r29 /* Reference param save area */
2202 ldo -FRAME_SIZE(%r30), %r30
2203 LDREG -RP_OFFSET(%r30), %r2
2208 .export sys_rt_sigsuspend_wrapper
2209 sys_rt_sigsuspend_wrapper:
2210 mfctl %cr30,%r24 /* get pt regs */
2212 ldo TASK_REGS(%r24),%r24
2215 STREG %r2, -RP_OFFSET(%r30)
2217 ldo FRAME_SIZE(%r30), %r30
2218 bl sys_rt_sigsuspend,%r2
2219 ldo -16(%r30),%r29 /* Reference param save area */
2221 bl sys_rt_sigsuspend,%r2
2222 ldo FRAME_SIZE(%r30), %r30
2225 ldo -FRAME_SIZE(%r30), %r30
2226 LDREG -RP_OFFSET(%r30), %r2
2228 mfctl %cr30,%r1 /* get pt regs */
2230 ldo TASK_REGS(%r1),%r1
2236 .export syscall_exit
2238 /* NOTE: HP-UX syscalls also come through here
2239 after hpux_syscall_exit fixes up return
2241 /* NOTE: Not all syscalls exit this way. rt_sigreturn will exit
2242 * via syscall_exit_rfi if the signal was received while the process
2246 /* save return value now */
2250 STREG %r28,TASK_PT_GR28(%r1)
2252 /* Save other hpux returns if personality is PER_HPUX */
2254 /* <linux/personality.h> cannot be easily included */
2255 #define PER_HPUX 0x10
2256 LDREG TASK_PERSONALITY(%r1),%r19
2257 #warning the ldo+CMPIB could probably be done better but 0x10 i soutside of range of CMPIB
2258 ldo -PER_HPUX(%r19), %r19
2260 STREG %r22,TASK_PT_GR22(%r1)
2261 STREG %r29,TASK_PT_GR29(%r1)
2264 /* Seems to me that dp could be wrong here, if the syscall involved
2265 * calling a module, and nothing got round to restoring dp on return.
2271 /* Check for software interrupts */
2273 .import irq_stat,data
2275 ldil L%irq_stat,%r19
2276 ldo R%irq_stat(%r19),%r19
2279 /* sched.h: int processor */
2280 /* %r26 is used as scratch register to index into irq_stat[] */
2281 ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
2283 /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
2289 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
2290 #endif /* CONFIG_SMP */
2292 LDREG IRQSTAT_SIRQ_PEND(%r19),%r20 /* hardirq.h: unsigned long */
2293 cmpib,<>,n 0,%r20,syscall_do_softirq /* forward */
2295 syscall_check_resched:
2297 /* check for reschedule */
2299 LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* long */
2300 bb,<,n %r19, 31-TIF_NEED_RESCHED, syscall_do_resched /* forward */
2303 /* These should be the same effect, but which is faster? */
2307 ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get thread info ptr */
2309 /* check for pending signals */
2310 LDREG TI_FLAGS(%r1),%r19
2311 bb,<,n %r19, 31-TIF_SIGPENDING, syscall_do_signal /* forward */
2315 LDREG TI_FLAGS(%r1), %r19 /* Are we being ptraced? */
2316 bb,< %r19, 31-TIF_SYSCALL_TRACE,syscall_restore_rfi
2317 LDREG 0(%r1),%r1 /* delay slot! */
2318 ldo TASK_PT_FR31(%r1),%r19 /* reload fpregs */
2321 LDREG TASK_PT_SAR(%r1),%r19 /* restore SAR */
2324 LDREG TASK_PT_GR2(%r1),%r2 /* restore user rp */
2325 LDREG TASK_PT_GR19(%r1),%r19
2326 LDREG TASK_PT_GR20(%r1),%r20
2327 LDREG TASK_PT_GR21(%r1),%r21
2328 LDREG TASK_PT_GR22(%r1),%r22
2329 LDREG TASK_PT_GR23(%r1),%r23
2330 LDREG TASK_PT_GR24(%r1),%r24
2331 LDREG TASK_PT_GR25(%r1),%r25
2332 LDREG TASK_PT_GR26(%r1),%r26
2333 LDREG TASK_PT_GR27(%r1),%r27 /* restore user dp */
2334 LDREG TASK_PT_GR28(%r1),%r28 /* syscall return value */
2335 LDREG TASK_PT_GR29(%r1),%r29
2336 LDREG TASK_PT_GR31(%r1),%r31 /* restore syscall rp */
2339 LDREG TASK_PT_GR30(%r1),%r30 /* restore user sp */
2340 mfsp %sr3,%r1 /* Get users space id */
2341 mtsp %r1,%sr7 /* Restore sr7 */
2343 mtsp %r1,%sr4 /* Restore sr4 */
2344 mtsp %r1,%sr5 /* Restore sr5 */
2345 mtsp %r1,%sr6 /* Restore sr6 */
2347 depi 3,31,2,%r31 /* ensure return to user mode. */
2350 /* Since we are returning to a 32 bit user process, we always
2351 * clear the W bit. This means that the be (and mtsp) gets
2352 * executed in narrow mode, but that is OK, since we are
2353 * returning to a 32 bit process. When we support 64 bit processes
2354 * we won't clear the W bit, so the be will run in wide mode.
2357 be 0(%sr3,%r31) /* return to user space */
2360 be,n 0(%sr3,%r31) /* return to user space */
2363 /* We have to return via an RFI, so that PSW T and R bits can be set
2365 * This sets up pt_regs so we can return via intr_restore, which is not
2366 * the most efficient way of doing things, but it works.
2368 syscall_restore_rfi:
2369 LDREG TASK_PTRACE(%r1), %r19
2370 ldo -1(%r0),%r2 /* Set recovery cntr to -1 */
2371 mtctl %r2,%cr0 /* for immediate trap */
2372 LDREG TASK_PT_PSW(%r1),%r2 /* Get old PSW */
2373 ldi 0x0b,%r20 /* Create new PSW */
2374 depi -1,13,1,%r20 /* C, Q, D, and I bits */
2375 bb,>=,n %r19,15,try_tbit /* PT_SINGLESTEP */
2376 depi -1,27,1,%r20 /* R bit */
2378 bb,>=,n %r19,14,psw_setup /* PT_BLOCKSTEP, see ptrace.c */
2379 depi -1,7,1,%r20 /* T bit */
2381 STREG %r20,TASK_PT_PSW(%r1)
2383 /* Always store space registers, since sr3 can be changed (e.g. fork) */
2386 STREG %r25,TASK_PT_SR3(%r1)
2387 STREG %r25,TASK_PT_SR4(%r1)
2388 STREG %r25,TASK_PT_SR5(%r1)
2389 STREG %r25,TASK_PT_SR6(%r1)
2390 STREG %r25,TASK_PT_SR7(%r1)
2391 STREG %r25,TASK_PT_IASQ0(%r1)
2392 STREG %r25,TASK_PT_IASQ1(%r1)
2395 /* Now if old D bit is clear, it means we didn't save all registers
2396 * on syscall entry, so do that now. This only happens on TRACEME
2397 * calls, or if someone attached to us while we were on a syscall.
2398 * We could make this more efficient by not saving r3-r18, but
2399 * then we wouldn't be able to use the common intr_restore path.
2400 * It is only for traced processes anyway, so performance is not
2403 bb,< %r2,30,pt_regs_ok /* Branch if D set */
2404 ldo TASK_REGS(%r1),%r25
2405 reg_save %r25 /* Save r3 to r18 */
2407 STREG %r2,TASK_PT_SR0(%r1)
2409 STREG %r2,TASK_PT_SR1(%r1)
2411 STREG %r2,TASK_PT_SR2(%r1)
2413 LDREG TASK_PT_GR31(%r1),%r2
2414 depi 3,31,2,%r2 /* ensure return to user mode. */
2415 STREG %r2,TASK_PT_IAOQ0(%r1)
2417 STREG %r2,TASK_PT_IAOQ1(%r1)
2422 .import do_softirq,code
2426 b syscall_check_resched
2427 ssm PSW_SM_I, %r0 /* do_softirq returns with I bit off */
2429 .import schedule,code
2433 ldo -16(%r30),%r29 /* Reference param save area */
2437 b syscall_check_bh /* if resched, we start over again */
2440 .import do_signal,code
2442 /* Save callee-save registers (for sigcontext).
2443 FIXME: After this point the process structure should be
2444 consistent with all the relevant state of the process
2445 before the syscall. We need to verify this. */
2447 ldo TASK_REGS(%r1), %r25 /* struct pt_regs *regs */
2450 ldi 1, %r24 /* unsigned long in_syscall */
2453 ldo -16(%r30),%r29 /* Reference param save area */
2455 #warning TAUSQ FIXME, this is wrong
2457 copy %r0, %r26 /* sigset_t *oldset = NULL */
2459 mfctl %cr30,%r1 /* reload task ptr */
2461 ldo TASK_REGS(%r1), %r20 /* reload pt_regs */
2467 * get_register is used by the non access tlb miss handlers to
2468 * copy the value of the general register specified in r8 into
2469 * r1. This routine can't be used for shadowed registers, since
2470 * the rfir will restore the original value. So, for the shadowed
2471 * registers we put a -1 into r1 to indicate that the register
2472 * should not be used (the register being copied could also have
2473 * a -1 in it, but that is OK, it just means that we will have
2474 * to use the slow path instead).
2480 bv %r0(%r25) /* r0 */
2482 bv %r0(%r25) /* r1 - shadowed */
2484 bv %r0(%r25) /* r2 */
2486 bv %r0(%r25) /* r3 */
2488 bv %r0(%r25) /* r4 */
2490 bv %r0(%r25) /* r5 */
2492 bv %r0(%r25) /* r6 */
2494 bv %r0(%r25) /* r7 */
2496 bv %r0(%r25) /* r8 - shadowed */
2498 bv %r0(%r25) /* r9 - shadowed */
2500 bv %r0(%r25) /* r10 */
2502 bv %r0(%r25) /* r11 */
2504 bv %r0(%r25) /* r12 */
2506 bv %r0(%r25) /* r13 */
2508 bv %r0(%r25) /* r14 */
2510 bv %r0(%r25) /* r15 */
2512 bv %r0(%r25) /* r16 - shadowed */
2514 bv %r0(%r25) /* r17 - shadowed */
2516 bv %r0(%r25) /* r18 */
2518 bv %r0(%r25) /* r19 */
2520 bv %r0(%r25) /* r20 */
2522 bv %r0(%r25) /* r21 */
2524 bv %r0(%r25) /* r22 */
2526 bv %r0(%r25) /* r23 */
2528 bv %r0(%r25) /* r24 - shadowed */
2530 bv %r0(%r25) /* r25 - shadowed */
2532 bv %r0(%r25) /* r26 */
2534 bv %r0(%r25) /* r27 */
2536 bv %r0(%r25) /* r28 */
2538 bv %r0(%r25) /* r29 */
2540 bv %r0(%r25) /* r30 */
2542 bv %r0(%r25) /* r31 */
2546 * set_register is used by the non access tlb miss handlers to
2547 * copy the value of r1 into the general register specified in
2554 bv %r0(%r25) /* r0 (silly, but it is a place holder) */
2556 bv %r0(%r25) /* r1 */
2558 bv %r0(%r25) /* r2 */
2560 bv %r0(%r25) /* r3 */
2562 bv %r0(%r25) /* r4 */
2564 bv %r0(%r25) /* r5 */
2566 bv %r0(%r25) /* r6 */
2568 bv %r0(%r25) /* r7 */
2570 bv %r0(%r25) /* r8 */
2572 bv %r0(%r25) /* r9 */
2574 bv %r0(%r25) /* r10 */
2576 bv %r0(%r25) /* r11 */
2578 bv %r0(%r25) /* r12 */
2580 bv %r0(%r25) /* r13 */
2582 bv %r0(%r25) /* r14 */
2584 bv %r0(%r25) /* r15 */
2586 bv %r0(%r25) /* r16 */
2588 bv %r0(%r25) /* r17 */
2590 bv %r0(%r25) /* r18 */
2592 bv %r0(%r25) /* r19 */
2594 bv %r0(%r25) /* r20 */
2596 bv %r0(%r25) /* r21 */
2598 bv %r0(%r25) /* r22 */
2600 bv %r0(%r25) /* r23 */
2602 bv %r0(%r25) /* r24 */
2604 bv %r0(%r25) /* r25 */
2606 bv %r0(%r25) /* r26 */
2608 bv %r0(%r25) /* r27 */
2610 bv %r0(%r25) /* r28 */
2612 bv %r0(%r25) /* r29 */
2614 bv %r0(%r25) /* r30 */
2616 bv %r0(%r25) /* r31 */