/*1* etrap.S: Sparc trap window preparation for entry into the2* Linux kernel.3*4* Copyright (C) 1995 David S. Miller ([email protected])5*/67#include <asm/head.h>8#include <asm/asi.h>9#include <asm/contregs.h>10#include <asm/page.h>11#include <asm/psr.h>12#include <asm/ptrace.h>13#include <asm/winmacro.h>14#include <asm/asmmacro.h>15#include <asm/thread_info.h>1617/* Registers to not touch at all. */18#define t_psr l0 /* Set by caller */19#define t_pc l1 /* Set by caller */20#define t_npc l2 /* Set by caller */21#define t_wim l3 /* Set by caller */22#define t_twinmask l4 /* Set at beginning of this entry routine. */23#define t_kstack l5 /* Set right before pt_regs frame is built */24#define t_retpc l6 /* If you change this, change winmacro.h header file */25#define t_systable l7 /* Never touch this, could be the syscall table ptr. */26#define curptr g6 /* Set after pt_regs frame is built */2728.text29.align 43031/* SEVEN WINDOW PATCH INSTRUCTIONS */32.globl tsetup_7win_patch1, tsetup_7win_patch233.globl tsetup_7win_patch3, tsetup_7win_patch434.globl tsetup_7win_patch5, tsetup_7win_patch635tsetup_7win_patch1: sll %t_wim, 0x6, %t_wim36tsetup_7win_patch2: and %g2, 0x7f, %g237tsetup_7win_patch3: and %g2, 0x7f, %g238tsetup_7win_patch4: and %g1, 0x7f, %g139tsetup_7win_patch5: sll %t_wim, 0x6, %t_wim40tsetup_7win_patch6: and %g2, 0x7f, %g241/* END OF PATCH INSTRUCTIONS */4243/* At trap time, interrupts and all generic traps do the44* following:45*46* rd %psr, %l047* b some_handler48* rd %wim, %l349* nop50*51* Then 'some_handler' if it needs a trap frame (ie. it has52* to call c-code and the trap cannot be handled in-window)53* then it does the SAVE_ALL macro in entry.S which does54*55* sethi %hi(trap_setup), %l456* jmpl %l4 + %lo(trap_setup), %l657* nop58*/5960/* 2 3 4 window number61* -----62* O T S mnemonic63*64* O == Current window before trap65* T == Window entered when trap occurred66* S == Window we will need to save if (1<<T) == %wim67*68* Before execution gets here, it must be guaranteed that69* %l0 contains trap time %psr, %l1 and %l2 contain the70* trap pc and npc, and %l3 contains the trap time %wim.71*/7273.globl trap_setup, tsetup_patch1, tsetup_patch274.globl tsetup_patch3, tsetup_patch475.globl tsetup_patch5, tsetup_patch676trap_setup:77/* Calculate mask of trap window. See if from user78* or kernel and branch conditionally.79*/80mov 1, %t_twinmask81andcc %t_psr, PSR_PS, %g0 ! fromsupv_p = (psr & PSR_PS)82be trap_setup_from_user ! nope, from user mode83sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)8485/* From kernel, allocate more kernel stack and86* build a pt_regs trap frame.87*/88sub %fp, (STACKFRAME_SZ + TRACEREG_SZ), %t_kstack89STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)9091/* See if we are in the trap window. */92andcc %t_twinmask, %t_wim, %g093bne trap_setup_kernel_spill ! in trap window, clean up94nop9596/* Trap from kernel with a window available.97* Just do it...98*/99jmpl %t_retpc + 0x8, %g0 ! return to caller100mov %t_kstack, %sp ! jump onto new stack101102trap_setup_kernel_spill:103ld [%curptr + TI_UWINMASK], %g1104orcc %g0, %g1, %g0105bne trap_setup_user_spill ! there are some user windows, yuck106/* Spill from kernel, but only kernel windows, adjust107* %wim and go.108*/109srl %t_wim, 0x1, %g2 ! begin computation of new %wim110tsetup_patch1:111sll %t_wim, 0x7, %t_wim ! patched on 7 window Sparcs112or %t_wim, %g2, %g2113tsetup_patch2:114and %g2, 0xff, %g2 ! patched on 7 window Sparcs115116save %g0, %g0, %g0117118/* Set new %wim value */119wr %g2, 0x0, %wim120121/* Save the kernel window onto the corresponding stack. */122STORE_WINDOW(sp)123124restore %g0, %g0, %g0125126jmpl %t_retpc + 0x8, %g0 ! return to caller127mov %t_kstack, %sp ! and onto new kernel stack128129#define STACK_OFFSET (THREAD_SIZE - TRACEREG_SZ - STACKFRAME_SZ)130131trap_setup_from_user:132/* We can't use %curptr yet. */133LOAD_CURRENT(t_kstack, t_twinmask)134135sethi %hi(STACK_OFFSET), %t_twinmask136or %t_twinmask, %lo(STACK_OFFSET), %t_twinmask137add %t_kstack, %t_twinmask, %t_kstack138139mov 1, %t_twinmask140sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)141142/* Build pt_regs frame. */143STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)144145#if 0146/* If we're sure every task_struct is THREAD_SIZE aligned,147we can speed this up. */148sethi %hi(STACK_OFFSET), %curptr149or %curptr, %lo(STACK_OFFSET), %curptr150sub %t_kstack, %curptr, %curptr151#else152sethi %hi(~(THREAD_SIZE - 1)), %curptr153and %t_kstack, %curptr, %curptr154#endif155156/* Clear current_thread_info->w_saved */157st %g0, [%curptr + TI_W_SAVED]158159/* See if we are in the trap window. */160andcc %t_twinmask, %t_wim, %g0161bne trap_setup_user_spill ! yep we are162orn %g0, %t_twinmask, %g1 ! negate trap win mask into %g1163164/* Trap from user, but not into the invalid window.165* Calculate new umask. The way this works is,166* any window from the %wim at trap time until167* the window right before the one we are in now,168* is a user window. A diagram:169*170* 7 6 5 4 3 2 1 0 window number171* ---------------172* I L T mnemonic173*174* Window 'I' is the invalid window in our example,175* window 'L' is the window the user was in when176* the trap occurred, window T is the trap window177* we are in now. So therefore, windows 5, 4 and178* 3 are user windows. The following sequence179* computes the user winmask to represent this.180*/181subcc %t_wim, %t_twinmask, %g2182bneg,a 1f183sub %g2, 0x1, %g21841:185andn %g2, %t_twinmask, %g2186tsetup_patch3:187and %g2, 0xff, %g2 ! patched on 7win Sparcs188st %g2, [%curptr + TI_UWINMASK] ! store new umask189190jmpl %t_retpc + 0x8, %g0 ! return to caller191mov %t_kstack, %sp ! and onto kernel stack192193trap_setup_user_spill:194/* A spill occurred from either kernel or user mode195* and there exist some user windows to deal with.196* A mask of the currently valid user windows197* is in %g1 upon entry to here.198*/199200tsetup_patch4:201and %g1, 0xff, %g1 ! patched on 7win Sparcs, mask202srl %t_wim, 0x1, %g2 ! compute new %wim203tsetup_patch5:204sll %t_wim, 0x7, %t_wim ! patched on 7win Sparcs205or %t_wim, %g2, %g2 ! %g2 is new %wim206tsetup_patch6:207and %g2, 0xff, %g2 ! patched on 7win Sparcs208andn %g1, %g2, %g1 ! clear this bit in %g1209st %g1, [%curptr + TI_UWINMASK]210211save %g0, %g0, %g0212213wr %g2, 0x0, %wim214215/* Call MMU-architecture dependent stack checking216* routine.217*/218.globl tsetup_mmu_patchme219tsetup_mmu_patchme:220b tsetup_sun4c_stackchk221andcc %sp, 0x7, %g0222223/* Architecture specific stack checking routines. When either224* of these routines are called, the globals are free to use225* as they have been safely stashed on the new kernel stack226* pointer. Thus the definition below for simplicity.227*/228#define glob_tmp g1229230tsetup_sun4c_stackchk:231/* Done by caller: andcc %sp, 0x7, %g0 */232bne trap_setup_user_stack_is_bolixed233sra %sp, 29, %glob_tmp234235add %glob_tmp, 0x1, %glob_tmp236andncc %glob_tmp, 0x1, %g0237bne trap_setup_user_stack_is_bolixed238and %sp, 0xfff, %glob_tmp ! delay slot239240/* See if our dump area will be on more than one241* page.242*/243add %glob_tmp, 0x38, %glob_tmp244andncc %glob_tmp, 0xff8, %g0245be tsetup_sun4c_onepage ! only one page to check246lda [%sp] ASI_PTE, %glob_tmp ! have to check first page anyways247248tsetup_sun4c_twopages:249/* Is first page ok permission wise? */250srl %glob_tmp, 29, %glob_tmp251cmp %glob_tmp, 0x6252bne trap_setup_user_stack_is_bolixed253add %sp, 0x38, %glob_tmp /* Is second page in vma hole? */254255sra %glob_tmp, 29, %glob_tmp256add %glob_tmp, 0x1, %glob_tmp257andncc %glob_tmp, 0x1, %g0258bne trap_setup_user_stack_is_bolixed259add %sp, 0x38, %glob_tmp260261lda [%glob_tmp] ASI_PTE, %glob_tmp262263tsetup_sun4c_onepage:264srl %glob_tmp, 29, %glob_tmp265cmp %glob_tmp, 0x6 ! can user write to it?266bne trap_setup_user_stack_is_bolixed ! failure267nop268269STORE_WINDOW(sp)270271restore %g0, %g0, %g0272273jmpl %t_retpc + 0x8, %g0274mov %t_kstack, %sp275276.globl tsetup_srmmu_stackchk277tsetup_srmmu_stackchk:278/* Check results of callers andcc %sp, 0x7, %g0 */279bne trap_setup_user_stack_is_bolixed280sethi %hi(PAGE_OFFSET), %glob_tmp281282cmp %glob_tmp, %sp283bleu,a 1f284lda [%g0] ASI_M_MMUREGS, %glob_tmp ! read MMU control285286trap_setup_user_stack_is_bolixed:287/* From user/kernel into invalid window w/bad user288* stack. Save bad user stack, and return to caller.289*/290SAVE_BOLIXED_USER_STACK(curptr, g3)291restore %g0, %g0, %g0292293jmpl %t_retpc + 0x8, %g0294mov %t_kstack, %sp2952961:297/* Clear the fault status and turn on the no_fault bit. */298or %glob_tmp, 0x2, %glob_tmp ! or in no_fault bit299sta %glob_tmp, [%g0] ASI_M_MMUREGS ! set it300301/* Dump the registers and cross fingers. */302STORE_WINDOW(sp)303304/* Clear the no_fault bit and check the status. */305andn %glob_tmp, 0x2, %glob_tmp306sta %glob_tmp, [%g0] ASI_M_MMUREGS307mov AC_M_SFAR, %glob_tmp308lda [%glob_tmp] ASI_M_MMUREGS, %g0309mov AC_M_SFSR, %glob_tmp310lda [%glob_tmp] ASI_M_MMUREGS, %glob_tmp ! save away status of winstore311andcc %glob_tmp, 0x2, %g0 ! did we fault?312bne trap_setup_user_stack_is_bolixed ! failure313nop314315restore %g0, %g0, %g0316317jmpl %t_retpc + 0x8, %g0318mov %t_kstack, %sp319320321322