patch-2.4.0-test12 linux/arch/parisc/kernel/entry.S
Next file: linux/arch/parisc/kernel/hardware.c
Previous file: linux/arch/parisc/kernel/drivers.c
Back to the patch index
Back to the overall index
- Lines: 1868
- Date:
Wed Dec 6 11:46:39 2000
- Orig file:
v2.4.0-test11/linux/arch/parisc/kernel/entry.S
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.4.0-test11/linux/arch/parisc/kernel/entry.S linux/arch/parisc/kernel/entry.S
@@ -0,0 +1,1867 @@
+/*------------------------------------------------------------------------------
+ * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+ *
+ * kernel entry points (interruptions, system call wrappers)
+ * Copyright (C) 1999,2000 Philipp Rumpf
+ * Copyright (C) 1999 SuSE GmbH Nuernberg
+ * Copyright (C) 2000 Hewlett-Packard (John Marvin)
+ * Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <asm/offset.h>
+
+/* the following is the setup i think we should follow:
+ * whenever the CPU is interruptible, the following has to be true:
+ * CR30 is the kernel sp or 0 if we currently use the kernel stack
+ * CR31 is the kernel gp */
+
+/* we have the following possibilities to act on an interruption:
+ * - handle in assembly and use shadowed registers only
+ * - save registers to kernel stack and handle in assembly or C */
+
+ .text
+
+#ifdef __LP64__
+ .level 2.0w
+#endif
+
+#define __ASSEMBLY__
+#include <asm/assembly.h> /* for LDREG/STREG defines */
+#include <asm/pgtable.h>
+#include <asm/psw.h>
+#include <asm/signal.h>
+
+#ifdef __LP64__
+#define FRAME_SIZE 64
+#else
+#define FRAME_SIZE 64
+#endif
+
+ /* Switch to virtual mapping, trashing only %r1 */
+ .macro virt_map rfi_type
+ mtsm %r0
+ tovirt %r29
+ tovirt %r30
+ mfsp %sr7, %r1
+ mtsp %r1, %sr3
+ mtsp %r0, %sr4
+ mtsp %r0, %sr5
+ mtsp %r0, %sr6
+ mtsp %r0, %sr7
+ ldil L%KERNEL_PSW, %r1
+ ldo R%KERNEL_PSW(%r1), %r1
+ LDIL_FIXUP(%r1)
+ mtctl %r1, %cr22
+ mtctl %r0, %cr17
+ mtctl %r0, %cr17
+ ldil L%.+28, %r1
+ ldo R%.+24(%r1), %r1
+ LDIL_FIXUP(%r1)
+ mtctl %r1, %cr18
+ ldo 4(%r1), %r1
+ mtctl %r1, %cr18
+ \rfi_type
+ nop
+ .endm
+
+ .macro get_stack
+ mfctl %cr30, %r1
+ comib,=,n 0, %r1, 0f /* forward so predicted not taken */
+
+ /* we save the registers in the task struct */
+ ldo TASK_REGS(%r1), %r29
+ tophys %r29
+ STREG %r30, PT_GR30(%r29)
+ STREG %r1, PT_CR30(%r29)
+ ldo TASK_SZ_ALGN(%r1), %r30
+ b 1f /* unconditional so predicted taken */
+ mtctl %r0,%cr30
+0:
+ /* we put a struct pt_regs on the stack and save the registers there */
+ copy %r30,%r29
+ ldo PT_SZ_ALGN(%r30),%r30
+ tophys %r29
+ STREG %r30,PT_GR30(%r29)
+ STREG %r0,PT_CR30(%r29)
+1:
+ .endm
+
+ .macro rest_stack regs
+ LDREG PT_CR30(\regs), %r1
+ comib,=,n 0, %r1, 2f/* forward so predicted not taken */
+
+ /* we restore the registers out of the task struct */
+ mtctl %r1, %cr30
+ LDREG PT_GR1(\regs), %r1
+ LDREG PT_GR30(\regs),%r30
+ b 3f
+ LDREG PT_GR29(\regs),%r29
+2:
+ /* we take a struct pt_regs off the stack */
+ LDREG PT_GR1(\regs), %r1
+ LDREG PT_GR29(\regs), %r29
+ ldo -PT_SZ_ALGN(%r30), %r30
+3:
+ .endm
+
+#ifdef OLD
+ /* fixme interruption handler */
+ .macro def code
+ /* WARNING!!! THIS IS DEBUG CODE ONLY!!! */
+ b unimplemented_64bitirq
+ ldi \code, %r1
+ .align 32
+ .endm
+
+ /* Use def to enable break - KWDB wants em
+ * (calls traps.c:handle_interruption) */
+ .macro pass_break code
+
+#else
+ /* default interruption handler
+ * (calls traps.c:handle_interruption) */
+ .macro def code
+#endif
+ mtctl %r29, %cr31
+ mtctl %r1, %cr28
+ ldi \code, %r1
+ b intr_save
+ mtctl %r1, %cr29
+ .align 32
+ .endm
+
+ /* Interrupt interruption handler
+ * (calls irq.c:do_irq_mask) */
+ .macro extint code
+ mtctl %r29, %cr31
+ mtctl %r1, %cr28
+ mfctl %cr23, %r1
+ mtctl %r1, %cr23
+ b intr_extint
+ mtctl %r1, %cr29
+ .align 32
+ .endm
+
+ .import os_hpmc, code
+
+ /* HPMC handler */
+ .macro hpmc code
+ nop /* must be a NOP, will be patched later */
+ ldil L%PA(os_hpmc), %r3
+ ldo R%PA(os_hpmc)(%r3), %r3
+ bv,n 0(%r3)
+ nop
+ .word 0 /* checksum (will be patched) */
+ .word PA(os_hpmc) /* address of handler */
+ .word 0 /* length of handler */
+ .endm
+
+ /*
+ * Performance Note: Instructions will be moved up into
+ * this part of the code later on, once we are sure
+ * that the tlb miss handlers are close to final form.
+ */
+
+ /* Register definitions for tlb miss handler macros */
+
+ va = r8 /* virtual address for which the trap occured */
+ spc = r24 /* space for which the trap occured */
+
+#ifndef __LP64__
+
+ /*
+ * itlb miss interruption handler (parisc 1.1 - 32 bit)
+ */
+
+ .macro itlb_11 code
+
+ mfctl %pcsq, spc
+ b itlb_miss_11
+ mfctl %pcoq, va
+
+ .align 32
+ .endm
+#endif
+
+ /*
+ * itlb miss interruption handler (parisc 2.0)
+ */
+
+ .macro itlb_20 code
+
+ mfctl %pcsq, spc
+#ifdef __LP64__
+ b itlb_miss_20w
+#else
+ b itlb_miss_20
+#endif
+ mfctl %pcoq, va
+
+ .align 32
+ .endm
+
+#ifndef __LP64__
+ /*
+ * naitlb miss interruption handler (parisc 1.1 - 32 bit)
+ *
+ * Note: naitlb misses will be treated
+ * as an ordinary itlb miss for now.
+ * However, note that naitlb misses
+ * have the faulting address in the
+ * IOR/ISR.
+ */
+
+ .macro naitlb_11 code
+
+ mfctl %isr,spc
+ b itlb_miss_11
+ mfctl %ior,va
+ /* FIXME: If user causes a naitlb miss, the priv level may not be in
+ * lower bits of va, where the itlb miss handler is expecting them
+ */
+
+ .align 32
+ .endm
+#endif
+
+ /*
+ * naitlb miss interruption handler (parisc 2.0)
+ *
+ * Note: naitlb misses will be treated
+ * as an ordinary itlb miss for now.
+ * However, note that naitlb misses
+ * have the faulting address in the
+ * IOR/ISR.
+ */
+
+ .macro naitlb_20 code
+
+ mfctl %isr,spc
+#ifdef __LP64__
+ b itlb_miss_20w
+#else
+ b itlb_miss_20
+#endif
+ mfctl %ior,va
+ /* FIXME: If user causes a naitlb miss, the priv level may not be in
+ * lower bits of va, where the itlb miss handler is expecting them
+ */
+
+ .align 32
+ .endm
+
+#ifndef __LP64__
+ /*
+ * dtlb miss interruption handler (parisc 1.1 - 32 bit)
+ */
+
+ .macro dtlb_11 code
+
+ mfctl %isr, spc
+ b dtlb_miss_11
+ mfctl %ior, va
+
+ .align 32
+ .endm
+#endif
+
+ /*
+ * dtlb miss interruption handler (parisc 2.0)
+ */
+
+ .macro dtlb_20 code
+
+ mfctl %isr, spc
+#ifdef __LP64__
+ b dtlb_miss_20w
+#else
+ b dtlb_miss_20
+#endif
+ mfctl %ior, va
+
+ .align 32
+ .endm
+
+#ifndef __LP64__
+ /* nadtlb miss interruption handler (parisc 1.1 - 32 bit)
+ *
+ * Note: nadtlb misses will be treated
+ * as an ordinary dtlb miss for now.
+ *
+ */
+
+ .macro nadtlb_11 code
+
+ mfctl %isr,spc
+ b dtlb_miss_11
+ mfctl %ior,va
+
+ .align 32
+ .endm
+#endif
+
+ /* nadtlb miss interruption handler (parisc 2.0)
+ *
+ * Note: nadtlb misses will be treated
+ * as an ordinary dtlb miss for now.
+ *
+ */
+
+ .macro nadtlb_20 code
+
+ mfctl %isr,spc
+#ifdef __LP64__
+ b dtlb_miss_20w
+#else
+ b dtlb_miss_20
+#endif
+ mfctl %ior,va
+
+ .align 32
+ .endm
+
+#ifndef __LP64__
+ /*
+ * dirty bit trap interruption handler (parisc 1.1 - 32 bit)
+ */
+
+ .macro dbit_11 code
+
+ mfctl %isr,spc
+ b dbit_trap_11
+ mfctl %ior,va
+
+ .align 32
+ .endm
+#endif
+
+ /*
+ * dirty bit trap interruption handler (parisc 2.0)
+ */
+
+ .macro dbit_20 code
+
+ mfctl %isr,spc
+#ifdef __LP64__
+ b dbit_trap_20w
+#else
+ b dbit_trap_20
+#endif
+ mfctl %ior,va
+
+ .align 32
+ .endm
+
+ /*
+ * Align fault_vector_20 on 4K boundary so that both
+ * fault_vector_11 and fault_vector_20 are on the
+ * same page. This is only necessary as long as we
+ * write protect the kernel text, which we may stop
+ * doing once we use large parge translations to cover
+ * the static part of the kernel address space.
+ */
+
+
+ .export fault_vector_20
+
+ .align 4096
+
+fault_vector_20:
+ /* First vector is invalid (0) */
+ .ascii "cows can fly"
+ .byte 0
+ .align 32
+
+ hpmc 1
+ def 2
+ def 3
+ extint 4
+ def 5
+ itlb_20 6
+ def 7
+ def 8
+ def 9
+ def 10
+ def 11
+ def 12
+ def 13
+ def 14
+ dtlb_20 15
+ naitlb_20 16
+ nadtlb_20 17
+ def 18
+ def 19
+ dbit_20 20
+ def 21
+ def 22
+ def 23
+ def 24
+ def 25
+ def 26
+ def 27
+ def 28
+ def 29
+ def 30
+ def 31
+
+#ifndef __LP64__
+
+ .export fault_vector_11
+
+ .align 2048
+
+fault_vector_11:
+ /* First vector is invalid (0) */
+ .ascii "cows can fly"
+ .byte 0
+ .align 32
+
+ hpmc 1
+ def 2
+ def 3
+ extint 4
+ def 5
+ itlb_11 6
+ def 7
+ def 8
+ def 9
+ def 10
+ def 11
+ def 12
+ def 13
+ def 14
+ dtlb_11 15
+ naitlb_11 16
+ nadtlb_11 17
+ def 18
+ def 19
+ dbit_11 20
+ def 21
+ def 22
+ def 23
+ def 24
+ def 25
+ def 26
+ def 27
+ def 28
+ def 29
+ def 30
+ def 31
+
+#endif
+
+ .import handle_interruption,code
+ .import handle_real_interruption,code
+ .import do_irq_mask,code
+ .import parisc_stopkernel,code
+ .import cpu_irq_region,data
+
+ /*
+ * r26 = function to be called
+ * r25 = argument to pass in
+ * r24 = flags for do_fork()
+ *
+ * Kernel threads don't ever return, so they don't need
+ * a true register context. We just save away the arguments
+ * for copy_thread/ret_ to properly set up the child.
+ */
+
+#define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */
+
+ .export __kernel_thread, code
+ .import do_fork
+__kernel_thread:
+ STREG %r2, -RP_OFFSET(%r30)
+
+ copy %r30, %r1
+ ldo PT_SZ_ALGN(%r30),%r30
+#ifdef __LP64__
+ /* Yo, function pointers in wide mode are little structs... -PB */
+ /* XXX FIXME do we need to honor the fptr's %dp value too? */
+ ldd 16(%r26), %r26
+#endif
+ STREG %r26, PT_GR26(%r1) /* Store function & argument for child */
+ STREG %r25, PT_GR25(%r1)
+ ldo CLONE_VM(%r0), %r26 /* Force CLONE_VM since only init_mm */
+ or %r26, %r24, %r26 /* will have kernel mappings. */
+ copy %r0, %r25
+ bl do_fork, %r2
+ copy %r1, %r24
+
+ /* Parent Returns here */
+
+ ldo -PT_SZ_ALGN(%r30), %r30
+ LDREG -RP_OFFSET(%r30), %r2
+ bv %r0(%r2)
+ nop
+
+ /*
+ * Child Returns here
+ *
+ * copy_thread moved args from temp save area set up above
+ * into task save area.
+ */
+
+ .export ret_from_kernel_thread
+ret_from_kernel_thread:
+
+ LDREG TASK_PT_GR26-TASK_SZ_ALGN(%r30), %r1
+ LDREG TASK_PT_GR25-TASK_SZ_ALGN(%r30), %r26
+ ble 0(%sr7, %r1)
+ copy %r31, %r2
+
+ b sys_exit
+ ldi 0, %r26
+
+ .import sys_execve, code
+ .export __execve, code
+__execve:
+ copy %r2, %r15
+ copy %r23, %r17
+ copy %r30, %r16
+ ldo PT_SZ_ALGN(%r30), %r30
+ STREG %r26, PT_GR26(%r16)
+ STREG %r25, PT_GR25(%r16)
+ STREG %r24, PT_GR24(%r16)
+ bl sys_execve, %r2
+ copy %r16, %r26
+
+ comib,<>,n 0,%r28,__execve_failed
+
+ b intr_return
+ STREG %r17, PT_CR30(%r16)
+
+__execve_failed:
+ /* yes, this will trap and die. */
+ copy %r15, %r2
+ bv %r0(%r2)
+ nop
+
+ .align 4
+
+ /*
+ * struct task_struct *_switch_to(struct task_struct *prev,
+ * struct task_struct *next)
+ *
+ * switch kernel stacks and return prev */
+ .export _switch_to, code
+_switch_to:
+ STREG %r2, -RP_OFFSET(%r30)
+
+ callee_save
+
+ ldil L%_switch_to_ret, %r2
+ ldo R%_switch_to_ret(%r2), %r2
+ LDIL_FIXUP(%r2)
+
+ STREG %r2, TASK_PT_KPC(%r26)
+ LDREG TASK_PT_KPC(%r25), %r2
+
+ STREG %r30, TASK_PT_KSP(%r26)
+ LDREG TASK_PT_KSP(%r25), %r30
+
+ bv %r0(%r2)
+ nop
+
+_switch_to_ret:
+ mtctl %r0, %cr0 /* Needed for single stepping */
+ callee_rest
+
+ LDREG -RP_OFFSET(%r30), %r2
+ bv %r0(%r2)
+ copy %r26, %r28
+
+ /*
+ * Common rfi return path for interruptions, kernel execve, and some
+ * syscalls. The sys_rt_sigreturn syscall will return via this path
+ * if the signal was received when the process was running; if the
+ * process was blocked on a syscall then the normal syscall_exit
+ * path is used. All syscalls for traced proceses exit via
+ * intr_restore.
+ * Note that the following code uses a "relied upon translation". See
+ * the parisc ACD for details. The ssm is necessary due to a PCXT bug.
+ */
+
+ .align 4096
+
+ .export syscall_exit_rfi
+syscall_exit_rfi:
+ copy %r30,%r16
+ /* FIXME! depi below has hardcoded dependency on kernel stack size */
+ depi 0,31,14,%r16 /* get task pointer */
+ ldo TASK_REGS(%r16),%r16
+ /* Force iaoq to userspace, as the user has had access to our current
+ * context via sigcontext.
+ * XXX do we need any other protection here?
+ */
+ LDREG PT_IAOQ0(%r16),%r19
+ depi 3,31,2,%r19
+ STREG %r19,PT_IAOQ0(%r16)
+ LDREG PT_IAOQ1(%r16),%r19
+ depi 3,31,2,%r19
+ STREG %r19,PT_IAOQ1(%r16)
+
+intr_return:
+
+ /* Check for software interrupts */
+
+ .import irq_stat,data
+
+ ldil L%irq_stat,%r19
+ ldo R%irq_stat(%r19),%r19
+ LDIL_FIXUP(%r19)
+
+#ifdef CONFIG_SMP
+ copy %r30,%r1
+ /* FIXME! depi below has hardcoded dependency on kernel stack size */
+ depi 0,31,14,%r1 /* get task pointer */
+ ldw TASK_PROCESSOR(%r1),%r20 /* get cpu # - int */
+#if (IRQSTAT_SZ == 32)
+ dep %r20,26,27,%r20 /* shift left 5 bits */
+#else
+#error IRQSTAT_SZ changed, fix dep
+#endif /* IRQSTAT_SZ */
+ add %r19,%r20,%r19
+#endif /* CONFIG_SMP */
+
+ ldw IRQSTAT_SI_ACTIVE(%r19),%r20 /* hardirq.h: unsigned int */
+ ldw IRQSTAT_SI_MASK(%r19),%r19 /* hardirq.h: unsigned int */
+ and %r19,%r20,%r20
+ comib,<>,n 0,%r20,intr_do_softirq /* forward */
+
+intr_check_resched:
+
+ /* check for reschedule */
+ copy %r30,%r1
+ /* FIXME! depi below has hardcoded dependency on kernel stack size */
+ depi 0,31,14,%r1 /* get task pointer */
+ LDREG TASK_NEED_RESCHED(%r1),%r19 /* sched.h: long need_resched */
+ comib,<>,n 0,%r19,intr_do_resched /* forward */
+
+intr_check_sig:
+ /* As above */
+ copy %r30,%r1
+ depi 0,31,14,%r1 /* get task pointer */
+ ldw TASK_SIGPENDING(%r1),%r19 /* sched.h: int sigpending */
+ comib,<>,n 0,%r19,intr_do_signal /* forward */
+
+intr_restore:
+ copy %r16, %r29
+ ldo PT_FR31(%r29), %r29
+ rest_fp %r29
+ copy %r16, %r29
+ rest_general %r29
+ ssm 0,%r0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ tophys %r29
+ mtsm %r0
+ rest_specials %r29
+ rest_stack %r29
+ rfi
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ .import do_softirq,code
+intr_do_softirq:
+ bl do_softirq,%r2
+ nop
+ b intr_check_resched
+ nop
+
+ .import schedule,code
+intr_do_resched:
+ /* Only do reschedule if we are returning to user space */
+ LDREG PT_SR7(%r16), %r20
+ comib,= 0,%r20,intr_restore /* backward */
+ nop
+
+ bl schedule,%r2
+ ssm PSW_SM_I, %r0
+
+ /* It's OK to leave I bit on */
+ b intr_return /* start over if we got a resched */
+ nop
+
+ .import do_signal,code
+intr_do_signal:
+ /* Only do signals if we are returning to user space */
+ LDREG PT_SR7(%r16), %r20
+ comib,= 0,%r20,intr_restore /* backward */
+ nop
+
+ copy %r0, %r24 /* unsigned long in_syscall */
+ copy %r16, %r25 /* struct pt_regs *regs */
+ ssm PSW_SM_I, %r0
+ bl do_signal,%r2
+ copy %r0, %r26 /* sigset_t *oldset = NULL */
+
+ b intr_restore
+ nop
+
+ /* CR28 - saved GR1
+ * CR29 - argument for do_irq_mask */
+
+ /* External interrupts */
+intr_extint:
+ get_stack
+ save_specials %r29
+ virt_map rfi
+ save_general %r29
+
+ ldo PT_FR0(%r29), %r24
+ save_fp %r24
+
+ loadgp
+
+ copy %r29, %r24 /* arg2 is pt_regs */
+ copy %r29, %r16 /* save pt_regs */
+#ifdef CONFIG_KWDB
+ copy %r29, %r3 /* KWDB - update frame pointer (gr3) */
+#endif
+
+ /* sorry to put this cruft in the interrupt path */
+ ldil L%cpu_irq_region, %r25
+ ldo R%cpu_irq_region(%r25), %r25
+ bl do_irq_mask,%r2
+#ifdef __LP64__
+ LDIL_FIXUP(%r25)
+#else
+ nop
+#endif
+
+ b intr_return
+ nop
+
+ /* Generic interruptions (illegal insn, unaligned, page fault, etc) */
+
+ .export intr_save, code /* for os_hpmc */
+
+intr_save:
+ get_stack
+ save_specials %r29
+
+ mfctl %cr20, %r1
+ STREG %r1, PT_ISR(%r29)
+ mfctl %cr21, %r1
+ STREG %r1, PT_IOR(%r29)
+
+ virt_map rfi
+ save_general %r29
+
+ ldo PT_FR0(%r29), %r25
+ save_fp %r25
+
+ loadgp
+
+ copy %r29, %r25 /* arg1 is pt_regs */
+#ifdef CONFIG_KWDB
+ copy %r29, %r3 /* KWDB - update frame pointer (gr3) */
+#endif
+
+ bl handle_interruption,%r2
+ copy %r29, %r16 /* save pt_regs */
+
+ b intr_return
+ nop
+
+ /*
+ * Note for all tlb miss handlers:
+ *
+ * cr24 contains a pointer to the kernel address space
+ * page directory.
+ *
+ * cr25 contains a pointer to the current user address
+ * space page directory.
+ *
+ * sr3 will contain the space id of the user address space
+ * of the current running thread while that thread is
+ * running in the kernel.
+ */
+
+ /*
+ * register number allocations. Note that these are all
+ * in the shadowed registers
+ */
+
+ t0 = r1 /* temporary register 0 */
+ va = r8 /* virtual address for which the trap occured */
+ t1 = r9 /* temporary register 1 */
+ pte = r16 /* pte/phys page # */
+ prot = r17 /* prot bits */
+ spc = r24 /* space for which the trap occured */
+ ptp = r25 /* page directory/page table pointer */
+
+#ifdef __LP64__
+
+dtlb_miss_20w:
+
+ extrd,u spc,31,7,t1 /* adjust va */
+ depd t1,31,7,va /* adjust va */
+ depdi 0,31,7,spc /* adjust space */
+ mfctl %cr25,ptp /* Assume user space miss */
+ or,*<> %r0,spc,%r0 /* If it is user space, nullify */
+ mfctl %cr24,ptp /* Load kernel pgd instead */
+ extrd,u va,33,9,t1 /* Get pgd index */
+
+ mfsp %sr7,t0 /* Get current space */
+ or,*= %r0,t0,%r0 /* If kernel, nullify following test */
+ comb,<>,n t0,spc,dtlb_fault /* forward */
+
+ /* First level page table lookup */
+
+ ldd,s t1(ptp),ptp
+ extrd,u va,42,9,t0 /* get second-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault
+ depdi 0,63,12,ptp /* clear prot bits */
+
+ /* Second level page table lookup */
+
+ ldd,s t0(ptp),ptp
+ extrd,u va,51,9,t0 /* get third-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault
+ depdi 0,63,12,ptp /* clear prot bits */
+
+ /* Third level page table lookup */
+
+ shladd t0,3,ptp,ptp
+ ldi _PAGE_ACCESSED,t1
+ ldd 0(ptp),pte
+ bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault
+
+ /* Check whether the "accessed" bit was set, otherwise do so */
+
+ or t1,pte,t0 /* t0 has R bit set */
+ and,*<> t1,pte,%r0 /* test and nullify if already set */
+ std t0,0(ptp) /* write back pte */
+
+ copy spc,prot /* init prot with faulting space */
+
+ depd pte,8,7,prot
+ extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
+ depdi 1,12,1,prot
+ extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
+ depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
+ extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
+ depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
+
+ /* Get rid of prot bits and convert to page addr for idtlbt */
+
+ depdi 0,63,12,pte
+ extrd,u pte,56,32,pte
+ idtlbt %r16,%r17
+
+ rfir
+ nop
+#else
+
+dtlb_miss_11:
+ mfctl %cr25,ptp /* Assume user space miss */
+ or,<> %r0,spc,%r0 /* If it is user space, nullify */
+ mfctl %cr24,ptp /* Load kernel pgd instead */
+ extru va,9,10,t1 /* Get pgd index */
+
+ mfsp %sr7,t0 /* Get current space */
+ or,= %r0,t0,%r0 /* If kernel, nullify following test */
+ comb,<>,n t0,spc,dtlb_fault /* forward */
+
+ /* First level page table lookup */
+
+ ldwx,s t1(ptp),ptp
+ extru va,19,10,t0 /* get second-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault
+ depi 0,31,12,ptp /* clear prot bits */
+
+ /* Second level page table lookup */
+
+ sh2addl t0,ptp,ptp
+ ldi _PAGE_ACCESSED,t1
+ ldw 0(ptp),pte
+ bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault
+
+ /* Check whether the "accessed" bit was set, otherwise do so */
+
+ or t1,pte,t0 /* t0 has R bit set */
+ and,<> t1,pte,%r0 /* test and nullify if already set */
+ stw t0,0(ptp) /* write back pte */
+
+ copy spc,prot /* init prot with faulting space */
+ dep pte,8,7,prot
+
+ extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
+ depi 1,12,1,prot
+ extru,= pte,_PAGE_USER_BIT,1,r0
+ depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
+ extru,= pte,_PAGE_GATEWAY_BIT,1,r0
+ depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
+
+ /* Get rid of prot bits and convert to page addr for idtlba */
+
+ depi 0,31,12,pte
+ extru pte,24,25,pte
+
+ mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
+ mtsp spc,%sr1
+
+ idtlba pte,(%sr1,va)
+ idtlbp prot,(%sr1,va)
+
+ mtsp t0, %sr1 /* Restore sr1 */
+
+ rfir
+ nop
+
+dtlb_miss_20:
+ .level 2.0
+
+ mfctl %cr25,ptp /* Assume user space miss */
+ or,<> %r0,spc,%r0 /* If it is user space, nullify */
+ mfctl %cr24,ptp /* Load kernel pgd instead */
+ extru va,9,10,t1 /* Get pgd index */
+
+ mfsp %sr7,t0 /* Get current space */
+ or,= %r0,t0,%r0 /* If kernel, nullify following test */
+ comb,<>,n t0,spc,dtlb_fault /* forward */
+
+ /* First level page table lookup */
+
+ ldwx,s t1(ptp),ptp
+ extru va,19,10,t0 /* get second-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault
+ depi 0,31,12,ptp /* clear prot bits */
+
+ /* Second level page table lookup */
+
+ sh2addl t0,ptp,ptp
+ ldi _PAGE_ACCESSED,t1
+ ldw 0(ptp),pte
+ bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault
+
+ /* Check whether the "accessed" bit was set, otherwise do so */
+
+ or t1,pte,t0 /* t0 has R bit set */
+ and,<> t1,pte,%r0 /* test and nullify if already set */
+ stw t0,0(ptp) /* write back pte */
+
+ copy spc,prot /* init prot with faulting space */
+
+ depd pte,8,7,prot
+ extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
+ depdi 1,12,1,prot
+ extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
+ depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
+ extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
+ depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
+
+ /* Get rid of prot bits and convert to page addr for idtlbt */
+
+ depdi 0,63,12,pte
+ extrd,u pte,56,25,pte
+ idtlbt %r16,%r17
+
+ .level 1.1
+
+ rfir
+ nop
+#endif
+
+#ifdef __LP64__
+itlb_miss_20w:
+
+ /*
+ * I miss is a little different, since we allow users to fault
+ * on the gateway page which is in the kernel address space.
+ */
+
+ extrd,u spc,31,7,t1 /* adjust va */
+ depd t1,31,7,va /* adjust va */
+ depdi 0,31,7,spc /* adjust space */
+ cmpib,*= 0,spc,itlb_miss_kernel_20w
+ extrd,u va,33,9,t1 /* Get pgd index */
+
+ mfctl %cr25,ptp /* load user pgd */
+
+ mfsp %sr7,t0 /* Get current space */
+ or,*= %r0,t0,%r0 /* If kernel, nullify following test */
+ cmpb,*<>,n t0,spc,itlb_fault /* forward */
+
+ /* First level page table lookup */
+
+itlb_miss_common_20w:
+ ldd,s t1(ptp),ptp
+ extrd,u va,42,9,t0 /* get second-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
+ depdi 0,63,12,ptp /* clear prot bits */
+
+ /* Second level page table lookup */
+
+ ldd,s t0(ptp),ptp
+ extrd,u va,51,9,t0 /* get third-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
+ depdi 0,63,12,ptp /* clear prot bits */
+
+ /* Third level page table lookup */
+
+ shladd t0,3,ptp,ptp
+ ldi _PAGE_ACCESSED,t1
+ ldd 0(ptp),pte
+ bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
+
+ /* Check whether the "accessed" bit was set, otherwise do so */
+
+ or t1,pte,t0 /* t0 has R bit set */
+ and,*<> t1,pte,%r0 /* test and nullify if already set */
+ std t0,0(ptp) /* write back pte */
+
+ copy spc,prot /* init prot with faulting space */
+
+ depd pte,8,7,prot
+ extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
+ depdi 1,12,1,prot
+ extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
+ depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
+ extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
+ depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
+
+ /* Get rid of prot bits and convert to page addr for iitlbt */
+
+ depdi 0,63,12,pte
+ extrd,u pte,56,32,pte
+ iitlbt %r16,%r17
+
+ rfir
+ nop
+
+itlb_miss_kernel_20w:
+ b itlb_miss_common_20w
+ mfctl %cr24,ptp /* Load kernel pgd */
+#else
+
+itlb_miss_11:
+
+ /*
+ * I miss is a little different, since we allow users to fault
+ * on the gateway page which is in the kernel address space.
+ */
+
+ comib,= 0,spc,itlb_miss_kernel_11
+ extru va,9,10,t1 /* Get pgd index */
+
+ mfctl %cr25,ptp /* load user pgd */
+
+ mfsp %sr7,t0 /* Get current space */
+ or,= %r0,t0,%r0 /* If kernel, nullify following test */
+ comb,<>,n t0,spc,itlb_fault /* forward */
+
+ /* First level page table lookup */
+
+itlb_miss_common_11:
+ ldwx,s t1(ptp),ptp
+ extru va,19,10,t0 /* get second-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
+ depi 0,31,12,ptp /* clear prot bits */
+
+ /* Second level page table lookup */
+
+ sh2addl t0,ptp,ptp
+ ldi _PAGE_ACCESSED,t1
+ ldw 0(ptp),pte
+ bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
+
+ /* Check whether the "accessed" bit was set, otherwise do so */
+
+ or t1,pte,t0 /* t0 has R bit set */
+ and,<> t1,pte,%r0 /* test and nullify if already set */
+ stw t0,0(ptp) /* write back pte */
+
+ copy spc,prot /* init prot with faulting space */
+ dep pte,8,7,prot
+
+ extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
+ depi 1,12,1,prot
+ extru,= pte,_PAGE_USER_BIT,1,r0
+ depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
+ extru,= pte,_PAGE_GATEWAY_BIT,1,r0
+ depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
+
+ /* Get rid of prot bits and convert to page addr for iitlba */
+
+ depi 0,31,12,pte
+ extru pte,24,25,pte
+
+ mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
+ mtsp spc,%sr1
+
+ iitlba pte,(%sr1,va)
+ iitlbp prot,(%sr1,va)
+
+ mtsp t0, %sr1 /* Restore sr1 */
+
+ rfir
+ nop
+
+itlb_miss_kernel_11:
+ b itlb_miss_common_11
+ mfctl %cr24,ptp /* Load kernel pgd */
+
+itlb_miss_20:
+
+ /*
+ * I miss is a little different, since we allow users to fault
+ * on the gateway page which is in the kernel address space.
+ */
+
+ comib,= 0,spc,itlb_miss_kernel_20
+ extru va,9,10,t1 /* Get pgd index */
+
+ mfctl %cr25,ptp /* load user pgd */
+
+ mfsp %sr7,t0 /* Get current space */
+ or,= %r0,t0,%r0 /* If kernel, nullify following test */
+ comb,<>,n t0,spc,itlb_fault /* forward */
+
+ /* First level page table lookup */
+
+itlb_miss_common_20:
+ ldwx,s t1(ptp),ptp
+ extru va,19,10,t0 /* get second-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
+ depi 0,31,12,ptp /* clear prot bits */
+
+ /* Second level page table lookup */
+
+ sh2addl t0,ptp,ptp
+ ldi _PAGE_ACCESSED,t1
+ ldw 0(ptp),pte
+ bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
+
+ /* Check whether the "accessed" bit was set, otherwise do so */
+
+ or t1,pte,t0 /* t0 has R bit set */
+ and,<> t1,pte,%r0 /* test and nullify if already set */
+ stw t0,0(ptp) /* write back pte */
+
+ copy spc,prot /* init prot with faulting space */
+
+ .level 2.0
+
+ depd pte,8,7,prot
+ extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
+ depdi 1,12,1,prot
+ extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
+ depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
+ extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
+ depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
+
+ /* Get rid of prot bits and convert to page addr for iitlbt */
+
+ depdi 0,63,12,pte
+ extrd,u pte,56,25,pte
+ iitlbt %r16,%r17
+ .level 1.1
+
+ rfir
+ nop
+
+
+itlb_miss_kernel_20:
+ b itlb_miss_common_20
+ mfctl %cr24,ptp /* Load kernel pgd */
+#endif
+
+#ifdef __LP64__
+
+dbit_trap_20w:
+
+ extrd,u spc,31,7,t1 /* adjust va */
+ depd t1,31,7,va /* adjust va */
+ depdi 0,1,2,va /* adjust va */
+ depdi 0,31,7,spc /* adjust space */
+ mfctl %cr25,ptp /* Assume user space miss */
+ or,*<> %r0,spc,%r0 /* If it is user space, nullify */
+ mfctl %cr24,ptp /* Load kernel pgd instead */
+ extrd,u va,33,9,t1 /* Get pgd index */
+
+ mfsp %sr7,t0 /* Get current space */
+ or,*= %r0,t0,%r0 /* If kernel, nullify following test */
+ comb,<>,n t0,spc,dbit_fault /* forward */
+
+ /* First level page table lookup */
+
+ ldd,s t1(ptp),ptp
+ extrd,u va,42,9,t0 /* get second-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
+ depdi 0,63,12,ptp /* clear prot bits */
+
+ /* Second level page table lookup */
+
+ ldd,s t0(ptp),ptp
+ extrd,u va,51,9,t0 /* get third-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
+ depdi 0,63,12,ptp /* clear prot bits */
+
+ /* Third level page table lookup */
+
+ shladd t0,3,ptp,ptp
+ ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
+ ldd 0(ptp),pte
+ bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
+
+ /* Set Accessed and Dirty bits in the pte */
+
+ or t1,pte,pte
+ std pte,0(ptp) /* write back pte */
+
+ copy spc,prot /* init prot with faulting space */
+
+ depd pte,8,7,prot
+ extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
+ depdi 1,12,1,prot
+ extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
+ depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
+ extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
+ depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
+
+ /* Get rid of prot bits and convert to page addr for idtlbt */
+
+ depdi 0,63,12,pte
+ extrd,u pte,56,32,pte
+ idtlbt %r16,%r17
+
+ rfir
+ nop
+#else
+
+dbit_trap_11:
+ mfctl %cr25,ptp /* Assume user space trap */
+ or,<> %r0,spc,%r0 /* If it is user space, nullify */
+ mfctl %cr24,ptp /* Load kernel pgd instead */
+ extru va,9,10,t1 /* Get pgd index */
+
+ mfsp %sr7,t0 /* Get current space */
+ or,= %r0,t0,%r0 /* If kernel, nullify following test */
+ comb,<>,n t0,spc,dbit_fault /* forward */
+
+ /* First level page table lookup */
+
+ ldwx,s t1(ptp),ptp
+ extru va,19,10,t0 /* get second-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
+ depi 0,31,12,ptp /* clear prot bits */
+
+ /* Second level page table lookup */
+
+ sh2addl t0,ptp,ptp
+ ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
+ ldw 0(ptp),pte
+ bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
+
+ /* Set Accessed and Dirty bits in the pte */
+
+ or t1,pte,pte
+ stw pte,0(ptp) /* write back pte */
+
+ copy spc,prot /* init prot with faulting space */
+ dep pte,8,7,prot
+
+ extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
+ depi 1,12,1,prot
+ extru,= pte,_PAGE_USER_BIT,1,r0
+ depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
+ extru,= pte,_PAGE_GATEWAY_BIT,1,r0
+ depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
+
+ /* Get rid of prot bits and convert to page addr for idtlba */
+
+ depi 0,31,12,pte
+ extru pte,24,25,pte
+
+ mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
+ mtsp spc,%sr1
+
+ idtlba pte,(%sr1,va)
+ idtlbp prot,(%sr1,va)
+
+ mtsp t0, %sr1 /* Restore sr1 */
+
+ rfir
+ nop
+
+dbit_trap_20:
+ mfctl %cr25,ptp /* Assume user space trap */
+ or,<> %r0,spc,%r0 /* If it is user space, nullify */
+ mfctl %cr24,ptp /* Load kernel pgd instead */
+ extru va,9,10,t1 /* Get pgd index */
+
+ mfsp %sr7,t0 /* Get current space */
+ or,= %r0,t0,%r0 /* If kernel, nullify following test */
+ comb,<>,n t0,spc,dbit_fault /* forward */
+
+ /* First level page table lookup */
+
+ ldwx,s t1(ptp),ptp
+ extru va,19,10,t0 /* get second-level index */
+ bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
+ depi 0,31,12,ptp /* clear prot bits */
+
+ /* Second level page table lookup */
+
+ sh2addl t0,ptp,ptp
+ ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
+ ldw 0(ptp),pte
+ bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
+
+ /* Set Accessed and Dirty bits in the pte */
+
+ or t1,pte,pte
+ stw pte,0(ptp) /* write back pte */
+
+ copy spc,prot /* init prot with faulting space */
+
+ .level 2.0
+
+ depd pte,8,7,prot
+ extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
+ depdi 1,12,1,prot
+ extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
+ depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
+ extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
+ depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
+
+ /* Get rid of prot bits and convert to page addr for idtlbt */
+
+ depdi 0,63,12,pte
+ extrd,u pte,56,25,pte
+ idtlbt %r16,%r17
+
+ .level 1.1
+
+ rfir
+ nop
+#endif
+
+ .import handle_interruption,code
+
+kernel_bad_space:
+ b tlb_fault
+ ldi 31,%r1 /* Use an unused code */
+
+dbit_fault:
+ b tlb_fault
+ ldi 20,%r1
+
+itlb_fault:
+ b tlb_fault
+ ldi 6,%r1
+
+dtlb_fault:
+ ldi 15,%r1
+
+ /* Fall Through */
+
+tlb_fault:
+ mtctl %r1,%cr29
+ mtctl %r29,%cr31
+
+ get_stack
+ save_specials %r29 /* Note this saves a trashed r1 */
+
+ SAVE_CR (%cr20, PT_ISR(%r29))
+ SAVE_CR (%cr21, PT_IOR(%r29))
+
+ virt_map rfir
+
+ STREG %r1,PT_GR1(%r29) /* save good value after rfir */
+
+ save_general %r29
+
+ ldo PT_FR0(%r29), %r25
+ save_fp %r25
+
+ loadgp
+
+ copy %r29, %r25
+
+ bl handle_interruption, %r2
+ copy %r29, %r16
+
+ b intr_return
+ nop
+
+ /* Register saving semantics for system calls:
+
+ %r1 clobbered by system call macro in userspace
+ %r2 saved in PT_REGS by gateway page
+ %r3 - %r18 preserved by C code (saved by signal code)
+ %r19 - %r20 saved in PT_REGS by gateway page
+ %r21 - %r22 non-standard syscall args
+ stored in kernel stack by gateway page
+ %r23 - %r26 arg3-arg0, saved in PT_REGS by gateway page
+ %r27 - %r30 saved in PT_REGS by gateway page
+ %r31 syscall return pointer
+ */
+
+ /* Floating point registers (FIXME: what do we do with these?)
+
+ %fr0 - %fr3 status/exception, not preserved
+ %fr4 - %fr7 arguments
+ %fr8 - %fr11 not preserved by C code
+ %fr12 - %fr21 preserved by C code
+ %fr22 - %fr31 not preserved by C code
+ */
+
+ .macro reg_save regs
+ STREG %r3, PT_GR3(\regs)
+ STREG %r4, PT_GR4(\regs)
+ STREG %r5, PT_GR5(\regs)
+ STREG %r6, PT_GR6(\regs)
+ STREG %r7, PT_GR7(\regs)
+ STREG %r8, PT_GR8(\regs)
+ STREG %r9, PT_GR9(\regs)
+ STREG %r10,PT_GR10(\regs)
+ STREG %r11,PT_GR11(\regs)
+ STREG %r12,PT_GR12(\regs)
+ STREG %r13,PT_GR13(\regs)
+ STREG %r14,PT_GR14(\regs)
+ STREG %r15,PT_GR15(\regs)
+ STREG %r16,PT_GR16(\regs)
+ STREG %r17,PT_GR17(\regs)
+ STREG %r18,PT_GR18(\regs)
+ .endm
+
+ .macro reg_restore regs
+ LDREG PT_GR3(\regs), %r3
+ LDREG PT_GR4(\regs), %r4
+ LDREG PT_GR5(\regs), %r5
+ LDREG PT_GR6(\regs), %r6
+ LDREG PT_GR7(\regs), %r7
+ LDREG PT_GR8(\regs), %r8
+ LDREG PT_GR9(\regs), %r9
+ LDREG PT_GR10(\regs),%r10
+ LDREG PT_GR11(\regs),%r11
+ LDREG PT_GR12(\regs),%r12
+ LDREG PT_GR13(\regs),%r13
+ LDREG PT_GR14(\regs),%r14
+ LDREG PT_GR15(\regs),%r15
+ LDREG PT_GR16(\regs),%r16
+ LDREG PT_GR17(\regs),%r17
+ LDREG PT_GR18(\regs),%r18
+ .endm
+
+ .export sys_fork_wrapper
+sys_fork_wrapper:
+ ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */
+ reg_save %r1
+
+ STREG %r2,-RP_OFFSET(%r30)
+ ldo FRAME_SIZE(%r30),%r30
+
+ /* These are call-clobbered registers and therefore
+ also syscall-clobbered (we hope). */
+ STREG %r2,PT_GR19(%r1) /* save for child */
+ STREG %r30,PT_GR20(%r1)
+ ldil L%child_return, %r3
+ ldo R%child_return(%r3), %r3
+ LDIL_FIXUP(%r3)
+ STREG %r3,PT_GR21(%r1) /* save for child */
+
+ LDREG PT_GR30(%r1),%r25
+ copy %r1,%r24
+ bl sys_clone,%r2
+ ldi SIGCHLD,%r26
+
+ LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
+wrapper_exit:
+ ldo -FRAME_SIZE(%r30),%r30 /* get the stackframe */
+ ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */
+
+ reg_restore %r1
+
+ bv %r0(%r2)
+ nop
+
+ /* Set the return value for the child */
+child_return:
+ LDREG TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
+ b wrapper_exit
+ copy %r0,%r28
+
+
+ .export sys_clone_wrapper
+sys_clone_wrapper:
+ ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */
+ reg_save %r1
+
+ STREG %r2,-RP_OFFSET(%r30)
+ ldo FRAME_SIZE(%r30),%r30
+
+ STREG %r30,PT_GR20(%r1)
+ ldil L%child_return,%r3
+ ldo R%child_return(%r3),%r3
+ LDIL_FIXUP(%r3)
+
+ bl sys_clone,%r2
+ STREG %r3,PT_GR21(%r1) /* save for child */
+
+ b wrapper_exit
+ LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
+
+
+ .export sys_vfork_wrapper
+sys_vfork_wrapper:
+ ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */
+ reg_save %r1
+
+ STREG %r2,-RP_OFFSET(%r30)
+ ldo FRAME_SIZE(%r30),%r30
+
+ STREG %r30,PT_GR20(%r1)
+ ldil L%child_return,%r3
+ ldo R%child_return(%r3),%r3
+ LDIL_FIXUP(%r3)
+ STREG %r3,PT_GR21(%r1) /* save for child */
+
+ bl sys_vfork,%r2
+ copy %r1,%r26
+
+ b wrapper_exit
+ LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
+
+
+ .macro execve_wrapper execve
+ ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */
+
+ /*
+ * Do we need to save/restore r3-r18 here?
+ * I don't think so. why would new thread need old
+ * threads registers?
+ */
+
+ /* %arg0 - %arg3 are already saved for us. */
+
+ STREG %r2,-RP_OFFSET(%r30)
+ ldo FRAME_SIZE(%r30),%r30
+ bl \execve,%r2
+ copy %r1,%arg0
+
+ ldo -FRAME_SIZE(%r30),%r30
+ LDREG -RP_OFFSET(%r30),%r2
+
+ /* If exec succeeded we need to load the args */
+
+ ldo -1024(%r0),%r1
+ comb,>>= %r28,%r1,error_\execve
+ copy %r2,%r19
+
+error_\execve:
+ bv %r0(%r19)
+ nop
+ .endm
+
+ .export sys_execve_wrapper
+ .import sys_execve
+
+sys_execve_wrapper:
+ execve_wrapper sys_execve
+
+#ifdef __LP64__
+ .export sys32_execve_wrapper
+ .import sys32_execve
+
+sys32_execve_wrapper:
+ execve_wrapper sys32_execve
+#endif
+
+ .export sys_rt_sigreturn_wrapper
+sys_rt_sigreturn_wrapper:
+ ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r26
+ /* Don't save regs, we are going to restore them from sigcontext. */
+ STREG %r2, -RP_OFFSET(%r30)
+ bl sys_rt_sigreturn,%r2
+ ldo FRAME_SIZE(%r30), %r30
+
+ ldo -FRAME_SIZE(%r30), %r30
+ LDREG -RP_OFFSET(%r30), %r2
+
+ /* FIXME: I think we need to restore a few more things here. */
+ ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */
+ reg_restore %r1
+
+ /* If the signal was received while the process was blocked on a
+ * syscall, then r2 will take us to syscall_exit; otherwise r2 will
+ * take us to syscall_exit_rfi and on to intr_return.
+ */
+ bv %r0(%r2)
+ LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */
+
+ .export sys_sigaltstack_wrapper
+sys_sigaltstack_wrapper:
+ /* Get the user stack pointer */
+ LDREG -TASK_SZ_ALGN-FRAME_SIZE+TASK_PT_GR30(%r30), %r24
+ STREG %r2, -RP_OFFSET(%r30)
+ bl do_sigaltstack,%r2
+ ldo FRAME_SIZE(%r30), %r30
+
+ ldo -FRAME_SIZE(%r30), %r30
+ LDREG -RP_OFFSET(%r30), %r2
+ bv %r0(%r2)
+ nop
+
+ .export sys_rt_sigsuspend_wrapper
+sys_rt_sigsuspend_wrapper:
+ ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r24
+ reg_save %r24
+
+ STREG %r2, -RP_OFFSET(%r30)
+ bl sys_rt_sigsuspend,%r2
+ ldo FRAME_SIZE(%r30), %r30
+
+ ldo -FRAME_SIZE(%r30), %r30
+ LDREG -RP_OFFSET(%r30), %r2
+
+ ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1
+ reg_restore %r1
+
+ bv %r0(%r2)
+ nop
+
+ .export syscall_exit
+syscall_exit:
+ /* NOTE: HP-UX syscalls also come through here
+ after hpux_syscall_exit fixes up return
+ values. */
+ /* NOTE: Not all syscalls exit this way. rt_sigreturn will exit
+ * via syscall_exit_rfi if the signal was received while the process
+ * was running. All traced processes will probably exit via
+ * syscall_exit_rfi in the future.
+ */
+
+ /* save return value now */
+
+ STREG %r28,TASK_PT_GR28-TASK_SZ_ALGN-FRAME_SIZE(%r30)
+
+syscall_check_bh:
+
+/* #ifdef NOTNOW */
+ /* Check for software interrupts */
+
+ .import irq_stat,data
+
+ ldil L%irq_stat,%r19
+ ldo R%irq_stat(%r19),%r19
+ LDIL_FIXUP(%r19)
+
+#ifdef CONFIG_SMP
+ /* sched.h: int processor */
+ ldw TASK_PROCESSOR-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r20 /* get cpu # */
+#if (IRQSTAT_SZ == 32)
+ dep %r20,26,27,%r20 /* shift left 5 bits */
+#else
+#error IRQSTAT_SZ changed, fix dep
+#endif /* IRQSTAT_SZ */
+ add %r19,%r20,%r19
+#endif /* CONFIG_SMP */
+
+ ldw IRQSTAT_SI_ACTIVE(%r19),%r20 /* hardirq.h: unsigned int */
+ ldw IRQSTAT_SI_MASK(%r19),%r19 /* hardirq.h: unsigned int */
+ and %r19,%r20,%r20
+ comib,<>,n 0,%r20,syscall_do_softirq /* forward */
+/* #endif */
+
+
+syscall_check_resched:
+
+ /* check for reschedule */
+
+ LDREG TASK_NEED_RESCHED-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* long */
+ comib,<>,n 0,%r19,syscall_do_resched /* forward */
+
+syscall_check_sig:
+ ldo -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
+ /* check for pending signals */
+ ldw TASK_SIGPENDING(%r1),%r19
+ comib,<>,n 0,%r19,syscall_do_signal /* forward */
+
+syscall_restore:
+ /* disable interrupts while dicking with the kernel stack, */
+ /* or life can become unpleasant */
+ rsm PSW_SM_I, %r20
+ LDREG TASK_PTRACE(%r1), %r19 /* Are we being ptraced? */
+ bb,<,n %r19,31,syscall_restore_rfi
+ LDREG TASK_PT_GR20(%r1),%r19
+ mtctl %r19, %cr27
+
+ LDREG TASK_PT_GR2(%r1),%r2 /* restore user rp */
+ LDREG TASK_PT_GR21(%r1),%r21
+ LDREG TASK_PT_GR22(%r1),%r22
+ LDREG TASK_PT_GR23(%r1),%r23
+ LDREG TASK_PT_GR24(%r1),%r24
+ LDREG TASK_PT_GR25(%r1),%r25
+ LDREG TASK_PT_GR26(%r1),%r26
+ LDREG TASK_PT_GR27(%r1),%r27 /* restore user dp */
+ LDREG TASK_PT_GR28(%r1),%r28 /* syscall return value */
+ LDREG TASK_PT_GR29(%r1),%r29
+ LDREG TASK_PT_GR30(%r1),%r30 /* restore user sp */
+ LDREG TASK_PT_GR31(%r1),%r31 /* restore syscall rp */
+ ldo TASK_PT_FR31(%r1),%r19 /* reload fpregs */
+ rest_fp %r19
+ LDREG TASK_PT_SAR(%r1),%r19 /* restore SAR */
+ mtsar %r19
+ LDREG TASK_PT_GR19(%r1),%r19
+
+ mtctl %r1,%cr30 /* intrhandler okay. */
+ mfsp %sr3,%r1 /* Get users space id */
+ mtsp %r1,%sr4 /* Restore sr4 */
+ mtsp %r1,%sr5 /* Restore sr5 */
+ mtsp %r1,%sr6 /* Restore sr6 */
+
+ depi 3,31,2,%r31 /* ensure return to user mode. */
+
+ mtsm %r20 /* restore irq state */
+ mfctl %cr27,%r20
+
+ /*
+ * Due to a dependency in the tlb miss handlers on sr7, it
+ * is essential that sr7 get set in the delay slot.
+ */
+
+#ifdef __LP64__
+
+ /* Note the be (and mtsp) is executed in narrow mode. This is OK
+ * for 32 bit processes, but won't work once we support 64 bit
+ * processes.
+ */
+
+ rsm PSW_SM_W, %r0
+ be 0(%sr3,%r31) /* return to user space */
+ mtsp %r1,%sr7 /* Restore sr7 */
+#else
+ be 0(%sr3,%r31) /* return to user space */
+ mtsp %r1,%sr7 /* Restore sr7 */
+#endif
+
+ /* We have to return via an RFI, so that PSW T and R bits can be set
+ * appropriately.
+ * This sets up pt_regs so we can return via intr_restore, which is not
+ * the most efficient way of doing things, but it works.
+ */
+syscall_restore_rfi:
+ ldo -1(%r0),%r2 /* Set recovery cntr to -1 */
+ mtctl %r2,%cr0 /* for immediate trap */
+ copy %r0,%r2 /* Create a reasonable PSW */
+ /* XXX W bit??? */
+ depi -1,13,1,%r2
+ depi -1,28,1,%r2
+ depi -1,30,1,%r2
+ depi -1,31,1,%r2
+ bb,<,n %r19,15,set_rbit /* PT_SINGLESTEP */
+ bb,>=,n %r19,14,set_nobit /* PT_BLOCKSTEP, see ptrace.c */
+set_tbit:
+ depi -1,7,1,%r2
+ b,n set_nobit
+set_rbit:
+ depi -1,27,1,%r2
+set_nobit:
+ STREG %r2,TASK_PT_PSW(%r1)
+ STREG %r1,TASK_PT_CR30(%r1)
+ mfsp %sr0,%r2
+ STREG %r2,TASK_PT_SR0(%r1)
+ mfsp %sr1,%r2
+ STREG %r2,TASK_PT_SR1(%r1)
+ mfsp %sr2,%r2
+ STREG %r2,TASK_PT_SR2(%r1)
+ mfsp %sr3,%r2
+ STREG %r2,TASK_PT_SR3(%r1)
+ STREG %r2,TASK_PT_SR4(%r1)
+ STREG %r2,TASK_PT_SR5(%r1)
+ STREG %r2,TASK_PT_SR6(%r1)
+ STREG %r2,TASK_PT_SR7(%r1)
+ STREG %r2,TASK_PT_IASQ0(%r1)
+ STREG %r2,TASK_PT_IASQ1(%r1)
+ LDREG TASK_PT_GR31(%r1),%r2
+ depi 3,31,2,%r2 /* ensure return to user mode. */
+ STREG %r2,TASK_PT_IAOQ0(%r1)
+ ldo 4(%r2),%r2
+ STREG %r2,TASK_PT_IAOQ1(%r1)
+ ldo TASK_REGS(%r1),%r25
+ reg_save %r25 /* Save r3 to r18 */
+ copy %r25,%r16
+ b intr_restore
+ nop
+
+ .import do_softirq,code
+syscall_do_softirq:
+ bl do_softirq,%r2
+ nop
+ b syscall_check_resched
+ ssm PSW_SM_I, %r0 /* do_softirq returns with I bit off */
+
+ .import schedule,code
+syscall_do_resched:
+ bl schedule,%r2
+ nop
+ b syscall_check_bh /* if resched, we start over again */
+ nop
+
+ .import do_signal,code
+syscall_do_signal:
+ /* Save callee-save registers (for sigcontext).
+ FIXME: After this point the process structure should be
+ consistent with all the relevant state of the process
+ before the syscall. We need to verify this. */
+ ldo TASK_REGS(%r1), %r25 /* struct pt_regs *regs */
+ reg_save %r25
+
+ ldi 1, %r24 /* unsigned long in_syscall */
+
+ bl do_signal,%r2
+ copy %r0, %r26 /* sigset_t *oldset = NULL */
+
+ ldo -TASK_SZ_ALGN-FRAME_SIZE(%r30), %r1 /* reload task ptr */
+ ldo TASK_REGS(%r1), %r20 /* reload pt_regs */
+ reg_restore %r20
+
+ b,n syscall_restore
+
+#ifdef __LP64__
+unimplemented_64bitirq:
+ ssm PSW_SM_Q+PSW_SM_I, %r0
+ /* indicate that we had an interrupt */
+ ldi 0x77, %r28
+ ldi 0x77, %r29
+ /* save interrupt registers in GRs for diagnosis */
+ mfctl %cr17, %r17
+ mfctl %cr18, %r18
+ mfctl %cr19, %r19
+ mfctl %cr20, %r20
+ mfctl %cr21, %r21
+ mfctl %cr22, %r22
+ b,n .
+ nop
+#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)