root/sys/arch/vax/vax/intvec.S
/*      $NetBSD: intvec.S,v 1.23 2022/09/02 23:48:10 thorpej Exp $   */

/*
 * Copyright (c) 1994, 1997 Ludd, University of Lule}, Sweden.
 * 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 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.
 */


#include "assym.h"
#include <sys/cdefs.h>

#include "opt_ddb.h"
#include "opt_cputype.h"
#include "opt_emulate.h"
#include "opt_multiprocessor.h"
#include "opt_lockdebug.h"
#include "leds.h"

#define SCBENTRY(name) \
        .text                   ; \
        .align 2                ; \
        .globl __CONCAT(X,name) ; \
__CONCAT(X,name):

#define TRAPCALL(namn, typ) \
SCBENTRY(namn)                  ; \
        pushl $0                ; \
        pushl $typ              ; \
        jbr Xtrap

#define TRAPARGC(namn, typ) \
SCBENTRY(namn)                  ; \
        pushl $typ              ; \
        jbr Xtrap

#define FASTINTR(namn, rutin) \
SCBENTRY(namn)                  ; \
        pushr $0x3f             ; \
        calls $0,_C_LABEL(rutin)        ; \
        popr $0x3f              ; \
        rei

#define PUSHR   pushr   $0x3f
#define POPR    popr    $0x3f

#define KSTACK 0
#define ISTACK 1
#define NOVEC   .long 0
#define INTVEC(label,stack)     \
        .long   __CONCAT(X,label)+stack;

        .text

        .globl  _C_LABEL(kernbase), _C_LABEL(rpb), _C_LABEL(kernel_text)
        .set    _C_LABEL(kernel_text),KERNBASE
_C_LABEL(kernbase):
_C_LABEL(rpb):  
/*
 * First page in memory we have rpb; so that we know where
 * (must be on a 64k page boundary, easiest here). We use it
 * to store SCB vectors generated when compiling the kernel,
 * and move the SCB later to somewhere else.
 */

        NOVEC;                          # Unused, 0
        INTVEC(mcheck, ISTACK)          # Machine Check., 4
        INTVEC(invkstk, ISTACK)         # Kernel Stack Invalid., 8
        NOVEC;                          # Power Failed., C
        INTVEC(privinflt, KSTACK)       # Privileged/Reserved Instruction.
        INTVEC(xfcflt, KSTACK)          # Customer Reserved Instruction, 14
        INTVEC(resopflt, KSTACK)        # Reserved Operand/Boot Vector(?), 18
        INTVEC(resadflt, KSTACK)        # Reserved Address Mode., 1C
        INTVEC(access_v, KSTACK)        # Access Control Violation, 20
        INTVEC(transl_v, KSTACK)        # Translation Invalid, 24
        INTVEC(tracep, KSTACK)          # Trace Pending, 28
        INTVEC(breakp, KSTACK)          # Breakpoint Instruction, 2C
        NOVEC;                          # Compatibility Exception, 30
        INTVEC(arithflt, KSTACK)        # Arithmetic Fault, 34
        NOVEC;                          # Unused, 38
        NOVEC;                          # Unused, 3C
        INTVEC(syscall, KSTACK)         # main syscall trap, chmk, 40
        INTVEC(chmx, KSTACK)            # chme, 44
        INTVEC(chmx, KSTACK)            # chms, 48
        INTVEC(chmx, KSTACK)            # chmu, 4C
        NOVEC;                          # System Backplane Exception/BIerror, 50
        INTVEC(cmrerr, ISTACK)          # Corrected Memory Read, 54
        NOVEC;                          # System Backplane Alert/RXCD, 58
        INTVEC(sbiflt, ISTACK)          # System Backplane Fault, 5C
        NOVEC;                          # Memory Write Timeout, 60
        NOVEC;                          # Unused, 64
        NOVEC;                          # Unused, 68
        NOVEC;                          # Unused, 6C
        NOVEC;                          # Unused, 70
        NOVEC;                          # Unused, 74
        NOVEC;                          # Unused, 78
        NOVEC;                          # Unused, 7C
        NOVEC;                          # Unused, 80
        NOVEC;                          # Unused, 84
        INTVEC(astintr, KSTACK)         # Asynchronous Sustem Trap, AST (IPL 02)
        NOVEC;                          # Unused, 8C
        NOVEC;                          # Unused, 90
        NOVEC;                          # Unused, 94
        NOVEC;                          # Unused, 98
        NOVEC;                          # Unused, 9C
        INTVEC(softclock, KSTACK);      # Software clock interrupt, A0 (IPL 08)
        NOVEC;                          # Unused, A4 (IPL 09)
        NOVEC;                          # Unused, A8 (IPL 10)
        INTVEC(softbio, KSTACK);        # Software bio interrupt, AC (IPL 11)
        INTVEC(softnet, KSTACK);        # Software net interrupt, B0 (IPL 12)
        INTVEC(softserial, KSTACK);     # Software serial interrupt, B4 (IPL 13)
        NOVEC;                          # Unused, B8 (IPL 14)
        INTVEC(ddbtrap, ISTACK)         # Kernel debugger trap, BC (IPL 15)
        INTVEC(hardclock,ISTACK)        # Interval Timer
        NOVEC;                          # Unused, C4
        INTVEC(emulate, KSTACK)         # Subset instruction emulation, C8
        NOVEC;                          # Unused, CC
        NOVEC;                          # Unused, D0
        NOVEC;                          # Unused, D4
        NOVEC;                          # Unused, D8
        NOVEC;                          # Unused, DC
        NOVEC;                          # Unused, E0
        NOVEC;                          # Unused, E4
        NOVEC;                          # Unused, E8
        NOVEC;                          # Unused, EC
        NOVEC;          
        NOVEC;          
        NOVEC;          
        NOVEC;          

        /* space for adapter vectors */
        .space 0x100

                .align 2
