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>
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
82 mtctl %r0, %cr17 /* Clear IIASQ tail */
83 mtctl %r0, %cr17 /* Clear IIASQ head */
86 mtctl %r1, %cr18 /* Set IIAOQ tail */
88 mtctl %r1, %cr18 /* Set IIAOQ head */
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 TI_TASK(%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)
394 /* The following are simple 32 vs 64 bit instruction
395 * abstractions for the macros */
396 .macro EXTR reg1,start,length,reg2
398 extrd,u \reg1,32+\start,\length,\reg2
400 extrw,u \reg1,\start,\length,\reg2
404 .macro DEP reg1,start,length,reg2
406 depd \reg1,32+\start,\length,\reg2
408 depw \reg1,\start,\length,\reg2
412 .macro DEPI val,start,length,reg
414 depdi \val,32+\start,\length,\reg
416 depwi \val,\start,\length,\reg
420 /* In LP64, the space contains part of the upper 32 bits of the
421 * fault. We have to extract this and place it in the va,
422 * zeroing the corresponding bits in the space register */
423 .macro space_adjust spc,va,tmp
425 extrd,u \spc,63,SPACEID_SHIFT,\tmp
426 depd %r0,63,SPACEID_SHIFT,\spc
427 depd \tmp,31,SPACEID_SHIFT,\va
431 .import swapper_pg_dir,code
433 /* Get the pgd. For faults on space zero (kernel space), this
434 * is simply swapper_pg_dir. For user space faults, the
435 * pgd is stored in %cr25 */
436 .macro get_pgd spc,reg
437 ldil L%PA(swapper_pg_dir),\reg
438 ldo R%PA(swapper_pg_dir)(\reg),\reg
439 or,COND(=) %r0,\spc,%r0
443 /* Only allow faults on different spaces from the
444 * currently active one if we're the kernel */
445 .macro space_check spc,tmp,fault
447 or,COND(<>) %r0,\spc,%r0 /* user may execute gateway page
448 * as kernel, so defeat the space
451 or,COND(=) %r0,\tmp,%r0 /* nullify if executing as kernel */
452 cmpb,COND(<>),n \tmp,\spc,\fault
455 /* Look up a PTE in a 2-Level scheme (faulting at each
456 * level if the entry isn't present
458 * NOTE: we use ldw even for LP64 because our pte
459 * and pmd are allocated <4GB */
460 .macro L2_ptep pmd,pte,index,va,fault
462 EXTR \va,31-ASM_PMD_SHIFT,ASM_BITS_PER_PMD,\index
464 EXTR \va,31-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
466 DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */
468 ldw,s \index(\pmd),\pmd
469 EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
470 bb,>=,n \pmd,_PAGE_PRESENT_BIT,\fault
471 DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */
472 shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd
473 LDREG %r0(\pmd),\pte /* pmd is now pte */
474 bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault
477 /* Look up PTE in a 3-Level scheme.
479 * Here we implement a Hybrid L2/L3 scheme: we allocate the
480 * first pmd adjacent to the pgd. This means that we can
481 * subtract a constant offset to get to it. The pmd and pgd
482 * sizes are arranged so that a single pmd covers 4GB (giving
483 * a full LP64 process access to 8TB) so our lookups are
484 * effectively L2 for the first 4GB of the kernel (i.e. for
485 * all ILP32 processes and all the kernel for machines with
486 * under 4GB of memory) */
487 .macro L3_ptep pgd,pte,index,va,fault
488 extrd,u \va,63-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
490 extrd,u,*= \va,31,32,%r0
491 ldw,s \index(\pgd),\pgd
492 extrd,u,*<> \va,31,32,%r0
493 ldo ASM_PGD_PMD_OFFSET(\pgd),\pgd
494 extrd,u,*= \va,31,32,%r0
495 bb,>=,n \pgd,_PAGE_PRESENT_BIT,\fault
496 L2_ptep \pgd,\pte,\index,\va,\fault
499 /* Set the _PAGE_ACCESSED bit of the PTE. Be clever and
500 * don't needlessly dirty the cache line if it was already set */
501 .macro update_ptep ptep,pte,tmp,tmp1
502 ldi _PAGE_ACCESSED,\tmp1
504 and,COND(<>) \tmp1,\pte,%r0
508 /* Set the dirty bit (and accessed bit). No need to be
509 * clever, this is only used from the dirty fault */
510 .macro update_dirty ptep,pte,tmp,tmp1
511 ldi _PAGE_ACCESSED|_PAGE_DIRTY,\tmp
516 /* Convert the pte and prot to tlb insertion values. How
517 * this happens is quite subtle, read below */
518 .macro make_insert_tlb spc,pte,prot
519 space_to_prot \spc \prot /* create prot id from space */
520 /* The following is the real subtlety. This is depositing
521 * T <-> _PAGE_REFTRAP
523 * B <-> _PAGE_DMB (memory break)
525 * Then incredible subtlety: The access rights are
526 * _PAGE_GATEWAY _PAGE_EXEC _PAGE_READ
527 * See 3-14 of the parisc 2.0 manual
529 * Finally, _PAGE_READ goes in the top bit of PL1 (so we
530 * trigger an access rights trap in user space if the user
531 * tries to read an unreadable page */
534 /* PAGE_USER indicates the page can be read with user privileges,
535 * so deposit X1|11 to PL1|PL2 (remember the upper bit of PL1
536 * contains _PAGE_READ */
537 extrd,u,*= \pte,_PAGE_USER_BIT+32,1,%r0
539 /* If we're a gateway page, drop PL2 back to zero for promotion
540 * to kernel privilege (so we can execute the page as kernel).
541 * Any privilege promotion page always denys read and write */
542 extrd,u,*= \pte,_PAGE_GATEWAY_BIT+32,1,%r0
543 depd %r0,11,2,\prot /* If Gateway, Set PL2 to 0 */
545 /* Get rid of prot bits and convert to page addr for iitlbt */
547 depd %r0,63,PAGE_SHIFT,\pte
548 extrd,u \pte,56,32,\pte
551 /* Identical macro to make_insert_tlb above, except it
552 * makes the tlb entry for the differently formatted pa11
553 * insertion instructions */
554 .macro make_insert_tlb_11 spc,pte,prot
555 zdep \spc,30,15,\prot
557 extru,= \pte,_PAGE_NO_CACHE_BIT,1,%r0
559 extru,= \pte,_PAGE_USER_BIT,1,%r0
560 depi 7,11,3,\prot /* Set for user space (1 rsvd for read) */
561 extru,= \pte,_PAGE_GATEWAY_BIT,1,%r0
562 depi 0,11,2,\prot /* If Gateway, Set PL2 to 0 */
564 /* Get rid of prot bits and convert to page addr for iitlba */
567 extru \pte,24,25,\pte
571 /* This is for ILP32 PA2.0 only. The TLB insertion needs
572 * to extend into I/O space if the address is 0xfXXXXXXX
573 * so we extend the f's into the top word of the pte in
575 .macro f_extend pte,tmp
576 extrd,s \pte,42,4,\tmp
578 extrd,s \pte,63,25,\pte
581 /* The alias region is an 8MB aligned 16MB to do clear and
582 * copy user pages at addresses congruent with the user
585 * To use the alias page, you set %r26 up with the to TLB
586 * entry (identifying the physical page) and %r23 up with
587 * the from tlb entry (or nothing if only a to entry---for
588 * clear_user_page_asm) */
589 .macro do_alias spc,tmp,tmp1,va,pte,prot,fault
590 cmpib,COND(<>),n 0,\spc,\fault
591 ldil L%(TMPALIAS_MAP_START),\tmp
592 #if defined(__LP64__) && (TMPALIAS_MAP_START >= 0x80000000)
593 /* on LP64, ldi will sign extend into the upper 32 bits,
594 * which is behaviour we don't want */
599 cmpb,COND(<>),n \tmp,\tmp1,\fault
600 ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),\prot
601 depd,z \prot,8,7,\prot
603 * OK, it is in the temp alias region, check whether "from" or "to".
604 * Check "subtle" note in pacache.S re: r23/r26.
607 extrd,u,*= \va,41,1,%r0
609 extrw,u,= \va,9,1,%r0
611 or,COND(tr) %r23,%r0,\pte
617 * Align fault_vector_20 on 4K boundary so that both
618 * fault_vector_11 and fault_vector_20 are on the
619 * same page. This is only necessary as long as we
620 * write protect the kernel text, which we may stop
621 * doing once we use large page translations to cover
622 * the static part of the kernel address space.
625 .export fault_vector_20
632 /* First vector is invalid (0) */
633 .ascii "cows can fly"
675 .export fault_vector_11
680 /* First vector is invalid (0) */
681 .ascii "cows can fly"
723 .import handle_interruption,code
724 .import do_cpu_irq_mask,code
727 * r26 = function to be called
728 * r25 = argument to pass in
729 * r24 = flags for do_fork()
731 * Kernel threads don't ever return, so they don't need
732 * a true register context. We just save away the arguments
733 * for copy_thread/ret_ to properly set up the child.
736 #define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */
737 #define CLONE_UNTRACED 0x00800000
739 .export __kernel_thread, code
742 STREG %r2, -RP_OFFSET(%r30)
745 ldo PT_SZ_ALGN(%r30),%r30
747 /* Yo, function pointers in wide mode are little structs... -PB */
749 STREG %r2, PT_GR27(%r1) /* Store childs %dp */
752 STREG %r22, PT_GR22(%r1) /* save r22 (arg5) */
753 copy %r0, %r22 /* user_tid */
755 STREG %r26, PT_GR26(%r1) /* Store function & argument for child */
756 STREG %r25, PT_GR25(%r1)
757 ldil L%CLONE_UNTRACED, %r26
758 ldo CLONE_VM(%r26), %r26 /* Force CLONE_VM since only init_mm */
759 or %r26, %r24, %r26 /* will have kernel mappings. */
760 ldi 1, %r25 /* stack_start, signals kernel thread */
761 stw %r0, -52(%r30) /* user_tid */
763 ldo -16(%r30),%r29 /* Reference param save area */
766 copy %r1, %r24 /* pt_regs */
768 /* Parent Returns here */
770 LDREG -PT_SZ_ALGN-RP_OFFSET(%r30), %r2
771 ldo -PT_SZ_ALGN(%r30), %r30
778 * copy_thread moved args from temp save area set up above
779 * into task save area.
782 .export ret_from_kernel_thread
783 ret_from_kernel_thread:
785 /* Call schedule_tail first though */
786 bl schedule_tail, %r2
789 LDREG TI_TASK-THREAD_SZ_ALGN(%r30), %r1
790 LDREG TASK_PT_GR25(%r1), %r26
792 LDREG TASK_PT_GR27(%r1), %r27
793 LDREG TASK_PT_GR22(%r1), %r22
795 LDREG TASK_PT_GR26(%r1), %r1
800 ldo -16(%r30),%r29 /* Reference param save area */
801 loadgp /* Thread could have been in a module */
806 .import sys_execve, code
807 .export __execve, code
811 ldo PT_SZ_ALGN(%r30), %r30
812 STREG %r26, PT_GR26(%r16)
813 STREG %r25, PT_GR25(%r16)
814 STREG %r24, PT_GR24(%r16)
816 ldo -16(%r30),%r29 /* Reference param save area */
821 cmpib,=,n 0,%r28,intr_return /* forward */
823 /* yes, this will trap and die. */
832 * struct task_struct *_switch_to(struct task_struct *prev,
833 * struct task_struct *next)
835 * switch kernel stacks and return prev */
836 .export _switch_to, code
838 STREG %r2, -RP_OFFSET(%r30)
842 ldil L%_switch_to_ret, %r2
843 ldo R%_switch_to_ret(%r2), %r2
845 STREG %r2, TASK_PT_KPC(%r26)
846 LDREG TASK_PT_KPC(%r25), %r2
848 STREG %r30, TASK_PT_KSP(%r26)
849 LDREG TASK_PT_KSP(%r25), %r30
850 LDREG TASK_THREAD_INFO(%r25), %r25
855 mtctl %r0, %cr0 /* Needed for single stepping */
858 LDREG -RP_OFFSET(%r30), %r2
863 * Common rfi return path for interruptions, kernel execve, and
864 * sys_rt_sigreturn (sometimes). The sys_rt_sigreturn syscall will
865 * return via this path if the signal was received when the process
866 * was running; if the process was blocked on a syscall then the
867 * normal syscall_exit path is used. All syscalls for traced
868 * proceses exit via intr_restore.
870 * XXX If any syscalls that change a processes space id ever exit
871 * this way, then we will need to copy %sr3 in to PT_SR[3..7], and
874 * Note that the following code uses a "relied upon translation".
875 * See the parisc ACD for details. The ssm is necessary due to a
881 .export syscall_exit_rfi
884 LDREG TI_TASK(%r16), %r16 /* thread_info -> task_struct */
885 ldo TASK_REGS(%r16),%r16
886 /* Force iaoq to userspace, as the user has had access to our current
887 * context via sigcontext. Also Filter the PSW for the same reason.
889 LDREG PT_IAOQ0(%r16),%r19
891 STREG %r19,PT_IAOQ0(%r16)
892 LDREG PT_IAOQ1(%r16),%r19
894 STREG %r19,PT_IAOQ1(%r16)
895 LDREG PT_PSW(%r16),%r19
896 ldil L%USER_PSW_MASK,%r1
897 ldo R%USER_PSW_MASK(%r1),%r1
899 ldil L%USER_PSW_HI_MASK,%r20
900 ldo R%USER_PSW_HI_MASK(%r20),%r20
903 and %r19,%r1,%r19 /* Mask out bits that user shouldn't play with */
905 ldo R%USER_PSW(%r1),%r1
906 or %r19,%r1,%r19 /* Make sure default USER_PSW bits are set */
907 STREG %r19,PT_PSW(%r16)
910 * If we aren't being traced, we never saved space registers
911 * (we don't store them in the sigcontext), so set them
912 * to "proper" values now (otherwise we'll wind up restoring
913 * whatever was last stored in the task structure, which might
914 * be inconsistent if an interrupt occured while on the gateway
915 * page) Note that we may be "trashing" values the user put in
916 * them, but we don't support the the user changing them.
919 STREG %r0,PT_SR2(%r16)
921 STREG %r19,PT_SR0(%r16)
922 STREG %r19,PT_SR1(%r16)
923 STREG %r19,PT_SR3(%r16)
924 STREG %r19,PT_SR4(%r16)
925 STREG %r19,PT_SR5(%r16)
926 STREG %r19,PT_SR6(%r16)
927 STREG %r19,PT_SR7(%r16)
932 /* Check for software interrupts */
934 .import irq_stat,data
937 ldo R%irq_stat(%r19),%r19
940 ldw TI_CPU(%r1),%r1 /* get cpu # - int */
941 /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
942 ** irq_stat[] is defined using ____cacheline_aligned.
949 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
950 #endif /* CONFIG_SMP */
952 LDREG IRQSTAT_SIRQ_PEND(%r19),%r20 /* hardirq.h: unsigned long */
953 cmpib,<>,n 0,%r20,intr_do_softirq /* forward */
957 /* check for reschedule */
959 LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */
960 bb,<,n %r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */
965 LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_SIGPENDING */
966 bb,<,n %r19, 31-TIF_SIGPENDING, intr_do_signal /* forward */
970 ldo PT_FR31(%r29),%r1
982 rsm (PSW_SM_Q|PSW_SM_P|PSW_SM_D|PSW_SM_I),%r0
995 .import do_softirq,code
999 ldo -16(%r30),%r29 /* Reference param save area */
1003 b intr_check_resched
1006 .import schedule,code
1008 /* Only do reschedule if we are returning to user space */
1009 LDREG PT_IASQ0(%r16), %r20
1010 CMPIB= 0,%r20,intr_restore /* backward */
1012 LDREG PT_IASQ1(%r16), %r20
1013 CMPIB= 0,%r20,intr_restore /* backward */
1017 ldo -16(%r30),%r29 /* Reference param save area */
1020 ldil L%intr_check_sig, %r2
1022 ldo R%intr_check_sig(%r2), %r2
1025 .import do_signal,code
1027 /* Only do signals if we are returning to user space */
1028 LDREG PT_IASQ0(%r16), %r20
1029 CMPIB= 0,%r20,intr_restore /* backward */
1031 LDREG PT_IASQ1(%r16), %r20
1032 CMPIB= 0,%r20,intr_restore /* backward */
1035 copy %r0, %r24 /* unsigned long in_syscall */
1036 copy %r16, %r25 /* struct pt_regs *regs */
1038 ldo -16(%r30),%r29 /* Reference param save area */
1042 copy %r0, %r26 /* sigset_t *oldset = NULL */
1048 * External interrupts.
1057 #if 0 /* Interrupt Stack support not working yet! */
1060 /* FIXME! depi below has hardcoded idea of interrupt stack size (32k)*/
1078 ldo PT_FR0(%r29), %r24
1083 copy %r29, %r26 /* arg0 is pt_regs */
1084 copy %r29, %r16 /* save pt_regs */
1086 ldil L%intr_return, %r2
1089 ldo -16(%r30),%r29 /* Reference param save area */
1093 ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */
1096 /* Generic interruptions (illegal insn, unaligned, page fault, etc) */
1098 .export intr_save, code /* for os_hpmc */
1114 /* If this trap is a itlb miss, skip saving/adjusting isr/ior */
1117 * FIXME: 1) Use a #define for the hardwired "6" below (and in
1119 * 2) Once we start executing code above 4 Gb, we need
1120 * to adjust iasq/iaoq here in the same way we
1121 * adjust isr/ior below.
1124 CMPIB=,n 6,%r26,skip_save_ior
1126 /* save_specials left ipsw value in r8 for us to test */
1128 mfctl %cr20, %r16 /* isr */
1129 mfctl %cr21, %r17 /* ior */
1133 * If the interrupted code was running with W bit off (32 bit),
1134 * clear the b bits (bits 0 & 1) in the ior.
1136 extrd,u,*<> %r8,PSW_W_BIT,1,%r0
1140 * FIXME: This code has hardwired assumptions about the split
1141 * between space bits and offset bits. This will change
1142 * when we allow alternate page sizes.
1145 /* adjust isr/ior. */
1147 extrd,u %r16,63,7,%r1 /* get high bits from isr for ior */
1148 depd %r1,31,7,%r17 /* deposit them into ior */
1149 depdi 0,63,7,%r16 /* clear them from isr */
1151 STREG %r16, PT_ISR(%r29)
1152 STREG %r17, PT_IOR(%r29)
1159 ldo PT_FR0(%r29), %r25
1164 copy %r29, %r25 /* arg1 is pt_regs */
1166 ldo -16(%r30),%r29 /* Reference param save area */
1169 ldil L%intr_check_sig, %r2
1170 copy %r25, %r16 /* save pt_regs */
1172 b handle_interruption
1173 ldo R%intr_check_sig(%r2), %r2
1177 * Note for all tlb miss handlers:
1179 * cr24 contains a pointer to the kernel address space
1182 * cr25 contains a pointer to the current user address
1183 * space page directory.
1185 * sr3 will contain the space id of the user address space
1186 * of the current running thread while that thread is
1187 * running in the kernel.
1191 * register number allocations. Note that these are all
1192 * in the shadowed registers
1195 t0 = r1 /* temporary register 0 */
1196 va = r8 /* virtual address for which the trap occured */
1197 t1 = r9 /* temporary register 1 */
1198 pte = r16 /* pte/phys page # */
1199 prot = r17 /* prot bits */
1200 spc = r24 /* space for which the trap occured */
1201 ptp = r25 /* page directory/page table pointer */
1206 space_adjust spc,va,t0
1208 space_check spc,t0,dtlb_fault
1210 L3_ptep ptp,pte,t0,va,dtlb_check_alias_20w
1212 update_ptep ptp,pte,t0,t1
1214 make_insert_tlb spc,pte,prot
1221 dtlb_check_alias_20w:
1222 do_alias spc,t0,t1,va,pte,prot,dtlb_fault
1230 space_adjust spc,va,t0
1232 space_check spc,t0,nadtlb_fault
1234 L3_ptep ptp,pte,t0,va,nadtlb_check_flush_20w
1236 update_ptep ptp,pte,t0,t1
1238 make_insert_tlb spc,pte,prot
1245 nadtlb_check_flush_20w:
1246 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1248 /* Insert a "flush only" translation */
1253 /* Get rid of prot bits and convert to page addr for idtlbt */
1256 extrd,u pte,56,52,pte
1267 space_check spc,t0,dtlb_fault
1269 L2_ptep ptp,pte,t0,va,dtlb_check_alias_11
1271 update_ptep ptp,pte,t0,t1
1273 make_insert_tlb_11 spc,pte,prot
1275 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1278 idtlba pte,(%sr1,va)
1279 idtlbp prot,(%sr1,va)
1281 mtsp t0, %sr1 /* Restore sr1 */
1286 dtlb_check_alias_11:
1288 /* Check to see if fault is in the temporary alias region */
1290 cmpib,<>,n 0,spc,dtlb_fault /* forward */
1291 ldil L%(TMPALIAS_MAP_START),t0
1294 cmpb,<>,n t0,t1,dtlb_fault /* forward */
1295 ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
1296 depw,z prot,8,7,prot
1299 * OK, it is in the temp alias region, check whether "from" or "to".
1300 * Check "subtle" note in pacache.S re: r23/r26.
1304 or,tr %r23,%r0,pte /* If "from" use "from" page */
1305 or %r26,%r0,pte /* else "to", use "to" page */
1316 space_check spc,t0,nadtlb_fault
1318 L2_ptep ptp,pte,t0,va,nadtlb_check_flush_11
1320 update_ptep ptp,pte,t0,t1
1322 make_insert_tlb_11 spc,pte,prot
1325 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1328 idtlba pte,(%sr1,va)
1329 idtlbp prot,(%sr1,va)
1331 mtsp t0, %sr1 /* Restore sr1 */
1336 nadtlb_check_flush_11:
1337 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1339 /* Insert a "flush only" translation */
1344 /* Get rid of prot bits and convert to page addr for idtlba */
1349 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1352 idtlba pte,(%sr1,va)
1353 idtlbp prot,(%sr1,va)
1355 mtsp t0, %sr1 /* Restore sr1 */
1361 space_adjust spc,va,t0
1363 space_check spc,t0,dtlb_fault
1365 L2_ptep ptp,pte,t0,va,dtlb_check_alias_20
1367 update_ptep ptp,pte,t0,t1
1369 make_insert_tlb spc,pte,prot
1378 dtlb_check_alias_20:
1379 do_alias spc,t0,t1,va,pte,prot,dtlb_fault
1389 space_check spc,t0,nadtlb_fault
1391 L2_ptep ptp,pte,t0,va,nadtlb_check_flush_20
1393 update_ptep ptp,pte,t0,t1
1395 make_insert_tlb spc,pte,prot
1404 nadtlb_check_flush_20:
1405 bb,>=,n pte,_PAGE_FLUSH_BIT,nadtlb_emulate
1407 /* Insert a "flush only" translation */
1412 /* Get rid of prot bits and convert to page addr for idtlbt */
1415 extrd,u pte,56,32,pte
1425 * Non access misses can be caused by fdc,fic,pdc,lpa,probe and
1426 * probei instructions. We don't want to fault for these
1427 * instructions (not only does it not make sense, it can cause
1428 * deadlocks, since some flushes are done with the mmap
1429 * semaphore held). If the translation doesn't exist, we can't
1430 * insert a translation, so have to emulate the side effects
1431 * of the instruction. Since we don't insert a translation
1432 * we can get a lot of faults during a flush loop, so it makes
1433 * sense to try to do it here with minimum overhead. We only
1434 * emulate fdc,fic & pdc instructions whose base and index
1435 * registers are not shadowed. We defer everything else to the
1439 mfctl %cr19,%r9 /* Get iir */
1442 cmpb,<>,n %r16,%r17,nadtlb_fault /* Not fdc,fic,pdc */
1443 bb,>=,n %r9,26,nadtlb_nullify /* m bit not set, just nullify */
1444 b,l get_register,%r25
1445 extrw,u %r9,15,5,%r8 /* Get index register # */
1446 CMPIB=,n -1,%r1,nadtlb_fault /* have to use slow path */
1448 b,l get_register,%r25
1449 extrw,u %r9,10,5,%r8 /* Get base register # */
1450 CMPIB=,n -1,%r1,nadtlb_fault /* have to use slow path */
1451 b,l set_register,%r25
1452 add,l %r1,%r24,%r1 /* doesn't affect c/b bits */
1455 mfctl %cr22,%r8 /* Get ipsw */
1457 or %r8,%r9,%r8 /* Set PSW_N */
1467 * I miss is a little different, since we allow users to fault
1468 * on the gateway page which is in the kernel address space.
1471 space_adjust spc,va,t0
1473 space_check spc,t0,itlb_fault
1475 L3_ptep ptp,pte,t0,va,itlb_fault
1477 update_ptep ptp,pte,t0,t1
1479 make_insert_tlb spc,pte,prot
1491 space_check spc,t0,itlb_fault
1493 L2_ptep ptp,pte,t0,va,itlb_fault
1495 update_ptep ptp,pte,t0,t1
1497 make_insert_tlb_11 spc,pte,prot
1499 mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
1502 iitlba pte,(%sr1,va)
1503 iitlbp prot,(%sr1,va)
1505 mtsp t0, %sr1 /* Restore sr1 */
1513 space_check spc,t0,itlb_fault
1515 L2_ptep ptp,pte,t0,va,itlb_fault
1517 update_ptep ptp,pte,t0,t1
1519 make_insert_tlb spc,pte,prot
1533 space_adjust spc,va,t0
1535 space_check spc,t0,dbit_fault
1537 L3_ptep ptp,pte,t0,va,dbit_fault
1540 CMPIB=,n 0,spc,dbit_nolock_20w
1541 ldil L%PA(pa_dbit_lock),t0
1542 ldo R%PA(pa_dbit_lock)(t0),t0
1546 cmpib,= 0,t1,dbit_spin_20w
1551 update_dirty ptp,pte,t0,t1
1553 make_insert_tlb spc,pte,prot
1557 CMPIB=,n 0,spc,dbit_nounlock_20w
1572 space_check spc,t0,dbit_fault
1574 L2_ptep ptp,pte,t0,va,dbit_fault
1577 CMPIB=,n 0,spc,dbit_nolock_11
1578 ldil L%PA(pa_dbit_lock),t0
1579 ldo R%PA(pa_dbit_lock)(t0),t0
1583 cmpib,= 0,t1,dbit_spin_11
1588 update_dirty ptp,pte,t0,t1
1590 make_insert_tlb_11 spc,pte,prot
1592 mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
1595 idtlba pte,(%sr1,va)
1596 idtlbp prot,(%sr1,va)
1598 mtsp t1, %sr1 /* Restore sr1 */
1600 CMPIB=,n 0,spc,dbit_nounlock_11
1613 space_check spc,t0,dbit_fault
1615 L2_ptep ptp,pte,t0,va,dbit_fault
1618 CMPIB=,n 0,spc,dbit_nolock_20
1619 ldil L%PA(pa_dbit_lock),t0
1620 ldo R%PA(pa_dbit_lock)(t0),t0
1624 cmpib,= 0,t1,dbit_spin_20
1629 update_dirty ptp,pte,t0,t1
1631 make_insert_tlb spc,pte,prot
1638 CMPIB=,n 0,spc,dbit_nounlock_20
1649 .import handle_interruption,code
1653 ldi 31,%r8 /* Use an unused code */
1671 /* Register saving semantics for system calls:
1673 %r1 clobbered by system call macro in userspace
1674 %r2 saved in PT_REGS by gateway page
1675 %r3 - %r18 preserved by C code (saved by signal code)
1676 %r19 - %r20 saved in PT_REGS by gateway page
1677 %r21 - %r22 non-standard syscall args
1678 stored in kernel stack by gateway page
1679 %r23 - %r26 arg3-arg0, saved in PT_REGS by gateway page
1680 %r27 - %r30 saved in PT_REGS by gateway page
1681 %r31 syscall return pointer
1684 /* Floating point registers (FIXME: what do we do with these?)
1686 %fr0 - %fr3 status/exception, not preserved
1687 %fr4 - %fr7 arguments
1688 %fr8 - %fr11 not preserved by C code
1689 %fr12 - %fr21 preserved by C code
1690 %fr22 - %fr31 not preserved by C code
1693 .macro reg_save regs
1694 STREG %r3, PT_GR3(\regs)
1695 STREG %r4, PT_GR4(\regs)
1696 STREG %r5, PT_GR5(\regs)
1697 STREG %r6, PT_GR6(\regs)
1698 STREG %r7, PT_GR7(\regs)
1699 STREG %r8, PT_GR8(\regs)
1700 STREG %r9, PT_GR9(\regs)
1701 STREG %r10,PT_GR10(\regs)
1702 STREG %r11,PT_GR11(\regs)
1703 STREG %r12,PT_GR12(\regs)
1704 STREG %r13,PT_GR13(\regs)
1705 STREG %r14,PT_GR14(\regs)
1706 STREG %r15,PT_GR15(\regs)
1707 STREG %r16,PT_GR16(\regs)
1708 STREG %r17,PT_GR17(\regs)
1709 STREG %r18,PT_GR18(\regs)
1712 .macro reg_restore regs
1713 LDREG PT_GR3(\regs), %r3
1714 LDREG PT_GR4(\regs), %r4
1715 LDREG PT_GR5(\regs), %r5
1716 LDREG PT_GR6(\regs), %r6
1717 LDREG PT_GR7(\regs), %r7
1718 LDREG PT_GR8(\regs), %r8
1719 LDREG PT_GR9(\regs), %r9
1720 LDREG PT_GR10(\regs),%r10
1721 LDREG PT_GR11(\regs),%r11
1722 LDREG PT_GR12(\regs),%r12
1723 LDREG PT_GR13(\regs),%r13
1724 LDREG PT_GR14(\regs),%r14
1725 LDREG PT_GR15(\regs),%r15
1726 LDREG PT_GR16(\regs),%r16
1727 LDREG PT_GR17(\regs),%r17
1728 LDREG PT_GR18(\regs),%r18
1731 .export sys_fork_wrapper
1732 .export child_return
1734 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
1735 ldo TASK_REGS(%r1),%r1
1738 STREG %r3, PT_CR27(%r1)
1740 STREG %r2,-RP_OFFSET(%r30)
1741 ldo FRAME_SIZE(%r30),%r30
1743 ldo -16(%r30),%r29 /* Reference param save area */
1746 /* These are call-clobbered registers and therefore
1747 also syscall-clobbered (we hope). */
1748 STREG %r2,PT_GR19(%r1) /* save for child */
1749 STREG %r30,PT_GR21(%r1)
1751 LDREG PT_GR30(%r1),%r25
1756 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
1758 ldo -FRAME_SIZE(%r30),%r30 /* get the stackframe */
1759 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
1760 ldo TASK_REGS(%r1),%r1 /* get pt regs */
1762 LDREG PT_CR27(%r1), %r3
1766 /* strace expects syscall # to be preserved in r20 */
1769 STREG %r20,PT_GR20(%r1)
1771 /* Set the return value for the child */
1773 bl schedule_tail, %r2
1776 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1
1777 LDREG TASK_PT_GR19(%r1),%r2
1782 .export sys_clone_wrapper
1784 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
1785 ldo TASK_REGS(%r1),%r1 /* get pt regs */
1788 STREG %r3, PT_CR27(%r1)
1790 STREG %r2,-RP_OFFSET(%r30)
1791 ldo FRAME_SIZE(%r30),%r30
1793 ldo -16(%r30),%r29 /* Reference param save area */
1796 STREG %r2,PT_GR19(%r1) /* save for child */
1797 STREG %r30,PT_GR21(%r1)
1802 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
1804 .export sys_vfork_wrapper
1806 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
1807 ldo TASK_REGS(%r1),%r1 /* get pt regs */
1810 STREG %r3, PT_CR27(%r1)
1812 STREG %r2,-RP_OFFSET(%r30)
1813 ldo FRAME_SIZE(%r30),%r30
1815 ldo -16(%r30),%r29 /* Reference param save area */
1818 STREG %r2,PT_GR19(%r1) /* save for child */
1819 STREG %r30,PT_GR21(%r1)
1825 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
1828 .macro execve_wrapper execve
1829 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
1830 ldo TASK_REGS(%r1),%r1 /* get pt regs */
1833 * Do we need to save/restore r3-r18 here?
1834 * I don't think so. why would new thread need old
1835 * threads registers?
1838 /* %arg0 - %arg3 are already saved for us. */
1840 STREG %r2,-RP_OFFSET(%r30)
1841 ldo FRAME_SIZE(%r30),%r30
1843 ldo -16(%r30),%r29 /* Reference param save area */
1848 ldo -FRAME_SIZE(%r30),%r30
1849 LDREG -RP_OFFSET(%r30),%r2
1851 /* If exec succeeded we need to load the args */
1854 cmpb,>>= %r28,%r1,error_\execve
1862 .export sys_execve_wrapper
1866 execve_wrapper sys_execve
1869 .export sys32_execve_wrapper
1870 .import sys32_execve
1872 sys32_execve_wrapper:
1873 execve_wrapper sys32_execve
1876 .export sys_rt_sigreturn_wrapper
1877 sys_rt_sigreturn_wrapper:
1878 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26
1879 ldo TASK_REGS(%r26),%r26 /* get pt regs */
1880 /* Don't save regs, we are going to restore them from sigcontext. */
1881 STREG %r2, -RP_OFFSET(%r30)
1883 ldo FRAME_SIZE(%r30), %r30
1884 bl sys_rt_sigreturn,%r2
1885 ldo -16(%r30),%r29 /* Reference param save area */
1887 bl sys_rt_sigreturn,%r2
1888 ldo FRAME_SIZE(%r30), %r30
1891 ldo -FRAME_SIZE(%r30), %r30
1892 LDREG -RP_OFFSET(%r30), %r2
1894 /* FIXME: I think we need to restore a few more things here. */
1895 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
1896 ldo TASK_REGS(%r1),%r1 /* get pt regs */
1899 /* If the signal was received while the process was blocked on a
1900 * syscall, then r2 will take us to syscall_exit; otherwise r2 will
1901 * take us to syscall_exit_rfi and on to intr_return.
1904 LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */
1906 .export sys_sigaltstack_wrapper
1907 sys_sigaltstack_wrapper:
1908 /* Get the user stack pointer */
1909 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
1910 ldo TASK_REGS(%r1),%r24 /* get pt regs */
1911 LDREG TASK_PT_GR30(%r24),%r24
1912 STREG %r2, -RP_OFFSET(%r30)
1914 ldo FRAME_SIZE(%r30), %r30
1915 bl do_sigaltstack,%r2
1916 ldo -16(%r30),%r29 /* Reference param save area */
1918 bl do_sigaltstack,%r2
1919 ldo FRAME_SIZE(%r30), %r30
1922 ldo -FRAME_SIZE(%r30), %r30
1923 LDREG -RP_OFFSET(%r30), %r2
1928 .export sys32_sigaltstack_wrapper
1929 sys32_sigaltstack_wrapper:
1930 /* Get the user stack pointer */
1931 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r24
1932 LDREG TASK_PT_GR30(%r24),%r24
1933 STREG %r2, -RP_OFFSET(%r30)
1934 ldo FRAME_SIZE(%r30), %r30
1935 bl do_sigaltstack32,%r2
1936 ldo -16(%r30),%r29 /* Reference param save area */
1938 ldo -FRAME_SIZE(%r30), %r30
1939 LDREG -RP_OFFSET(%r30), %r2
1944 .export sys_rt_sigsuspend_wrapper
1945 sys_rt_sigsuspend_wrapper:
1946 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
1947 ldo TASK_REGS(%r1),%r24
1950 STREG %r2, -RP_OFFSET(%r30)
1952 ldo FRAME_SIZE(%r30), %r30
1953 bl sys_rt_sigsuspend,%r2
1954 ldo -16(%r30),%r29 /* Reference param save area */
1956 bl sys_rt_sigsuspend,%r2
1957 ldo FRAME_SIZE(%r30), %r30
1960 ldo -FRAME_SIZE(%r30), %r30
1961 LDREG -RP_OFFSET(%r30), %r2
1963 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
1964 ldo TASK_REGS(%r1),%r1
1970 .export syscall_exit
1972 /* NOTE: HP-UX syscalls also come through here
1973 after hpux_syscall_exit fixes up return
1975 /* NOTE: Not all syscalls exit this way. rt_sigreturn will exit
1976 * via syscall_exit_rfi if the signal was received while the process
1980 /* save return value now */
1983 LDREG TI_TASK(%r1),%r1
1984 STREG %r28,TASK_PT_GR28(%r1)
1988 /* <linux/personality.h> cannot be easily included */
1989 #define PER_HPUX 0x10
1990 LDREG TASK_PERSONALITY(%r1),%r19
1992 /* We can't use "CMPIB<> PER_HPUX" since "im5" field is sign extended */
1993 ldo -PER_HPUX(%r19), %r19
1996 /* Save other hpux returns if personality is PER_HPUX */
1997 STREG %r22,TASK_PT_GR22(%r1)
1998 STREG %r29,TASK_PT_GR29(%r1)
2001 #endif /* CONFIG_HPUX */
2003 /* Seems to me that dp could be wrong here, if the syscall involved
2004 * calling a module, and nothing got round to restoring dp on return.
2010 /* Check for software interrupts */
2012 .import irq_stat,data
2014 ldil L%irq_stat,%r19
2015 ldo R%irq_stat(%r19),%r19
2018 /* sched.h: int processor */
2019 /* %r26 is used as scratch register to index into irq_stat[] */
2020 ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
2022 /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
2028 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
2029 #endif /* CONFIG_SMP */
2031 LDREG IRQSTAT_SIRQ_PEND(%r19),%r20 /* hardirq.h: unsigned long */
2032 cmpib,<>,n 0,%r20,syscall_do_softirq /* forward */
2034 syscall_check_resched:
2036 /* check for reschedule */
2038 LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* long */
2039 bb,<,n %r19, 31-TIF_NEED_RESCHED, syscall_do_resched /* forward */
2042 LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* get ti flags */
2043 bb,<,n %r19, 31-TIF_SIGPENDING, syscall_do_signal /* forward */
2046 /* Are we being ptraced? */
2047 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2049 LDREG TASK_PTRACE(%r1), %r19
2050 bb,< %r19,31,syscall_restore_rfi
2053 ldo TASK_PT_FR31(%r1),%r19 /* reload fpregs */
2056 LDREG TASK_PT_SAR(%r1),%r19 /* restore SAR */
2059 LDREG TASK_PT_GR2(%r1),%r2 /* restore user rp */
2060 LDREG TASK_PT_GR19(%r1),%r19
2061 LDREG TASK_PT_GR20(%r1),%r20
2062 LDREG TASK_PT_GR21(%r1),%r21
2063 LDREG TASK_PT_GR22(%r1),%r22
2064 LDREG TASK_PT_GR23(%r1),%r23
2065 LDREG TASK_PT_GR24(%r1),%r24
2066 LDREG TASK_PT_GR25(%r1),%r25
2067 LDREG TASK_PT_GR26(%r1),%r26
2068 LDREG TASK_PT_GR27(%r1),%r27 /* restore user dp */
2069 LDREG TASK_PT_GR28(%r1),%r28 /* syscall return value */
2070 LDREG TASK_PT_GR29(%r1),%r29
2071 LDREG TASK_PT_GR31(%r1),%r31 /* restore syscall rp */
2074 LDREG TASK_PT_GR30(%r1),%r30 /* restore user sp */
2075 mfsp %sr3,%r1 /* Get users space id */
2076 mtsp %r1,%sr7 /* Restore sr7 */
2078 mtsp %r1,%sr4 /* Restore sr4 */
2079 mtsp %r1,%sr5 /* Restore sr5 */
2080 mtsp %r1,%sr6 /* Restore sr6 */
2082 depi 3,31,2,%r31 /* ensure return to user mode. */
2085 /* decide whether to reset the wide mode bit
2087 * For a syscall, the W bit is stored in the lowest bit
2088 * of sp. Extract it and reset W if it is zero */
2089 extrd,u,*<> %r30,63,1,%r1
2091 /* now reset the lowest bit of sp if it was set */
2094 be,n 0(%sr3,%r31) /* return to user space */
2096 /* We have to return via an RFI, so that PSW T and R bits can be set
2098 * This sets up pt_regs so we can return via intr_restore, which is not
2099 * the most efficient way of doing things, but it works.
2101 syscall_restore_rfi:
2102 ldo -1(%r0),%r2 /* Set recovery cntr to -1 */
2103 mtctl %r2,%cr0 /* for immediate trap */
2104 LDREG TASK_PT_PSW(%r1),%r2 /* Get old PSW */
2105 ldi 0x0b,%r20 /* Create new PSW */
2106 depi -1,13,1,%r20 /* C, Q, D, and I bits */
2108 /* The values of PA_SINGLESTEP_BIT and PA_BLOCKSTEP_BIT are
2109 * set in include/linux/ptrace.h and converted to PA bitmap
2110 * numbers in asm-offsets.c */
2112 /* if ((%r19.PA_SINGLESTEP_BIT)) { %r20.27=1} */
2113 extru,= %r19,PA_SINGLESTEP_BIT,1,%r0
2114 depi -1,27,1,%r20 /* R bit */
2116 /* if ((%r19.PA_BLOCKSTEP_BIT)) { %r20.7=1} */
2117 extru,= %r19,PA_BLOCKSTEP_BIT,1,%r0
2118 depi -1,7,1,%r20 /* T bit */
2120 STREG %r20,TASK_PT_PSW(%r1)
2122 /* Always store space registers, since sr3 can be changed (e.g. fork) */
2125 STREG %r25,TASK_PT_SR3(%r1)
2126 STREG %r25,TASK_PT_SR4(%r1)
2127 STREG %r25,TASK_PT_SR5(%r1)
2128 STREG %r25,TASK_PT_SR6(%r1)
2129 STREG %r25,TASK_PT_SR7(%r1)
2130 STREG %r25,TASK_PT_IASQ0(%r1)
2131 STREG %r25,TASK_PT_IASQ1(%r1)
2134 /* Now if old D bit is clear, it means we didn't save all registers
2135 * on syscall entry, so do that now. This only happens on TRACEME
2136 * calls, or if someone attached to us while we were on a syscall.
2137 * We could make this more efficient by not saving r3-r18, but
2138 * then we wouldn't be able to use the common intr_restore path.
2139 * It is only for traced processes anyway, so performance is not
2142 bb,< %r2,30,pt_regs_ok /* Branch if D set */
2143 ldo TASK_REGS(%r1),%r25
2144 reg_save %r25 /* Save r3 to r18 */
2146 STREG %r2,TASK_PT_SR0(%r1)
2148 STREG %r2,TASK_PT_SR1(%r1)
2150 STREG %r2,TASK_PT_SR2(%r1)
2152 LDREG TASK_PT_GR31(%r1),%r2
2153 depi 3,31,2,%r2 /* ensure return to user mode. */
2154 STREG %r2,TASK_PT_IAOQ0(%r1)
2156 STREG %r2,TASK_PT_IAOQ1(%r1)
2161 .import do_softirq,code
2165 b syscall_check_resched
2166 ssm PSW_SM_I, %r0 /* do_softirq returns with I bit off */
2168 .import schedule,code
2172 ldo -16(%r30),%r29 /* Reference param save area */
2176 b syscall_check_bh /* if resched, we start over again */
2179 .import do_signal,code
2181 /* Save callee-save registers (for sigcontext).
2182 FIXME: After this point the process structure should be
2183 consistent with all the relevant state of the process
2184 before the syscall. We need to verify this. */
2185 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2186 ldo TASK_REGS(%r1), %r25 /* struct pt_regs *regs */
2189 ldi 1, %r24 /* unsigned long in_syscall */
2192 ldo -16(%r30),%r29 /* Reference param save area */
2195 copy %r0, %r26 /* sigset_t *oldset = NULL */
2197 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
2198 ldo TASK_REGS(%r1), %r20 /* reload pt_regs */
2204 * get_register is used by the non access tlb miss handlers to
2205 * copy the value of the general register specified in r8 into
2206 * r1. This routine can't be used for shadowed registers, since
2207 * the rfir will restore the original value. So, for the shadowed
2208 * registers we put a -1 into r1 to indicate that the register
2209 * should not be used (the register being copied could also have
2210 * a -1 in it, but that is OK, it just means that we will have
2211 * to use the slow path instead).
2217 bv %r0(%r25) /* r0 */
2219 bv %r0(%r25) /* r1 - shadowed */
2221 bv %r0(%r25) /* r2 */
2223 bv %r0(%r25) /* r3 */
2225 bv %r0(%r25) /* r4 */
2227 bv %r0(%r25) /* r5 */
2229 bv %r0(%r25) /* r6 */
2231 bv %r0(%r25) /* r7 */
2233 bv %r0(%r25) /* r8 - shadowed */
2235 bv %r0(%r25) /* r9 - shadowed */
2237 bv %r0(%r25) /* r10 */
2239 bv %r0(%r25) /* r11 */
2241 bv %r0(%r25) /* r12 */
2243 bv %r0(%r25) /* r13 */
2245 bv %r0(%r25) /* r14 */
2247 bv %r0(%r25) /* r15 */
2249 bv %r0(%r25) /* r16 - shadowed */
2251 bv %r0(%r25) /* r17 - shadowed */
2253 bv %r0(%r25) /* r18 */
2255 bv %r0(%r25) /* r19 */
2257 bv %r0(%r25) /* r20 */
2259 bv %r0(%r25) /* r21 */
2261 bv %r0(%r25) /* r22 */
2263 bv %r0(%r25) /* r23 */
2265 bv %r0(%r25) /* r24 - shadowed */
2267 bv %r0(%r25) /* r25 - shadowed */
2269 bv %r0(%r25) /* r26 */
2271 bv %r0(%r25) /* r27 */
2273 bv %r0(%r25) /* r28 */
2275 bv %r0(%r25) /* r29 */
2277 bv %r0(%r25) /* r30 */
2279 bv %r0(%r25) /* r31 */
2283 * set_register is used by the non access tlb miss handlers to
2284 * copy the value of r1 into the general register specified in
2291 bv %r0(%r25) /* r0 (silly, but it is a place holder) */
2293 bv %r0(%r25) /* r1 */
2295 bv %r0(%r25) /* r2 */
2297 bv %r0(%r25) /* r3 */
2299 bv %r0(%r25) /* r4 */
2301 bv %r0(%r25) /* r5 */
2303 bv %r0(%r25) /* r6 */
2305 bv %r0(%r25) /* r7 */
2307 bv %r0(%r25) /* r8 */
2309 bv %r0(%r25) /* r9 */
2311 bv %r0(%r25) /* r10 */
2313 bv %r0(%r25) /* r11 */
2315 bv %r0(%r25) /* r12 */
2317 bv %r0(%r25) /* r13 */
2319 bv %r0(%r25) /* r14 */
2321 bv %r0(%r25) /* r15 */
2323 bv %r0(%r25) /* r16 */
2325 bv %r0(%r25) /* r17 */
2327 bv %r0(%r25) /* r18 */
2329 bv %r0(%r25) /* r19 */
2331 bv %r0(%r25) /* r20 */
2333 bv %r0(%r25) /* r21 */
2335 bv %r0(%r25) /* r22 */
2337 bv %r0(%r25) /* r23 */
2339 bv %r0(%r25) /* r24 */
2341 bv %r0(%r25) /* r25 */
2343 bv %r0(%r25) /* r26 */
2345 bv %r0(%r25) /* r27 */
2347 bv %r0(%r25) /* r28 */
2349 bv %r0(%r25) /* r29 */
2351 bv %r0(%r25) /* r30 */
2353 bv %r0(%r25) /* r31 */