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
80 mtctl %r0, %cr17 /* Clear IIASQ tail */
81 mtctl %r0, %cr17 /* Clear IIASQ head */
84 mtctl %r1, %cr18 /* Set IIAOQ tail */
86 mtctl %r1, %cr18 /* Set IIAOQ head */
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 ldi 1, %r25 /* stack_start, signals kernel thread */
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
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 /* Call schedule_tail first though */
562 bl schedule_tail, %r2
565 LDREG TI_TASK-THREAD_SZ_ALGN(%r30), %r1
566 LDREG TASK_PT_GR25(%r1), %r26
568 LDREG TASK_PT_GR27(%r1), %r27
569 LDREG TASK_PT_GR22(%r1), %r22
571 LDREG TASK_PT_GR26(%r1), %r1
576 ldo -16(%r30),%r29 /* Reference param save area */
577 loadgp /* Thread could have been in a module */
582 .import sys_execve, code
583 .export __execve, code
587 ldo PT_SZ_ALGN(%r30), %r30
588 STREG %r26, PT_GR26(%r16)
589 STREG %r25, PT_GR25(%r16)
590 STREG %r24, PT_GR24(%r16)
592 ldo -16(%r30),%r29 /* Reference param save area */
597 cmpib,=,n 0,%r28,intr_return /* forward */
599 /* yes, this will trap and die. */
608 * struct task_struct *_switch_to(struct task_struct *prev,
609 * struct task_struct *next)
611 * switch kernel stacks and return prev */
612 .export _switch_to, code
614 STREG %r2, -RP_OFFSET(%r30)
618 ldil L%_switch_to_ret, %r2
619 ldo R%_switch_to_ret(%r2), %r2
621 STREG %r2, TASK_PT_KPC(%r26)
622 LDREG TASK_PT_KPC(%r25), %r2
624 STREG %r30, TASK_PT_KSP(%r26)
625 LDREG TASK_PT_KSP(%r25), %r30
626 LDREG TASK_THREAD_INFO(%r25), %r25
631 mtctl %r0, %cr0 /* Needed for single stepping */
634 LDREG -RP_OFFSET(%r30), %r2
639 * Common rfi return path for interruptions, kernel execve, and
640 * sys_rt_sigreturn (sometimes). The sys_rt_sigreturn syscall will
641 * return via this path if the signal was received when the process
642 * was running; if the process was blocked on a syscall then the
643 * normal syscall_exit path is used. All syscalls for traced
644 * proceses exit via intr_restore.
646 * XXX If any syscalls that change a processes space id ever exit
647 * this way, then we will need to copy %sr3 in to PT_SR[3..7], and
650 * Note that the following code uses a "relied upon translation".
651 * See the parisc ACD for details. The ssm is necessary due to a
657 .export syscall_exit_rfi
660 LDREG TI_TASK(%r16), %r16 /* thread_info -> task_struct */
661 ldo TASK_REGS(%r16),%r16
662 /* Force iaoq to userspace, as the user has had access to our current
663 * context via sigcontext. Also Filter the PSW for the same reason.
665 LDREG PT_IAOQ0(%r16),%r19
667 STREG %r19,PT_IAOQ0(%r16)
668 LDREG PT_IAOQ1(%r16),%r19
670 STREG %r19,PT_IAOQ1(%r16)
671 LDREG PT_PSW(%r16),%r19
672 ldil L%USER_PSW_MASK,%r1
673 ldo R%USER_PSW_MASK(%r1),%r1
675 ldil L%USER_PSW_HI_MASK,%r20
676 ldo R%USER_PSW_HI_MASK(%r20),%r20
679 and %r19,%r1,%r19 /* Mask out bits that user shouldn't play with */
681 ldo R%USER_PSW(%r1),%r1
682 or %r19,%r1,%r19 /* Make sure default USER_PSW bits are set */
683 STREG %r19,PT_PSW(%r16)
686 * If we aren't being traced, we never saved space registers
687 * (we don't store them in the sigcontext), so set them
688 * to "proper" values now (otherwise we'll wind up restoring
689 * whatever was last stored in the task structure, which might
690 * be inconsistent if an interrupt occured while on the gateway
691 * page) Note that we may be "trashing" values the user put in
692 * them, but we don't support the the user changing them.
695 STREG %r0,PT_SR2(%r16)
697 STREG %r19,PT_SR0(%r16)
698 STREG %r19,PT_SR1(%r16)
699 STREG %r19,PT_SR3(%r16)
700 STREG %r19,PT_SR4(%r16)
701 STREG %r19,PT_SR5(%r16)
702 STREG %r19,PT_SR6(%r16)
703 STREG %r19,PT_SR7(%r16)
708 /* Check for software interrupts */
710 .import irq_stat,data
713 ldo R%irq_stat(%r19),%r19
716 ldw TI_CPU(%r1),%r1 /* get cpu # - int */
717 /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
718 ** irq_stat[] is defined using ____cacheline_aligned.
725 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
726 #endif /* CONFIG_SMP */
728 LDREG IRQSTAT_SIRQ_PEND(%r19),%r20 /* hardirq.h: unsigned long */
729 cmpib,<>,n 0,%r20,intr_do_softirq /* forward */
733 /* check for reschedule */
735 LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */
736 bb,<,n %r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */
741 LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_SIGPENDING */
742 bb,<,n %r19, 31-TIF_SIGPENDING, intr_do_signal /* forward */
746 ldo PT_FR31(%r29),%r1
758 rsm (PSW_SM_Q|PSW_SM_P|PSW_SM_D|PSW_SM_I),%r0
771 .import do_softirq,code
775 ldo -16(%r30),%r29 /* Reference param save area */
782 .import schedule,code
784 /* Only do reschedule if we are returning to user space */
785 LDREG PT_IASQ0(%r16), %r20
786 CMPIB= 0,%r20,intr_restore /* backward */
788 LDREG PT_IASQ1(%r16), %r20
789 CMPIB= 0,%r20,intr_restore /* backward */
793 ldo -16(%r30),%r29 /* Reference param save area */
796 ldil L%intr_check_sig, %r2
798 ldo R%intr_check_sig(%r2), %r2
801 .import do_signal,code
803 /* Only do signals if we are returning to user space */
804 LDREG PT_IASQ0(%r16), %r20
805 CMPIB= 0,%r20,intr_restore /* backward */
807 LDREG PT_IASQ1(%r16), %r20
808 CMPIB= 0,%r20,intr_restore /* backward */
811 copy %r0, %r24 /* unsigned long in_syscall */
812 copy %r16, %r25 /* struct pt_regs *regs */
814 ldo -16(%r30),%r29 /* Reference param save area */
818 copy %r0, %r26 /* sigset_t *oldset = NULL */
824 * External interrupts.
833 #if 0 /* Interrupt Stack support not working yet! */
836 /* FIXME! depi below has hardcoded idea of interrupt stack size (32k)*/
854 ldo PT_FR0(%r29), %r24
859 copy %r29, %r26 /* arg0 is pt_regs */
860 copy %r29, %r16 /* save pt_regs */
862 ldil L%intr_return, %r2
865 ldo -16(%r30),%r29 /* Reference param save area */
869 ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */
872 /* Generic interruptions (illegal insn, unaligned, page fault, etc) */
874 .export intr_save, code /* for os_hpmc */
890 /* If this trap is a itlb miss, skip saving/adjusting isr/ior */
893 * FIXME: 1) Use a #define for the hardwired "6" below (and in
895 * 2) Once we start executing code above 4 Gb, we need
896 * to adjust iasq/iaoq here in the same way we
897 * adjust isr/ior below.
900 CMPIB=,n 6,%r26,skip_save_ior
902 /* save_specials left ipsw value in r8 for us to test */
904 mfctl %cr20, %r16 /* isr */
905 mfctl %cr21, %r17 /* ior */
909 * If the interrupted code was running with W bit off (32 bit),
910 * clear the b bits (bits 0 & 1) in the ior.
912 extrd,u,*<> %r8,PSW_W_BIT,1,%r0
916 * FIXME: This code has hardwired assumptions about the split
917 * between space bits and offset bits. This will change
918 * when we allow alternate page sizes.
921 /* adjust isr/ior. */
923 extrd,u %r16,63,7,%r1 /* get high bits from isr for ior */
924 depd %r1,31,7,%r17 /* deposit them into ior */
925 depdi 0,63,7,%r16 /* clear them from isr */
927 STREG %r16, PT_ISR(%r29)
928 STREG %r17, PT_IOR(%r29)
935 ldo PT_FR0(%r29), %r25
940 copy %r29, %r25 /* arg1 is pt_regs */
942 ldo -16(%r30),%r29 /* Reference param save area */
945 ldil L%intr_check_sig, %r2
946 copy %r25, %r16 /* save pt_regs */
948 b handle_interruption
949 ldo R%intr_check_sig(%r2), %r2
953 * Note for all tlb miss handlers:
955 * cr24 contains a pointer to the kernel address space
958 * cr25 contains a pointer to the current user address
959 * space page directory.
961 * sr3 will contain the space id of the user address space
962 * of the current running thread while that thread is
963 * running in the kernel.
967 * register number allocations. Note that these are all
968 * in the shadowed registers
971 t0 = r1 /* temporary register 0 */
972 va = r8 /* virtual address for which the trap occured */
973 t1 = r9 /* temporary register 1 */
974 pte = r16 /* pte/phys page # */
975 prot = r17 /* prot bits */
976 spc = r24 /* space for which the trap occured */
977 ptp = r25 /* page directory/page table pointer */
982 extrd,u spc,63,7,t1 /* adjust va */
983 depd t1,31,7,va /* adjust va */
984 depdi 0,63,7,spc /* adjust space */
985 mfctl %cr25,ptp /* Assume user space miss */
986 or,*<> %r0,spc,%r0 /* If it is user space, nullify */
987 mfctl %cr24,ptp /* Load kernel pgd instead */
988 extrd,u va,33,9,t1 /* Get pgd index */
990 mfsp %sr7,t0 /* Get current space */
991 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
992 cmpb,*<>,n t0,spc,dtlb_fault /* forward */
994 /* First level page table lookup */
997 extrd,u va,42,9,t0 /* get second-level index */
998 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
999 depdi 0,63,12,ptp /* clear prot bits */
1001 /* Second level page table lookup */
1004 extrd,u va,51,9,t0 /* get third-level index */
1005 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
1006 depdi 0,63,12,ptp /* clear prot bits */
1008 /* Third level page table lookup */
1011 ldi _PAGE_ACCESSED,t1
1013 bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
1015 /* Check whether the "accessed" bit was set, otherwise do so */
1017 or t1,pte,t0 /* t0 has R bit set */
1018 and,*<> t1,pte,%r0 /* test and nullify if already set */
1019 std t0,0(ptp) /* write back pte */
1021 space_to_prot spc prot /* create prot id from space */
1022 depd pte,8,7,prot /* add in prot bits from pte */
1024 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1025 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1026 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1027 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1029 /* Get rid of prot bits and convert to page addr for idtlbt */
1032 extrd,u pte,56,52,pte
1038 dtlb_check_alias_20w:
1040 /* Check to see if fault is in the temporary alias region */
1042 cmpib,*<>,n 0,spc,dtlb_fault /* forward */
1043 ldil L%(TMPALIAS_MAP_START),t0
1046 cmpb,*<>,n t0,t1,dtlb_fault /* forward */
1047 ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
1048 depd,z prot,8,7,prot
1051 * OK, it is in the temp alias region, check whether "from" or "to".
1052 * Check "subtle" note in pacache.S re: r23/r26.
1055 extrd,u,*= va,41,1,r0
1056 or,*tr %r23,%r0,pte /* If "from" use "from" page */
1057 or,* %r26,%r0,pte /* else "to", use "to" page */
1065 extrd,u spc,63,7,t1 /* adjust va */
1066 depd t1,31,7,va /* adjust va */
1067 depdi 0,63,7,spc /* adjust space */
1068 mfctl %cr25,ptp /* Assume user space miss */
1069 or,*<> %r0,spc,%r0 /* If it is user space, nullify */
1070 mfctl %cr24,ptp /* Load kernel pgd instead */
1071 extrd,u va,33,9,t1 /* Get pgd index */
1073 mfsp %sr7,t0 /* Get current space */
1074 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
1075 cmpb,*<>,n t0,spc,nadtlb_fault /* forward */
1077 /* First level page table lookup */
1080 extrd,u va,42,9,t0 /* get second-level index */
1081 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1082 depdi 0,63,12,ptp /* clear prot bits */
1084 /* Second level page table lookup */
1087 extrd,u va,51,9,t0 /* get third-level index */
1088 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1089 depdi 0,63,12,ptp /* clear prot bits */
1091 /* Third level page table lookup */
1094 ldi _PAGE_ACCESSED,t1
1096 bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20w
1098 space_to_prot spc prot /* create prot id from space */
1099 depd pte,8,7,prot /* add in prot bits from pte */
1101 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1102 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1103 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1104 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1106 /* Get rid of prot bits and convert to page addr for idtlbt */
1109 extrd,u pte,56,52,pte
1115 nadtlb_check_flush_20w:
1116 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1118 /* Insert a "flush only" translation */
1123 /* Get rid of prot bits and convert to page addr for idtlbt */
1126 extrd,u pte,56,52,pte
1135 mfctl %cr25,ptp /* Assume user space miss */
1136 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1137 mfctl %cr24,ptp /* Load kernel pgd instead */
1138 extru va,9,10,t1 /* Get pgd index */
1140 mfsp %sr7,t0 /* Get current space */
1141 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1142 cmpb,<>,n t0,spc,dtlb_fault /* forward */
1144 /* First level page table lookup */
1147 extru va,19,10,t0 /* get second-level index */
1148 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_11
1149 depi 0,31,12,ptp /* clear prot bits */
1151 /* Second level page table lookup */
1154 ldi _PAGE_ACCESSED,t1
1156 bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_11
1158 /* Check whether the "accessed" bit was set, otherwise do so */
1160 or t1,pte,t0 /* t0 has R bit set */
1161 and,<> t1,pte,%r0 /* test and nullify if already set */
1162 stw t0,0(ptp) /* write back pte */
1164 zdep spc,30,15,prot /* create prot id from space */
1165 dep pte,8,7,prot /* add in prot bits from pte */
1167 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1169 extru,= pte,_PAGE_USER_BIT,1,r0
1170 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1171 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1172 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1174 /* Get rid of prot bits and convert to page addr for idtlba */
1179 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1182 idtlba pte,(%sr1,va)
1183 idtlbp prot,(%sr1,va)
1185 mtsp t0, %sr1 /* Restore sr1 */
1190 dtlb_check_alias_11:
1192 /* Check to see if fault is in the temporary alias region */
1194 cmpib,<>,n 0,spc,dtlb_fault /* forward */
1195 ldil L%(TMPALIAS_MAP_START),t0
1198 cmpb,<>,n t0,t1,dtlb_fault /* forward */
1199 ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
1200 depw,z prot,8,7,prot
1203 * OK, it is in the temp alias region, check whether "from" or "to".
1204 * Check "subtle" note in pacache.S re: r23/r26.
1208 or,tr %r23,%r0,pte /* If "from" use "from" page */
1209 or %r26,%r0,pte /* else "to", use "to" page */
1218 mfctl %cr25,ptp /* Assume user space miss */
1219 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1220 mfctl %cr24,ptp /* Load kernel pgd instead */
1221 extru va,9,10,t1 /* Get pgd index */
1223 mfsp %sr7,t0 /* Get current space */
1224 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1225 cmpb,<>,n t0,spc,nadtlb_fault /* forward */
1227 /* First level page table lookup */
1230 extru va,19,10,t0 /* get second-level index */
1231 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1232 depi 0,31,12,ptp /* clear prot bits */
1234 /* Second level page table lookup */
1237 ldi _PAGE_ACCESSED,t1
1239 bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_11
1241 zdep spc,30,15,prot /* create prot id from space */
1242 dep pte,8,7,prot /* add in prot bits from pte */
1244 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1246 extru,= pte,_PAGE_USER_BIT,1,r0
1247 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1248 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1249 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1251 /* Get rid of prot bits and convert to page addr for idtlba */
1256 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1259 idtlba pte,(%sr1,va)
1260 idtlbp prot,(%sr1,va)
1262 mtsp t0, %sr1 /* Restore sr1 */
1267 nadtlb_check_flush_11:
1268 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1270 /* Insert a "flush only" translation */
1275 /* Get rid of prot bits and convert to page addr for idtlba */
1280 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1283 idtlba pte,(%sr1,va)
1284 idtlbp prot,(%sr1,va)
1286 mtsp t0, %sr1 /* Restore sr1 */
1292 mfctl %cr25,ptp /* Assume user space miss */
1293 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1294 mfctl %cr24,ptp /* Load kernel pgd instead */
1295 extru va,9,10,t1 /* Get pgd index */
1297 mfsp %sr7,t0 /* Get current space */
1298 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1299 cmpb,<>,n t0,spc,dtlb_fault /* forward */
1301 /* First level page table lookup */
1304 extru va,19,10,t0 /* get second-level index */
1305 bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20
1306 depi 0,31,12,ptp /* clear prot bits */
1308 /* Second level page table lookup */
1311 ldi _PAGE_ACCESSED,t1
1313 bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20
1315 /* Check whether the "accessed" bit was set, otherwise do so */
1317 or t1,pte,t0 /* t0 has R bit set */
1318 and,<> t1,pte,%r0 /* test and nullify if already set */
1319 stw t0,0(ptp) /* write back pte */
1321 space_to_prot spc prot /* create prot id from space */
1322 depd pte,8,7,prot /* add in prot bits from pte */
1324 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1325 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1326 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1327 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1329 /* Get rid of prot bits and convert to page addr for idtlbt */
1332 depdi 0,63,12,pte /* clear lower 12 bits */
1334 extrd,u,*tr pte,56,25,pte
1335 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1341 dtlb_check_alias_20:
1343 /* Check to see if fault is in the temporary alias region */
1345 cmpib,<>,n 0,spc,dtlb_fault /* forward */
1346 ldil L%(TMPALIAS_MAP_START),t0
1349 cmpb,<>,n t0,t1,dtlb_fault /* forward */
1350 ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
1351 depd,z prot,8,7,prot
1354 * OK, it is in the temp alias region, check whether "from" or "to".
1355 * Check "subtle" note in pacache.S re: r23/r26.
1359 or,tr %r23,%r0,pte /* If "from" use "from" page */
1360 or %r26,%r0,pte /* else "to", use "to" page */
1368 mfctl %cr25,ptp /* Assume user space miss */
1369 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1370 mfctl %cr24,ptp /* Load kernel pgd instead */
1371 extru va,9,10,t1 /* Get pgd index */
1373 mfsp %sr7,t0 /* Get current space */
1374 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1375 cmpb,<>,n t0,spc,nadtlb_fault /* forward */
1377 /* First level page table lookup */
1380 extru va,19,10,t0 /* get second-level index */
1381 bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
1382 depi 0,31,12,ptp /* clear prot bits */
1384 /* Second level page table lookup */
1387 ldi _PAGE_ACCESSED,t1
1389 bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20
1391 space_to_prot spc prot /* create prot id from space */
1392 depd pte,8,7,prot /* add in prot bits from pte */
1394 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1395 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1396 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1397 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1399 /* Get rid of prot bits and convert to page addr for idtlbt */
1402 depdi 0,63,12,pte /* clear lower 12 bits */
1404 extrd,u,*tr pte,56,25,pte
1405 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1411 nadtlb_check_flush_20:
1412 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1414 /* Insert a "flush only" translation */
1419 /* Get rid of prot bits and convert to page addr for idtlbt */
1422 extrd,u pte,56,32,pte
1432 * Non access misses can be caused by fdc,fic,pdc,lpa,probe and
1433 * probei instructions. We don't want to fault for these
1434 * instructions (not only does it not make sense, it can cause
1435 * deadlocks, since some flushes are done with the mmap
1436 * semaphore held). If the translation doesn't exist, we can't
1437 * insert a translation, so have to emulate the side effects
1438 * of the instruction. Since we don't insert a translation
1439 * we can get a lot of faults during a flush loop, so it makes
1440 * sense to try to do it here with minimum overhead. We only
1441 * emulate fdc,fic & pdc instructions whose base and index
1442 * registers are not shadowed. We defer everything else to the
1446 mfctl %cr19,%r9 /* Get iir */
1449 cmpb,<>,n %r16,%r17,nadtlb_fault /* Not fdc,fic,pdc */
1450 bb,>=,n %r9,26,nadtlb_nullify /* m bit not set, just nullify */
1451 b,l get_register,%r25
1452 extrw,u %r9,15,5,%r8 /* Get index register # */
1453 CMPIB=,n -1,%r1,nadtlb_fault /* have to use slow path */
1455 b,l get_register,%r25
1456 extrw,u %r9,10,5,%r8 /* Get base register # */
1457 CMPIB=,n -1,%r1,nadtlb_fault /* have to use slow path */
1458 b,l set_register,%r25
1459 add,l %r1,%r24,%r1 /* doesn't affect c/b bits */
1462 mfctl %cr22,%r8 /* Get ipsw */
1464 or %r8,%r9,%r8 /* Set PSW_N */
1474 * I miss is a little different, since we allow users to fault
1475 * on the gateway page which is in the kernel address space.
1478 extrd,u spc,63,7,t1 /* adjust va */
1479 depd t1,31,7,va /* adjust va */
1480 depdi 0,63,7,spc /* adjust space */
1481 cmpib,*= 0,spc,itlb_miss_kernel_20w
1482 extrd,u va,33,9,t1 /* Get pgd index */
1484 mfctl %cr25,ptp /* load user pgd */
1486 mfsp %sr7,t0 /* Get current space */
1487 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
1488 cmpb,*<>,n t0,spc,itlb_fault /* forward */
1490 /* First level page table lookup */
1492 itlb_miss_common_20w:
1494 extrd,u va,42,9,t0 /* get second-level index */
1495 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1496 depdi 0,63,12,ptp /* clear prot bits */
1498 /* Second level page table lookup */
1501 extrd,u va,51,9,t0 /* get third-level index */
1502 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1503 depdi 0,63,12,ptp /* clear prot bits */
1505 /* Third level page table lookup */
1508 ldi _PAGE_ACCESSED,t1
1510 bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
1512 /* Check whether the "accessed" bit was set, otherwise do so */
1514 or t1,pte,t0 /* t0 has R bit set */
1515 and,*<> t1,pte,%r0 /* test and nullify if already set */
1516 std t0,0(ptp) /* write back pte */
1518 space_to_prot spc prot /* create prot id from space */
1519 depd pte,8,7,prot /* add in prot bits from pte */
1521 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1522 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1523 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1524 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1526 /* Get rid of prot bits and convert to page addr for iitlbt */
1529 extrd,u pte,56,32,pte
1535 itlb_miss_kernel_20w:
1536 b itlb_miss_common_20w
1537 mfctl %cr24,ptp /* Load kernel pgd */
1543 * I miss is a little different, since we allow users to fault
1544 * on the gateway page which is in the kernel address space.
1547 cmpib,= 0,spc,itlb_miss_kernel_11
1548 extru va,9,10,t1 /* Get pgd index */
1550 mfctl %cr25,ptp /* load user pgd */
1552 mfsp %sr7,t0 /* Get current space */
1553 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1554 cmpb,<>,n t0,spc,itlb_fault /* forward */
1556 /* First level page table lookup */
1558 itlb_miss_common_11:
1560 extru va,19,10,t0 /* get second-level index */
1561 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1562 depi 0,31,12,ptp /* clear prot bits */
1564 /* Second level page table lookup */
1567 ldi _PAGE_ACCESSED,t1
1569 bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
1571 /* Check whether the "accessed" bit was set, otherwise do so */
1573 or t1,pte,t0 /* t0 has R bit set */
1574 and,<> t1,pte,%r0 /* test and nullify if already set */
1575 stw t0,0(ptp) /* write back pte */
1577 zdep spc,30,15,prot /* create prot id from space */
1578 dep pte,8,7,prot /* add in prot bits from pte */
1580 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1582 extru,= pte,_PAGE_USER_BIT,1,r0
1583 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1584 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1585 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1587 /* Get rid of prot bits and convert to page addr for iitlba */
1592 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1595 iitlba pte,(%sr1,va)
1596 iitlbp prot,(%sr1,va)
1598 mtsp t0, %sr1 /* Restore sr1 */
1603 itlb_miss_kernel_11:
1604 b itlb_miss_common_11
1605 mfctl %cr24,ptp /* Load kernel pgd */
1610 * I miss is a little different, since we allow users to fault
1611 * on the gateway page which is in the kernel address space.
1614 cmpib,= 0,spc,itlb_miss_kernel_20
1615 extru va,9,10,t1 /* Get pgd index */
1617 mfctl %cr25,ptp /* load user pgd */
1619 mfsp %sr7,t0 /* Get current space */
1620 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1621 cmpb,<>,n t0,spc,itlb_fault /* forward */
1623 /* First level page table lookup */
1625 itlb_miss_common_20:
1627 extru va,19,10,t0 /* get second-level index */
1628 bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
1629 depi 0,31,12,ptp /* clear prot bits */
1631 /* Second level page table lookup */
1634 ldi _PAGE_ACCESSED,t1
1636 bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
1638 /* Check whether the "accessed" bit was set, otherwise do so */
1640 or t1,pte,t0 /* t0 has R bit set */
1641 and,<> t1,pte,%r0 /* test and nullify if already set */
1642 stw t0,0(ptp) /* write back pte */
1644 space_to_prot spc prot /* create prot id from space */
1645 depd pte,8,7,prot /* add in prot bits from pte */
1647 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1648 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1649 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1650 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1652 /* Get rid of prot bits and convert to page addr for iitlbt */
1655 depdi 0,63,12,pte /* clear lower 12 bits */
1657 extrd,u,*tr pte,56,25,pte
1658 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1665 itlb_miss_kernel_20:
1666 b itlb_miss_common_20
1667 mfctl %cr24,ptp /* Load kernel pgd */
1673 extrd,u spc,63,7,t1 /* adjust va */
1674 depd t1,31,7,va /* adjust va */
1675 depdi 0,1,2,va /* adjust va */
1676 depdi 0,63,7,spc /* adjust space */
1677 mfctl %cr25,ptp /* Assume user space miss */
1678 or,*<> %r0,spc,%r0 /* If it is user space, nullify */
1679 mfctl %cr24,ptp /* Load kernel pgd instead */
1680 extrd,u va,33,9,t1 /* Get pgd index */
1682 mfsp %sr7,t0 /* Get current space */
1683 or,*= %r0,t0,%r0 /* If kernel, nullify following test */
1684 cmpb,*<>,n t0,spc,dbit_fault /* forward */
1686 /* First level page table lookup */
1689 extrd,u va,42,9,t0 /* get second-level index */
1690 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1691 depdi 0,63,12,ptp /* clear prot bits */
1693 /* Second level page table lookup */
1696 extrd,u va,51,9,t0 /* get third-level index */
1697 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1698 depdi 0,63,12,ptp /* clear prot bits */
1700 /* Third level page table lookup */
1704 CMPIB=,n 0,spc,dbit_nolock_20w
1705 ldil L%PA(pa_dbit_lock),t0
1706 ldo R%PA(pa_dbit_lock)(t0),t0
1710 cmpib,= 0,t1,dbit_spin_20w
1715 ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
1717 bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
1719 /* Set Accessed and Dirty bits in the pte */
1722 std pte,0(ptp) /* write back pte */
1724 space_to_prot spc prot /* create prot id from space */
1725 depd pte,8,7,prot /* add in prot bits from pte */
1727 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1728 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1729 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1730 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1732 /* Get rid of prot bits and convert to page addr for idtlbt */
1735 extrd,u pte,56,52,pte
1738 CMPIB=,n 0,spc,dbit_nounlock_20w
1750 mfctl %cr25,ptp /* Assume user space trap */
1751 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1752 mfctl %cr24,ptp /* Load kernel pgd instead */
1753 extru va,9,10,t1 /* Get pgd index */
1755 mfsp %sr7,t0 /* Get current space */
1756 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1757 cmpb,<>,n t0,spc,dbit_fault /* forward */
1759 /* First level page table lookup */
1762 extru va,19,10,t0 /* get second-level index */
1763 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1764 depi 0,31,12,ptp /* clear prot bits */
1766 /* Second level page table lookup */
1770 CMPIB=,n 0,spc,dbit_nolock_11
1771 ldil L%PA(pa_dbit_lock),t0
1772 ldo R%PA(pa_dbit_lock)(t0),t0
1776 cmpib,= 0,t1,dbit_spin_11
1781 ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
1783 bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
1785 /* Set Accessed and Dirty bits in the pte */
1788 stw pte,0(ptp) /* write back pte */
1790 zdep spc,30,15,prot /* create prot id from space */
1791 dep pte,8,7,prot /* add in prot bits from pte */
1793 extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
1795 extru,= pte,_PAGE_USER_BIT,1,r0
1796 depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1797 extru,= pte,_PAGE_GATEWAY_BIT,1,r0
1798 depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1800 /* Get rid of prot bits and convert to page addr for idtlba */
1805 mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
1808 idtlba pte,(%sr1,va)
1809 idtlbp prot,(%sr1,va)
1811 mtsp t1, %sr1 /* Restore sr1 */
1813 CMPIB=,n 0,spc,dbit_nounlock_11
1824 mfctl %cr25,ptp /* Assume user space trap */
1825 or,<> %r0,spc,%r0 /* If it is user space, nullify */
1826 mfctl %cr24,ptp /* Load kernel pgd instead */
1827 extru va,9,10,t1 /* Get pgd index */
1829 mfsp %sr7,t0 /* Get current space */
1830 or,= %r0,t0,%r0 /* If kernel, nullify following test */
1831 cmpb,<>,n t0,spc,dbit_fault /* forward */
1833 /* First level page table lookup */
1836 extru va,19,10,t0 /* get second-level index */
1837 bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
1838 depi 0,31,12,ptp /* clear prot bits */
1840 /* Second level page table lookup */
1844 CMPIB=,n 0,spc,dbit_nolock_20
1845 ldil L%PA(pa_dbit_lock),t0
1846 ldo R%PA(pa_dbit_lock)(t0),t0
1850 cmpib,= 0,t1,dbit_spin_20
1855 ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
1857 bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
1859 /* Set Accessed and Dirty bits in the pte */
1862 stw pte,0(ptp) /* write back pte */
1864 space_to_prot spc prot /* create prot id from space */
1865 depd pte,8,7,prot /* add in prot bits from pte */
1867 extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
1868 depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
1869 extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
1870 depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
1873 depdi 0,63,12,pte /* clear lower 12 bits */
1875 extrd,u,*tr pte,56,25,pte
1876 extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
1880 CMPIB=,n 0,spc,dbit_nounlock_20
1891 .import handle_interruption,code
1895 ldi 31,%r8 /* Use an unused code */
1913 /* Register saving semantics for system calls:
1915 %r1 clobbered by system call macro in userspace
1916 %r2 saved in PT_REGS by gateway page
1917 %r3 - %r18 preserved by C code (saved by signal code)
1918 %r19 - %r20 saved in PT_REGS by gateway page
1919 %r21 - %r22 non-standard syscall args
1920 stored in kernel stack by gateway page
1921 %r23 - %r26 arg3-arg0, saved in PT_REGS by gateway page
1922 %r27 - %r30 saved in PT_REGS by gateway page
1923 %r31 syscall return pointer
1926 /* Floating point registers (FIXME: what do we do with these?)
1928 %fr0 - %fr3 status/exception, not preserved
1929 %fr4 - %fr7 arguments
1930 %fr8 - %fr11 not preserved by C code
1931 %fr12 - %fr21 preserved by C code
1932 %fr22 - %fr31 not preserved by C code
1935 .macro reg_save regs
1936 STREG %r3, PT_GR3(\regs)
1937 STREG %r4, PT_GR4(\regs)
1938 STREG %r5, PT_GR5(\regs)
1939 STREG %r6, PT_GR6(\regs)
1940 STREG %r7, PT_GR7(\regs)
1941 STREG %r8, PT_GR8(\regs)
1942 STREG %r9, PT_GR9(\regs)
1943 STREG %r10,PT_GR10(\regs)
1944 STREG %r11,PT_GR11(\regs)
1945 STREG %r12,PT_GR12(\regs)
1946 STREG %r13,PT_GR13(\regs)
1947 STREG %r14,PT_GR14(\regs)
1948 STREG %r15,PT_GR15(\regs)
1949 STREG %r16,PT_GR16(\regs)
1950 STREG %r17,PT_GR17(\regs)
1951 STREG %r18,PT_GR18(\regs)
1954 .macro reg_restore regs
1955 LDREG PT_GR3(\regs), %r3
1956 LDREG PT_GR4(\regs), %r4
1957 LDREG PT_GR5(\regs), %r5
1958 LDREG PT_GR6(\regs), %r6
1959 LDREG PT_GR7(\regs), %r7
1960 LDREG PT_GR8(\regs), %r8
1961 LDREG PT_GR9(\regs), %r9
1962 LDREG PT_GR10(\regs),%r10
1963 LDREG PT_GR11(\regs),%r11
1964 LDREG PT_GR12(\regs),%r12
1965 LDREG PT_GR13(\regs),%r13
1966 LDREG PT_GR14(\regs),%r14
1967 LDREG PT_GR15(\regs),%r15
1968 LDREG PT_GR16(\regs),%r16
1969 LDREG PT_GR17(\regs),%r17
1970 LDREG PT_GR18(\regs),%r18
1973 .export sys_fork_wrapper
1974 .export child_return
1976 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
1977 ldo TASK_REGS(%r1),%r1
1980 STREG %r3, PT_CR27(%r1)
1982 STREG %r2,-RP_OFFSET(%r30)
1983 ldo FRAME_SIZE(%r30),%r30
1985 ldo -16(%r30),%r29 /* Reference param save area */
1988 /* These are call-clobbered registers and therefore
1989 also syscall-clobbered (we hope). */
1990 STREG %r2,PT_GR19(%r1) /* save for child */
1991 STREG %r30,PT_GR21(%r1)
1993 LDREG PT_GR30(%r1),%r25
1998 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
2000 ldo -FRAME_SIZE(%r30),%r30 /* get the stackframe */
2001 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2002 ldo TASK_REGS(%r1),%r1 /* get pt regs */
2004 LDREG PT_CR27(%r1), %r3
2008 /* strace expects syscall # to be preserved in r20 */
2011 STREG %r20,PT_GR20(%r1)
2013 /* Set the return value for the child */
2015 bl schedule_tail, %r2
2018 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1
2019 LDREG TASK_PT_GR19(%r1),%r2
2024 .export sys_clone_wrapper
2026 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2027 ldo TASK_REGS(%r1),%r1 /* get pt regs */
2030 STREG %r3, PT_CR27(%r1)
2032 STREG %r2,-RP_OFFSET(%r30)
2033 ldo FRAME_SIZE(%r30),%r30
2035 ldo -16(%r30),%r29 /* Reference param save area */
2038 STREG %r2,PT_GR19(%r1) /* save for child */
2039 STREG %r30,PT_GR21(%r1)
2044 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
2046 .export sys_vfork_wrapper
2048 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2049 ldo TASK_REGS(%r1),%r1 /* get pt regs */
2052 STREG %r3, PT_CR27(%r1)
2054 STREG %r2,-RP_OFFSET(%r30)
2055 ldo FRAME_SIZE(%r30),%r30
2057 ldo -16(%r30),%r29 /* Reference param save area */
2060 STREG %r2,PT_GR19(%r1) /* save for child */
2061 STREG %r30,PT_GR21(%r1)
2067 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
2070 .macro execve_wrapper execve
2071 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2072 ldo TASK_REGS(%r1),%r1 /* get pt regs */
2075 * Do we need to save/restore r3-r18 here?
2076 * I don't think so. why would new thread need old
2077 * threads registers?
2080 /* %arg0 - %arg3 are already saved for us. */
2082 STREG %r2,-RP_OFFSET(%r30)
2083 ldo FRAME_SIZE(%r30),%r30
2085 ldo -16(%r30),%r29 /* Reference param save area */
2090 ldo -FRAME_SIZE(%r30),%r30
2091 LDREG -RP_OFFSET(%r30),%r2
2093 /* If exec succeeded we need to load the args */
2096 cmpb,>>= %r28,%r1,error_\execve
2104 .export sys_execve_wrapper
2108 execve_wrapper sys_execve
2111 .export sys32_execve_wrapper
2112 .import sys32_execve
2114 sys32_execve_wrapper:
2115 execve_wrapper sys32_execve
2118 .export sys_rt_sigreturn_wrapper
2119 sys_rt_sigreturn_wrapper:
2120 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26
2121 ldo TASK_REGS(%r26),%r26 /* get pt regs */
2122 /* Don't save regs, we are going to restore them from sigcontext. */
2123 STREG %r2, -RP_OFFSET(%r30)
2125 ldo FRAME_SIZE(%r30), %r30
2126 bl sys_rt_sigreturn,%r2
2127 ldo -16(%r30),%r29 /* Reference param save area */
2129 bl sys_rt_sigreturn,%r2
2130 ldo FRAME_SIZE(%r30), %r30
2133 ldo -FRAME_SIZE(%r30), %r30
2134 LDREG -RP_OFFSET(%r30), %r2
2136 /* FIXME: I think we need to restore a few more things here. */
2137 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2138 ldo TASK_REGS(%r1),%r1 /* get pt regs */
2141 /* If the signal was received while the process was blocked on a
2142 * syscall, then r2 will take us to syscall_exit; otherwise r2 will
2143 * take us to syscall_exit_rfi and on to intr_return.
2146 LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */
2148 .export sys_sigaltstack_wrapper
2149 sys_sigaltstack_wrapper:
2150 /* Get the user stack pointer */
2151 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2152 ldo TASK_REGS(%r1),%r24 /* get pt regs */
2153 LDREG TASK_PT_GR30(%r24),%r24
2154 STREG %r2, -RP_OFFSET(%r30)
2156 ldo FRAME_SIZE(%r30), %r30
2157 bl do_sigaltstack,%r2
2158 ldo -16(%r30),%r29 /* Reference param save area */
2160 bl do_sigaltstack,%r2
2161 ldo FRAME_SIZE(%r30), %r30
2164 ldo -FRAME_SIZE(%r30), %r30
2165 LDREG -RP_OFFSET(%r30), %r2
2170 .export sys32_sigaltstack_wrapper
2171 sys32_sigaltstack_wrapper:
2172 /* Get the user stack pointer */
2173 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r24
2174 LDREG TASK_PT_GR30(%r24),%r24
2175 STREG %r2, -RP_OFFSET(%r30)
2176 ldo FRAME_SIZE(%r30), %r30
2177 bl do_sigaltstack32,%r2
2178 ldo -16(%r30),%r29 /* Reference param save area */
2180 ldo -FRAME_SIZE(%r30), %r30
2181 LDREG -RP_OFFSET(%r30), %r2
2186 .export sys_rt_sigsuspend_wrapper
2187 sys_rt_sigsuspend_wrapper:
2188 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
2189 ldo TASK_REGS(%r1),%r24
2192 STREG %r2, -RP_OFFSET(%r30)
2194 ldo FRAME_SIZE(%r30), %r30
2195 bl sys_rt_sigsuspend,%r2
2196 ldo -16(%r30),%r29 /* Reference param save area */
2198 bl sys_rt_sigsuspend,%r2
2199 ldo FRAME_SIZE(%r30), %r30
2202 ldo -FRAME_SIZE(%r30), %r30
2203 LDREG -RP_OFFSET(%r30), %r2
2205 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
2206 ldo TASK_REGS(%r1),%r1
2212 .export syscall_exit
2214 /* NOTE: HP-UX syscalls also come through here
2215 after hpux_syscall_exit fixes up return
2217 /* NOTE: Not all syscalls exit this way. rt_sigreturn will exit
2218 * via syscall_exit_rfi if the signal was received while the process
2222 /* save return value now */
2225 LDREG TI_TASK(%r1),%r1
2226 STREG %r28,TASK_PT_GR28(%r1)
2230 /* <linux/personality.h> cannot be easily included */
2231 #define PER_HPUX 0x10
2232 LDREG TASK_PERSONALITY(%r1),%r19
2234 /* We can't use "CMPIB<> PER_HPUX" since "im5" field is sign extended */
2235 ldo -PER_HPUX(%r19), %r19
2238 /* Save other hpux returns if personality is PER_HPUX */
2239 STREG %r22,TASK_PT_GR22(%r1)
2240 STREG %r29,TASK_PT_GR29(%r1)
2243 #endif /* CONFIG_HPUX */
2245 /* Seems to me that dp could be wrong here, if the syscall involved
2246 * calling a module, and nothing got round to restoring dp on return.
2252 /* Check for software interrupts */
2254 .import irq_stat,data
2256 ldil L%irq_stat,%r19
2257 ldo R%irq_stat(%r19),%r19
2260 /* sched.h: int processor */
2261 /* %r26 is used as scratch register to index into irq_stat[] */
2262 ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
2264 /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
2270 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
2271 #endif /* CONFIG_SMP */
2273 LDREG IRQSTAT_SIRQ_PEND(%r19),%r20 /* hardirq.h: unsigned long */
2274 cmpib,<>,n 0,%r20,syscall_do_softirq /* forward */
2276 syscall_check_resched:
2278 /* check for reschedule */
2280 LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* long */
2281 bb,<,n %r19, 31-TIF_NEED_RESCHED, syscall_do_resched /* forward */
2284 LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* get ti flags */
2285 bb,<,n %r19, 31-TIF_SIGPENDING, syscall_do_signal /* forward */
2288 LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* get ti flags */
2289 bb,< %r19, 31-TIF_SYSCALL_TRACE,syscall_restore_rfi
2290 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* delay slot! */
2291 ldo TASK_PT_FR31(%r1),%r19 /* reload fpregs */
2294 LDREG TASK_PT_SAR(%r1),%r19 /* restore SAR */
2297 LDREG TASK_PT_GR2(%r1),%r2 /* restore user rp */
2298 LDREG TASK_PT_GR19(%r1),%r19
2299 LDREG TASK_PT_GR20(%r1),%r20
2300 LDREG TASK_PT_GR21(%r1),%r21
2301 LDREG TASK_PT_GR22(%r1),%r22
2302 LDREG TASK_PT_GR23(%r1),%r23
2303 LDREG TASK_PT_GR24(%r1),%r24
2304 LDREG TASK_PT_GR25(%r1),%r25
2305 LDREG TASK_PT_GR26(%r1),%r26
2306 LDREG TASK_PT_GR27(%r1),%r27 /* restore user dp */
2307 LDREG TASK_PT_GR28(%r1),%r28 /* syscall return value */
2308 LDREG TASK_PT_GR29(%r1),%r29
2309 LDREG TASK_PT_GR31(%r1),%r31 /* restore syscall rp */
2312 LDREG TASK_PT_GR30(%r1),%r30 /* restore user sp */
2313 mfsp %sr3,%r1 /* Get users space id */
2314 mtsp %r1,%sr7 /* Restore sr7 */
2316 mtsp %r1,%sr4 /* Restore sr4 */
2317 mtsp %r1,%sr5 /* Restore sr5 */
2318 mtsp %r1,%sr6 /* Restore sr6 */
2320 depi 3,31,2,%r31 /* ensure return to user mode. */
2323 /* decide whether to reset the wide mode bit
2325 * For a syscall, the W bit is stored in the lowest bit
2326 * of sp. Extract it and reset W if it is zero */
2327 extrd,u,*<> %r30,63,1,%r1
2329 /* now reset the lowest bit of sp if it was set */
2332 be,n 0(%sr3,%r31) /* return to user space */
2334 /* We have to return via an RFI, so that PSW T and R bits can be set
2336 * This sets up pt_regs so we can return via intr_restore, which is not
2337 * the most efficient way of doing things, but it works.
2339 syscall_restore_rfi:
2340 LDREG TASK_PTRACE(%r1), %r19
2341 ldo -1(%r0),%r2 /* Set recovery cntr to -1 */
2342 mtctl %r2,%cr0 /* for immediate trap */
2343 LDREG TASK_PT_PSW(%r1),%r2 /* Get old PSW */
2344 ldi 0x0b,%r20 /* Create new PSW */
2345 depi -1,13,1,%r20 /* C, Q, D, and I bits */
2347 /* The values of PA_SINGLESTEP_BIT and PA_BLOCKSTEP_BIT are
2348 * set in include/linux/ptrace.h and converted to PA bitmap
2349 * numbers in asm-offsets.c */
2351 /* if ((%r19.PA_SINGLESTEP_BIT)) { %r20.27=1} */
2352 extru,= %r19,PA_SINGLESTEP_BIT,1,%r0
2353 depi -1,27,1,%r20 /* R bit */
2355 /* if ((%r19.PA_BLOCKSTEP_BIT)) { %r20.7=1} */
2356 extru,= %r19,PA_BLOCKSTEP_BIT,1,%r0
2357 depi -1,7,1,%r20 /* T bit */
2359 STREG %r20,TASK_PT_PSW(%r1)
2361 /* Always store space registers, since sr3 can be changed (e.g. fork) */
2364 STREG %r25,TASK_PT_SR3(%r1)
2365 STREG %r25,TASK_PT_SR4(%r1)
2366 STREG %r25,TASK_PT_SR5(%r1)
2367 STREG %r25,TASK_PT_SR6(%r1)
2368 STREG %r25,TASK_PT_SR7(%r1)
2369 STREG %r25,TASK_PT_IASQ0(%r1)
2370 STREG %r25,TASK_PT_IASQ1(%r1)
2373 /* Now if old D bit is clear, it means we didn't save all registers
2374 * on syscall entry, so do that now. This only happens on TRACEME
2375 * calls, or if someone attached to us while we were on a syscall.
2376 * We could make this more efficient by not saving r3-r18, but
2377 * then we wouldn't be able to use the common intr_restore path.
2378 * It is only for traced processes anyway, so performance is not
2381 bb,< %r2,30,pt_regs_ok /* Branch if D set */
2382 ldo TASK_REGS(%r1),%r25
2383 reg_save %r25 /* Save r3 to r18 */
2385 STREG %r2,TASK_PT_SR0(%r1)
2387 STREG %r2,TASK_PT_SR1(%r1)
2389 STREG %r2,TASK_PT_SR2(%r1)
2391 LDREG TASK_PT_GR31(%r1),%r2
2392 depi 3,31,2,%r2 /* ensure return to user mode. */
2393 STREG %r2,TASK_PT_IAOQ0(%r1)
2395 STREG %r2,TASK_PT_IAOQ1(%r1)
2400 .import do_softirq,code
2404 b syscall_check_resched
2405 ssm PSW_SM_I, %r0 /* do_softirq returns with I bit off */
2407 .import schedule,code
2411 ldo -16(%r30),%r29 /* Reference param save area */
2415 b syscall_check_bh /* if resched, we start over again */
2418 .import do_signal,code
2420 /* Save callee-save registers (for sigcontext).
2421 FIXME: After this point the process structure should be
2422 consistent with all the relevant state of the process
2423 before the syscall. We need to verify this. */
2424 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2425 ldo TASK_REGS(%r1), %r25 /* struct pt_regs *regs */
2428 ldi 1, %r24 /* unsigned long in_syscall */
2431 ldo -16(%r30),%r29 /* Reference param save area */
2434 copy %r0, %r26 /* sigset_t *oldset = NULL */
2436 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2437 ldo TASK_REGS(%r1), %r20 /* reload pt_regs */
2443 * get_register is used by the non access tlb miss handlers to
2444 * copy the value of the general register specified in r8 into
2445 * r1. This routine can't be used for shadowed registers, since
2446 * the rfir will restore the original value. So, for the shadowed
2447 * registers we put a -1 into r1 to indicate that the register
2448 * should not be used (the register being copied could also have
2449 * a -1 in it, but that is OK, it just means that we will have
2450 * to use the slow path instead).
2456 bv %r0(%r25) /* r0 */
2458 bv %r0(%r25) /* r1 - shadowed */
2460 bv %r0(%r25) /* r2 */
2462 bv %r0(%r25) /* r3 */
2464 bv %r0(%r25) /* r4 */
2466 bv %r0(%r25) /* r5 */
2468 bv %r0(%r25) /* r6 */
2470 bv %r0(%r25) /* r7 */
2472 bv %r0(%r25) /* r8 - shadowed */
2474 bv %r0(%r25) /* r9 - shadowed */
2476 bv %r0(%r25) /* r10 */
2478 bv %r0(%r25) /* r11 */
2480 bv %r0(%r25) /* r12 */
2482 bv %r0(%r25) /* r13 */
2484 bv %r0(%r25) /* r14 */
2486 bv %r0(%r25) /* r15 */
2488 bv %r0(%r25) /* r16 - shadowed */
2490 bv %r0(%r25) /* r17 - shadowed */
2492 bv %r0(%r25) /* r18 */
2494 bv %r0(%r25) /* r19 */
2496 bv %r0(%r25) /* r20 */
2498 bv %r0(%r25) /* r21 */
2500 bv %r0(%r25) /* r22 */
2502 bv %r0(%r25) /* r23 */
2504 bv %r0(%r25) /* r24 - shadowed */
2506 bv %r0(%r25) /* r25 - shadowed */
2508 bv %r0(%r25) /* r26 */
2510 bv %r0(%r25) /* r27 */
2512 bv %r0(%r25) /* r28 */
2514 bv %r0(%r25) /* r29 */
2516 bv %r0(%r25) /* r30 */
2518 bv %r0(%r25) /* r31 */
2522 * set_register is used by the non access tlb miss handlers to
2523 * copy the value of r1 into the general register specified in
2530 bv %r0(%r25) /* r0 (silly, but it is a place holder) */
2532 bv %r0(%r25) /* r1 */
2534 bv %r0(%r25) /* r2 */
2536 bv %r0(%r25) /* r3 */
2538 bv %r0(%r25) /* r4 */
2540 bv %r0(%r25) /* r5 */
2542 bv %r0(%r25) /* r6 */
2544 bv %r0(%r25) /* r7 */
2546 bv %r0(%r25) /* r8 */
2548 bv %r0(%r25) /* r9 */
2550 bv %r0(%r25) /* r10 */
2552 bv %r0(%r25) /* r11 */
2554 bv %r0(%r25) /* r12 */
2556 bv %r0(%r25) /* r13 */
2558 bv %r0(%r25) /* r14 */
2560 bv %r0(%r25) /* r15 */
2562 bv %r0(%r25) /* r16 */
2564 bv %r0(%r25) /* r17 */
2566 bv %r0(%r25) /* r18 */
2568 bv %r0(%r25) /* r19 */
2570 bv %r0(%r25) /* r20 */
2572 bv %r0(%r25) /* r21 */
2574 bv %r0(%r25) /* r22 */
2576 bv %r0(%r25) /* r23 */
2578 bv %r0(%r25) /* r24 */
2580 bv %r0(%r25) /* r25 */
2582 bv %r0(%r25) /* r26 */
2584 bv %r0(%r25) /* r27 */
2586 bv %r0(%r25) /* r28 */
2588 bv %r0(%r25) /* r29 */
2590 bv %r0(%r25) /* r30 */
2592 bv %r0(%r25) /* r31 */