#
# mcheck is the badaddress trap, also called when referencing
# a invalid address (busserror)
# _memtest (memtest in C) holds the address to continue execution
# at when returning from a intentional test.
#
SCBENTRY(mcheck)
        tstl    _C_LABEL(cold)          # Ar we still in coldstart?
        bneq    L4              # Yes.

        pushr   $0x7f
        pushab  24(%sp)
        movl    _C_LABEL(dep_call),%r6  # CPU dependent mchk handling
        calls   $1,*MCHK(%r6)
        tstl    %r0             # If not machine check, try memory error
        beql    1f
        calls   $0,*MEMERR(%r6)
        pushab  2f
        calls   $1,_C_LABEL(panic)
2:      .asciz  "mchk"
1:      popr    $0x7f
        addl2   (%sp)+,%sp

        rei

L4:     addl2   (%sp)+,%sp      # remove info pushed on stack
        pushr   $0x3f           # save regs for clobbering
        movl    _C_LABEL(dep_call),%r0  # get CPU-specific mchk handler
        tstl    BADADDR(%r0)    # any handler available?
        bneq    4f              # yep, call it
        popr    $0x3f           # nope, restore regs
        brb     0f              # continue
4:      calls   $0,*BADADDR(%r0)        # call machine-specific handler
        popr    $0x3f           # restore regs
        brb     2f

0:      cmpl    _C_LABEL(vax_cputype),$1 # Is it a 11/780?
        bneq    1f              # No...

        mtpr    $0, $PR_SBIFS   # Clear SBI fault register
        brb     2f

1:      cmpl    _C_LABEL(vax_cputype),$4 # Is it a 8600?
        bneq    3f

        mtpr    $0, $PR_EHSR    # Clear Error status register
        brb     2f

3:      mtpr    $0xF,$PR_MCESR  # clear the bus error bit
2:      movl    _C_LABEL(memtest),(%sp) # REI to new address
        rei

        TRAPCALL(invkstk, T_KSPNOTVAL)

SCBENTRY(privinflt)     # Privileged/unimplemented instruction
#ifndef NO_INSN_EMULATE
        jsb     _C_LABEL(unimemu)       # do not return if insn emulated
#endif
        pushl   $0
        pushl   $T_PRIVINFLT
        jbr     Xtrap

        TRAPCALL(xfcflt, T_XFCFLT);
        TRAPCALL(resopflt, T_RESOPFLT)
        TRAPCALL(resadflt, T_RESADFLT)

/*
 * default handler for CHME and CHMS
 */
SCBENTRY(chmx)
        clrl    (%sp)                   # CHM code already on stack
        pushl   $T_RESOPFLT
        jbr     Xtrap

/*
 * Translation fault, used only when simulating page reference bit.
 * Therefore it is done a fast revalidation of the page if it is
 * referenced. Trouble here is the hardware bug on KA650 CPUs that
 * put in a need for an extra check when the fault is gotten during
 * PTE reference. Handled in pmap.c.
 */
SCBENTRY(transl_v)              # 20: Translation violation
        pushr   $0x3f
        pushl   28(%sp)
        pushl   28(%sp)
        calls   $2,_C_LABEL(pmap_simulref)
        tstl    %r0
        bneq    1f
        popr    $0x3f
        addl2   $8,%sp
        rei
1:      popr    $0x3f
        brw     Xaccess_v

SCBENTRY(access_v)                      # 24: Access cntrl viol fault
        blbs    (%sp), ptelen
        pushl   $T_ACCFLT
        bbc     $1,4(%sp),1f
        bisl2   $T_PTEFETCH,(%sp)
