Files
Arquivotheca.SunOS-4.1.4/sys/sun4/locore.s
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

2603 lines
71 KiB
ArmAsm

.ident "@(#)locore.s 1.1 94/10/31 SMI(PATCH)"
/*
* Copyright (c) 1989 by Sun Microsystems, Inc.
*/
#include <sys/param.h>
#include <sys/vmparam.h>
#include <sys/errno.h>
#include <netinet/in_systm.h>
#include <sun4/asm_linkage.h>
#include <sun4/buserr.h>
#include <sun4/clock.h>
#include <sun4/cpu.h>
#include <sun4/diag.h>
#include <sun4/enable.h>
#include <sun4/intreg.h>
#include <sun4/memerr.h>
#include <sun4/eccreg.h>
#include <sun4/eeprom.h>
#include <sun4/iocache.h>
#include <sun4/mmu.h>
#include <sun4/pcb.h>
#include <sun4/psl.h>
#include <sun4/pte.h>
#include <sun4/reg.h>
#include <sun4/trap.h>
#include <sun4/scb.h>
#include "assym.s"
.seg "data"
PROT = (PG_V | PG_W) >> PG_S_BIT
P_INVAL = (PG_V) >> PG_S_BIT
VALID = (PG_V) >> PG_S_BIT
!
! MINFRAME and the register offsets in struct regs must add up to allow
! double word loading of struct regs. PCB_WBUF must also be aligned.
!
#if (MINFRAME & 7) == 0 || (G2 & 1) == 0 || (O0 & 1) == 0
ERROR - struct regs not aligned
#endif
#if (PCB_WBUF & 7)
ERROR - pcb_wbuf not aligned
#endif
/*
* Absolute external symbols.
* On the sun4 we put the message buffer and the pte's
* for proc 0 on the same page, since we have such a large page size.
* We set things up so that the first page of KERNELBASE is illegal
* to act as a redzone during copyin/copyout type operations. One of
* the reasons the message buffer is allocated in low memory to
* prevent being overwritten during booting operations (besides
* the fact that it is small enough to share a page with others).
*/
.global _DVMA, _msgbuf
_DVMA = DVMABASE ! address of DVMA area
_msgbuf = KERNELBASE + NBPG ! address of printf message buffer
#if MSGBUFSIZE > NBPG
ERROR - msgbuf too large
#endif
#if USIZE-KERNSTACK >= 4096
ERROR - user area too large
#endif
/*
* Define some variables used by post-mortem debuggers
* to help them work on kernels with changing structures.
*/
.global UPAGES_DEBUG, KERNELBASE_DEBUG, VADDR_MASK_DEBUG
.global PGSHIFT_DEBUG, SLOAD_DEBUG
UPAGES_DEBUG = UPAGES
KERNELBASE_DEBUG = KERNELBASE
VADDR_MASK_DEBUG = 0xffffffff
PGSHIFT_DEBUG = PGSHIFT
SLOAD_DEBUG = SLOAD
/*
* The interrupt stack. This must be the first thing in the data
* segment (other than an sccs string) so that we don't stomp
* on anything important during interrupt handling. We get a
* red zone below this stack for free when the kernel text is
* write protected. The interrupt entry code assumes that the
* interrupt stack is at a lower address than
* both eintstack and the kernel stack in the u area.
*/
#define INTSTACKSIZE 0x3000
.align 8
.global intstack, eintstack, intu, eexitstack
intstack: ! bottom of interrupt stack
.skip INTSTACKSIZE
eintstack: ! end (top) of interrupt stack
exitstack: ! bottom of exit stack
.skip INTSTACKSIZE
eexitstack: ! end (top) of exit stack
.global _ubasic ! the primordial uarea
_ubasic:
.skip KERNSTACK
_p0uarea:
.skip USIZE
intu: ! a fake uarea for the kernel
.skip USIZE ! when a process is exiting
.global _uunix
_uunix:
.word _p0uarea
/*
* System software page tables
*/
#define vaddr_h(x) ((((x)-_Heapptes)/4)*NBPG + HEAPBASE)
#define HEAPMAP(mname, vname, npte) \
.global mname; \
mname: .skip (4*npte); \
.global vname; \
vname = vaddr_h(mname);
HEAPMAP(_Heapptes ,_Heapbase ,HEAPPAGES )
HEAPMAP(_Eheapptes ,_Heaplimit ,0 )
HEAPMAP(_Bufptes ,_Bufbase ,BUFPAGES )
HEAPMAP(_Ebufptes ,_Buflimit ,0 )
#define vaddr(x) ((((x)-_Sysmap)/4)*NBPG + SYSBASE)
#define SYSMAP(mname, vname, npte) \
.global mname; \
mname: .skip (4*npte); \
.global vname; \
vname = vaddr(mname);
SYSMAP(_Sysmap ,_Sysbase ,SYSPTSIZE )
SYSMAP(_CMAP1 ,_CADDR1 ,1 ) ! local tmp
SYSMAP(_CMAP2 ,_CADDR2 ,1 ) ! local tmp
SYSMAP(_mmap ,_vmmap ,1 )
SYSMAP(_Mbmap ,_mbutl ,MBPOOLMMUPAGES )
SYSMAP(_ESysmap ,_Syslimit ,0 ) ! must be last
.global _Syssize
_Syssize = (_ESysmap-_Heapptes)/4
#ifdef SAS
.global _availmem
_availmem:
.word 0
#endif SAS
/*
* Software copy of system enable register
* This is always atomically updated
*/
.global _enablereg
_enablereg: .byte 0 ! UNIX's system enable register
/*
* Opcodes for instructions in PATCH macros
*/
#define MOVPSRL0 0xa1480000
#define MOVL4 0xa8102000
#define BA 0x10800000
#define NO_OP 0x01000000
/*
* Trap vector macros.
*
* A single kernel that supports machines with differing
* numbers of windows has to write the last byte of every
* trap vector with NW-1, the number of windows minus 1.
* It does this at boot time after it has read the implementation
* type from the psr.
*
* NOTE: All trap vectors are generated by the following macros.
* The macros must maintain that a write to the last byte to every
* trap vector with the number of windows minus one is safe.
*/
#define TRAP(H) \
b (H); mov %psr,%l0; nop; nop;
/* the following trap uses only the trap window, you must be prepared */
#define WIN_TRAP(H) \
mov %psr,%l0; mov %wim,%l3; b (H); mov 7,%l6;
#define SYS_TRAP(T) \
mov %psr,%l0; mov (T),%l4; b sys_trap; mov 7,%l6;
#define BAD_TRAP SYS_TRAP((. - _scb) >> 4);
#define PATCH_ST(T, V) \
set _scb, %g1; \
set MOVPSRL0, %g2; \
st %g2, [%g1 + ((V)*16+0*4)]; \
set sys_trap, %g2; \
sub %g2, %g1, %g2; \
sub %g2, ((V)*16 + 8), %g2; \
srl %g2, 2, %g2; \
set BA, %g3; \
or %g2, %g3, %g2; \
st %g2, [%g1 + ((V)*16+2*4)]; \
set MOVL4 + (T), %g2; \
st %g2, [%g1 + ((V)*16+1*4)];
#define PATCH_T(H, V) \
set _scb, %g1; \
set (H), %g2; \
sub %g2, %g1, %g2; \
sub %g2, (V)*16, %g2; \
srl %g2, 2, %g2; \
set BA, %g3; \
or %g2, %g3, %g2; \
st %g2, [%g1 + ((V)*16+0*4)]; \
set MOVPSRL0, %g2; \
st %g2, [%g1 + ((V)*16+1*4)];
/*
* Trap vector table.
* This must be the first text in the boot image.
*
* When a trap is taken, we vector to KERNELBASE+(TT*16) and we have
* the following state:
* 2) traps are disabled
* 3) the previous state of PSR_S is in PSR_PS
* 4) the CWP has been incremented into the trap window
* 5) the previous pc and npc is in %l1 and %l2 respectively.
*
* Registers:
* %l0 - %psr immediately after trap
* %l1 - trapped pc
* %l2 - trapped npc
* %l3 - wim (sys_trap only)
* %l4 - system trap number (sys_trap only)
* %l6 - number of windows - 1
* %l7 - stack pointer (interrupts and system calls)
*
* Note: UNIX receives control at vector 0 (trap)
*/
.seg "text"
.align 4
.global _start, _scb
_start:
_scb:
TRAP(entry); ! 00
SYS_TRAP(T_FAULT | T_TEXT_FAULT); ! 01
WIN_TRAP(multiply_check); ! 02
SYS_TRAP(T_PRIV_INSTR); ! 03
SYS_TRAP(T_FP_DISABLED); ! 04
WIN_TRAP(window_overflow); ! 05
WIN_TRAP(window_underflow); ! 06
SYS_TRAP(T_ALIGNMENT); ! 07
SYS_TRAP(T_FP_EXCEPTION); ! 08
SYS_TRAP(T_FAULT | T_DATA_FAULT); ! 09
BAD_TRAP; ! 0A tag_overflow
BAD_TRAP; BAD_TRAP; ! 0B - 0C
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 0D - 10
SYS_TRAP(T_INTERRUPT | 1); ! 11
SYS_TRAP(T_INTERRUPT | 2); ! 12
SYS_TRAP(T_INTERRUPT | 3); ! 13
SYS_TRAP(T_INTERRUPT | 4); ! 14
SYS_TRAP(T_INTERRUPT | 5); ! 15
SYS_TRAP(T_INTERRUPT | 6); ! 16
SYS_TRAP(T_INTERRUPT | 7); ! 17
SYS_TRAP(T_INTERRUPT | 8); ! 18
SYS_TRAP(T_INTERRUPT | 9); ! 19
SYS_TRAP(T_INTERRUPT | 10); ! 1A
SYS_TRAP(T_INTERRUPT | 11); ! 1B
SYS_TRAP(T_INTERRUPT | 12); ! 1C
SYS_TRAP(T_INTERRUPT | 13); ! 1D
#ifdef GPROF
TRAP(test_prof); ! 1E
#else
SYS_TRAP(T_INTERRUPT | 14); ! 1E
#endif GPROF
SYS_TRAP(T_INTERRUPT | 15); ! 1F
#ifdef SUNDBE
#define HRES_TRAP TRAP(hrestimetrap)
#else SUNDBE
#define HRES_TRAP BAD_TRAP
#endif SUNDBE
/*
* The rest of the traps in the table up to 0x80 should 'never'
* be generated by hardware.
*/
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 20 - 23
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 24 - 27
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 28 - 2B
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 2C - 2F
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 30 - 33
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 34 - 37
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 38 - 33
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 3C - 3F
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 40 - 43
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 44 - 47
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 48 - 4B
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 4C - 4F
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 50 - 53
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 54 - 57
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 58 - 5B
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 5C - 5F
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 60 - 63
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 64 - 67
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 68 - 6B
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 6C - 6F
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 70 - 73
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 74 - 77
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 78 - 7B
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 7C - 7F
/*
* User generated traps
*/
SYS_TRAP(T_SYSCALL); ! 80 - system call
SYS_TRAP(T_BREAKPOINT); ! 81 - user breakpoint
SYS_TRAP(T_DIV0); ! 82 - divide by zero
SYS_TRAP(T_FLUSH_WINDOWS); ! 83 - flush windows
TRAP(clean_windows); ! 84 - clean windows
BAD_TRAP; ! 85 - range check
TRAP(fix_alignment); ! 86 - do unaligned references
SYS_TRAP(T_INT_OVERFLOW); ! 87 - integer overflow
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 88 - 8B
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 8C - 8F
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 90 - 93
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 94 - 97
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 98 - 9B
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 9C - 9F
TRAP(getcc); ! A0 - get condition codes
TRAP(setcc); ! A1 - set condition codes
BAD_TRAP; ! A2
HRES_TRAP; ! A3 - high res timer
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! A4 - A7
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! A8 - AB
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! AC - AF
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! B0 - B3
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! B4 - B7
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! B8 - BB
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! BC - BF
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! C0 - C3
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! C4 - C7
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! C8 - CB
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! CC - CF
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! D0 - D3
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! D4 - D7
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! D8 - DB
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! DC - DF
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! E0 - E3
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! E4 - E7
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! E8 - EB
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! EC - EF
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! F0 - F3
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! F4 - F7
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! F8 - FB
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! FC - FF
/*
* skip to next page, in case the trap table needs special mappings.
*
* CURRRENT SPECIAL MAPPINGS FOR THE SCB:
* SUNRAY IU v.1 requires SCB to be user readable
* SUN4_330 requires the SCB to be uncached
*/
#if defined(SUN4_330)
.skip 4096
#endif
!
! here we have a cache-aligned string of non_writeable
! zeros used mainly by bcopy hardware
!
.global _zeros
_zeros:
.word 0,0,0,0,0,0,0,0
/*
* The number of windows, set once on entry. Note that it is
* in the text segment so that it is write protected in startup().
*/
.global _nwindows
_nwindows:
.word 8
/*
* System initialization
*
* Do a halfhearted job of setting up the mmu so that we can run out
* of the high address space. We do this by copying the pmeg numbers
* for the physical locations to the correct virtual locations.
* NOTE - Assumes that the real and virtual locations have the same
* segment offsets from 0 and KERNELBASE!!!
*
* We make the following assumptions about our environment
* as set up by the monitor:
*
* - traps are disabled
* - we are loaded at 0x4000
* - we have enough memory mapped for the entire kernel + some more
* - all pages are writable
* - the last pmeg [SEGINV] has no valid pme's
* - the next to the last pmeg has no valid pme's
* - when the monitor's romp->v_memorybitmap points to a zero
* - each low segment i is mapped to use pmeg i
* - each page map entry i maps physical page i
* - on systems w/ ecc memory, that the monitor has set the base
* addresses and enabled all the memory cards correctly
*
* We will set the protection properly in startup().
* Before we set up the new mapping and start running with the correct
* addresses, all of the code must be carefully written to be position
* independent code, since we are linked for running out of high addresses,
* but we get control running in low addresses.
*/
entry:
set PSR_S|PSR_PIL, %g1 ! setup psr, disable traps
mov %g1, %psr
set CONTEXT_REG, %g1 ! setup kernel context (0)
stba %g0, [%g1]ASI_CTL
mov 0x02, %wim ! setup wim
!
! read machine type from idprom
!
set ID_PROM, %g1
inc %g1 ! machine type is second byte of idprom
lduba [%g1]ASI_CTL, %g5 ! g5 = id.id_machine, cpu type
cmp %g5, CPU_SUN4_470 ! relocate sunray by copying regions
set KERNELBASE, %l1 ! correct virtual address
set (KERNELBASE + MAINMEM_SIZE), %l2 ! ending virtual address
bne 3f ! relocate others by copying segments
clr %l0 ! current virtual address
!
! relocate the sunray kernel by copying region map entries
! this loop will not work if KERNELBASE is an address
! that is mod SMGRPSIZE (16M)
!
set SMGRPSIZE, %l3
1:
or %l0, 2, %l0
lduha [%l0]ASI_RM, %g1
or %l1, 2, %l1
stha %g1, [%l1]ASI_RM
add %l1, %l3, %l1
cmp %l1, %l2
ble,a 1b
add %l0, %l3, %l0 ! delay slot
b 2f
.empty ! hush assembler warnings
!
! Loop through the kernel segment maps starting at zero, copying the
! pmeg numbers to the correct virtual addresses, which start at
! KERNELBASE.
! NOTE: This loop won't work if the kernel size is greater than
! KERNELBASE.
!
3: set PMGRPSIZE, %l3
1: lduha [%l0]ASI_SM, %g1
stha %g1, [%l1]ASI_SM
add %l1, %l3, %l1
cmp %l1, %l2
ble,a 1b
add %l0, %l3, %l0 ! delay slot
!
! The correct virtual addresses are now mapped. Do an absolute jump
! to set the pc to the correct virtual addresses.
!
2: set 1f, %g1
jmp %g1
nop
1:
!
! Now we are running with correct addresses
! and can use non-position independent code.
!
!
! Patch vector 0 trap to "zero" in case it happens again.
!
PATCH_ST(T_ZERO, 0)
!
! Find the the number of implemented register windows.
! The last byte of every trap vector must be equal to
! the number of windows in the implementation minus one.
! The trap vector macros (above) depend on it!
!
mov %g0, %wim ! note psr has cwp = 0
set _scb, %g2
mov 256, %g3 ! number of trap vectors
sethi %hi(_nwindows), %g4 ! initialize pointer to _nwindows
save ! decrement cwp, wraparound to NW-1
mov %psr, %g1
and %g1, PSR_CWP, %g1 ! we now have nwindows-1
restore ! get back to orignal window
mov 2, %wim ! reset initial wim
0:
stb %g1, [%g2 + 15] ! write last byte of trap vectors
subcc %g3, 1, %g3 ! with nwindows-1
bnz 0b
add %g2, 16, %g2
inc %g1 ! inialize the nwindows variable
st %g1, [%g4 + %lo(_nwindows)]
#if defined(SUN4_470) || defined(SUN4_330)
!
! The code that flushes windows may have an extra save/restore
! as current sparc implementations have 7 and 8 windows.
! On those implementations with 7 windows write nops over the
! unneeded save/restore.
!
cmp %g1, 8
be 1f
.empty ! hush assembler warnings
set _fixnwindows, %o3
set NO_OP, %o2
st %o2, [%o3]
st %o2, [%o3 + 4]
1:
#endif defined(SUN4_470) || defined(SUN4_330)
#ifdef SAS
!
! If we are in the simulator we now size memory by counting the
! valid segment maps.
!
clr %l0
set PMGRPSIZE, %g2
2:
lduha [%l0]ASI_SM, %g1
cmp %g1, 255 ! 64 Meg - handles 260 and 70
blu,a 2b
add %l0, %g2, %l0
sethi %hi(_availmem), %g1
st %l0, [%g1 + %lo(_availmem)]
cmp %g5, CPU_SUN4_470 ! is this a sunray machine?
bne 1f
.empty ! next instruction ok in delay slot
!
! For sunray-type 3 level mmu we use the smeg
! after SYSPTSIZE for any virtual address
! mappings that must be in the upper 16 M of vm.
! The last smeg is reserved as the invalid smeg.
!
sethi %hi(0xffffc000), %l0 ! initialize last region for
! eeprom, clock, ...
set ((SYSPTSIZE*NBPG)+SMGRPSIZE-1)/SMGRPSIZE, %g2
andn %l0, 1, %l0 ! tweak address and data to get
or %l0, 2, %l0 ! the bits in just the right
sll %g2, 8, %g2 ! place (per Sunray spec)
stha %g2, [%l0]ASI_RM ! map second to last smeg
#endif SAS
!
! use a segment to map on board devices
!
1: sethi %hi(0xffffc000), %l0 ! initialize last region for
! eeprom, clock, ...
set ((SYSPTSIZE*NBPG)+PMGRPSIZE-1)/PMGRPSIZE, %g1
stha %g1, [%l0]ASI_SM ! write segment map
!
! Clear u area.
!
set _ubasic, %l0
set KERNSTACK+USIZE, %g1
2: subcc %g1, 4, %g1
bnz 2b
clr [%l0 + %g1]
!
! get software copy of enable register
!
set ENABLEREG, %g1 ! address of real version in hardware
lduba [%g1]ASI_CTL, %g1
sethi %hi(_enablereg), %g2 ! software copy of enable register
stb %g1, [%g2 + %lo(_enablereg)] ! update software copy
!
! Setup trap base and make a kernel stack.
!
mov %tbr, %l4 ! save monitor's tbr
bclr 0xfff, %l4 ! remove tt
set _scb, %g1 ! setup trap handler
mov %g1, %tbr
!
! set the initial kernel stack pointer for proc 0
!
set _ubasic, %l0
set KERNSTACK - SA(MINFRAME + REGSIZE), %sp
add %l0, %sp, %sp
mov 0, %fp
!
! Dummy up fake user registers on the stack.
!
set USRSTACK-WINDOWSIZE, %g1
st %g1, [%sp + MINFRAME + SP*4] ! user stack pointer
set PSL_USER, %l0
st %l0, [%sp + MINFRAME + PSR*4] ! psr
set USRTEXT, %g1
st %g1, [%sp + MINFRAME + PC*4] ! pc
add %g1, 4, %g1
st %g1, [%sp + MINFRAME + nPC*4] ! npc
mov %psr, %g1
wr %g1, PSR_ET, %psr ! enable traps
!
! Zero bss.
!
set _edata, %o0
set _end, %o1
call _bzero
sub %o1, %o0, %o1
#ifndef SAS
!
! Save monitor's level14 clock interrupt vector code.
!
or %l4, TT(T_INT_LEVEL_14), %o0
set _mon_clock14_vec, %o1
call _bcopy ! bcopy(mon tbr level 14 vec,
mov 16, %o2 ! _mon_clock14_vec, 16)
#endif SAS
!
! Call main. We will return as process 1 (init).
!
call _main
add %sp, MINFRAME, %o0
!
! Proceed as if this was a normal user trap.
!
b,a sys_rtt ! fake return from trap
/*
* Generic system trap handler.
*/
.global sys_trap
sys_trap:
!
! Prepare to go to C (batten down the hatches).
!
mov 0x01, %l5 ! CWM = 0x01 << CWP
sll %l5, %l0, %l5
mov %wim, %l3 ! get WIM
btst PSR_PS, %l0 ! test pS
bz st_user ! branch if user trap
btst %l5, %l3 ! delay slot, compare WIM and CWM
!
! Trap from supervisor.
! We can be either on the system stack or interrupt stack.
!
sub %fp, MINFRAME+REGSIZE, %l7 ! save sys globals on stack
SAVE_GLOBALS(%l7 + MINFRAME)
#ifdef TRAPWINDOW
!
! store the window at the time of the trap into a static area.
!
set _trap_window, %g1
mov %wim, %g2
st %g2, [%g1+96]
mov %psr, %g2
restore
st %o0, [%g1]; st %o1, [%g1+4]; st %o2, [%g1+8]; st %o3, [%g1+12]
st %o4, [%g1+16]; st %o5, [%g1+20]; st %o6, [%g1+24]; st %o7, [%g1+28]
st %l0, [%g1+32]; st %l1, [%g1+36]; st %l2, [%g1+40]; st %l3, [%g1+44]
st %l4, [%g1+48]; st %l5, [%g1+52]; st %l6, [%g1+56]; st %l7, [%g1+60]
st %i0, [%g1+64]; st %i1, [%g1+68]; st %i2, [%g1+72]; st %i3, [%g1+76]
st %i4, [%g1+80]; st %i5, [%g1+84]; st %i6, [%g1+88]; st %i7, [%g1+92]
mov %g2, %psr
nop; nop; nop;
btst %l5, %l3 ! retest
#endif TRAPWINDOW
st %fp, [%l7 + MINFRAME + SP*4] ! stack pointer
st %l0, [%l7 + MINFRAME + PSR*4] ! psr
st %l1, [%l7 + MINFRAME + PC*4] ! pc
!
! If we are in last trap window, all windows are occupied and
! we must do window overflow stuff in order to do further calls
!
bz st_have_window ! if ((CWM&WIM)==0) no overflow
st %l2, [%l7 + MINFRAME + nPC*4] ! npc
b,a st_sys_ovf
st_user:
!
! Trap from user. Save user globals and prepare system stack.
! Test whether the current window is the last available window
! in the register file (CWM == WIM).
!
set _masterprocp, %l7
ld [%l7], %l7
ld [%l7 + P_STACK], %l7 ! initial kernel sp for this process
SAVE_GLOBALS(%l7 + MINFRAME)
SAVE_OUTS(%l7 + MINFRAME)
st %l0, [%l7 + MINFRAME + PSR*4] ! psr
st %l1, [%l7 + MINFRAME + PC*4] ! pc
st %l2, [%l7 + MINFRAME + nPC*4] ! npc
set _uunix, %g5
ld [%g5], %g5
!
! If we are in last trap window, all windows are occupied and
! we must do window overflow stuff in order to do further calls
!
bz 1f ! if ((CWM&WIM)==0) no overflow
clr [%g5 + PCB_WBCNT] ! delay slot, save buffer ptr = 0
not %l5, %g2 ! UWM = ~CWM
mov -2, %g3 ! gen window mask from NW-1 in %l6
sll %g3, %l6, %g3
andn %g2, %g3, %g2
b st_user_ovf ! overflow
srl %l3, 1, %g1 ! delay slot,WIM = %g1 = ror(WIM, 1, NW)
!
! Compute the user window mask (u.u_pcb.pcb_uwm), which is a mask of
! window which contain user data. It is all the windows "between"
! CWM and WIM.
!
1:
subcc %l3, %l5, %g1 ! if (WIM >= CWM)
bneg,a 2f ! u.u_pcb.pcb_uwm = (WIM-CWM)&~CWM
sub %g1, 1, %g1 ! else
2: ! u.u_pcb.pcb_uwm = (WIM-CWM-1)&~CWM
bclr %l5, %g1
mov -2, %g3 ! gen window mask from NW-1 in %l6
sll %g3, %l6, %g3
andn %g1, %g3, %g1
set _uunix, %g5 ! XXX - global u register?
ld [%g5], %g5
st %g1, [%g5 + PCB_UWM]
st_have_window:
!
! The next window is open.
!
mov %l7, %sp ! setup previously computed stack
!
! Part of fix for 1041977 (fitoX fix can panic kernel):
! Before we enable traps, see if this is a machine that needs
! the fitoX fix. If so, then see if we came from user mode with
! FPU enabled. If so, save (compute) rp in fpneedsyncfpu.
! Then, after we process the trap, we see if fpneedsyncfpu is set.
! If so, we call syncfpu with it, and clear fpneedsyncfpu when
! it returns. There is a race in that we could call syncfpu
! twice, but that would be harmless.
!
sethi %hi(_fpneedfitoX), %g1 ! do we need FitoX fix?
ld [%g1 + %lo(_fpneedfitoX)],%g1
tst %g1
bz 1f ! branch if needfitoX == 0
.empty
set PSR_PS|PSR_EF, %o1
and %l0, %o1, %o2
set PSR_EF, %o1
cmp %o2, %o1
bne 1f ! branch if PS=1 or EF=0
add %l7, MINFRAME, %o0
sethi %hi(fpneedsyncfpu), %g1
st %o0, [%g1 + %lo(fpneedsyncfpu)]
1:
! End of part of fix for 1041977
!
! Process trap according to type
!
btst T_INTERRUPT, %l4 ! interrupt
bnz interrupt
cmp %l4, T_SYSCALL ! syscall
be syscall
btst T_FAULT, %l4 ! fault
bnz,a fault
bclr T_FAULT, %l4
cmp %l4, T_FP_EXCEPTION ! floating point exception
be _fp_exception
cmp %l4, T_FP_DISABLED ! fpu is disabled
be _fp_disabled
cmp %l4, T_FLUSH_WINDOWS ! flush user windows to stack
bne 1f
wr %l0, PSR_ET, %psr ! enable traps
nop ! psr delay
!
! Flush windows trap.
!
call _flush_user_windows ! flush user windows
nop
!
! Don't redo trap instruction.
!
ld [%sp + MINFRAME + nPC*4], %g1
st %g1, [%sp + MINFRAME + PC*4] ! pc = npc
add %g1, 4, %g1
b sys_rtt
st %g1, [%sp + MINFRAME + nPC*4] ! npc = npc + 4
nop ! psr delay
1:
!
! All other traps. Call C trap handler.
!
mov %l4, %o0 ! trap(t, rp)
call _trap ! C trap handler
add %sp, MINFRAME, %o1
b,a sys_rtt ! return from trap
/* end systrap */
/*
* Sys_trap overflow handling.
* Psuedo subroutine returns to st_have_window.
*/
st_sys_ovf:
!
! Overflow from system.
! Determine whether the next window is a user window.
! If u.u_pcb.pcb_uwm has any bits set, then it is a user window
! which must be saved.
!
#ifdef PERFMETER
sethi %hi(_overflowcnt), %g5
ld [%g5 + %lo(_overflowcnt)], %g2
inc %g2
st %g2, [%g5 + %lo(_overflowcnt)]
#endif PERFMETER
set _uunix, %g5 ! XXX - global u register?
ld [%g5], %g5
ld [%g5 + PCB_UWM], %g2 ! if (u.u_pcb.pcb_uwm)
tst %g2 ! user window
bnz st_user_ovf
srl %l3, 1, %g1 ! delay slot,WIM = %g1 = ror(WIM, 1, NW)
!
! Save supervisor window. Compute the new WIM and change current window
! to the window to be saved.
!
sll %l3, %l6, %l3 ! %l6 == NW-1
or %l3, %g1, %g1
save ! get into window to be saved
mov %g1, %wim ! install new WIM
!
! Save window on the stack.
!
st_stack_res:
SAVE_WINDOW(%sp)
b st_have_window ! finished overflow processing
restore ! delay slot, back to original window
st_user_ovf:
!
! Overflow. Window to be saved is a user window.
! Compute the new WIM and change the current window to the
! window to be saved.
!
sll %l3, %l6, %l3 ! %l6 == NW-1
or %l3, %g1, %g1
bclr %g1, %g2 ! turn off uwm bit for window
set _uunix, %g5 ! XXX - global u register?
ld [%g5], %g5
st %g2, [%g5 + PCB_UWM] ! we are about to save
save ! get into window to be saved
mov %g1, %wim ! install new WIM
!
! We must check whether the user stack is resident where the window
! will be saved, which is pointed to by the window's sp.
! We must also check that the sp is aligned to a word boundary.
! Normally, we would check the alignment, and then probe the top
! and bottom of the save area on the stack. However we optimize
! this by checking that both ends of the save area are within a
! 4k unit (the biggest mask we can generate in one cycle), and
! the alignment in one shot. This allows us to do one probe to
! the page map. NOTE: this assumes a page size of at least 4k.
!
and %sp, 0xfff, %g1
#ifdef VA_HOLE
! check if the sp points into the hole in the address space
sethi %hi(_hole_shift), %g2 ! hole shift address
ld [%g2 + %lo(_hole_shift)], %g3
add %g1, (14*4), %g1 ! interlock, top of save area
sra %sp, %g3, %g2
inc %g2
andncc %g2, 1, %g2
bz 1f
andncc %g1, 0xff8, %g0
b,a st_stack_not_res ! sp points into the hole
1:
#else
add %g1, (14*4), %g1
andncc %g1, 0xff8, %g0
#endif
bz,a st_sp_bot
lda [%sp]ASI_PM, %g1 ! check for stack page resident
!
! Stack is either misaligned or crosses a 4k boundary.
!
btst 0x7, %sp ! test sp alignment
bz st_sp_top
add %sp, (14*4), %g1 ! delay slot, check top of save area
b,a st_stack_not_res ! stack misaligned, catch it later
st_sp_top:
#ifdef VA_HOLE
! check if the sp points into the hole in the address space
sra %g1, %g3, %g2
inc %g2
andncc %g2, 1, %g2
bz,a 1f
lda [%g1]ASI_PM, %g1 ! get pme for this address
b,a st_stack_not_res ! stack page can never be resident
1:
srl %g1, PG_S_BIT, %g1 ! get vws bits
sra %sp, %g3, %g2
inc %g2
andncc %g2, 1, %g2
bz 1f
cmp %g1, PROT ! look for valid, writeable, user
b,a st_stack_not_res ! stack not resident, catch it later
1:
#else
lda [%g1]ASI_PM, %g1 ! get pme for this address
srl %g1, PG_S_BIT, %g1 ! get vws bits
cmp %g1, PROT ! look for valid, writeable, user
#endif
be,a st_sp_bot
lda [%sp]ASI_PM, %g1 ! delay slot, check bottom of save area
b,a st_stack_not_res ! stack not resident, catch it later
st_sp_bot:
srl %g1, PG_S_BIT, %g1 ! get vws bits
cmp %g1, PROT ! look for valid, writeable, user
be st_stack_res
nop ! extra nop in rare case
st_stack_not_res:
!
! User stack is not resident, save in u area for processing in sys_rtt.
!
sethi %hi(_uunix), %g5 ! XXX - global u register?
ld [%g5 + %lo(_uunix)], %g5
ld [%g5 + PCB_WBCNT], %g1
sll %g1, 2, %g1 ! convert to spbuf offset
add %g1, %g5, %g2
st %sp, [%g2 + PCB_SPBUF] ! save sp
sll %g1, 4, %g1 ! convert wbcnt to pcb_wbuf offset
sethi %hi(_uunix), %g5 ! XXX - global u register?
ld [%g5 + %lo(_uunix)], %g5
add %g1, %g5, %g2
set PCB_WBUF, %g4
add %g4, %g2, %g2
SAVE_WINDOW(%g2)
srl %g1, 6, %g1 ! increment u.u_pcb.pcb_wbcnt
add %g1, 1, %g1
sethi %hi(_uunix), %g5 ! XXX - global u register?
ld [%g5 + %lo(_uunix)], %g5
st %g1, [%g5 + PCB_WBCNT]
b st_have_window ! finished overflow processing
restore ! delay slot, back to original window
/* end sys_trap overflow */
.seg "data"
.align 4
.global _overflowcnt, _underflowcnt
_overflowcnt:
.word 0
_underflowcnt:
.word 0
.global _qrunflag, _queueflag, _queuerun
.global fzero, f0save, fsrsave
fzero: .word 0 ! used in the fitoX fix below
f0save: .word 0
fsrsave: .word 0
! part of fix for 1041977 (fitoX fix can panic kernel)
.global _fpneedfitoX, fpneedsyncfpu
_fpneedfitoX: .word 0
fpneedsyncfpu: .word 0
.seg "text"
.align 4
/*
* Return from sys_trap routine.
*/
.global sys_rtt
sys_rtt:
#if defined(SUN4_260) || defined(SUN4_110)
! The above #if is misleading, since all binaries will have this code!
!
! code to fix fitoX bug
! part of fix for 1041977 (fitoX fix can panic kernel)
! Now that we have processed the trap, we see if fpneedsyncfpu is set.
! If so, we call syncfpu with it, and clear fpneedsyncfpu when
! it returns. There is a race in that we could call syncfpu
! twice, but that would be harmless.
! Note that we could have switched to another process, but that
! is okay, as then syncfpu() would have been called from trap()
! or syscall() prior to the switch, and this one will not cause
! an exception, so the fact that fpneedsyncfpu contains the
! "wrong" value is okay.
!
sethi %hi(_fpneedfitoX), %o0 ! do we need FitoX fix?
ld [%o0 + %lo(_fpneedfitoX)],%o0
sethi %hi(fpneedsyncfpu), %g1
tst %o0
bz 1f ! no, skip FitoX fix
ld [%g1 + %lo(fpneedsyncfpu)], %o0
tst %o0
bz 2f
nop
call _syncfpu
nop
sethi %hi(fpneedsyncfpu), %g1
st %g0, [%g1 + %lo(fpneedsyncfpu)]
2:
! End of part of fix for 1041977
!
mov %psr, %o1
set PSR_EF, %o2 ! is the FPU enabled
btst %o2, %o1
bz 1f ! FPU not enabled, skip FitoX fix
or %o1, PSR_PIL, %o1 ! splhi, while writing global f0save
mov %o1, %psr
nop;nop ! psr delay
sethi %hi(fsrsave), %o0 ! save %fsr
st %fsr, [%o0 + %lo(fsrsave)]
sethi %hi(f0save), %o1 ! use %f0, save it before changing
st %f0, [%o1 + %lo(f0save)]! save %f0
sethi %hi(fzero), %o2 ! ld value for 0.0
ld [%o2 + %lo(fzero)], %f0
.global _klo_fadds
_klo_fadds:
fadds %f0, %f0, %f0 ! clear fitoX state machine
fmovs %f0, %f0 ! if exception generated, ignore
ld [%o1 + %lo(f0save)], %f0! restore %f0
sethi %hi(fsrsave), %o0
ld [%o0 + %lo(fsrsave)], %fsr ! restore %fsr
1:
#endif /* SUN4_260 || SUN4_110 */
!
! Return from trap.
!
ld [%sp + MINFRAME + PSR*4], %l0 ! get saved psr
btst PSR_PS, %l0 ! test pS for return to supervisor
bnz sr_sup
mov %psr, %g1
#ifdef LWP
.global ___Nrunnable, _lwpschedule
#endif
sr_user:
!
! Return to user. Turn off traps using the current CWP (because
! we are returning to user). Test for streams actions.
! Test for LWP, AST for resched. or prof, or streams.
!
sethi %hi(_uunix), %g5 ! XXX - global u register?
ld [%g5 + %lo(_uunix)], %g5
and %g1, PSR_CWP, %g1 ! insert current CWP in old psr
andn %l0, PSR_CWP, %l0
or %l0, %g1, %l0
mov %l0, %psr ! install old psr, disable traps
nop; nop; ! psr delay
#ifdef LWP
sethi %hi(___Nrunnable), %g2
ld [%g2 + %lo(___Nrunnable)], %g2
tst %g2
bz 1f
nop
!
! Runnable thread for async I/O
!
wr %l0, PSR_ET, %psr ! turn on traps
nop ! psr delay
call _flush_user_windows
nop
call _lwpschedule
nop
!
! Use kernel context (for now) since lwpschedule may
! change the context reg. This causes a fault.
!
set CONTEXT_REG, %g2
b sys_rtt ! try again
stba %g0, [%g2]ASI_CTL
1:
#endif LWP
sethi %hi(_qrunflag), %g1
ldub [%g1 + %lo(_qrunflag)], %g1
sethi %hi(_queueflag), %l5 ! interlock slot
tst %g1 ! need to run stream queues?
bz,a 3f ! no
ld [%g5 + PCB_FLAGS], %g1 ! delay slot, test for ast.
ldub [%l5 + %lo(_queueflag)], %g1
tst %g1 ! already running queues?
bnz,a 3f ! yes
ld [%g5 + PCB_FLAGS], %g1 ! delay slot, test for ast.
!
! Run the streams queues.
!
andn %l0, PSR_PIL, %g2 ! splhi
or %g2, 10 << PSR_PIL_BIT, %g2
mov %g2, %psr ! change priority (IU bug)
wr %g2, PSR_ET, %psr ! turn on traps
add %g1, 1, %g1 ! mark that we're running the queues
call _queuerun
stb %g1, [%l5 + %lo(_queueflag)]
clrb [%l5 + %lo(_queueflag)] ! done running queues
b,a sys_rtt
3:
srl %g1, AST_SCHED_BIT, %g1
btst 1, %g1
bz,a 1f
ld [%g5 + PCB_WBCNT], %g3 ! delay slot, user regs been saved?
!
! Let trap handle the AST.
!
wr %l0, PSR_ET, %psr ! turn on traps
mov T_AST, %o0
call _trap ! trap(T_AST, rp)
add %sp, MINFRAME, %o1
b,a sys_rtt
!
! Return from trap, for yield_child
!
.global _fork_rtt
_fork_rtt:
sethi %hi(_masterprocp), %l6
ld [%l6 + %lo(_masterprocp)], %o0
ld [%o0 + P_STACK], %l7
mov %sp, %o2
call _sys_rttchk ! sys_rttchk(procp)
mov %l7, %o1
ld [%sp + MINFRAME + PSR*4], %l0 ! get saved psr
btst PSR_PS, %l0 ! test pS for return to supervisor
bnz sr_sup
mov %psr, %g1
sethi %hi(_uunix), %g5
ld [%g5 + %lo(_uunix)], %g5
and %g1, PSR_CWP, %g1 ! insert current CWP in old psr
andn %l0, PSR_CWP, %l0
or %l0, %g1, %l0
mov %l0, %psr ! install old psr, disable traps
nop ! psr delay
b 3b
ld [%g5 + PCB_FLAGS], %g1 ! delay slot, test for ast.
1:
!
! If user regs have been saved to the window buffer we must clean it.
!
tst %g3
bz,a 2f
ld [%g5 + PCB_UWM], %l4 ! delay slot, user windows in reg file?
!
! User regs have been saved into the u area.
! Let trap handle putting them on the stack.
!
mov %l0, %psr ! in case of changed priority (IU bug)
wr %l0, PSR_ET, %psr ! turn on traps
mov T_WIN_OVERFLOW, %o0
call _trap ! trap(T_WIN_OVERFLOW, rp)
add %sp, MINFRAME, %o1
b,a sys_rtt
2:
!
! We must insure that the rett will not take a window underflow trap.
!
RESTORE_OUTS(%sp + MINFRAME) ! restore user outs
tst %l4
bnz sr_user_regs
ld [%sp + MINFRAME + PC*4], %l1 ! restore user pc
!
! The user has no windows in the register file.
! Try to get one from his stack.
!
#ifdef PERFMETER
sethi %hi(_underflowcnt), %l6
ld [%l6 + %lo(_underflowcnt)], %l3
inc %l3
st %l3, [%l6 + %lo(_underflowcnt)]
#endif PERFMETER
set _scb, %l6 ! get NW-1 for rol calculation
ldub [%l6+(5*16)+15], %l6 ! last byte of overflow trap vector
mov %wim, %l3 ! get wim
sll %l3, 1, %l4 ! next WIM = rol(WIM, 1, NW)
srl %l3, %l6, %l5 ! %l6 == NW-1
or %l5, %l4, %l5
mov %l5, %wim ! install it
!
! Normally, we would check the alignment, and then probe the top
! and bottom of the save area on the stack. However we optimize
! this by checking that both ends of the save area are within a
! 4k unit (the biggest mask we can generate in one cycle), and
! the alignment in one shot. This allows us to do one probe to
! the page map. NOTE: this assumes a page size of at least 4k.
!
and %fp, 0xfff, %g1
#ifdef VA_HOLE
! check if the fp points into the hole in the address space
sethi %hi(_hole_shift), %g2 ! hole shift address
ld [%g2 + %lo(_hole_shift)], %g3
add %g1, (14*4), %g1 ! interlock, bottom of save area
sra %fp, %g3, %g2
inc %g2
andncc %g2, 1, %g2
bz 1f
andncc %g1, 0xff8, %g0
b,a sr_stack_not_res ! stack page can never be resident
1:
#else
add %g1, (14*4), %g1
andncc %g1, 0xff8, %g0
#endif
bz,a sr_sp_bot
lda [%fp]ASI_PM, %g2 ! check for stack page resident
!
! Stack is either misaligned or crosses a 4k boundary.
!
btst 0x7, %fp ! test fp alignment
bz sr_sp_top
add %fp, (14*4), %g1 ! delay slot, check top of save area
!
! A user underflow with a misaligned sp.
! Fake a memory alignment trap.
!
mov %l3, %wim ! restore old wim
sr_align_trap:
mov %l0, %psr ! in case of changed priority (IU bug)
wr %l0, PSR_ET, %psr ! turn on traps
mov T_ALIGNMENT, %o0
call _trap ! trap(T_ALIGNMENT, rp)
add %sp, MINFRAME, %o1
b,a sys_rtt
sr_sp_top:
#ifdef VA_HOLE
sra %g1, %g3, %g2
inc %g2
andncc %g2, 1, %g2
bz,a 1f
lda [%g1]ASI_PM, %g2 ! get pme for this address
b,a sr_stack_not_res ! stack page can never be resident
1:
srl %g2, PG_S_BIT, %g2 ! get vws bits
sra %fp, %g3, %g3
inc %g3
andncc %g3, 1, %g3
bz 1f
andcc %g2, VALID, %g0 ! look for valid bit
b sr_stack_not_res ! stack page can never be resident
mov %fp, %g1
1:
#else
lda [%g1]ASI_PM, %g2 ! get pme for this address
srl %g2, PG_S_BIT, %g2 ! get vws bits
andcc %g2, VALID, %g0 ! look for valid bit
#endif
bnz,a sr_sp_bot
lda [%fp]ASI_PM, %g2 ! delay slot, check bottom of save area
b,a sr_stack_not_res ! stack page not resident
sr_sp_bot:
srl %g2, PG_S_BIT, %g2 ! get vws bits
andcc %g2, VALID, %g0 ! look for valid bit
bnz,a sr_stack_res
restore ! get into window to be restored
mov %fp, %g1 ! save fault address
sr_stack_not_res:
!
! Restore area on user stack is not resident.
! We punt and fake a page fault so that trap can bring the page in.
!
mov %l3, %wim ! restore old wim
mov %l0, %psr ! in case of changed priority (IU bug)
wr %l0, PSR_ET, %psr ! enable traps
mov T_DATA_FAULT, %o0
add %sp, MINFRAME, %o1
mov %g1, %o2
mov BE_INVALID, %o3 ! was stack protected or invalid?
btst P_INVAL, %g2
bnz,a 1f
mov BE_PROTERR, %o3
1:
call _trap ! trap(T_DATA_FAULT,
mov S_READ, %o4 ! rp, addr, be, S_READ)
b,a sys_rtt
sr_stack_res:
!
! Resident user window. Restore window from stack
!
RESTORE_WINDOW(%sp)
save ! get back to original window
sr_user_regs:
!
! User has at least one window in the register file.
!
sethi %hi(_uunix), %g5 ! XXX - global u register?
ld [%g5 + %lo(_uunix)], %g5
ld [%g5 + PCB_FLAGS], %l3
ld [%sp + MINFRAME + nPC*4], %l2 ! user npc
!
! check user pc alignment. This can get messed up either using
! ptrace, or by using the '-T' flag of ld to place the text
! section at a strange location (bug id #1015631)
!
andcc %l1, 0x3, %g0 ! pc must be word aligned
bz 1f
andcc %l2, 0x3, %g0 ! npc also
b,a sr_align_trap
1:
bz,a 2f
btst CLEAN_WINDOWS, %l3
b,a sr_align_trap
2:
bz,a 3f
mov %l0, %psr ! install old PSR_CC
!
! Maintain clean windows.
!
mov %wim, %g2 ! put wim in global
mov 0, %wim ! zero wim to allow saving
mov %l0, %g3 ! put original psr in global
b 2f ! test next window for invalid
save
!
! Loop through windows past the trap window
! clearing them until we hit the invlaid window.
!
1:
clr %l1 ! clear the window
clr %l2
clr %l3
clr %l4
clr %l5
clr %l6
clr %l7
clr %o0
clr %o1
clr %o2
clr %o3
clr %o4
clr %o5
clr %o6
clr %o7
save
2:
mov %psr, %g1 ! get CWP
srl %g2, %g1, %g1 ! test WIM bit
btst 1, %g1
bz,a 1b ! not invalid window yet
clr %l0 ! clear the window
!
! Clean up trap window.
!
mov %g3, %psr ! back to trap window, restore PSR_CC
mov %g2, %wim ! restore wim
nop; nop; ! psr delay
RESTORE_GLOBALS(%sp + MINFRAME) ! restore user globals
mov %l1, %o6 ! put pc, npc in unobtrusive place
mov %l2, %o7
clr %l0 ! clear the rest of the window
clr %l1
clr %l2
clr %l3
clr %l4
clr %l5
clr %l6
clr %l7
clr %o0
clr %o1
clr %o2
clr %o3
clr %o4
clr %o5
jmp %o6 ! return
rett %o7
3:
RESTORE_GLOBALS(%sp + MINFRAME) ! restore user globals
jmp %l1 ! return
rett %l2
.empty
sr_sup:
!
! Returning to supervisor.
! We will restore the trap psr. This has the effect of disabling
! traps and changing the CWP back to the original trap CWP. This
! completely restores the PSR so that if we get a trap between a
! rdpsr and a wrpsr its OK. We only do this for supervisor return
! since users can't manipulate the psr.
!
sethi %hi(_nwindows), %g5
ld [%g5 + %lo(_nwindows)], %g5 ! number of windows on this machine
ld [%sp + MINFRAME + SP*4], %fp ! get sys sp
xor %g1, %l0, %g1 ! test for CWP change
btst PSR_CWP, %g1
bz,a sr_samecwp
mov %l0, %psr ! install old psr, disable traps
!
! The CWP will be changed. We must save sp and the ins
! and recompute WIM. We know we need to restore the next
! window in this case.
!
mov %l0, %g3 ! save old psr
mov %sp, %g4 ! save sp, ins for new window
std %i0, [%sp +(8*4)] ! normal stack save area
std %i2, [%sp +(10*4)]
std %i4, [%sp +(12*4)]
std %i6, [%sp +(14*4)]
mov %g3, %psr ! old psr, disable traps, CWP, PSR_CC
mov 0x4, %g1 ! psr delay, compute mask for CWP + 2
sll %g1, %g3, %g1 ! psr delay, won't work for NW == 32
srl %g1, %g5, %g2 ! psr delay
or %g1, %g2, %g1
mov %g1, %wim ! install new wim
mov %g4, %sp ! reestablish sp
ldd [%sp + (8*4)], %i0 ! reestablish ins
ldd [%sp + (10*4)], %i2
ldd [%sp + (12*4)], %i4
ldd [%sp + (14*4)], %i6
restore ! restore return window
RESTORE_WINDOW(%sp)
b sr_out
save
sr_samecwp:
!
! There is no CWP change.
! We must make sure that there is a window to return to.
!
mov 0x2, %g1 ! compute mask for CWP + 1
sll %g1, %l0, %g1 ! XXX won't work for NW == 32
srl %g1, %g5, %g2 ! %g5 == NW, from above
or %g1, %g2, %g1
mov %wim, %g2 ! cmp with wim to check for underflow
btst %g1, %g2
bz sr_out
mov %l0, %psr ! install old PSR_CC
!
! No window to return to. Restore it.
!
sll %g2, 1, %g1 ! compute new WIM = rol(WIM, 1, NW)
dec %g5 ! %g5 == NW-1
srl %g2, %g5, %g2
or %g1, %g2, %g1
mov %g1, %wim ! install it
nop; nop; nop; ! wim delay
restore ! get into window to be restored
RESTORE_WINDOW(%sp)
save ! get back to original window
sr_out:
RESTORE_GLOBALS(%sp + MINFRAME) ! restore system globals
ld [%sp + MINFRAME + PC*4], %l1 ! delay slot, restore sys pc
ld [%sp + MINFRAME + nPC*4], %l2 ! sys npc
jmp %l1 ! return to trapped instruction
rett %l2
.empty
/* end sys_rtt*/
#ifdef SUNDBE
!
! syscall_debug in trap.c is a C language equivalent of the sparc code below
!
#ifdef SUNDBE_DEBUG
syscall:
wr %l0, PSR_ET, %psr ! enable traps (no priority change)
nop ! psr delay
call _syscall_debug ! syscall_debug(rp)
add %sp, MINFRAME, %o0 ! ptr to reg struct
b,a sys_rtt
#else /* SYSCALLOPTIM_DEBUG */
syscall:
wr %l0, PSR_ET, %psr ! enable traps (no priority change)
nop ! psr delay
! if (u.u_prof.pr_scale) {
! sec = u.u_ru.ru_stime.tv_sec; %l2
! usec = u.u_ru.ru_stime.tv_usec; %l3
! syst_flag = 1; %l4
! pid = u.u_procp->p_pid; %l5
! } else
! syst_flag = 0;
!
sethi %hi(_uunix), %l0
ld [%l0 + %lo(_uunix)], %l0
ld [%l0 + U_PROF_SCALE], %o0
tst %o0
bz,a sc_preamble
mov 0, %l4
ld [%l0 + U_RU_STIME_SEC], %l2
ld [%l0 + U_RU_STIME_USEC], %l3
ld [%l0 + U_PROCP], %o0
set 1, %l4
ldsh [%o0 + P_PID], %l5
sc_preamble:
!
! f = syscall_preamble(rp);
! if (f == NULL)
! goto sc_postamble;
!
call _syscall_preamble
add %sp, MINFRAME, %o0
tst %o0
bz sc_postamble
mov %o0, %l1
!
! if (setjmp(&u.u_qsave)) {
! if (u.u_error == 0 && u.u_eosys == NORMALRETURN)
! u.u_error = EINTR;
! } else {
! (*funcp)(u.u_ap);
! }
!
call _setjmp
add %l0, U_QSAVE, %o0
tst %o0
bz sc_dispatch
ldsb [%l0 + U_ERROR], %o0
tst %o0
bne sc_postamble
ldsb [%l0 + U_EOSYS], %o0
cmp %o0, NORMALRETURN
bne sc_postamble
set EINTR, %o0 ! XXX
b sc_postamble
stb %o0, [%l0 + U_ERROR]
sc_dispatch:
call %l1
ld [%l0 + U_AP], %o0
sc_postamble:
!
! syscall_postamble(rp);
!
call _syscall_postamble
add %sp, MINFRAME, %o0
!
! if (runrun) {
! (void) spl6();
! setrq(u.u_procp);
! u.u_ru.ru_nivcsw++;
! swtch();
! (void) spl0();
! }
!
sethi %hi(_runrun), %o0
ld [%o0 + %lo(_runrun)], %o0
tst %o0
be sc_userprof
nop
call _spl6
sethi %hi(_uunix), %l0
ld [%l0 + %lo(_uunix)], %l0
call _setrq
ld [%l0 + U_PROCP], %o0
ld [%l0 + U_RU_NIVCSW], %o0
inc %o0
call _swtch
st %o0, [%l0 + U_RU_NIVCSW]
call _spl0
nop
!
! curpri = u.u_procp->p_pri;
!
sethi %hi(_uunix), %l0
ld [%l0 + %lo(_uunix)], %l0
sethi %hi(_curpri), %o0
ld [%l0 + U_PROCP], %l0
ldsb [%l0 + P_PRI], %l0
stb %l0, [%o0 + %lo(_curpri)]
sc_userprof:
!
! if (syst_flag)
! syscall_userprof(rp, pid, syst.tv_sec, syst.tv_usec);
!
tst %l4
bz sys_rtt
mov %l5, %o1
mov %l2, %o2
mov %l3, %o3
call _syscall_userprof
add %sp, MINFRAME, %o0
b,a sys_rtt
/* end syscall */
#endif /* SYSCALLOPTIM_DEBUG */
#else /* SYSCALLOPTIM */
/*
* System call handler.
*/
syscall:
wr %l0, PSR_ET, %psr ! enable traps (no priority change)
nop ! psr delay
call _syscall ! syscall(rp)
add %sp, MINFRAME, %o0 ! ptr to reg struct
b,a sys_rtt
/* end syscall */
#endif /* SUNDBE */
#define ST_OP_SHIFT 21 /* opcode bit that determines ld vs st */
/*
* Fault handler.
*/
fault:
#ifdef notdef
/* enable this code when MEMERR_ADDR fix is in */
mov S_EXEC, %o4 ! assume execute fault
cmp %l4, T_TEXT_FAULT ! text fault?
be,a 2f
mov %l1, %o2 ! pc is text fault address
#endif notdef
set MEMERR_ADDR, %g1
ld [%g1 + ME_VADDR], %o2 ! get data fault address in mem err reg
ld [%g1], %g2 ! is this a memory error or a fault?
mov %g2, %o5 ! get cntl reg, for parity stuff
btst ER_INTR, %g2
bz,a 1f ! memory error
clr [%g1 + ME_VADDR] ! clear fault address
!
! Memory error. Enable traps to let interrupt happen.
!
wr %l0, PSR_ET, %psr
nop ! psr delay
b,a sys_rtt ! return from trap
1:
/* XXX remove from here ... */
mov S_EXEC, %o4 ! assume execute fault
cmp %l4, T_TEXT_FAULT ! text fault?
be,a 2f
mov %l1, %o2 ! pc is text fault address
/* ... to here when MEMERR_ADDR fix is in */
mov S_READ, %o4 ! assume read fault
ld [%l1], %g1 ! get instruction (must be ld* or st*)
srl %g1, ST_OP_SHIFT, %g1 ! load or store?
btst 1, %g1
bnz,a 2f
mov S_WRITE, %o4 ! store, write fault
2:
set BUS_ERROR_REG, %g2 ! get bus error reg before trap enable
lduba [%g2]ASI_CTL, %o3
wr %l0, PSR_ET, %psr ! enable traps (no priority change)
cmp %o3, BE_INVALID
bne 3f
mov %l4, %o0
mov %o2, %l2 ! save %o2 - %o4 in locals
mov %o3, %l3
mov %o4, %l5
call _hat_fault ! hat_fault(addr)
mov %o2, %o0
tst %o0
be sys_rtt ! hat layer resolved the fault
!
! hat_fault didn't resolve the fault.
! Restore saved %o2 - %o4 and call trap.
!
mov %l2, %o2
mov %l3, %o3
mov %l5, %o4
mov %l4, %o0
3:
!
! Call C trap handler
!
call _trap ! trap(t, rp, addr, be, rw)
add %sp, MINFRAME, %o1
b,a sys_rtt ! return from trap
/* end fault */
/*
* Interrupt vector table
*/
.seg "data"
.align 4
!
! all interrupts are vectored via the following table
! we can't vector directly from the scb because
! we haven't done window setup
!
.global _int_vector
_int_vector:
.word _spurious ! level 0, should not happen
.word level1 ! level 1, softint, interrupt enable register 1
.word (1<<1) ! level 2, vme level 1
.word (2<<1) ! level 3, vme level 2
.word level4 ! level 4, SCSI or IE register 2
.word (3<<1) ! level 5, vme level 3
.word level6 ! level 6, ethernet or IE register 3
.word (4<<1) ! level 7, vme level 4
.word level8 ! level 8, video retrace
.word (5<<1) ! level 9, vme level 5
.word level10 ! level 10, normal clock
.word (6<<1) ! level 11, vme level 6
#ifdef SAS
.word _simcintr ! sas console interrupt
#else
.word _zslevel12 ! level 12, scc - serial i/o
#endif SAS
.word (7<<1) ! level 13, vme level 7
.word _spurious ! kprof (not done here) / monitor clock
.word memory_err ! level 15, memory error
.seg "text"
/*
* Generic interrupt handler.
*/
.global interrupt
interrupt:
set eintstack, %g1 ! on interrupt stack?
cmp %sp, %g1
bgu,a 1f
sub %g1, SA(MINFRAME), %sp ! get on it.
1:
andn %l0, PSR_PIL, %l5 ! compute new psr with proper PIL
and %l4, T_INT_LEVEL, %l4
sll %l4, PSR_PIL_BIT, %g1
or %l5, %g1, %l0
!
! If we just took a memory error we don't want to turn interrupts
! on just yet in case there is another memory error waiting in the
! wings. So disable interrupts if the PIL is 15.
!
cmp %g1, PSR_PIL
bne 2f
sll %l4, 2, %l6 ! convert level to word offset
mov IR_ENA_INT, %o0
call _set_intreg
mov 0, %o1
2:
!
! Get handler address for level.
!
set _int_vector, %g1
ld [%g1 + %l6], %l3 ! grab vector
!
! no code can exist at a low address (< 8192)
! so we use this to weed out vme generated interrupts
! the vector will be the vme level that we should
! acknowledge for the current interrupt if it is a vme
! interrupt otherwise we get an interrupt routine address
!
cmp %l3, 16 ! is this a vme generated interrupt?
blu,a vme_interrupt
mov (14<<PSR_PIL_BIT), %g1
!
! On board interrupt.
! Due to a bug in the IU, we cannot increase the PIL and
! enable traps at the same time. In effect, ET changes
! slightly before the new PIL becomes effective.
! So we write the psr twice, once to set the PIL and
! once to set ET.
!
mov %l0, %psr ! set level (IU bug)
wr %l0, PSR_ET, %psr ! enable traps
nop
call %l3 ! non-vme interrupt
nop
int_rtt:
sethi %hi(_cnt+V_INTR), %g2 ! cnt.v_intr++
ld [%g2 + %lo(_cnt+V_INTR)], %g1
inc %g1
st %g1, [%g2 + %lo(_cnt+V_INTR)]
b sys_rtt ! restore previous stack pointer
mov %l7, %sp ! reset stack pointer
/* end interrupt */
/*
* VME interrupt. Do vectoring.
* The VME vector is read off the VME bus. If this fails (data fault),
* _trap will check the PC of the fault and jump to _spurious.
*/
.global vme_interrupt, _vme_read_vector
vme_interrupt:
or %l5, %g1, %l5 ! spl 14
mov %l5, %psr ! set level (IU bug)
wr %l5, PSR_ET, %psr ! enable traps
mov -1, %l5 ! bad vector value for _spurious
set VME_INT_VEC, %g1 ! get VME vector from the bus
or %g1, %l3, %g1 ! create address to read in alt space
or %g1, 1, %g1 ! a0 should always be a 1
_vme_read_vector:
lduba [%g1]ASI_CTL, %l5 ! read vector number, acknowledge int.
wr %l0, PSR_ET, %psr ! set proper interrupt level
cmp %l5, VEC_MAX ! check vector limits
bg _spurious
subcc %l5, VEC_MIN, %g3 ! normalize vector
bl _spurious
sll %g3, 2, %g5 ! scale for interrupt counting
sll %g3, 3, %g3 ! scale vector
set _intrcnt, %g4 ! per-device interrupt counts table
ld [%g5 + %g4], %g1 ! interrupt count
set _vme_vector, %g2 ! table of interrupt vectors
inc %g1 ! count interrupt
st %g1, [%g5 + %g4] ! and store result
ld [%g2 + %g3], %g1 ! get handler address
add %g2, 4, %g2 ! generate address of arg ptr
ld [%g2 + %g3], %o0 ! delay slot, get arg ptr
call %g1 ! call handler
ld [%o0], %o0 ! read arg ptr
b,a int_rtt ! restore previous stack pointer
/* end vme_interrupt */
/*
* Vme vectors are compatible with the sun3 family in which
* there were possible valid vectors from 64 to 255 inclusive.
* This requires 192 vectors, each vector is two words long
* the first word being the interrupt routine address and the
* second word is the arg.
*
* Vectors 0xC8-0xFF (200-255) are reserved for customer use.
*/
/*
* The vme vectoring uses the following table of routines
* and arguments. The values for the vectors in the following
* table are loaded by autoconf at boot time.
*/
#define ERRV .word _spurious, _zeros
.seg "data"
.align 4
.global _vme_vector
_vme_vector: ! vector numbers
ERRV; ERRV; ERRV; ERRV ! 0x40 - 0x43 sc0 | sc?
ERRV; ERRV; ERRV; ERRV ! 0x44 - 0x47 xdc0 | xdc1 | xdc2 | xdc3
ERRV; ERRV; ERRV; ERRV ! 0x48 - 0x4B xyc0 | xyc1 | xyc?
ERRV; ERRV; ERRV; ERRV ! 0x4C - 0x4F future disk controllers
ERRV; ERRV; ERRV; ERRV ! 0x50 - 0x53 future disk controllers
ERRV; ERRV; ERRV; ERRV ! 0x54 - 0x57 future disk controllers
ERRV; ERRV; ERRV; ERRV ! 0x58 - 0x5B future disk controllers
ERRV; ERRV; ERRV; ERRV ! 0x5C - 0x5F future disk controllers
ERRV; ERRV; ERRV; ERRV ! 0x60 - 0x63 tm0 | tm1 | tm?
ERRV; ERRV; ERRV; ERRV ! 0x64 - 0x67 xtc0 | xtc1 | xtc?
ERRV; ERRV; ERRV; ERRV ! 0x68 - 0x6B future tape controllers
ERRV; ERRV; ERRV; ERRV ! 0x6C - 0x6F future tape controllers
ERRV; ERRV; ERRV; ERRV ! 0x70 - 0x73 ec?
ERRV; ERRV; ERRV; ERRV ! 0x74 - 0x77 ie0 | ie1 | ie2 | ie3
ERRV; ERRV; ERRV; ERRV ! 0x78 - 0x7B fddi0 | fddi1 | fddi2 | fddi3
ERRV; ERRV; ERRV; ERRV ! 0x7C - 0x7F ie4 | future ethernet devices
ERRV; ERRV; ERRV; ERRV ! 0x80 - 0x83 vpc0 | vpc1 | vpc?
ERRV; ERRV; ERRV; ERRV ! 0x84 - 0x87 vp?
ERRV; ERRV; ERRV; ERRV ! 0x88 - 0x8B mti0 | mti1 | mti2 | mti3
ERRV; ERRV; ERRV; ERRV ! 0x8C - 0x8F SunLink SCP (Systech DCP-8804)
ERRV; ERRV; ERRV; ERRV ! 0x90 - 0x93 Sun-3 zs0 (8 even vectors)
ERRV; ERRV; ERRV; ERRV ! 0x94 - 0x97 Sun-3 zs1 (8 odd vectors)
ERRV; ERRV; ERRV; ERRV ! 0x98 - 0x9B Sun-3 zs0 (8 even vectors)
ERRV; ERRV; ERRV; ERRV ! 0x9C - 0x9F Sun-3 zs1 (8 odd vectors)
ERRV; ERRV; ERRV; ERRV ! 0xA0 - 0xA3 future serial
ERRV; ERRV; ERRV; ERRV ! 0xA4 - 0xA7 pc0 | pc1 | pc2 | pc3
ERRV; ERRV; ERRV; ERRV ! 0xA8 - 0xAB cg2 | future frame buffers
ERRV; ERRV; ERRV; ERRV ! 0xAC - 0xAF gp1 | future graphics processors
ERRV; ERRV; ERRV; ERRV ! 0xB0 - 0xB3 sky0 | ?
ERRV; ERRV; ERRV; ERRV ! 0xB4 - 0xB7 SunLink / channel attach
ERRV; ERRV; ERRV; ERRV ! 0xB8 - 0xBB (token bus) tbi0 | tbi1 | ?
ERRV; ERRV; ERRV; ERRV ! 0xBC - 0xBF Reserved for Sun
ERRV; ERRV; ERRV; ERRV ! 0xC0 - 0xC3 Reserved for Sun
ERRV; ERRV; ERRV; ERRV ! 0xC4 - 0xC7 Reserved for Sun
ERRV; ERRV; ERRV; ERRV ! 0xC8 - 0xCB Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xCC - 0xCF Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xD0 - 0xD3 Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xD4 - 0xD7 Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xD8 - 0xDB Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xDC - 0xDF Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xE0 - 0xE3 Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xE4 - 0xE7 Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xE8 - 0xEB Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xEC - 0xEF Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xF0 - 0xF3 Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xF4 - 0xF7 Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xF8 - 0xFB Reserved for User
ERRV; ERRV; ERRV; ERRV ! 0xFC - 0xFF Reserved for User
/*
* names of vectored interrupt devices -- for vmstat.
*/
.seg "data"
.globl _intrnames
.globl _eintrnames
_intrnames:
.asciz "sc0", "sc1", "sc2", "sc3"
.asciz "xdc0", "xdc1", "xdc2", "xdc3"
.asciz "xyc0", "xyc1", "xyc2", "xyc3"
.asciz "?disk0", "?disk1", "?disk2", "?disk3"
.asciz "?disk0", "?disk1", "?disk2", "?disk3"
.asciz "?disk0", "?disk1", "?disk2", "?disk3"
.asciz "?disk0", "?disk1", "?disk2", "?disk3"
.asciz "?disk0", "?disk1", "?disk2", "?disk3"
.asciz "tm0", "tm1", "tm2", "tm3"
.asciz "xtc0", "xtc1", "xtc2", "xtc3"
.asciz "?tape0", "?tape1", "?tape2", "?tape3"
.asciz "?tape0", "?tape1", "?tape2", "?tape3"
.asciz "ec0", "ec1", "ec2", "ec3"
.asciz "ie0", "ie1", "ie2", "ie3"
.asciz "fddi0", "fddi1", "fddi2", "fddi3"
.asciz "ie4", "?ether1", "?ether2", "?ether3"
.asciz "vpc0", "vpc1", "vpc2", "vpc3"
.asciz "vp0", "vp1", "vp2", "vp3"
.asciz "mti0", "mti1", "mti2", "mti3"
.asciz "SCP", "SCP", "SCP", "SCP"
.asciz "zs0", "zs0", "zs0", "zs0"
.asciz "zs1", "zs1", "zs1", "zs1"
.asciz "zs0", "zs0", "zs0", "zs0"
.asciz "zs1", "zs1", "zs1", "zs1"
.asciz "?serial0", "?serial1", "?serial2", "?serial3"
.asciz "pc0", "pc1", "pc2", "pc3"
.asciz "cgtwo0", "?frbuf", "?frbuf", "?frbuf"
.asciz "gpone0", "?gp", "?gp", "?gp"
.asciz "sky0", "???", "???", "???"
.asciz "slchan", "slchan", "slchan", "slchan"
.asciz "tbi0", "tbi1", "tbi2", "tbi3"
.asciz "?Sun", "?Sun", "?Sun", "?Sun"
.asciz "?Sun", "?Sun", "?Sun", "?Sun"
.asciz "?Sun", "?Sun", "?Sun", "?Sun"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
.asciz "?User", "?User", "?User", "?User"
_eintrnames:
/*
* Places (initialized to 0) to count vectored interrupts in.
* Used by vmstat.
*/
.seg "bss"
.align 4
.globl _intrcnt
.globl _eintrcnt
_intrcnt:
.skip 4 * 192
_eintrcnt:
.seg "text"
.align 4
/*
* Spurious trap... 'should not happen'
* %l4 - processor interrupt level
* %l3 - vme interrupt level << 1 (or interrupt handler address)
* %l5 - vme vector
*/
.seg "data"
.global _ie1_intr
_ie1_intr: .word 1
.text
.global _spurious
_spurious:
cmp %l3, 16 ! is this a vme generated interrupt?
blu spurious_vme
nop
!
! Spurious on-board interrupt.
!
set 1f, %o0
call _printf
mov %l4, %o1
b,a int_rtt
.seg "data"
1: .asciz "spurious interrupt at processor level %d\n"
.seg "text"
!
! Spurious VME interrupt.
!
spurious_vme:
set 2f, %o0
mov %l4, %o1
srl %l3, 1, %o2
set _ie1_intr, %o3
ld [%o3], %o3
cmp %o3, 0
be 1f
cmp %o2, 3
be int_rtt
nop
1:
call _printf
mov %l5, %o3
b,a int_rtt
.seg "data"
2: .asciz "spurious VME interrupt at processor level %d\nVME level %d, VME vector 0x%x\n"
.seg "text"
/* end spurious */
/*
* Macro for autovectored interrupts.
*/
#define IOINTR(LEVEL) \
set _level/**/LEVEL/**/_vector,%l5 /* get vector ptr */;\
clr %l4 /* clear offset */;\
1: ld [%l5 + %l4], %g1/* get routine address */;\
call %g1 /* go there */;\
nop ;\
tst %o0 /* success? */;\
bz,a 1b /* no, try next one */;\
add %l4, 4, %l4 /* delay slot, next one to try */;\
set _level/**/LEVEL/**/_intcnt, %l5 /* get interrupt counter */;\
ld [%l5 + %l4], %g1/* increment proper counter */;\
inc %g1 ;\
bneg int_rtt /* was interrupt spurious? */;\
st %g1, [%l5 + %l4];\
/* non-spurious interrupt, clear count */;\
sethi %hi(_level/**/LEVEL/**/_spurious), %g1;\
b int_rtt /* done */;\
clr [%g1 + %lo(_level/**/LEVEL/**/_spurious)]
/*
* Handle software interrupts
* Just call C routine softint - executes all accumulated softcalls
*/
.global level1
level1:
mov %psr, %g2
or %g2, PSR_PIL, %g1 ! spl hi to protect intreg update
mov %g1, %psr
nop; nop; ! psr delay
set INTREG_ADDR, %l1 ! interrupt register address
ldub [%l1], %g1 ! get current setting
bclr IR_SOFT_INT1, %g1 ! reset level one int request bit
stb %g1, [%l1] ! turn off the level one interrupt
mov %g2, %psr ! splx
nop ! psr delay
call _softint ! go do accumulated softcalls
nop
b,a int_rtt
/* end level1 */
/*
* Level 4 interrupts, normally used by SCSI or interrupt register 2
*/
level4:
IOINTR(2)
/*
* Level 6 interrupts, normally used by Ethernet or interrupt register 3
*/
level6:
IOINTR(3)
/*
* Level 8 interrupts, normally used by video retrace
*/
level8:
IOINTR(4)
/*
* LED data for idle pattern of diagnostic register.
* NOTE: pattern is sampled at 100hz.
*/
LEDTICKS = 33
LEDPATCNT = 18
.seg "data"
led:
! LEDPAT
.byte 0x7e, 0x7e
.byte 0x7e, 0xbd
.byte 0xbd, 0xbd
.byte 0xdb, 0xdb
.byte 0xdb, 0xe7
.byte 0xe7, 0xe7
.byte 0xdb, 0xdb
.byte 0xdb, 0xbd
.byte 0xbd, 0xbd
! end of LEDPAT
.byte 0 ! LEDCNT current count of ticks
.byte 0 ! LEDPTR offset in pattern
LEDPAT = 0
LEDCNT = 18
LEDPTR = 19
.seg "text"
/*
* This code assumes that the real time clock interrupts 100 times
* per second, for SUN4 we call hardclock at that rate.
*
* If idle, update the LEDs with new values before calling hardclock so
* at least the user can tell that something is still running.
*/
.seg "bss"
.align 4
.globl _clk_intr
_clk_intr:
.skip 4
.seg "text"
.global level10
level10:
mov %psr, %g3
or %g3, PSR_PIL, %g1 ! spl hi to protect intreg update
mov %g1, %psr
nop; nop; ! psr delay
sethi %hi(_clock_type), %l5 ! which clock_type?
ld [%l5 + %lo(_clock_type)], %g1
cmp %g1, INTERSIL7170
bnz 5f ! if intersil then
nop ! (delay slot)
#ifndef SAS
set CLOCK0_ADDR+CLK_INTRREG, %l5 ! read CLOCK_ADDR->CLK_INTRRER
ldub [%l5], %g1 ! to clear clock chip
#endif !SAS
set INTREG_ADDR, %g1
ldub [%g1], %g2 ! read interrupt register
bclr IR_ENA_CLK10, %g2
stb %g2, [%g1] ! reset interrupt
bset IR_ENA_CLK10, %g2
stb %g2, [%g1] ! re-enable interrupt
#ifndef SAS
!
! Clear interrupt register again. If we lose
! an interrupt we will resync later anyway.
!
ldub [%l5], %g1
#endif !SAS
ba,a 6f
5: ! else if mostek then
#ifndef SAS
set COUNTER_ADDR+LIM10, %l5 ! read limit10 reg
ld [%l5], %g1 ! to clear interrupt
#endif !SAS
6:
mov %g3, %psr ! restore psr
!
! Check if executing in the idle loop.
! _swtch immediately follows _idle in swtch.s.
!
#ifndef SAS
set led, %l5 ! countdown to next update of LEDs
set _swtch, %g1 ! end of idle loop
cmp %l1, %g1 ! if pc >= swtch not in idle loop
bgeu 4f ! no, don't update LEDs
.empty ! next instruction ok in delay slot
set _idle, %g1 ! address of idle loop
cmp %l1, %g1 ! if pc < idle not in idle loop
bgeu 1f ! yes, update LEDs
nop
4:
ldub [%l5 + LEDCNT], %g1
subcc %g1, 1, %g1
bge,a 3f ! not zero, just call hardclock
stb %g1, [%l5 + LEDCNT] ! delay, write out new ledcnt
1:
mov LEDTICKS, %g1
stb %g1, [%l5 + LEDCNT]
ldub [%l5 + LEDPTR], %g1
ldub [%l5 + %g1], %g2 ! get LED pattern
subcc %g1, 1, %g1 ! point to next one
bneg,a 2f
mov LEDPATCNT-1, %g1
2:
stb %g1, [%l5 + LEDPTR] ! update pattern pointer
set DIAGREG, %g1
stba %g2, [%g1]ASI_CTL ! write led pattern to LEDs
#endif !SAS
3:
sethi %hi(_clk_intr), %g2 ! count clock interrupt
ld [%lo(_clk_intr) + %g2], %g3
inc %g3
st %g3, [%lo(_clk_intr) + %g2]
ld [%l7 + MINFRAME + PC*4], %o0 ! pc
call _hardclock
ld [%l7 + MINFRAME + PSR*4], %o1 ! psr
b,a int_rtt ! return to restore previous stack
/* end level10 */
/*
* Level 14 interrupts can be caused by the clock when
* kernel profiling is enabled. It is handled immediately
* in the trap window.
*/
#ifdef GPROF
.global test_prof
test_prof:
sethi %hi(_clock_type), %l3 ! which clock type?
ld [%l3 + %lo(_clock_type)], %l4
cmp %l4, INTERSIL7170
bnz 1f ! if intersil then
nop ! (delay slot)
sethi %hi(CLOCK0_ADDR+CLK_INTRREG), %l3 ! read clk intrreg
ldub [%l3 + %lo(CLOCK0_ADDR+CLK_INTRREG)], %l3 ! to clear clock chip
sethi %hi(INTREG_ADDR), %l3
ldub [%l3 + %lo(INTREG_ADDR)], %l4 ! reset interrupt reg bit
bclr IR_ENA_CLK14, %l4
stb %l4, [%l3 + %lo(INTREG_ADDR)]
bset IR_ENA_CLK14, %l4 ! reenable interrupt
stb %l4, [%l3 + %lo(INTREG_ADDR)]
ba,a 2f
1:
sethi %hi(COUNTER_ADDR+LIM14), %l3 ! read limit14 reg
ld [%l3 + %lo(COUNTER_ADDR+LIM14)], %l3 ! to clear intr
2:
sethi %hi(_mon_clock_on), %l3 ! see if profiling is enabled
ldub [%l3 + %lo(_mon_clock_on)], %l3
tst %l3
bz kprof ! profiling on, do it.
nop
b sys_trap ! do normal interrupt processing
mov (T_INTERRUPT | 14), %l4
#endif GPROF
/*
* Level 15 interrupts can only be caused by parity/ECC errors.
* This is fatal if the error is an incorrectable ECC or parity.
* If the error is correctable ECC, memerr will eventually return
* after logging some diagnostic information.
*/
.global memory_err
memory_err:
set MEMERR_ADDR, %g1 ! get address of mem err reg
ld [%g1], %g2 ! read it
btst ER_INTR, %g2 ! valid memory interrupt pending?
bz 1f
nop
call _memerr ! sometimes returns
nop
b,a 3f
1:
sethi %hi(2f), %o0 ! print stray interrupt message
call _printf ! print a message to the console
or %o0, %lo(2f), %o0
3:
mov IR_ENA_INT, %o0 ! reenable interrupts
call _set_intreg
mov 1, %o1
b,a int_rtt
.seg "data"
2: .asciz "stray level 15 interrupt\n"
.seg "text"
/* end level15 */
/*
* Flush all windows to memory, except for the one we entered in.
* We do this by doing NWINDOW-2 saves then the same number of restores.
* This leaves the WIM immediately before window entered in.
* This is used for context switching.
*/
ENTRY(flush_windows)
save %sp, -WINDOWSIZE, %sp
save %sp, -WINDOWSIZE, %sp
save %sp, -WINDOWSIZE, %sp
save %sp, -WINDOWSIZE, %sp
save %sp, -WINDOWSIZE, %sp
#if defined(SUN4_470) || defined(SUN4_330)
.global _fixnwindows
_fixnwindows:
save %sp, -WINDOWSIZE, %sp ! could be no-ops if machine
restore ! has only 7 register windows
#endif SUN4_470 || SUN4_330
restore
restore
restore
restore
ret
restore
/*
* flush user windows to memory.
*/
ENTRY(flush_user_windows)
sethi %hi(_uunix), %g5 ! XXX - global u register?
ld [%g5 + %lo(_uunix)], %g5
ld [%g5 + PCB_UWM], %g1 ! get user window mask
tst %g1 ! do save until mask is zero
bz 3f
clr %g2
1:
save %sp, -WINDOWSIZE, %sp
sethi %hi(_uunix), %g5 ! XXX - global u register?
ld [%g5 + %lo(_uunix)], %g5
ld [%g5 + PCB_UWM], %g1 ! get user window mask
tst %g1 ! do save until mask is zero
bnz 1b
add %g2, 1, %g2
2:
subcc %g2, 1, %g2 ! restore back to orig window
bnz 2b
restore
3:
retl
.empty ! next instruction ok in delya slot
/*
* Throw out any user windows in the register file.
* Used by setregs (exec) to clean out old user.
* Used by sigcleanup to remove extraneous windows when returning from a
* signal.
*/
ENTRY(trash_user_windows)
sethi %hi(_uunix), %g5 ! XXX - global u register?
ld [%g5 + %lo(_uunix)], %g5
ld [%g5 + PCB_UWM], %g1 ! get user window mask
tst %g1
bz 3f ! user windows?
nop
!
! There are old user windows in the register file. We disable traps
! and increment the WIM so that we don't overflow on these windows.
! Also, this sets up a nice underflow when first returning to the
! new user.
!
mov %psr, %g4
or %g4, PSR_PIL, %g1 ! spl hi to prevent interrupts
mov %g1, %psr
nop; nop; nop ! psr delay
ld [%g5 + PCB_UWM], %g1 ! get user window mask
clr [%g5 + PCB_UWM] ! throw user windows away
set _scb, %g5
b 2f
ld [%g5 + 31], %g5 ! %g5 == NW-1
1:
srl %g2, 1, %g3 ! next WIM = ror(WIM, 1, NW)
sll %g2, %g5, %g2 ! %g5 == NW-1
or %g2, %g3, %g2
mov %g2, %wim ! install wim
bclr %g2, %g1 ! clear bit from UWM
2:
tst %g1 ! more user windows?
bnz,a 1b
mov %wim, %g2 ! get wim
mov %g4, %psr ! enable traps
nop ! psr delay
3:
sethi %hi(_uunix), %g5 ! XXX - global u register?
ld [%g5 + %lo(_uunix)], %g5
retl
clr [%g5 + PCB_WBCNT] ! zero window buffer cnt
/*
* Clean out register file.
*/
clean_windows:
sethi %hi(_uunix), %l5 ! XXX - global u register?
ld [%l5 + %lo(_uunix)], %l5
ld [%l5 + PCB_FLAGS], %l4 ! set CLEAN_WINDOWS in pcb_flags
mov %wim, %l3
bset CLEAN_WINDOWS, %l4
st %l4, [%l5 + PCB_FLAGS]
srl %l3, %l0, %l3 ! test WIM bit
btst 1, %l3
bnz,a cw_out ! invalid window, just return
mov %l0, %psr ! restore PSR_CC
mov %g1, %l5 ! save some globals
mov %g2, %l6
mov %g3, %l7
mov %wim, %g2 ! put wim in global
mov 0, %wim ! zero wim to allow saving
mov %l0, %g3 ! put original psr in global
b 2f ! test next window for invalid
save
!
! Loop through windows past the trap window
! clearing them until we hit the invlaid window.
!
1:
clr %l1 ! clear the window
clr %l2
clr %l3
clr %l4
clr %l5
clr %l6
clr %l7
clr %o0
clr %o1
clr %o2
clr %o3
clr %o4
clr %o5
clr %o6
clr %o7
save
2:
mov %psr, %g1 ! get CWP
srl %g2, %g1, %g1 ! test WIM bit
btst 1, %g1
bz,a 1b ! not invalid window yet
clr %l0 ! clear the window
!
! Clean up trap window.
!
mov %g3, %psr ! back to trap window, restore PSR_CC
mov %g2, %wim ! restore wim
nop; nop; ! psr delay
mov %l5, %g1 ! restore globals
mov %l6, %g2
mov %l7, %g3
mov %l2, %o6 ! put npc in unobtrusive place
clr %l0 ! clear the rest of the window
clr %l1
clr %l2
clr %l3
clr %l4
clr %l5
clr %l6
clr %l7
clr %o0
clr %o1
clr %o2
clr %o3
clr %o4
clr %o5
clr %o7
jmp %o6 ! return to npc
rett %o6 + 4
cw_out:
nop ! psr delay
jmp %l2 ! return to npc
rett %l2 + 4
/*
* Enter the monitor -- called from console abort
*/
ENTRY(montrap)
save %sp, -SA(MINFRAME), %sp ! get a new window
call _flush_windows ! flush windows to stack
nop
#ifdef SAS
ta 255 ! trap to siumlator
nop
#else
call %i0 ! go to monitor
nop
#endif SAS
ret
restore
/*
* return the condition codes in %g1
*/
getcc:
sll %l0, 8, %g1 ! right justify condition code
srl %g1, 28, %g1
1: jmp %l2 ! return, skip trap instruction
rett %l2+4
/*
* set the condtion codes from the value in %g1
*/
setcc:
sll %g1, 20, %l5 ! mov icc bits to their position in psr
set PSR_ICC, %l4 ! condition code mask
andn %l0, %l4, %l0 ! zero the current bits in the psr
or %l5, %l0, %l0 ! or new icc bits
mov %l0, %psr ! write new psr
nop ! psr delay
b,a 1b
/*
* some user has to do unaligned references, yuk!
* set a flag in the pcb so that when alignment traps happen
* we fix it up instead of killing the user
* Note: this routine is using the trap window
*/
fix_alignment:
sethi %hi(_uunix), %l5
ld [%l5 + %lo(_uunix)], %l5
ld [%l5 + PCB_FLAGS], %l4 ! get pcb_flags
bset FIX_ALIGNMENT, %l4
ba 1b
st %l4, [%l5 + PCB_FLAGS]
/*
* icode1
* When a process is created by main to do init, it starts here.
* We hack the stack to make it look like a system call frame.
* Then, icode exec's init.
*/
ENTRY(icode1)
call _icode
add %sp, MINFRAME, %o0 ! pointer to struct regs
b,a sys_rtt
#ifdef SUNDBE
/*
* Fast trap to return hi-res-time, use trap windows, leaves traps disabled.
* Returns the value of the hi-res timer in the globals g2 and g3.
* returns with the number of seconds in g2 and the number ticks in g3.
* [since since 00:00 GMT, January 1, 1970 (zero hour)]
*
* Note: only the MOSTEK chip (4/3x0, 4/4x0) has the high res. counters.
* Sun 4/2x0 doesn't support the high res. counters. The resolution
* for 4/2x0 will be 10 millisecs because we return the value of `time'.
*
*/
hrestimetrap: ! Uses %l3-%l5
sethi %hi(_clock_type), %l5 ! which clock_type?
ld [%l5 + %lo(_clock_type)], %g1
cmp %g1, MOSTEK48T02
bz,a 0f ! mostek chip?
sethi %hi(COUNTER_ADDR), %l3 ! delay slot
sethi %hi(_time), %l4
b 1f
clr %l3
0:
ld [%l3 + %lo(COUNTER_ADDR)], %l3 ! read counter from COUNTER_ADDR
sethi %hi(_time), %l4
tst %l3 ! check bit 31 (CTR_LIMIT_BIT)
bpos,a 1f ! limit bit not set
srl %l3, CTR_USEC_SHIFT, %l3 ! get usec count in %l3
! (delay slot)
set 10000, %l3
1:
ld [%l4 + %lo(_time)], %g2 ! g2 --- time.tv_sec
sethi %hi(1000000), %l5 ! 1000000 (ticks/sec)
ld [%l4 + %lo(_time+4)], %g3 ! g3 --- time.tv_ticks
or %l5, %lo(1000000), %l5 ! 1000000 (ticks/sec)
add %g3, %l3, %g3 ! %g3 <- tv_ticks + tick in ctr
cmp %g3, %l5 ! compar sum and tick per sec
bl 2f ! if (%l3 < 1 sec) goto 2f
mov %l0, %psr ! restore psr
sub %g3, %l5, %g3 ! Otherwise, %g3 -= 1 sec,
add %g2, 0x1, %g2 ! tv_sec += 1
2:
jmp %l2
rett %l2+4
#endif SUNDBE