/* @(#)overflow.s 1.1 94/10/31 SMI */ #undef WO_TRAP_CHECKS_CPUID /* * Copyright (c) 1990 by Sun Microsystems, Inc. */ #include #include #include #include #include #include #include #include #include #include #ifdef MULTIPROCESSOR #include "percpu_def.h" #endif MULTIPROCESSOR #include "assym.s" .seg "text" .align 4 /* * window overflow trap handler */ .global window_overflow window_overflow: sethi %hi(_nwindows), %l6 ld [%l6+%lo(_nwindows)], %l6 dec %l6 #ifdef WO_TRAP_CHECKS_CPUID set _cpuid, %l5 lda [%l5]ASI_FLPR, %l7 and %l7, 3, %l7 cmp %l7, 2 ! cpuid not mapped bne 1f nop sta %g0, [%l5]ASI_FLPR ! flush tlb set CACHE_LINES*CACHE_LINESZ-1, %l3 and %l5, %l3, %l7 ! modulo cache size set PAGEMASK, %l3 and %l7, %l3, %l7 ! round down to base of page set KERNELBASE + CACHE_LINES*CACHE_LINESZ, %l3 ld [%l3 + %l7], %g0 ! replace the line ld [%l5], %l7 GETCPU(%l5) cmp %l5, %l7 bne _cpuid_bad nop !!! add more tests here, as desired. 1: #endif WO_TRAP_CHECKS_CPUID mov %wim, %l3 #ifdef PERFMETER sethi %hi(_overflowcnt), %l5 ld [%l5 + %lo(_overflowcnt)], %l7 inc %l7 st %l7, [%l5 + %lo(_overflowcnt)] #endif PERFMETER mov %g1, %l7 ! save %g1 mov %g2, %l5 ! save %g2 srl %l3, 1, %g1 ! next WIM = %g1 = ror(WIM, 1, NW) sll %l3, %l6, %l4 ! trap vector set %l6 = NW - 1 btst PSR_PS, %l0 ! test for user or sup trap bz wo_user or %l4, %g1, %g1 ! delay slot ! ! Overflow from supervisor mode. Determine whether the window ! to be saved is a user window. ! U.u_pcb.pcb_uwm has a bit set for each user window which is still ! in the register file. If u.u_pcb.pcb_uwm has any bits on, then it ! is a user window that must be saved. ! sethi %hi(_uunix), %g2 ! XXX - global u register? ld [%g2 + %lo(_uunix)], %g2 ld [%g2+PCB_UWM], %l4 ! if (u.u_pcb.pcb_uwm != 0) sup window tst %l4 bne,a wo_user_window bclr %g1, %l4 ! delay slot, UWM &= ~(new WIM) ! ! Window to be saved is a supervisor window. ! Put it on the stack. ! save ! get into window to be saved mov %g1, %wim ! install new wim nop; nop; nop ! add delay wo_stack_res: SAVE_WINDOW(%sp) restore ! go back to trap window mov %l5, %g2 ! restore g2 mov %l0, %psr ! reinstall system PSR_CC nop; nop; nop mov %l7, %g1 ! restore g1 jmp %l1 ! reexecute save rett %l2 wo_user_window: ! ! Window to be saved is a user window. ! sethi %hi(_uunix), %g2 ld [%g2 + %lo(_uunix)], %g2 st %l4, [%g2+PCB_UWM] ! update u.u_uwm wo_user: ! ! The window to be saved is a user window. ! mov %g3, %l4 ! save %g3 ! must execute a save before we install the new wim ! because, otherwise, the save would cause another ! window overflow trap (watchdog). also, must install ! the new wim here before doing the restore below, or ! else the restore would cause a window overflow. these ! restrictions are responsible for alot of inefficiency ! in this code. the situation would be alot better if ! the locals for the trap window were actually globals. save ! get into window to be saved mov %g1, %wim ! install new wim nop; nop; nop ! add some delay ! ! In order to save the window onto the stack, the stack ! must be aligned on a word boundary, and the part of the ! stack where the save will be done must be present. ! We first check for alignment. btst 0x7, %sp ! test sp alignment bz wo_assume_stack_res nop ! ! Misaligned sp. If this is a userland trap fake a memory alignment ! trap. Otherwise, put the window in the window save buffer so that ! we can catch it again later. ! mov %psr, %g1 ! get psr (not in trap window) btst PSR_PS, %g1 ! test for user or sup trap bnz wo_save_to_buf ! sup trap, save window in uarea buf nop restore mov %l4, %g3 ! restore g3 mov %l5, %g2 ! restore g2 mov %l7, %g1 ! restore g1 mov %l3, %wim ! restore old wim, so regs are dumped nop; nop; nop ! added paranoid delay b sys_trap mov T_ALIGNMENT, %l4 ! delay slot, fake alignment trap ! Most of the time the stack is resident in main memory, ! so we don't verify its presence before attempting to save ! the window onto the stack. Rather, we simply set the ! no-fault bit of the SRMMU's control register, so that ! doing the save won't cause another trap in the case ! where the stack is not present. By checking the ! synchronous fault status register, we can determine ! whether the save actually worked (ie. stack was present), ! or whether we first need to fault in the stack. ! Other sun4 trap handlers first probe for the stack, and ! then, if the stack is present, they store to the stack. ! This approach CANNOT be used with a multiprocessor system ! because of a race condition: between the time that the ! stack is probed, and the store to the stack is done, the ! stack could be stolen by the page daemon. wo_assume_stack_res: !!! SECURITY NOTE: this per-processor stuff uses supervisor !!! mode stores, so the MMU never checks user permissions. !!! So, check here that he is garfing user space. set KERNELBASE, %g1 cmp %g1, %sp ! if in supervisor space, mov 0x8E, %g1 ! [fake up SFSR] bleu wo_stack_not_res ! branch out to "nonresident" mov %sp, %g2 ! [fake up SFAR] sethi %hi(_v_mmu_wo), %g1 ld [%g1 + %lo(_v_mmu_wo)], %g1 jmp %g1 nop ! here is where we return after attempting to save the ! overflowed window onto the stack. check to see if the ! stack was actually present. .global wo_chk_flt wo_chk_flt: btst MMU_SFSR_FAV, %g1 ! did a fault occurr? bz wo_out ! no; just clean up and leave. nop ! a fault occurred, so the stack is not resident. wo_stack_not_res: mov %psr, %g3 ! not in trap window. btst PSR_PS, %g3 ! test for user or sup trap bnz wo_save_to_buf ! sup trap, save window in uarea buf nop ! ! We first save the window in the first window buffer in the u area. ! Then we fake a user data fault. If the fault succeeds, we will ! reexecute the save and overflow again, but this time the page ! will be resident sethi %hi(_uunix), %g3 ld [%g3 + %lo(_uunix)], %g3 st %sp, [%g3+PCB_SPBUF] ! save sp SAVE_WINDOW(%g3+PCB_WBUF) restore ! get back into original window ! ! Compute the user window mask (u.u_pcb.pcb_uwm), which is a mask of ! which windows contain user data. In this case it is all the register ! except the one at the old WIM and the one we just saved. ! mov %wim, %g3 ! get new WIM or %g3, %l3, %g3 ! or in old WIM not %g3 mov -2, %l3 !note %l3 was freed up above. sll %l3, %l6, %l3 andn %g3, %l3, %g3 sethi %hi(_uunix), %l3 ld [%l3 + %lo(_uunix)], %l3 st %g3, [%l3+PCB_UWM] ! u->u_pcb.pcb_uwm = ~(OWIM|NWIM) ! ! Set the save buffer ptr to next buffer ! mov 1, %g3 st %g3, [%l3+PCB_WBCNT] ! u->u_pcb.pcb_wbcnt = 1 set _masterprocp, %g3 ld [%g3], %g3 ld [%g3 + P_STACK], %sp mov %g1, %l3 ! save SFSR mov %g2, %l6 ! save SFAR mov %l7, %g1 ! restore g1, so we can save it mov %l5, %g2 ! restore g2, so we can save it mov %l4, %g3 ! restore g3, so we can save it SAVE_GLOBALS(%sp + MINFRAME) SAVE_OUTS(%sp + MINFRAME) st %l0, [%sp + MINFRAME + PSR*4] ! psr st %l1, [%sp + MINFRAME + PC*4] ! pc st %l2, [%sp + MINFRAME + nPC*4] ! npc #ifdef PC_cpu_tpsr sethi %hi(_cpu_tpsr), %o0 st %l0, [%o0 + %lo(_cpu_tpsr)] #endif wr %l0, PSR_ET, %psr ! enable traps nop; nop; nop ! add psr delay mov T_DATA_FAULT, %o0 add %sp, MINFRAME, %o1 mov %l6, %o2 ! fault address. mov %l3, %o3 ! fault status. call _trap ! trap(T_DATA_FAULT, mov S_WRITE, %o4 ! rp, addr, be, S_WRITE) b,a sys_rtt ! return wo_save_to_buf: ! ! The user's stack is not accessable while trying to save a user window ! during a supervisor overflow. We save the window in the u area to ! be processed when we return to the user. ! sethi %hi(_uunix), %g2 ld [%g2 + %lo(_uunix)], %g2 ld [%g2 + PCB_WBCNT], %g1 sll %g1, 2, %g1 add %g1, %g2, %g1 st %sp, [%g1 + PCB_SPBUF] ! save sp sub %g1, %g2, %g1 sll %g1, 4, %g1 ! convert to offset add %g2, PCB_WBUF, %g2 add %g1, %g2, %g1 SAVE_WINDOW(%g1) sub %g1, %g2, %g1 sub %g2, PCB_WBUF, %g2 srl %g1, 6, %g1 ! increment u.u_pcb.pcb_wbcnt add %g1, 1, %g1 set _uunix, %g2 ld [%g2], %g2 st %g1, [%g2 + PCB_WBCNT] restore ! get back to orig window ! ! Return to supervisor. Rett will not underflow since traps ! were never disabled. ! mov %l0, %psr ! reinstall system PSR_CC nop; nop; nop mov %l7, %g1 ! restore g1 mov %l5, %g2 ! restore g2 mov %l4, %g3 ! restore g3 jmp %l1 ! reexecute save rett %l2 wo_out: ! restore ! get back to orig window sethi %hi(_uunix), %l3 ld [%l3 + %lo(_uunix)], %l3 mov %l5, %g2 ! restore g2 ld [%l3+PCB_FLAGS], %l3 ! check for clean window maintenance mov %l7, %g1 ! restore g1 mov %l4, %g3 ! restore g3 btst CLEAN_WINDOWS, %l3 bz 1f mov %l0, %psr ! reinstall system PSR_CC ! ! Maintain clean windows. ! nop; nop; nop mov %l1, %o6 ! put pc, npc in an unobtrusive place mov %l2, %o7 clr %l0 ! clean the rest 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 ! reexecute save rett %o7 1: nop; nop; nop ! psr delay jmp %l1 ! reexecute save rett %l2