1:      bbc     $2,4(%sp),2f
        bisl2   $T_WRITE,(%sp)
2:      movl    (%sp), 4(%sp)
        addl2   $4, %sp
        jbr     Xtrap

ptelen: movl    $T_PTELEN, (%sp)                # PTE must expand (or send segv)
        jbr     Xtrap;

TRAPCALL(tracep, T_TRCTRAP)
TRAPCALL(breakp, T_BPTFLT)

TRAPARGC(arithflt, T_ARITHFLT)

SCBENTRY(syscall)                       # Main system call
#if 1
        cmpl    (%sp), $SYS__lwp_getprivate
        bneq    1f
        mfpr    $PR_SSP, %r0            # get curlwp
        movl    L_PRIVATE(%r0), %r0     # get l_private
        addl2   $4, %sp                 # eat the code
        rei
1:
#endif
        pushl   $T_SYSCALL
        pushr   $0xfff
        mfpr    $PR_USP, -(%sp)
        mfpr    $PR_SSP, %r0            /* SSP contains curlwp */
        movl    L_PROC(%r0), %r0
        pushl   %ap
        pushl   %fp
        pushl   %sp             # pointer to syscall frame; defined in trap.h
        calls   $1, *P_MD_SYSCALL(%r0)
        movl    (%sp)+, %fp
        movl    (%sp)+, %ap
        mtpr    (%sp)+, $PR_USP
        popr    $0xfff
        addl2   $8, %sp
        mtpr    $IPL_HIGH, $PR_IPL      # Be sure we can REI
        rei


SCBENTRY(cmrerr)
        PUSHR
        movl    _C_LABEL(dep_call),%r0
        calls   $0,*MEMERR(%r0)
        POPR
        rei

SCBENTRY(sbiflt);
        pushab  sbifltmsg
        calls   $1, _C_LABEL(panic)

TRAPCALL(astintr, T_ASTFLT)

TRAPCALL(ddbtrap, T_KDBTRAP)

SCBENTRY(hardclock)
#ifdef DDB
        tstl    0x80000100              # rpb wait element
        beql    1f                      # set, jmp to debugger
        pushl   $0
        pushl   $T_KDBTRAP
        jbr     Xtrap
#endif
1:      pushr   $0x3f
        mfpr    $PR_ICCS,%r0
        tstl    %r0
        bgeq    2f
        incl    _C_LABEL(clock_misscnt)+EV_COUNT
        adwc    $0,_C_LABEL(clock_misscnt)+EV_COUNT+4
2:      mtpr    $0x800000c1,$PR_ICCS            # Reset interrupt flag
        incl    _C_LABEL(clock_intrcnt)+EV_COUNT        # count the number of clock interrupts
        adwc    $0,_C_LABEL(clock_intrcnt)+EV_COUNT+4

        mfpr    $PR_SSP, %r0            /* SSP contains curlwp */
        movl    L_CPU(%r0), %r0         /* get current CPU */
        incl    CI_NINTR(%r0)
        adwc    $0,(CI_NINTR+4)(%r0)
        
#if VAX46 || VAXANY
        cmpl    _C_LABEL(vax_boardtype),$VAX_BTYP_46
        bneq    1f
        movl    _C_LABEL(ka46_cpu),%r0
        clrl    VC_DIAGTIMM(%r0)
#endif
1:      pushl   %sp
        addl2   $24,(%sp)
        calls   $1,_C_LABEL(hardclock)
#if NLEDS
        calls   $0,_C_LABEL(leds_intr)
#endif
        popr    $0x3f
        rei

/*
 * Main routine for traps; all go through this.
 * Note that we put USP on the frame here, which sometimes should
 * be KSP to be correct, but because we only alters it when we are 
 * called from user space it doesn't care.
 * _sret is used in cpu_set_kpc to jump out to user space first time.
 */
        .globl  _C_LABEL(sret)
Xtrap:  pushr   $0xfff
        mfpr    $PR_USP, -(%sp)
        pushl   %ap
        pushl   %fp
        pushl   %sp
        calls   $1, _C_LABEL(trap)
_C_LABEL(sret):
        movl    (%sp)+, %fp
        movl    (%sp)+, %ap
        mtpr    (%sp)+, $PR_USP
        popr    $0xfff
        addl2   $8, %sp
        mtpr    $IPL_HIGH, $PR_IPL      # Be sure we can REI
        rei

sbifltmsg:
        .asciz  "SBI fault"

#ifndef NO_INSN_EMULATE
/*
 * Table of emulated Microvax instructions supported by emulate.s.
 * Use noemulate to convert unimplemented ones to reserved instruction faults.
 */
        .globl  _C_LABEL(emtable)
