/* $NetBSD: trap.S,v 1.72 2019/04/16 07:08:46 skrll Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Matthew Fredette. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* $OpenBSD: locore.S,v 1.158 2008/07/28 19:08:46 miod Exp $ */ /* * Copyright (c) 1998-2004 Michael Shalayeff * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Portitions of this file are derived from other sources, see * the copyrights and acknowledgements below. */ /* * (c) Copyright 1988 HEWLETT-PACKARD COMPANY * * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this file * for any purpose is hereby granted without fee, provided that * the above copyright notice and this notice appears in all * copies, and that the name of Hewlett-Packard Company not be * used in advertising or publicity pertaining to distribution * of the software without specific, written prior permission. * Hewlett-Packard Company makes no representations about the * suitability of this software for any purpose. */ /* * Copyright (c) 1990,1991,1992,1994 The University of Utah and * the Computer Systems Laboratory (CSL). All rights reserved. * * Permission to use, copy, modify and distribute this software is hereby * granted provided that (1) source code retains these copyright, permission, * and disclaimer notices, and (2) redistributions including binaries * reproduce the notices in supporting documentation, and (3) all advertising * materials mentioning features or use of this software display the following * acknowledgement: ``This product includes software developed by the * Computer Systems Laboratory at the University of Utah.'' * * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * CSL requests users of this software to return to csl-dist@cs.utah.edu any * improvements that they make and grant CSL redistribution rights. * * Utah $Hdr: locore.s 1.63 95/01/20$ */ #include "opt_multiprocessor.h" #include "opt_cputype.h" /* * NOTICE: This is not a standalone file. To use it, #include it in * your port's locore.S, like so: * * #include */ .section .data /* Normal stack alignment */ .align 64 .export emergency_stack_start, data emergency_stack_start: .block 32768 .export emergency_stack_end, data emergency_stack_end: .text /* * Kernel Gateway Page (must be at known address) * System Call Gate * * GATEway instructions have to be at a fixed known locations because their * addresses are hard coded in routines such as those in the C library. */ .align NBPG .export gateway_page, entry gateway_page: nop /* @ 0.C0000000 (Nothing) */ gate,n bsd_syscall,%r0 /* @ 0.C0000004 (HPUX/BSD) */ nop /* @ 0.C0000008 (HPOSF UNIX) */ nop /* @ 0.C000000C (HPOSF Mach) */ nop nop nop nop bsd_syscall: /* * Set up a space register and a protection id so that we can access * kernel memory. */ mfctl %eiem, %r1 mtctl %r0, %eiem mtsp %r0, %sr1 mfctl %pidr1, %ret0 ldi HPPA_PID_KERNEL, %t2 mtctl %t2, %pidr1 /* * now call the syscall handler */ .import syscall_entry,code .call ldil L%syscall_entry, %t2 be R%syscall_entry(%sr1, %t2) nop ! nop ! nop ! nop .size gateway_page, .-gateway_page .align NBPG .export gateway_page_end, entry gateway_page_end: .export syscall_entry,entry .proc .callinfo calls .entry syscall_entry: /* * %r1: eiem * %ret0: process protection id * %t1: syscall number * %sr0, %r31: return address * %sp: user stack * */ /* t2 = curlwp PCB */ GET_CURLWP_SPACE(%sr1, %t3) ldw L_PCB(%sr1, %t3), %t2 /* XXX can use ,sl */ /* * NB: Even though t4 is a caller-saved register, we save it anyways, as * a convenience to __vfork14 and any other syscalls that absolutely * must have a register that is saved for it. */ /* calculate kernel sp, load, create kernel stack frame */ ldo NBPG+TRAPFRAME_SIZEOF(%t2), %t3 /* see cpu_lwp_fork */ stw %t4, TF_R19-TRAPFRAME_SIZEOF(%sr1, %t3) /* t4 for vfork */ stw %t1, TF_R22-TRAPFRAME_SIZEOF(%sr1, %t3) /* syscall # */ copy %sp, %t4 /* gotta save the args, in case we gonna restart */ stw %arg3, TF_R23 -TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg2, TF_R24 -TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg1, TF_R25 -TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg0, TF_R26 -TRAPFRAME_SIZEOF(%sr1, %t3) stw %r27, TF_R27 -TRAPFRAME_SIZEOF(%sr1, %t3) /* dp */ stw %sp, TF_R30 -TRAPFRAME_SIZEOF(%sr1, %t3) /* user stack */ copy %t3, %sp /* * Make space for the syscall arguments. * * Match the offset from %sp to the trapframe with the offset in * TLABEL(all) for the benefit of ddb. */ stwm %r0, HPPA_FRAME_SIZE+HPPA_FRAME_MAXARGS(%sr1, %sp) /* Align correctly */ ldo HPPA_FRAME_SIZE-1(%sp),%sp depi 0, 31, 6, %sp stw %r0, HPPA_FRAME_CRP(%sr1, %sp) GET_CURCPU_SPACE(%sr1, %t1) ldw CI_PSW(%sr1, %t1), %t1 stw %r1, TF_CR15-TRAPFRAME_SIZEOF(%sr1, %t3) /* eiem ,bc (block copy cache control hint) */ stw %t1, TF_CR22-TRAPFRAME_SIZEOF(%sr1, %t3) /* ipsw */ mfsp %sr3, %t1 stw %t1, TF_SR3-TRAPFRAME_SIZEOF(%sr1, %t3) stw %ret0, TF_CR8-TRAPFRAME_SIZEOF(%sr1, %t3) /* pidr1 */ /* now we can allow interrupts to happen */ mtctl %r1, %eiem /* * Normally, we only have to save the caller-saved registers, because * the callee-saved registers will be naturally saved and restored by * our callee(s). However, see the longer comment in the trap handling * code below for the reasons why we need to save and restore all of * them. */ stw %r2 , TF_R2 -TRAPFRAME_SIZEOF(%sr1, %t3) stw %r3 , TF_R3 -TRAPFRAME_SIZEOF(%sr1, %t3) /* We can now set the frame pointer */ copy %t3, %r3 stw %r4 , TF_R4 -TRAPFRAME_SIZEOF(%sr1, %t3) stw %r5 , TF_R5 -TRAPFRAME_SIZEOF(%sr1, %t3) stw %r6 , TF_R6 -TRAPFRAME_SIZEOF(%sr1, %t3) stw %r7 , TF_R7 -TRAPFRAME_SIZEOF(%sr1, %t3) stw %r8 , TF_R8 -TRAPFRAME_SIZEOF(%sr1, %t3) stw %r9 , TF_R9 -TRAPFRAME_SIZEOF(%sr1, %t3) stw %r10, TF_R10-TRAPFRAME_SIZEOF(%sr1, %t3) stw %r11, TF_R11-TRAPFRAME_SIZEOF(%sr1, %t3) stw %r12, TF_R12-TRAPFRAME_SIZEOF(%sr1, %t3) stw %r13, TF_R13-TRAPFRAME_SIZEOF(%sr1, %t3) stw %r14, TF_R14-TRAPFRAME_SIZEOF(%sr1, %t3) stw %r15, TF_R15-TRAPFRAME_SIZEOF(%sr1, %t3) stw %r16, TF_R16-TRAPFRAME_SIZEOF(%sr1, %t3) stw %r17, TF_R17-TRAPFRAME_SIZEOF(%sr1, %t3) stw %r18, TF_R18-TRAPFRAME_SIZEOF(%sr1, %t3) stw %r0, 0(%sr1, %t3) /* terminate frame */ copy %r0 , %r3 stw %r0, HPPA_FRAME_PSP(%sr1, %sp) stw %r0, HPPA_FRAME_CRP(%sr1, %sp) /* * Copy Arguments * * Unfortunately mmap() under bsd requires 7 words; linux is confined to * 5, and hpux to 6. Assuming the `long' syscall it gives us the * maximum 9 words, which very much overkill for an average of 3. We * keep it at 10, since bundling will keep it at the same speed as 9 * anyway. */ /* * XXX fredette - possible security hole here. * What happens if the user hands us a stack * that points to nowhere, or to data that they * should not be reading? */ stw %arg0, 1*4(%sr1, %t3) /* XXX can use ,bc */ stw %arg1, 2*4(%sr1, %t3) stw %arg2, 3*4(%sr1, %t3) stw %arg3, 4*4(%sr1, %t3) ldw HPPA_FRAME_ARG( 4)(%t4), %arg0 ldw HPPA_FRAME_ARG( 5)(%t4), %arg1 ldw HPPA_FRAME_ARG( 6)(%t4), %arg2 ldw HPPA_FRAME_ARG( 7)(%t4), %arg3 stw %arg0, 5*4(%sr1, %t3) stw %arg1, 6*4(%sr1, %t3) stw %arg2, 7*4(%sr1, %t3) stw %arg3, 8*4(%sr1, %t3) ldw HPPA_FRAME_ARG( 8)(%t4), %arg0 ldw HPPA_FRAME_ARG( 9)(%t4), %arg1 stw %arg0, 9*4(%sr1, %t3) stw %arg1,10*4(%sr1, %t3) /* * Save the rest of the CPU context */ /* XXXNH: Should do a be 0(%sr1, %r31) instead of rfi when possible */ ldo 4(%r31), %arg1 stw %r31, TF_IIOQH-TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg1, TF_IIOQT-TRAPFRAME_SIZEOF(%sr1, %t3) mfsp %sr0, %arg0 stw %arg0, TF_IISQH-TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg0, TF_IISQT-TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg0, TF_CR20-TRAPFRAME_SIZEOF(%sr1, %t3) stw %r31, TF_CR21-TRAPFRAME_SIZEOF(%sr1, %t3) ldil L%(TFF_LAST|TFF_SYS), %arg1 stw %r0, TF_CR19-TRAPFRAME_SIZEOF(%sr1, %t3) /* iir */ stw %arg1, TF_FLAGS-TRAPFRAME_SIZEOF(%sr1, %t3) /* Already done above: mfsp %sr0, %arg0 */ mfsp %sr2, %arg2 mfsp %sr4, %arg3 stw %arg0, TF_SR0-TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg0, TF_SR1-TRAPFRAME_SIZEOF(%sr1, %t3) /* we overwrote sr1 earlier */ stw %arg2, TF_SR2-TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg3, TF_SR4-TRAPFRAME_SIZEOF(%sr1, %t3) mfsp %sr5, %arg0 mfsp %sr6, %arg1 mfsp %sr7, %arg2 mfctl %pidr2, %arg3 stw %arg0, TF_SR5-TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg1, TF_SR6-TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg2, TF_SR7-TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg3, TF_CR9-TRAPFRAME_SIZEOF(%sr1, %t3) #if pbably_not_worth_it mfctl %pidr3, %arg2 mfctl %pidr4, %arg3 stw %arg2, TF_CR12-TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg3, TF_CR13-TRAPFRAME_SIZEOF(%sr1, %t3) #endif mfctl CR_TLS, %arg0 stw %arg0, TF_CR27-TRAPFRAME_SIZEOF(%sr1, %t3) #if defined(DDB) || defined(KGDB) /* * Save v2p translation table pointer */ mfctl %eirr, %arg0 mfctl CR_VTOP, %arg1 stw %arg0, TF_CR23-TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg1, TF_CR25-TRAPFRAME_SIZEOF(%sr1, %t3) mfctl %cr24, %arg0 mfctl %cr28, %arg1 stw %arg0, TF_CR24-TRAPFRAME_SIZEOF(%sr1, %t3) stw %arg1, TF_CR28-TRAPFRAME_SIZEOF(%sr1, %t3) #endif /* setup kernel context */ mtsp %r0, %sr0 mtsp %r0, %sr1 mtsp %r0, %sr2 mtsp %r0, %sr3 mtsp %r0, %sr4 mtsp %r0, %sr5 mtsp %r0, %sr6 mtsp %r0, %sr7 ldo -TRAPFRAME_SIZEOF(%t3), %arg0 ldo 4(%t3), %arg1 ldil L%$global$,%dp ldo R%$global$(%dp),%dp /* do a syscall */ .import syscall,code CALL(syscall, %r1) /* load curlwp's trapframe pointer */ GET_CURLWP(%r1) ldw L_MD(%r1), %t3 .exit .procend /* FALLTHROUGH */ .export syscall_return, entry .proc .callinfo no_calls .entry syscall_return: /* t3 == VA trapframe */ /* disable interrupts, just in case */ mtctl %r0, %eiem /* * Copy the `phys' part of the frame into CPU local temporary store (see * a note for trapall). Hopefully no page fault would happen on or after * the copy, and interrupts are disabled. */ GET_CURCPU(%t2) ldo CI_TRAPSAVE(%t2), %t2 ldw 0(%t3), %r1 ! ldw 4(%t3), %t1 ! stw %r1, 0(%t2) ! stw %t1, 4(%t2) ldw 8(%t3), %r1 ! ldw 12(%t3), %t1 ! stw %r1, 8(%t2) ! stw %t1, 12(%t2) ldw 16(%t3), %r1 ! ldw 20(%t3), %t1 ! stw %r1, 16(%t2) ! stw %t1, 20(%t2) ldw 24(%t3), %r1 ! ldw 28(%t3), %t1 ! stw %r1, 24(%t2) ! stw %t1, 28(%t2) ldw 32(%t3), %r1 ! ldw 36(%t3), %t1 ! stw %r1, 32(%t2) ! stw %t1, 36(%t2) ldw 40(%t3), %r1 ! ldw 44(%t3), %t1 ! stw %r1, 40(%t2) ! stw %t1, 44(%t2) ldw 48(%t3), %r1 ! ldw 52(%t3), %t1 ! stw %r1, 48(%t2) ! stw %t1, 52(%t2) ldw 56(%t3), %r1 ! ldw 60(%t3), %t1 ! stw %r1, 56(%t2) ! stw %t1, 60(%t2) /* 1b. restore most of the general registers */ ldw TF_CR11(%t3), %t1 mtctl %t1, %sar ldw TF_R1(%t3), %r1 ldw TF_R2(%t3), %r2 ldw TF_R3(%t3), %r3 /* * See the comment in the trap handling code below about why we need to * save and restore all general registers under these cases. */ ldw TF_R4(%t3), %r4 ldw TF_R5(%t3), %r5 ldw TF_R6(%t3), %r6 ldw TF_R7(%t3), %r7 ldw TF_R8(%t3), %r8 ldw TF_R9(%t3), %r9 ldw TF_R10(%t3), %r10 ldw TF_R11(%t3), %r11 ldw TF_R12(%t3), %r12 ldw TF_R13(%t3), %r13 ldw TF_R14(%t3), %r14 ldw TF_R15(%t3), %r15 ldw TF_R16(%t3), %r16 ldw TF_R17(%t3), %r17 ldw TF_R18(%t3), %r18 ldw TF_R19(%t3), %t4 /* %r20(%t3) is used as a temporary and will be restored later */ /* %r21(%t2) is used as a temporary and will be restored later */ /* %r22(%t1) is used as a temporary and will be restored later */ ldw TF_R23(%t3), %r23 ldw TF_R24(%t3), %r24 ldw TF_R25(%t3), %r25 ldw TF_R26(%t3), %r26 ldw TF_R27(%t3), %r27 ldw TF_R28(%t3), %r28 ldw TF_R29(%t3), %r29 /* %r30 (%sp) will be restored later */ ldw TF_R31(%t3), %r31 /* 2. restore all the space regs and pid regs, except sr3, pidr1 */ ldw TF_SR0(%t3), %t1 ldw TF_SR1(%t3), %t2 mtsp %t1, %sr0 mtsp %t2, %sr1 ldw TF_SR2(%sr3, %t3), %t1 ldw TF_SR4(%sr3, %t3), %t2 mtsp %t1, %sr2 mtsp %t2, %sr4 ldw TF_SR5(%sr3, %t3), %t1 ldw TF_SR6(%sr3, %t3), %t2 mtsp %t1, %sr5 mtsp %t2, %sr6 ldw TF_SR7(%sr3, %t3), %t1 ldw TF_CR9(%sr3, %t3), %t2 mtsp %t1, %sr7 mtctl %t2, %pidr2 #if pbably_not_worth_it ldw TF_CR12(%sr3, %t3), %t1 ldw TF_CR13(%sr3, %t3), %t2 mtctl %t1, %pidr3 mtctl %t2, %pidr4 #endif ldw TF_CR27(%sr3, %t3), %t1 ldw TF_CR30(%sr3, %t3), %t2 mtctl %t1, CR_TLS mtctl %t2, CR_FPPADDR ldw TF_CR0(%sr3, %t3), %t1 mtctl %t1, CR_RCTR GET_CURCPU_SPACE(%sr3, %t3) /* * Clear the system mask, this puts us back into physical mode. Reload * the trapframe pointer with the correspondent PA value. %sp will be * left in virtual until restored from trapframe, since we don't use it * anyway. */ ssm 0, %r0 ldo CI_TRAPSAVE(%t3), %t3 nop ! nop ! nop ! nop ! nop ! nop rsm RESET_PSW, %r0 /* finally we can restore the space and offset queues and the ipsw */ ldw TF_IISQH(%t3), %t1 ldw TF_IISQT(%t3), %t2 mtctl %t1, %pcsq mtctl %t2, %pcsq ldw TF_IIOQH(%t3), %t1 ldw TF_IIOQT(%t3), %t2 mtctl %t1, %pcoq mtctl %t2, %pcoq ldw TF_CR15(%t3), %t1 ldw TF_CR22(%t3), %t2 mtctl %t1, %eiem mtctl %t2, %ipsw ldw TF_SR3(%t3), %t1 ldw TF_CR8(%t3), %t2 mtsp %t1, %sr3 mtctl %t2, %pidr1 ldw TF_R22(%t3), %t1 ldw TF_R21(%t3), %t2 ldw TF_R30(%t3), %sp ldw TF_R20(%t3), %t3 rfi nop .exit .procend .size syscall_entry, .- syscall_entry /* * interrupt vector table */ #define TLABEL(name) __CONCAT(trap_,name) #define TRAPLABEL(name,num) __CONCAT(TLABEL(name),num) #define TELABEL(num) __CONCAT(trap_ep_,num) #define TRAP(name,num) \ mtctl %r1, %tr7 ! \ .call ! \ .import TLABEL(name), code ! \ b TLABEL(name) ! \ ldi num, %r1 ! \ .align 32 #define ATRAP(name,num) \ .export TRAPLABEL(name,num), entry ! \ .label TRAPLABEL(name,num) ! \ TRAP(all,num) ! \ .size TRAPLABEL(name,num), .-TRAPLABEL(name,num) #define CTRAP(name,num,pre) \ .export TRAPLABEL(name,num), entry ! \ .label TRAPLABEL(name,num) ! \ pre ! \ TRAP(name,num) ! \ .size TRAPLABEL(name,num), .-TRAPLABEL(name,num) #define STRAP(name,num,pre) \ .export TRAPLABEL(name,num), entry ! \ .label TRAPLABEL(name,num) ! \ pre ! \ mtctl %r1, %tr7 ! \ .export TELABEL(num), entry ! \ .label TELABEL(num) ! \ ldil 0,%r1 ! \ ldo 0(%r1), %r1 ! \ .call ! \ bv 0(%r1) ! \ ldi num, %r1 ! \ .align 32 ! \ .size TRAPLABEL(name,num), .-TRAPLABEL(name,num) #define LDILDO(name) ! \ .export name, entry ! \ .label name ! \ ldil L%TLABEL(name),%r1 ! \ ldo R%TLABEL(name)(%r1), %r1 #ifdef HP7000_CPU LDILDO(itlb_x) LDILDO(itlbna_x) LDILDO(dtlb_x) LDILDO(dtlbna_x) LDILDO(tlbd_x) LDILDO(itlb_s) LDILDO(itlbna_s) LDILDO(dtlb_s) LDILDO(dtlbna_s) LDILDO(tlbd_s) #endif #if defined(HP7100_CPU) || defined(HP7200_CPU) LDILDO(itlb_t) LDILDO(itlbna_t) LDILDO(dtlb_t) LDILDO(dtlbna_t) LDILDO(tlbd_t) #endif #if defined(HP7100LC_CPU) || defined(HP7300LC_CPU) LDILDO(itlb_l) LDILDO(itlbna_l) LDILDO(dtlb_l) LDILDO(dtlbna_l) LDILDO(tlbd_l) #endif #if defined(HP8000_CPU) || defined(HP8200_CPU) || \ defined(HP8500_CPU) || defined(HP8600_CPU) || \ defined(HP8700_CPU) LDILDO(itlb_u) LDILDO(itlbna_u) LDILDO(dtlb_u) LDILDO(dtlbna_u) LDILDO(tlbd_u) #endif #define ITLBPRE \ mfctl %pcoq,%r9 /* Offset */ ! \ mfctl %pcsq,%r8 /* Space */ #define DTLBPRE \ mfctl %ior, %r9 /* Offset */ ! \ mfctl %isr, %r8 /* Space */ #define HPMCPRE \ nop .align NBPG .export ivaaddr, entry .export os_hpmc, entry ivaaddr: ATRAP(null,T_NONEXIST) /* 0. invalid interrupt vector */ os_hpmc: CTRAP(hpmc,T_HPMC,HPMCPRE) /* 1. high priority machine check */ ATRAP(power,T_POWERFAIL) /* 2. power failure */ ATRAP(recnt,T_RECOVERY) /* 3. recovery counter trap */ ATRAP(intr,T_INTERRUPT) /* 4. external interrupt */ ATRAP(lpmc,T_LPMC) /* 5. low-priority machine check */ STRAP(itlb,T_ITLBMISS,ITLBPRE) /* 6. instruction TLB miss fault */ ATRAP(iprot,T_IPROT) /* 7. instruction protection trap */ ATRAP(ill,T_ILLEGAL) /* 8. Illegal instruction trap */ CTRAP(ibrk,T_IBREAK,) /* 9. break instruction trap */ ATRAP(privop,T_PRIV_OP) /* 10. privileged operation trap */ ATRAP(privr,T_PRIV_REG) /* 11. privileged register trap */ ATRAP(ovrfl,T_OVERFLOW) /* 12. overflow trap */ ATRAP(cond,T_CONDITION) /* 13. conditional trap */ ATRAP(excpt,T_EXCEPTION) /* 14. assist exception trap */ STRAP(dtlb,T_DTLBMISS,DTLBPRE) /* 15. data TLB miss fault */ STRAP(itlbna,T_ITLBMISSNA,DTLBPRE)/* 16. ITLB non-access miss fault */ STRAP(dtlbna,T_DTLBMISSNA,DTLBPRE)/* 17. DTLB non-access miss fault */ ATRAP(dprot,T_DPROT) /* 18. data protection trap unaligned data reference trap */ ATRAP(dbrk,T_DBREAK) /* 19. data break trap */ STRAP(tlbd,T_TLB_DIRTY,DTLBPRE) /* 20. TLB dirty bit trap */ ATRAP(pgref,T_PAGEREF) /* 21. page reference trap */ CTRAP(emu,T_EMULATION,) /* 22. assist emulation trap */ ATRAP(hpl,T_HIGHERPL) /* 23. higher-privelege transfer trap*/ ATRAP(lpl,T_LOWERPL) /* 24. lower-privilege transfer trap */ ATRAP(tknbr,T_TAKENBR) /* 25. taken branch trap */ ATRAP(dacc,T_DATACC) /* 26. data access rights trap */ ATRAP(dpid,T_DATAPID) /* 27. data protection ID trap */ ATRAP(dalgn,T_DATALIGN) /* 28. unaligned data ref trap */ ATRAP(unk,29) ATRAP(unk,30) ATRAP(unk,31) ATRAP(unk,32) ATRAP(unk,33) ATRAP(unk,34) ATRAP(unk,35) ATRAP(unk,36) ATRAP(unk,37) ATRAP(unk,38) ATRAP(unk,39) ATRAP(unk,40) ATRAP(unk,41) ATRAP(unk,42) ATRAP(unk,43) ATRAP(unk,44) ATRAP(unk,45) ATRAP(unk,46) ATRAP(unk,47) ATRAP(unk,48) ATRAP(unk,49) ATRAP(unk,50) ATRAP(unk,51) ATRAP(unk,52) ATRAP(unk,53) ATRAP(unk,54) ATRAP(unk,55) ATRAP(unk,56) ATRAP(unk,57) ATRAP(unk,58) ATRAP(unk,59) ATRAP(unk,60) ATRAP(unk,61) ATRAP(unk,62) ATRAP(unk,63) /* 64 */ .size ivaaddr, .-ivaaddr /* * This is the locore support for HPMC and TOC machine checks. In the HPMC * case, this is a continuation of the HPMC handler that begins in the interrupt * vector table. In the TOC case, this is the handler installed in page zero. * * Notable points about the CPU state for the OS_TOC handler: * * - The PSW Q bit is 1, all other PSW bits are 0. * - CR14 (IVA) does not point to our vector table. * - CR22 (IPSW) is valid. * - All other control registers HVERSION dependent. * - The TLB is initialized and invalid. * * Notable points about the CPU state for the OS_HPMC handler: * * - The PSW M bit is 1, all other PSW bits are 0. * - CR14 (IVA) does point to our vector table. * - CR22 (IPSW) is valid. * - All other control registers HVERSION dependent. * - The TLB is unchanged. * * The TOC CPU state is actually trickier. Whereas in the HPMC case, we can * return to virtual mode right away, in the TOC case we can't return to virtual * mode until the kernel mapping is reloaded into the BTLB. * * Otherwise, we set up the kernel context, move onto the emergency stack, and * call hppa_machine_check. */ ENTRY_NOPROFILE(os_toc, 0) /* This loads %arg0 and nullifies the next instruction. */ addi,tr T_INTERRUPT, %r0, %arg0 EXIT(os_toc) ENTRY_NOPROFILE(TLABEL(hpmc),0) ALTENTRY(os_hpmc_cont) ldi T_HPMC, %arg0 /* Disable interrupts. */ mtctl %r0, %eiem /* Load protection and space registers for the kernel. */ ldi HPPA_PID_KERNEL, %r1 mtctl %r1, %pidr1 ldi HPPA_SID_KERNEL, %r1 mtsp %r1, %sr0 mtsp %r1, %sr1 mtsp %r1, %sr2 mtsp %r1, %sr3 mtsp %r1, %sr4 mtsp %r1, %sr5 mtsp %r1, %sr6 mtsp %r1, %sr7 /* Reload the Interruption Vector Address. */ ldil L%ivaaddr, %r1 ldo R%ivaaddr(%r1), %r1 mtctl %r1, %iva /* Reload the HPT base and mask. */ ldil L%hppa_vtop, %r1 ldw R%hppa_vtop(%r1), %r1 mtctl %r1, CR_VTOP /* Disable interrupts for the long haul. */ GET_CURCPU(%t1) ldw CI_PSW(%t1), %r1 depi 0, PSW_I_POS, 1, %r1 stw %r1, CI_PSW(%t1) /* Reload the global data pointer. */ ldil L%$global$, %dp ldo R%$global$(%dp), %dp /* Move onto the emergency stack. */ ldil L%emergency_stack_start, %sp ldo R%emergency_stack_start(%sp), %sp stwm %r0, HPPA_FRAME_SIZE(%sp) copy %sp, %r3 /* Start stack calling convention. */ stw %r0, HPPA_FRAME_CRP(%sp) stw %r0, HPPA_FRAME_PSP(%sp) copy %r3, %r1 copy %sp, %r3 stwm %r1, HPPA_FRAME_SIZE(%sp) /* If this is a TOC, remap the kernel. */ comib,<>,n T_INTERRUPT, %arg0, L$check_do_rfi /* Clear kernelmapped. */ ldil L%kernelmapped, %r1 stw %r0, R%kernelmapped(%r1) /* Call hppa_btlb_reload. */ ldil L%hppa_btlb_reload, %r1 ldo R%hppa_btlb_reload(%r1), %r1 blr 0, %rp bv %r0(%r1) nop /* Set kernelmapped. */ ldil L%kernelmapped, %r1 stw %r1, R%kernelmapped(%r1) /* Reload %arg0 (it may have been destroyed). */ ldi T_INTERRUPT, %arg0 /* Disable the interrupt queues. */ rsm RESET_PSW, %r0 L$check_do_rfi: /* Load IPSW. */ GET_CURCPU(%r1) ldw CI_PSW(%r1), %r1 mtctl %r1, %ipsw /* Get the address of hppa_machine_check. */ ldil L%hppa_machine_check, %r1 ldo R%hppa_machine_check(%r1), %r1 /* Load the instruction address queues. */ mtctl %r1, %pcoq ldo 4(%r1), %r1 mtctl %r1, %pcoq ldi HPPA_SID_KERNEL, %r1 mtctl %r1, %pcsq mtctl %r1, %pcsq blr 0, %rp rfi nop nop nop nop nop nop ALTENTRY(os_hpmc_cont_end) nop ALTENTRY(os_toc_end) EXIT(TLABEL(hpmc)) /* * This handles all assist emulation traps. We break these down into three * categories and dispatch accordingly. The categories are: * * - emulate special function unit, * - emulate non-FPU coprocessor, and * - emulate FPU coprocessor. * */ .export TLABEL(emu), entry LEAF_ENTRY_NOPROFILE(TLABEL(emu)) /* * Save %arg0 and load it with the instruction that caused the emulation * trap. */ mtctl %arg0, %tr2 mfctl %iir, %arg0 /* * If the opcode field in the instruction is 4, indicating a special * function unit SPOP instruction, branch to emulate an sfu. If the * opcode field is 0xe, then it's an FPU instruction. */ extru %arg0, 5, 6, %r1 comib,=,n 4, %r1, L$emulate_sfu comib,=,n 0xe, %r1, hppa_fpu_emulate /* * If the uid field in the instruction is not zero or one, indicating a * coprocessor other than an FPU, branch to emulate a non-FPU * coprocessor. */ extru %arg0, 25, 3, %r1 comib,<<,n 1, %r1, L$emulate_coproc /* * If we're still here, this is a FPU coprocessor instruction. That we * trapped to emulate it means one of two things. * * If we do have a hardware FPU but it is disabled, we trapped because * the current process' state is not loaded into the FPU. We load that * state in, possibly swapping out another process' state first. * * If we do have a hardware FPU and it is enabled, we trapped because of * an instruction that isn't supported by this FPU, and so we need to * emulate it. */ hppa_fpu_emulate: /* * We have a hardware FPU. If it is enabled, branch to emulate the * instruction. */ mfctl CR_CCR, %arg0 extru,= %arg0, 25, 2, %r1 b,n L$emulate_fpu /* * The hardware FPU is disabled, so we need to swap in the FPU state of * the LWP whose uspace physical address in CR_FPPADDR. We may also * need to swap out the FPU state of any LWP whose uspace physical * address is in curcpu()->ci_fpu_state. */ /* * So far, the CTRAP() macro has saved %r1 in %tr7, and the dispatching * above has saved %arg0 in tr2. Save the other registers that we want * to use. hppa_fpu_swap deliberately uses only these registers and %r1 * and %arg0. */ mtctl %arg1, %tr4 mtctl %rp, %tr5 /* Call hppa_fpu_swap. */ GET_CURCPU(%arg0) ldw CI_FPU_STATE(%arg0), %arg0 mfctl CR_FPPADDR, %arg1 blr 0, %rp b hppa_fpu_swap nop /* Restore registers and rfi. */ mfctl %tr5, %rp mfctl %tr4, %arg1 mfctl %tr2, %arg0 mfctl %tr7, %r1 rfi nop /* * We branch here to emulate a special function unit instruction. On * entry, %r1 is saved in %tr7 (courtesy of CTRAP), and %arg0 is saved * in %tr2 (courtesy of the sfu/coprocessor dispatcher). */ L$emulate_sfu: /* * Currently we just restore %arg0 and trap with an illegal instruction. */ mfctl %tr2, %arg0 b TLABEL(all) ldi T_ILLEGAL, %r1 /* * We branch here to emulate a non-FPU coprocessor instruction. On * entry, %r1 is saved in %tr7 (courtesy of CTRAP), and %t1 is saved in * %tr2 (courtesy of the sfu/coprocessor dispatcher). */ L$emulate_coproc: /* * Currently we just restore %arg0 and trap with an illegal instruction. */ mfctl %tr2, %arg0 b TLABEL(all) ldi T_ILLEGAL, %r1 /* * We branch here to emulate an FPU coprocessor instruction. On entry, * %r1 is saved in %tr7 (courtesy of CTRAP), and %t1 is saved in %tr2 * (courtesy of the sfu/coprocessor dispatcher). */ L$emulate_fpu: /* * We get back to C via the normal generic trap mechanism, as opposed to * switching to a special stack, setting up a trapframe, etc. ourselves, * for three reasons. * * One, I want to turn interrupts back on, since the emulation code * might not be fast. Two, because the instruction to emulate might be * a load or a store, I need to turn address translation back on (i.e., * return to virtual mode.) Third, doing both of those plus setting up * a trapframe is a pain, and the generic trap handling already does it * all. * * To relieve trap() from having to check for sfu and non-FPU inst- * ructions again, it assumes that these kinds of instructions have * already been translated into some other trap type (as they have, by * the above L$emulate_sfu and L$emulate_coproc), and all * T_EMULATION | T_USER traps are FPU instructions that need emulating. * * So we just restore %arg0 and trap with T_EMULATION. */ mfctl %tr2, %arg0 b TLABEL(all) ldi T_EMULATION, %r1 EXIT(TLABEL(emu)) /* * void hppa_fpu_swapout(struct pcb *out); * void hppa_fpu_swap(struct fpreg *out, struct fpreg *in); */ LEAF_ENTRY_NOPROFILE(hppa_fpu_swapout) ldw PCB_FPREGS(%arg0), %arg0 copy %r0, %arg1 ALTENTRY(hppa_fpu_swap) /* * Note that this function must work in physical mode as well as virtual * mode, because it can be called by a trap handler. This also further * restricts the registers we can use. We can only use %arg0, %arg1, * and %r1. */ /* * Assuming that out and in aren't both NULL, we will have to run co- * processor instructions, so we'd better enable it. * * Also, branch if there's no FPU state to swap out. */ mfctl CR_CCR, %r1 depi 3, 25, 2, %r1 comb,= %r0, %arg0, L$fpu_swap_in mtctl %r1, CR_CCR /* * Swap out the current FPU state. */ fstds,ma %fr0 , 8(%arg0) /* fr0 must be saved first */ fstds,ma %fr1 , 8(%arg0) fstds,ma %fr2 , 8(%arg0) fstds,ma %fr3 , 8(%arg0) fstds,ma %fr4 , 8(%arg0) fstds,ma %fr5 , 8(%arg0) fstds,ma %fr6 , 8(%arg0) fstds,ma %fr7 , 8(%arg0) fstds,ma %fr8 , 8(%arg0) fstds,ma %fr9 , 8(%arg0) fstds,ma %fr10, 8(%arg0) fstds,ma %fr11, 8(%arg0) fstds,ma %fr12, 8(%arg0) fstds,ma %fr13, 8(%arg0) fstds,ma %fr14, 8(%arg0) fstds,ma %fr15, 8(%arg0) fstds,ma %fr16, 8(%arg0) fstds,ma %fr17, 8(%arg0) fstds,ma %fr18, 8(%arg0) fstds,ma %fr19, 8(%arg0) fstds,ma %fr20, 8(%arg0) fstds,ma %fr21, 8(%arg0) fstds,ma %fr22, 8(%arg0) fstds,ma %fr23, 8(%arg0) fstds,ma %fr24, 8(%arg0) fstds,ma %fr25, 8(%arg0) fstds,ma %fr26, 8(%arg0) fstds,ma %fr27, 8(%arg0) fstds,ma %fr28, 8(%arg0) fstds,ma %fr29, 8(%arg0) fstds,ma %fr30, 8(%arg0) fstds %fr31, 0(%arg0) L$fpu_swap_in: /* * Stash the incoming user structure in curcpu->ci_fpu_state. Because * this variable holds a physical address, this means that hppa_fpu_swap * can only be called with a non-zero user_in from physical mode (i.e., * from the emulation assist trap handler). And that's exactly what * happens now. * * So stash ci->ci_fpu_state, branching past the swap-in code if it is * zero. */ GET_CURCPU(%r1) comb,= %r0, %arg1, L$fpu_no_swap_in stw %arg1, CI_FPU_STATE(%r1) /* * Swap in the new FPU state. */ ldo 31*8(%arg1), %arg1 fldds,ma -8(%arg1), %fr31 fldds,ma -8(%arg1), %fr30 fldds,ma -8(%arg1), %fr29 fldds,ma -8(%arg1), %fr28 fldds,ma -8(%arg1), %fr27 fldds,ma -8(%arg1), %fr26 fldds,ma -8(%arg1), %fr25 fldds,ma -8(%arg1), %fr24 fldds,ma -8(%arg1), %fr23 fldds,ma -8(%arg1), %fr22 fldds,ma -8(%arg1), %fr21 fldds,ma -8(%arg1), %fr20 fldds,ma -8(%arg1), %fr19 fldds,ma -8(%arg1), %fr18 fldds,ma -8(%arg1), %fr17 fldds,ma -8(%arg1), %fr16 fldds,ma -8(%arg1), %fr15 fldds,ma -8(%arg1), %fr14 fldds,ma -8(%arg1), %fr13 fldds,ma -8(%arg1), %fr12 fldds,ma -8(%arg1), %fr11 fldds,ma -8(%arg1), %fr10 fldds,ma -8(%arg1), %fr9 fldds,ma -8(%arg1), %fr8 fldds,ma -8(%arg1), %fr7 fldds,ma -8(%arg1), %fr6 fldds,ma -8(%arg1), %fr5 fldds,ma -8(%arg1), %fr4 fldds,ma -8(%arg1), %fr3 fldds,ma -8(%arg1), %fr2 fldds,ma -8(%arg1), %fr1 fldds 0(%arg1), %fr0 /* fr0 must be restored last */ L$fpu_swap_done: /* Increment the switch count and return. */ ldil L%fpu_csw, %r1 ldw R%fpu_csw(%r1), %arg0 ldo 1(%arg0), %arg0 bv %r0(%rp) stw %arg0, R%fpu_csw(%r1) L$fpu_no_swap_in: /* We didn't swap any FPU state in, so disable the FPU. */ mfctl CR_CCR, %r1 depi 0, 25, 2, %r1 b L$fpu_swap_done mtctl %r1, CR_CCR EXIT(hppa_fpu_swapout) /* Construct the virtual address tag. */ /* NB: it is legal for off and t to be the same. */ #define VTAG(sp,off,t) \ shd %r0, off, 1, t /* t[1..15] = off[0..14] */ ! \ dep sp, 31, 16, t /* put in the space id */ ! \ depi 1, 0, 1, t /* and set the valid bit */ #if 0 BSS(dtlb_c, 8) BSS(tlbd_c, 8) BSS(itlb_c, 8) /* XXX this touches tr5, which it should not, perhaps */ #define TLB_STATS_PRE(t) \ mfctl CR_ITMR, %r17 ! \ mtctl %r17, %tr5 #define TLB_STATS_AFT(t) \ mfctl CR_ITMR, %r16 ! \ mfctl %tr5, %r17 ! \ ldil L%__CONCAT(t,_c), %r25 ! \ ldo R%__CONCAT(t,_c)(%r25), %r25 ! \ sub %r16, %r17, %r16 ! \ ldw 0(%r25), %r24 ! \ ldw 4(%r25), %r17 ! \ ldo 1(%r24), %r24 ! \ ldo -2(%r16), %r16 /* for mtctl */ ! \ add %r16, %r17, %r17 ! \ stw %r24, 0(%r25) ! \ stw %r17, 4(%r25) #else #define TLB_STATS_PRE(t) /**/ #define TLB_STATS_AFT(t) /**/ #endif #define TLB_PULL(bits,lbl) ! \ /* space:pgaddr -- %r8:%r9 */ ! \ mfctl CR_VTOP, %r16 ! \ ldwax,s %r8(%r16), %r17 /* space -> page directory */ ! \ extru %r9, 9, 10, %r25 /* r25 = r9[31..22] */ ! \ combt,=,n %r0, %r17, lbl ! \ ldwax,s %r25(%r17), %r24 /* page -> page table */ ! \ extru %r9, 19, 10, %r16 /* r16 = r9[22..12] */ ! \ combt,=,n %r0, %r24, lbl ! \ ldwax,s %r16(%r24), %r17 /* va -> pa:prot */ ! \ sh2addl %r16, %r24, %r25 /* r25 = r16 << 2 + r24 */ ! \ combt,=,n %r0, %r17, lbl ! \ copy %r17, %r16 ! \ depi (bits), 21+bits, 1+bits, %r17 ! \ sub,= %r16, %r17, %r0 /* do not store if unchanged */ ! \ stwas %r17, 0(%r25) /* store back w/ the bits */ ! \ shd %r17, %r0, 13, %r25 ! \ dep %r8, 30, 15, %r25 /* mix0r the pid from the sid */! \ dep %r0, 31, 12, %r17 /* needed ? */ ! \ addi 2, %r25, %r25 ! \ extru %r17, 24, 25, %r17 /* * possible optimizations: * change pte to reduce number of shifts * reorder to reduce stalls */ #define TLB_PULL_L(bits,lbl) ! \ /* space:pgaddr -- %r8:%r9 */ ! \ mfctl CR_VTOP, %r16 ! \ ldwx,s %r8(%r16), %r17 /* space -> page directory */ ! \ extru %r9, 9, 10, %r25 ! \ combt,=,n %r0, %r17, lbl ! \ ldwx,s %r25(%r17), %r24 /* page -> page table */ ! \ extru %r9, 19, 10, %r16 ! \ combt,=,n %r0, %r24, lbl ! \ ldwx,s %r16(%r24), %r17 /* va -> pa:prot */ ! \ sh2addl %r16, %r24, %r25 ! \ combt,=,n %r0, %r17, lbl ! \ copy %r17, %r16 ! \ depi (bits), 21+bits, 1+bits, %r17 ! \ sub,= %r16, %r17, %r0 /* do not store if unchanged */ ! \ stws %r17, 0(%r25) /* store back w/ the bits */ ! \ shd %r17, %r0, 13, %r25 ! \ dep %r8, 30, 15, %r25 /* mix0r the pid from the sid */! \ dep %r0, 31, 12, %r17 /* needed ? */ ! \ addi 2, %r25, %r25 ! \ extru %r17, 24, 25, %r17 /* tlbbtop(%r17) */ ! \ sync #if defined(HP7000_CPU) || defined(HP7100_CPU) || defined(HP7200_CPU) .align 32 /* * This is a handler for interruption 20, "TLB dirty bit trap". It is used on * the PA7000 (PCX), PA7000 (PCX-S), and PA7100 (PCX-T). * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = data address space identifier. Copied from %isr. * %r9 = data address offset. Copied from %ior. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ LEAF_ENTRY_NOPROFILE(TLABEL(tlbd_s)) ALTENTRY(TLABEL(tlbd_t)) ALTENTRY(TLABEL(tlbd_x)) TLB_STATS_PRE(tlbd) TLB_PULL(1, TLABEL(all)) mfsp %sr1, %r16 mtsp %r8, %sr1 idtlba %r17,(%sr1, %r9) idtlbp %r25,(%sr1, %r9) mtsp %r16, %sr1 TLB_STATS_AFT(tlbd) rfir nop EXIT(TLABEL(tlbd_s)) /* * This is a handler for interruption 6, "Instruction TLB miss fault". It is * used on the PA7000 (PCX), PA7000 (PCX-S), PA7100 (PCX-T) and PA7200 (PCX-T') * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = instruction address space identifier. Copied from %pcsq. * %r9 = instruction address offset. Copied from %pcoq. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ LEAF_ENTRY_NOPROFILE(TLABEL(itlb_s)) ALTENTRY(TLABEL(itlb_t)) ALTENTRY(TLABEL(itlb_x)) TLB_STATS_PRE(itlb) TLB_PULL(0, TLABEL(all)) extru,= %r25, 5, 1, %r0 /* gate needs a kernel pid */ depi 0, 30, 15, %r25 mfsp %sr1, %r16 mtsp %r8, %sr1 iitlba %r17,(%sr1, %r9) iitlbp %r25,(%sr1, %r9) mtsp %r16, %sr1 TLB_STATS_AFT(itlb) rfir nop EXIT(TLABEL(itlb_s)) /* * This is a handler for interruption 15, "Data TLB miss fault". It is used on * the PA7000 (PCX), PA7000 (PCX-S), PA7100 (PCX-T) and PA7200 (PCX-T'). * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = data address space identifier. Copied from %isr. * %r9 = data address offset. Copied from %ior. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ LEAF_ENTRY_NOPROFILE(TLABEL(dtlb_s)) ALTENTRY(TLABEL(dtlb_t)) ALTENTRY(TLABEL(dtlb_x)) TLB_STATS_PRE(dtlb) TLB_PULL(0, TLABEL(all)) mfsp %sr1, %r16 mtsp %r8, %sr1 idtlba %r17,(%sr1, %r9) idtlbp %r25,(%sr1, %r9) mtsp %r16, %sr1 TLB_STATS_AFT(dtlb) rfir nop EXIT(TLABEL(dtlb_s)) /* * This is a handler for interruption 16, "Non-access instruction TLB miss * fault", and interrupt 17, "Non-access data TLB miss fault / Non-access data * page fault". It is used on the PA7000 (PCX), PA7000 (PCX-S), PA7100 (PCX-T) * and PA7200 (PCX-T'). * * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = instruction address space identifier. Copied from %isr. * %r9 = instruction address offset. Copied from %ior. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ LEAF_ENTRY_NOPROFILE(TLABEL(dtlbna_s)) ALTENTRY(TLABEL(itlbna_s)) ALTENTRY(TLABEL(dtlbna_t)) ALTENTRY(TLABEL(itlbna_t)) ALTENTRY(TLABEL(dtlbna_x)) ALTENTRY(TLABEL(itlbna_x)) TLB_STATS_PRE(dtlb) TLB_PULL(0, L$dtlbna_t_fake) mfsp %sr1, %r16 mtsp %r8, %sr1 idtlba %r17,(%sr1, %r9) idtlbp %r25,(%sr1, %r9) mtsp %r16, %sr1 TLB_STATS_AFT(dtlb) rfir nop L$dtlbna_s_fake: L$dtlbna_t_fake: /* parse prober/w insns, have to decent to trap() to set regs proper */ mfctl %iir, %r16 extru %r16, 6, 6, %r24 comib,=,n 1, %r24, TLABEL(all) extru %r16, 24, 6, %r24 subi,<> 0x23, %r24, %r0 b TLABEL(all) /* otherwise generate a flush-only tlb entry */ copy %r0, %r17 zdep %r8, 30, 15, %r25 depi -13, 11, 7, %r25 ldo 2(%r25), %r25 /* 3? */ mfsp %sr1, %r16 mtsp %r8, %sr1 idtlba %r17,(%sr1, %r9) idtlbp %r25,(%sr1, %r9) mtsp %r16, %sr1 TLB_STATS_AFT(dtlb) rfir nop EXIT(TLABEL(dtlbna_s)) #endif /* defined(HP7000_CPU) || defined(HP7100_CPU) || defined(HP7200_CPU) */ #if defined(HP7100LC_CPU) || defined(HP7300LC_CPU) #define IITLBAF(r) .word 0x04000440 | ((r) << 16) #define IITLBPF(r) .word 0x04000400 | ((r) << 16) #define IDTLBAF(r) .word 0x04001440 | ((r) << 16) #define IDTLBPF(r) .word 0x04001400 | ((r) << 16) .align 32 /* * This is a handler for interruption 20, "TLB dirty bit trap". It is used on * the PA7100LC (PCX-L), PA7300LC (PCX-L2). * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = data address space identifier. Copied from %ior. * %r9 = data address offset. Copied from %isr. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ LEAF_ENTRY_NOPROFILE(TLABEL(tlbd_l)) TLB_STATS_PRE(tlbd) TLB_PULL_L(1, TLABEL(all)) IDTLBAF(17) IDTLBPF(25) #ifdef USE_HPT /* invalidate instead of update */ mfctl %cr28, %r17 ldw 0(%r17), %r24 VTAG(%r8, %r9, %r16) sub,<> %r16, %r24, %r0 stw %r0, 0(%r17) #endif TLB_STATS_AFT(tlbd) rfir nop EXIT(TLABEL(tlbd_l)) /* * This is a handler for interruption 6, "Instruction TLB miss fault". It is * used on the PA7100LC (PCX-L), PA7300LC (PCX-L2). * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = instruction address space identifier. Copied from %pcsq. * %r9 = instruction address offset. Copied from %pcoq. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ /* * from 7100lc ers, pg.6: * we found a post-silicon bug that makes cr28 * unreliable for the itlb miss handler */ LEAF_ENTRY_NOPROFILE(TLABEL(itlb_l)) TLB_STATS_PRE(itlb) TLB_PULL_L(0, TLABEL(all)) extru,= %r25, 5, 1, %r0 /* gate needs a kernel pid */ depi 0, 30, 15, %r25 IITLBAF(17) IITLBPF(25) TLB_STATS_AFT(itlb) rfir nop EXIT(TLABEL(itlb_l)) /* * This is a handler for interruption 16, "Non-access instruction TLB miss * fault", and interrupt 17, "Non-access data TLB miss fault / Non-access data * page fault". It is used on the PA7100LC (PCX-L), PA7300LC (PCX-L2). * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = instruction address space identifier. Copied from %isr. * %r9 = instruction address offset. Copied from %ior. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ LEAF_ENTRY_NOPROFILE(TLABEL(dtlbna_l)) ALTENTRY(TLABEL(itlbna_l)) TLB_STATS_PRE(dtlb) TLB_PULL_L(0, L$dtlbna_l_fake) IDTLBAF(17) IDTLBPF(25) TLB_STATS_AFT(dtlb) rfir nop L$dtlbna_l_fake: /* parse prober/w insns, have to decent to trap() to set regs proper */ mfctl %iir, %r16 extru %r16, 6, 6, %r24 comib,=,n 1, %r24, TLABEL(all) extru %r16, 24, 6, %r24 subi,<> 0x23, %r24, %r0 b TLABEL(all) /* otherwise generate a flush-only tlb entry */ copy %r0, %r17 zdep %r8, 30, 15, %r25 depi -13, 11, 7, %r25 ldo 2(%r25), %r25 /* 3? */ IDTLBAF(17) IDTLBPF(25) TLB_STATS_AFT(dtlb) rfir nop EXIT(TLABEL(dtlbna_l)) /* * This is a handler for interruption 15, "Data TLB miss fault". It is used on * the PA7100LC (PCX-L), PA7300LC (PCX-L2). * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = instruction address space identifier. Copied from %isr. * %r9 = instruction address offset. Copied from %ior. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ LEAF_ENTRY_NOPROFILE(TLABEL(dtlb_l)) TLB_STATS_PRE(dtlb) TLB_PULL_L(0, TLABEL(all)) IDTLBAF(17) IDTLBPF(25) #ifdef USE_HPT /* * cache the next page mapping in the hpt. * * mapping for a page at the end of each 128k is uncachable * in the hvt since it'd be in the tlb itself and thus there * is no reason to cache it! * as a side effect this avoids recomputing hpt entry and * retraversing the whole page table each time. */ ldo PAGE_SIZE(%r9), %r9 extru,<> %r9, 20, 5, %r0 b,n L$dtlb_done_l /* skip if no simple advance */ /* do not check the PT overlap since the above * check already guaranties that */ /* ripped from TLB_PULL_L(0) */ extru %r9, 19, 10, %r16 /* %r24 was loaded in the TLB_PULL_L */ ldwx,s %r16(%r24), %r17 /* va -> pa:prot */ sh2addl %r16, %r24, %r25 combt,=,n %r0, %r17, L$dtlb_done_l copy %r17, %r16 depi 0, 21, 1, %r17 sub,= %r16, %r17, %r0 /* do not store if unchanged */ stws %r17, 0(%r25) /* store back w/ the bits */ shd %r17, %r0, 13, %r25 dep %r8, 30, 15, %r25 /* mix0r the pid from the sid */ dep %r0, 31, 12, %r17 /* needed ? */ addi 2, %r25, %r25 extru %r17, 24, 25, %r17 sync mfctl %cr28, %r24 VTAG(%r8, %r9, %r16) ldo 16(%r24), %r24 stw %r16, 0(%r24) stw %r25, 4(%r24) stw %r17, 8(%r24) L$dtlb_done_l: #endif TLB_STATS_AFT(dtlb) rfir nop EXIT(TLABEL(dtlb_l)) #endif /* defined(HP7100LC_CPU) || defined(HP7300LC_CPU) */ #if defined(HP8000_CPU) || defined(HP8200_CPU) || \ defined(HP8500_CPU) || defined(HP8600_CPU) || \ defined(HP8700_CPU) .level 2.0w /* xlate 32bit->64bit pte */ #define TLB_PCX2PCXU \ extrw,u %r25, 14, 13, %r16 ! \ depdi 0, 31, 32, %r17 ! \ /* fix io mappings */ ! \ extrd,s %r17, 42, 4, %r1 ! \ addi,<> 1, %r1, %r0 ! \ depdi -1, 38, 32, %r17 ! \ /* fix prom mappings */ ! \ extrd,s %r17, 46, 8, %r1 ! \ addi,<> 0x10, %r1, %r0 ! \ depdi 0, 38, 4, %r17 ! \ /* weak ordering, dyn bp */ ! \ depwi 1, 31, 2, %r16 ! \ depdi 0, 44, 30, %r25 ! \ depd %r16, 14, 15, %r25 /* * This is a handler for interruption 20, "TLB dirty bit trap". It is used by * the PA8000 (PCX-U), PA8200 (PCX-W), PA8500 (PCX-W), and PA8600 (PCX-W+). * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = data address space identifier. Copied from %isr. * %r9 = data address offset. Copied from %ior. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ LEAF_ENTRY_NOPROFILE(TLABEL(tlbd_u)) TLB_STATS_PRE(tlbd) TLB_PULL_L(1, TLABEL(all)) TLB_PCX2PCXU idtlbt %r17, %r25 TLB_STATS_AFT(tlbd) rfir nop EXIT(TLABEL(tlbd_u)) /* * This is a handler for interruption 6, "Instruction TLB miss fault". It is * the PA8000 (PCX-U), PA8200 (PCX-W), PA8500 (PCX-W), and PA8600 (PCX-W+). * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = data address space identifier. Copied from %isr. * %r9 = data address offset. Copied from %ior. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ LEAF_ENTRY_NOPROFILE(TLABEL(itlb_u)) TLB_STATS_PRE(itlb) TLB_PULL_L(0, TLABEL(all)) extru,= %r25, 5, 1, %r0 /* gate needs a kernel pid */ depi 0, 30, 15, %r25 TLB_PCX2PCXU iitlbt %r17, %r25 TLB_STATS_AFT(itlb) rfir nop EXIT(TLABEL(itlb_u)) /* * This is a handler for interruption 16, "Non-access instruction TLB miss * fault", and interrupt 17, "Non-access data TLB miss fault / Non-access data * page fault". It is the PA8000 (PCX-U), PA8200 (PCX-W), PA8500 (PCX-W), * and PA8600 (PCX-W+). * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = instruction address space identifier. Copied from %isr. * %r9 = instruction address offset. Copied from %ior. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ LEAF_ENTRY_NOPROFILE(TLABEL(dtlbna_u)) ALTENTRY(TLABEL(itlbna_u)) TLB_STATS_PRE(dtlb) TLB_PULL_L(0, L$dtlbna_u_fake) TLB_PCX2PCXU idtlbt %r17, %r25 TLB_STATS_AFT(dtlb) rfir nop L$dtlbna_u_fake: /* parse prober/w insns, have to decent to trap() to set regs proper */ mfctl %iir, %r16 extru %r16, 6, 6, %r24 comib,=,n 1, %r24, TLABEL(all) extru %r16, 24, 6, %r24 subi,<> 0x23, %r24, %r0 b TLABEL(all) /* otherwise generate a flush-only tlb entry */ copy %r0, %r17 zdep %r8, 30, 15, %r25 depi -13, 11, 7, %r25 ldo 2(%r25), %r25 /* 3? */ idtlbt %r17, %r25 TLB_STATS_AFT(dtlb) rfir nop EXIT(TLABEL(dtlbna_u)) /* * This is a handler for interruption 15, "Data TLB miss fault". It is the * PA8000 (PCX-U), PA8200 (PCX-W), PA8500 (PCX-W), and PA8600 (PCX-W+). * Only shadowed registers are available, and they are: * * %r1 = C trap number * %r8 = instruction address space identifier. Copied from %isr. * %r9 = instruction address offset. Copied from %ior. * %r16 = undefined * %r17 = undefined * %r24 = undefined * %r25 = undefined */ LEAF_ENTRY_NOPROFILE(TLABEL(dtlb_u)) TLB_STATS_PRE(dtlb) TLB_PULL_L(0, TLABEL(all)) TLB_PCX2PCXU idtlbt %r17, %r25 TLB_STATS_AFT(dtlb) rfir nop EXIT(TLABEL(dtlb_u)) .level 1.1 #endif /* HP8000_CPU */ #if defined(HP7000_CPU) /* * int desidhash_s(void) * int desidhash_x(void) */ LEAF_ENTRY_NOPROFILE(desidhash_s) ALTENTRY(desidhash_x) sync MFCPU_T(DR_CPUCFG,22) /* %t1 */ MFCPU_T(DR_CPUCFG,22) nop nop depi 0, DR0_PCXS_DHE, 3, %t1 /* 3 4 DR0_PCXS_DOMAIN|DR0_PCXS_IHE */ depi 1, DR0_PCXS_EQWSTO, 1, %t1 depi 0, DR0_PCXS_DHPMC, 1, %t1 depi 0, DR0_PCXS_ILPMC, 1, %t1 sync MTCPU_T(22,DR_CPUCFG) MTCPU_T(22,DR_CPUCFG) nop nop bv 0(%rp) extru %t1, 4, 5, %ret0 /* return chip revision */ EXIT(desidhash_s) #endif /* defined(HP7000_CPU) */ #if defined(HP7100_CPU) || defined(HP7200_CPU) /* * void desidhash_t(void) */ LEAF_ENTRY_NOPROFILE(desidhash_t) sync MFCPU_T(DR_CPUCFG,22) /* %t1 */ MFCPU_T(DR_CPUCFG,22) nop nop depi 0, DR0_PCXT_IHE, 1, %t1 depi 0, DR0_PCXT_DHE, 1, %t1 depi 0, DR0_PCXT_DHPMC, 1, %t1 depi 0, DR0_PCXT_ILPMC, 1, %t1 sync MTCPU_T(22,DR_CPUCFG) MTCPU_T(22,DR_CPUCFG) nop nop bv 0(%rp) extru %t1, 4, 5, %ret0 /* return chip revision */ EXIT(desidhash_t) #endif /* defined(HP7100_CPU) || defined(HP7200_CPU) */ #if defined(HP7100LC_CPU) || defined(HP7300LC_CPU) /* * int * ibtlb_l(int i, pa_space_t sp, vaddr_t va, paddr_t pa, vsize_t sz, * u_int prot) */ LEAF_ENTRY_NOPROFILE(ibtlb_l) rsm (PSW_R|PSW_I), %t4 nop ! nop ! nop ! nop ! nop ! nop ! nop /* XXXNH why? */ bv 0(%rp) mtsm %t4 EXIT(ibtlb_l) /* * void * hpti_l(addr,size) */ LEAF_ENTRY_NOPROFILE(hpti_l) ldo -1(%arg1), %arg1 depi 0, 31, 12, %arg1 ldi 0x1c0, %t1 /* cache size assumed 128k XXX */ or %arg0, %t1, %arg0 sync MTCPU_C(26,DR0_PCXL2_HTLB_ADDR) MTCPU_C(25,DR0_PCXL2_HTLB_CFG) nop nop bv,n %r0(%rp) nop EXIT(hpti_l) /* * int * pbtlb_l(int i) */ LEAF_ENTRY_NOPROFILE(pbtlb_l) ; DR_PAGE0 rsm (PSW_R|PSW_I), %t4 nop ! nop ! nop ! nop ldil L%0xc041, %t1 ldo R%0xc041(%t1), %t1 dep %arg0, 30, 3, %t1 sync MTCPU_T(22,DR_DTLB) /* t1 */ nop nop mtsp %r0, %sr1 idtlba %r0,(%sr1,%r0) idtlbp %r0,(%sr1,%r0) zdepi -1, 18, 1, %t1 nop sync MTCPU_T(22,DR_DTLB) nop nop bv 0(%rp) mtsm %t4 EXIT(pbtlb_l) /* * int desidhash_l(void) */ LEAF_ENTRY_NOPROFILE(desidhash_l) MFCPU_C(DR_CPUCFG,22) /* t1 */ nop nop depi 0, DR0_PCXL_L2IHASH_EN, 2, %t1 /* + DR0_PCXL_L2DHASH_EN */ depi 0, DR0_PCXL_L2IHPMC, 1, %t1 /* don't reset */ depi 0, DR0_PCXL_L2DHPMC, 1, %t1 /* don't reset */ depi 0, DR0_PCXL_L1IHPMC, 1, %t1 /* don't reset */ depi 0, DR0_PCXL_L2PARERR,1, %t1 /* don't reset */ sync /* set DR0_PCXL_L1ICACHE_EN ??? */ MTCPU_C(22,DR_CPUCFG) nop nop bv 0(%rp) extru %t1, 4, 5, %ret0 /* return chip revision */ EXIT(desidhash_l) #endif /* defined(HP7100LC_CPU) || defined(HP7300LC_CPU) */ #if defined(HP8000_CPU) || defined(HP8200_CPU) || \ defined(HP8500_CPU) || defined(HP8600_CPU) || \ defined(HP8700_CPU) .level 2.0w LEAF_ENTRY_NOPROFILE(desidhash_u) MFCPU_U(2,28) depdi 0, 54, 1, %r28 MTCPU_U(28,2) bv %r0(%rp) copy %r0, %ret0 /* XXX dunno how to get chip rev */ EXIT(desidhash_u) LEAF_ENTRY_NOPROFILE(ibtlb_u) /* TODO insert a locked large tlb entry */ bv 0(%rp) nop EXIT(ibtlb_u) LEAF_ENTRY_NOPROFILE(pbtlb_u) /* TODO purge a locked tlb entry */ bv 0(%rp) nop EXIT(pbtlb_u) .level 1.1 #endif /* HP8000_CPU || HP8200_CPU || HP8500_CPU || HP8600_CPU || HP8700_CPU */ .align 64 .export TLABEL(all), entry ENTRY_NOPROFILE(TLABEL(all),0) /* * at this point we have: * - psw copied into ipsw * - psw E(default), M(1 if HPMC, else 0), all others 0, i.e. * interrupts masked, absolute accesses are enabled, etc. * - PL 0 (highest privilege) * - r1, r8, r9, r16, r17, r24, r25 shadowed (maybe) * - r1: trap number * - tr7: old r1 */ mtctl %t3, %tr2 GET_CURCPU(%t3) stw %t1, CI_TRAPSAVE + TF_R22(%t3) /* use ,bc */ stw %t2, CI_TRAPSAVE + TF_R21(%t3) mfctl %tr2, %t1 stw %sp, CI_TRAPSAVE + TF_R30(%t3) /* sp */ stw %t1, CI_TRAPSAVE + TF_R20(%t3) /* t3 */ /* * Now, save away other volatile state that prevents us from turning * the PC queue back on, namely, the pc queue and ipsw, and the * interrupt information. */ mfctl %eiem, %t1 mfctl %ipsw, %t2 stw %t1, CI_TRAPSAVE + TF_CR15(%t3) /* use ,bc */ stw %t2, CI_TRAPSAVE + TF_CR22(%t3) mfsp %sr3, %t1 mfctl %pidr1, %t2 stw %t1, CI_TRAPSAVE + TF_SR3(%t3) stw %t2, CI_TRAPSAVE + TF_CR8(%t3) /* Setup kernel context */ ldi HPPA_PID_KERNEL,%t1 mtctl %t1, %pidr1 mtsp %r0, %sr3 /* this will enable interrupts after `cold' */ GET_CURCPU(%t1) ldw CI_PSW(%t1), %t2 mtctl %r0, %eiem mtctl %t2, %ipsw /* save interruption instruction address space queue */ mfctl %pcsq, %t1 mtctl %r0, %pcsq mfctl %pcsq, %t2 stw %t1, CI_TRAPSAVE + TF_IISQH(%t3) /* use ,bc */ stw %t2, CI_TRAPSAVE + TF_IISQT(%t3) mtctl %r0, %pcsq /* * Set up the kernel stack pointer. If the trap happened while we were * in unprivileged code, or in privileged code in the SYSCALLGATE page, * move to the kernel stack in curlwp's PCB; otherwise, start a new * stack frame on whatever kernel stack we're already on. * * This used to check only for a trap while we were in unprivileged * code, but this ignored the possibility that a trap could come in * during the period between a gateway instruction to raise privilege * and the disabling of interrupts. During this period we're still on * the user's stack, and we must move to the kernel stack. */ mfctl %pcoq, %t1 ldil L%SYSCALLGATE, %t2 /* t2 = SYSCALLGATE */ ldo HPPA_FRAME_SIZE-1(%sp), %sp /* Assumed stack align step 1 */ dep %t1, 31, PGSHIFT, %t2 /* t2 |= (pcoqh & PAGE_MASK) */ dep,<> %t1, 31, 2, %r0 /* Nullify if user mode (!0) */ comb,<> %t1, %t2, L$trap_from_kernel /* if %t1 != %t2 => kernel */ dep %r0, 31, 6, %sp /* Assumed stack align step 2 */ GET_CURLWP(%t2) depi 1, T_USER_POS, 1, %r1 depi 1, TFF_LAST_POS, 1, %r1 ldw L_PCB(%t2), %sp #ifdef DIAGNOSTIC b L$trap_have_stack #endif ldo NBPG(%sp), %sp L$trap_from_kernel: #ifdef DIAGNOSTIC /* * Use the emergency stack if we have taken some kind * of TLB or protection fault on the kernel stack. */ mtctl %t1, %tr2 ldw CI_TRAPSAVE + TF_R30(%t3), %t1 mfctl %ior, %t2 dep %r0, 31, PGSHIFT, %t1 dep %r0, 31, PGSHIFT, %t2 comb,=,n %t1, %t2, 0 ldo NBPG(%t1), %t1 comb,<> %t1, %t2, L$trap_have_stack mfctl %tr2, %t1 mfctl %isr, %t2 comib,<>,n HPPA_SID_KERNEL, %t2, L$trap_have_stack #define _CHECK_TRAP_TYPE(tt) ldi tt, %t2 ! comb,= %r1, %t2, L$trap_kstack_fault _CHECK_TRAP_TYPE(T_ITLBMISS) _CHECK_TRAP_TYPE(T_DTLBMISS) _CHECK_TRAP_TYPE(T_ITLBMISSNA) _CHECK_TRAP_TYPE(T_DTLBMISSNA) _CHECK_TRAP_TYPE(T_DPROT) _CHECK_TRAP_TYPE(T_DATACC) _CHECK_TRAP_TYPE(T_DATAPID) ldi T_DATALIGN, %t2 comb,<>,n %r1, %t2, L$trap_have_stack #undef _CHECK_TRAP_TYPE L$trap_kstack_fault: ldil L%emergency_stack_start, %sp ldo R%emergency_stack_start(%sp), %sp L$trap_have_stack: #endif ldil L%trapnowvirt, %t2 ldo R%trapnowvirt(%t2), %t2 mtctl %t2, %pcoq stw %t1, CI_TRAPSAVE + TF_IIOQH(%t3) ldo 4(%t2), %t2 mfctl %pcoq, %t1 stw %t1, CI_TRAPSAVE + TF_IIOQT(%t3) mtctl %t2, %pcoq /* save the interruption space and offset registers */ mfctl %isr, %t1 mfctl %ior, %t2 stw %t1, CI_TRAPSAVE + TF_CR20(%t3) /* use ,bc */ stw %t2, CI_TRAPSAVE + TF_CR21(%t3) /* save the interruption instruction register */ mfctl %iir, %t2 stw %t2, CI_TRAPSAVE + TF_CR19(%t3) /* save the trap type and flags */ stw %r1, CI_TRAPSAVE + TF_FLAGS(%t3) /* gotta get it before R is up */ mfctl CR_RCTR, %t1 copy %sp, %t3 ldo HPPA_FRAME_SIZE+TRAPFRAME_SIZEOF(%sp), %sp #if defined(DDB) || defined(KGDB) /* * Match the offset from %sp for the trapframe with syscall_entry */ ldo HPPA_FRAME_MAXARGS+HPPA_FRAME_SIZE-1(%sp),%sp depi 0, 31, 6, %sp #endif rfir nop ! nop ! nop ! nop ! nop ! nop ! nop ! nop trapnowvirt: /* * %t3 contains the virtual address of the trapframe * %sp is loaded w/ the right VA (we did not need it being physical) */ mfctl CR_CCR, %t2 stw %t1, TF_CR0(%sr3, %t3) stw %t2, TF_CR10(%sr3, %t3) mfsp %sr0, %t1 mfsp %sr1, %t2 stw %t1, TF_SR0(%sr3, %t3) stw %t2, TF_SR1(%sr3, %t3) mfsp %sr2, %t1 mfsp %sr4, %t2 stw %t1, TF_SR2(%sr3, %t3) stw %t2, TF_SR4(%sr3, %t3) mfsp %sr5, %t2 mfsp %sr6, %t1 stw %t2, TF_SR5(%sr3, %t3) stw %t1, TF_SR6(%sr3, %t3) mfsp %sr7, %t1 mfctl %pidr2, %t2 stw %t1, TF_SR7(%sr3, %t3) stw %t2, TF_CR9(%sr3, %t3) mtsp %r0, %sr0 mtsp %r0, %sr1 mtsp %r0, %sr2 mtsp %r0, %sr4 mtsp %r0, %sr5 mtsp %r0, %sr6 mtsp %r0, %sr7 #if pbably_not_worth_it mfctl %pidr3, %t1 mfctl %pidr4, %t2 stw %t1, TF_CR12(%t3) stw %t2, TF_CR13(%t3) #endif /* * Save all general registers that we haven't saved already */ /* XXXNH check this!!! */ #if defined(DDB) || defined(KGDB) stw %rp, HPPA_FRAME_CRP(%sp) stw %r0, -HPPA_FRAME_SIZE(%sp) #endif stw %t3, -HPPA_FRAME_SIZE+4(%sp) mfctl %sar, %t1 /* use ,bc each cache line */ stw %t1, TF_CR11(%t3) stw %r1, TF_R1(%t3) stw %r2, TF_R2(%t3) stw %r3, TF_R3(%t3) /* * Copy partially saved state from the store into the frame */ GET_CURCPU(%t2) ldo CI_TRAPSAVE(%t2), %t2 /* use ,bc each line */ ldw 0(%t2), %r1 ! ldw 4(%t2), %t1 ! stw %r1, 0(%t3) ! stw %t1, 4(%t3) ldw 8(%t2), %r1 ! ldw 12(%t2), %t1 ! stw %r1, 8(%t3) ! stw %t1, 12(%t3) ldw 16(%t2), %r1 ! ldw 20(%t2), %t1 ! stw %r1, 16(%t3) ! stw %t1, 20(%t3) ldw 24(%t2), %r1 ! ldw 28(%t2), %t1 ! stw %r1, 24(%t3) ! stw %t1, 28(%t3) ldw 32(%t2), %r1 ! ldw 36(%t2), %t1 ! stw %r1, 32(%t3) ! stw %t1, 36(%t3) ldw 40(%t2), %r1 ! ldw 44(%t2), %t1 ! stw %r1, 40(%t3) ! stw %t1, 44(%t3) ldw 48(%t2), %r1 ! ldw 52(%t2), %t1 ! stw %r1, 48(%t3) ! stw %t1, 52(%t3) ldw 56(%t2), %r1 ! ldw 60(%t2), %t1 ! stw %r1, 56(%t3) ! stw %t1, 60(%t3) /* * Normally, we'd only have to save and restore the caller-save * registers, because the callee-save registers will be saved and * restored automatically by our callee(s). * * However, in two cases we need to save and restore all of the general * registers in the trapframe. One, if we're running a debugger, we * want the debugging person to be able to see and change any and all * general register values at the trap site. Two, if we have an FPU * emulator, this trap may be to emulate an instruction that needs to * read and write any and all general registers (for example, a load * or store instruction with a modify completer). * * See similar #ifdefs in the syscall entry and exit code. */ stw %r4, TF_R4(%t3) stw %r5, TF_R5(%t3) stw %r6, TF_R6(%t3) stw %r7, TF_R7(%t3) stw %r8, TF_R8(%t3) stw %r9, TF_R9(%t3) stw %r10, TF_R10(%t3) stw %r11, TF_R11(%t3) stw %r12, TF_R12(%t3) stw %r13, TF_R13(%t3) stw %r14, TF_R14(%t3) stw %r15, TF_R15(%t3) stw %r16, TF_R16(%t3) stw %r17, TF_R17(%t3) stw %r18, TF_R18(%t3) stw %t4, TF_R19(%t3) stw %r23,TF_R23(%t3) stw %r24,TF_R24(%t3) stw %r25,TF_R25(%t3) stw %r26,TF_R26(%t3) stw %r27,TF_R27(%t3) stw %r28,TF_R28(%t3) stw %r29,TF_R29(%t3) stw %r31,TF_R31(%t3) /* * Save the necessary control registers that have not already saved. */ #if defined(DDB) || defined(KGDB) /* * Save v2p translation table pointer */ mfctl %eirr, %t1 mfctl CR_VTOP, %t2 stw %t1, TF_CR23(%t3) stw %t2, TF_CR25(%t3) mfctl %cr24, %t1 mfctl %cr28, %t2 stw %t1, TF_CR24(%t3) stw %t2, TF_CR28(%t3) #endif mfctl CR_TLS, %t1 mfctl CR_FPPADDR, %t2 stw %t1, TF_CR27(%t3) stw %t2, TF_CR30(%t3) /* * load the global pointer for the kernel */ ldil L%$global$, %dp ldo R%$global$(%dp), %dp /* * call the C routine trap(). * form trap type in the first argument to trap() */ ldw TF_FLAGS(%t3), %arg0 dep %r0, 24, 25, %arg0 copy %t3, %arg1 #if defined(DDB) || defined(KGDB) /* Mark frame pointer as NULL to indicate syscall/trap */ copy %r0, %r3 #endif .import trap, code CALL(trap, %t1) ldw -HPPA_FRAME_SIZE+4(%sp), %t3 /* see if curlwp has changed */ ldw TF_FLAGS(%t3), %arg0 bb,>=,n %arg0, TFF_LAST_POS, L$trap_return nop /* load curlwp's trapframe pointer */ GET_CURLWP(%t2) ldw L_MD(%t2), %t3 L$trap_return: ldil L%syscall_return, %t1 ldo R%syscall_return(%t1), %t1 bv,n %r0(%t1) nop EXIT(TLABEL(all)) .align 32 ENTRY_NOPROFILE(TLABEL(ibrk),0) /* If called by a user process then always pass it to trap() */ mfctl %pcoq, %r8 extru,= %r8, 31, 2, %r0 b,n L$ibrk_bad /* don't accept breaks from data segments */ .import etext ldil L%etext, %r9 ldo R%etext(%r9), %r9 comb,>>=,n %r8, %r9, L$ibrk_bad mfctl %iir, %r8 extru %r8, 31, 5, %r9 comib,<>,n HPPA_BREAK_KERNEL, %r9, L$ibrk_bad /* now process all those `break' calls we make */ extru %r8, 18, 13, %r9 comib,=,n HPPA_BREAK_GET_PSW, %r9, L$ibrk_getpsw comib,=,n HPPA_BREAK_SET_PSW, %r9, L$ibrk_setpsw L$ibrk_bad: /* illegal (unimplemented) break entry point */ b TLABEL(all) nop L$ibrk_getpsw: b L$ibrk_exit mfctl %ipsw, %ret0 L$ibrk_setpsw: mfctl %ipsw, %ret0 b L$ibrk_exit mtctl %arg0, %ipsw /* insert other fast breaks here */ nop ! nop L$ibrk_exit: /* skip the break */ mtctl %r0, %pcoq mfctl %pcoq, %r9 mtctl %r9, %pcoq ldo 4(%r9), %r9 mtctl %r9, %pcoq rfir nop EXIT(TLABEL(ibrk))