_C_LABEL(emtable):
/* f8 */ .long _C_LABEL(EMashp);        .long _C_LABEL(EMcvtlp)
/* fa */ .long noemulate;               .long noemulate
/* fc */ .long noemulate;               .long noemulate
/* fe */ .long noemulate;               .long noemulate
/* 00 */ .long noemulate;               .long noemulate
/* 02 */ .long noemulate;               .long noemulate
/* 04 */ .long noemulate;               .long noemulate
/* 05 */ .long noemulate;               .long noemulate
/* 08 */ .long _C_LABEL(EMcvtps);       .long _C_LABEL(EMcvtsp)
/* 0a */ .long noemulate;               .long _C_LABEL(EMcrc)
/* 0c */ .long noemulate;               .long noemulate
/* 0e */ .long noemulate;               .long noemulate
/* 10 */ .long noemulate;               .long noemulate
/* 12 */ .long noemulate;               .long noemulate
/* 14 */ .long noemulate;               .long noemulate
/* 16 */ .long noemulate;               .long noemulate
/* 18 */ .long noemulate;               .long noemulate
/* 1a */ .long noemulate;               .long noemulate
/* 1c */ .long noemulate;               .long noemulate
/* 1e */ .long noemulate;               .long noemulate
/* 20 */ .long _C_LABEL(EMaddp4);       .long _C_LABEL(EMaddp6)
/* 22 */ .long _C_LABEL(EMsubp4);       .long _C_LABEL(EMsubp6)
/* 24 */ .long _C_LABEL(EMcvtpt);       .long _C_LABEL(EMmulp)
/* 26 */ .long _C_LABEL(EMcvttp);       .long _C_LABEL(EMdivp)
/* 28 */ .long noemulate;               .long _C_LABEL(EMcmpc3)
/* 2a */ .long _C_LABEL(EMscanc);       .long _C_LABEL(EMspanc)
/* 2c */ .long noemulate;               .long _C_LABEL(EMcmpc5)
/* 2e */ .long _C_LABEL(EMmovtc);       .long _C_LABEL(EMmovtuc)
/* 30 */ .long noemulate;               .long noemulate
/* 32 */ .long noemulate;               .long noemulate
/* 34 */ .long _C_LABEL(EMmovp);        .long _C_LABEL(EMcmpp3)
/* 36 */ .long _C_LABEL(EMcvtpl);       .long _C_LABEL(EMcmpp4)
/* 38 */ .long _C_LABEL(EMeditpc);      .long _C_LABEL(EMmatchc)
/* 3a */ .long _C_LABEL(EMlocc);        .long _C_LABEL(EMskpc)
#endif
/*
 * The following is called with the stack set up as follows:
 *
 *        (%sp): Opcode
 *       4(%sp): Instruction PC
 *       8(%sp): Operand 1
 *      12(%sp): Operand 2
 *      16(%sp): Operand 3
 *      20(%sp): Operand 4
 *      24(%sp): Operand 5
 *      28(%sp): Operand 6
 *      32(%sp): Operand 7 (unused)
 *      36(%sp): Operand 8 (unused)
 *      40(%sp): Return PC
 *      44(%sp): Return PSL
 *      48(%sp): TOS before instruction
 *
 * Each individual routine is called with the stack set up as follows:
 *
 *        (%sp): Return address of trap handler
 *       4(%sp): Opcode (will get return PSL)
 *       8(%sp): Instruction PC
 *      12(%sp): Operand 1
 *      16(%sp): Operand 2
 *      20(%sp): Operand 3
 *      24(%sp): Operand 4
 *      28(%sp): Operand 5
 *      32(%sp): Operand 6
 *      36(%sp): saved register 11
 *      40(%sp): saved register 10
 *      44(%sp): Return PC
 *      48(%sp): Return PSL
 *      52(%sp): TOS before instruction
 *      See the VAX Architecture Reference Manual, Section B-5 for more
 *      information.
 */

SCBENTRY(emulate)
#ifndef NO_INSN_EMULATE
        movl    %r11,32(%sp)            # save register %r11 in unused operand
        movl    %r10,36(%sp)            # save register %r10 in unused operand
        cvtbl   (%sp),%r10              # get opcode
        addl2   $8,%r10                 # shift negative opcodes
        subl3   %r10,$0x43,%r11         # forget it if opcode is out of range
        bcs     noemulate
        movl    _C_LABEL(emtable)[%r10],%r10
                                # call appropriate emulation routine
        jsb     (%r10)          # routines put return values into regs 0-5
        movl    32(%sp),%r11            # restore register %r11
        movl    36(%sp),%r10            # restore register %r10
        insv    (%sp),$0,$4,44(%sp)     # and condition codes in Opcode spot
        addl2   $40,%sp                 # adjust stack for return
        rei
noemulate:
        addl2   $48,%sp                 # adjust stack for
#endif
        .word   0xffff                  # "reserved instruction fault"