/* SPDX-License-Identifier: GPL-2.0 */1/*2* etrap.S: Sparc trap window preparation for entry into the3* Linux kernel.4*5* Copyright (C) 1995 David S. Miller ([email protected])6*/78#include <asm/head.h>9#include <asm/asi.h>10#include <asm/contregs.h>11#include <asm/page.h>12#include <asm/psr.h>13#include <asm/ptrace.h>14#include <asm/winmacro.h>15#include <asm/asmmacro.h>16#include <asm/thread_info.h>1718/* Registers to not touch at all. */19#define t_psr l0 /* Set by caller */20#define t_pc l1 /* Set by caller */21#define t_npc l2 /* Set by caller */22#define t_wim l3 /* Set by caller */23#define t_twinmask l4 /* Set at beginning of this entry routine. */24#define t_kstack l5 /* Set right before pt_regs frame is built */25#define t_retpc l6 /* If you change this, change winmacro.h header file */26#define t_systable l7 /* Never touch this, could be the syscall table ptr. */27#define curptr g6 /* Set after pt_regs frame is built */2829.text30.align 43132/* SEVEN WINDOW PATCH INSTRUCTIONS */33.globl tsetup_7win_patch1, tsetup_7win_patch234.globl tsetup_7win_patch3, tsetup_7win_patch435.globl tsetup_7win_patch5, tsetup_7win_patch636tsetup_7win_patch1: sll %t_wim, 0x6, %t_wim37tsetup_7win_patch2: and %g2, 0x7f, %g238tsetup_7win_patch3: and %g2, 0x7f, %g239tsetup_7win_patch4: and %g1, 0x7f, %g140tsetup_7win_patch5: sll %t_wim, 0x6, %t_wim41tsetup_7win_patch6: and %g2, 0x7f, %g242/* END OF PATCH INSTRUCTIONS */4344/* At trap time, interrupts and all generic traps do the45* following:46*47* rd %psr, %l048* b some_handler49* rd %wim, %l350* nop51*52* Then 'some_handler' if it needs a trap frame (ie. it has53* to call c-code and the trap cannot be handled in-window)54* then it does the SAVE_ALL macro in entry.S which does55*56* sethi %hi(trap_setup), %l457* jmpl %l4 + %lo(trap_setup), %l658* nop59*/6061/* 2 3 4 window number62* -----63* O T S mnemonic64*65* O == Current window before trap66* T == Window entered when trap occurred67* S == Window we will need to save if (1<<T) == %wim68*69* Before execution gets here, it must be guaranteed that70* %l0 contains trap time %psr, %l1 and %l2 contain the71* trap pc and npc, and %l3 contains the trap time %wim.72*/7374.globl trap_setup, tsetup_patch1, tsetup_patch275.globl tsetup_patch3, tsetup_patch476.globl tsetup_patch5, tsetup_patch677trap_setup:78/* Calculate mask of trap window. See if from user79* or kernel and branch conditionally.80*/81mov 1, %t_twinmask82andcc %t_psr, PSR_PS, %g0 ! fromsupv_p = (psr & PSR_PS)83be trap_setup_from_user ! nope, from user mode84sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)8586/* From kernel, allocate more kernel stack and87* build a pt_regs trap frame.88*/89sub %fp, (STACKFRAME_SZ + TRACEREG_SZ), %t_kstack90STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)9192/* See if we are in the trap window. */93andcc %t_twinmask, %t_wim, %g094bne trap_setup_kernel_spill ! in trap window, clean up95nop9697/* Trap from kernel with a window available.98* Just do it...99*/100jmpl %t_retpc + 0x8, %g0 ! return to caller101mov %t_kstack, %sp ! jump onto new stack102103trap_setup_kernel_spill:104ld [%curptr + TI_UWINMASK], %g1105orcc %g0, %g1, %g0106bne trap_setup_user_spill ! there are some user windows, yuck107/* Spill from kernel, but only kernel windows, adjust108* %wim and go.109*/110srl %t_wim, 0x1, %g2 ! begin computation of new %wim111tsetup_patch1:112sll %t_wim, 0x7, %t_wim ! patched on 7 window Sparcs113or %t_wim, %g2, %g2114tsetup_patch2:115and %g2, 0xff, %g2 ! patched on 7 window Sparcs116117save %g0, %g0, %g0118119/* Set new %wim value */120wr %g2, 0x0, %wim121122/* Save the kernel window onto the corresponding stack. */123STORE_WINDOW(sp)124125restore %g0, %g0, %g0126127jmpl %t_retpc + 0x8, %g0 ! return to caller128mov %t_kstack, %sp ! and onto new kernel stack129130#define STACK_OFFSET (THREAD_SIZE - TRACEREG_SZ - STACKFRAME_SZ)131132trap_setup_from_user:133/* We can't use %curptr yet. */134LOAD_CURRENT(t_kstack, t_twinmask)135136sethi %hi(STACK_OFFSET), %t_twinmask137or %t_twinmask, %lo(STACK_OFFSET), %t_twinmask138add %t_kstack, %t_twinmask, %t_kstack139140mov 1, %t_twinmask141sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)142143/* Build pt_regs frame. */144STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)145146#if 0147/* If we're sure every task_struct is THREAD_SIZE aligned,148we can speed this up. */149sethi %hi(STACK_OFFSET), %curptr150or %curptr, %lo(STACK_OFFSET), %curptr151sub %t_kstack, %curptr, %curptr152#else153sethi %hi(~(THREAD_SIZE - 1)), %curptr154and %t_kstack, %curptr, %curptr155#endif156157/* Clear current_thread_info->w_saved */158st %g0, [%curptr + TI_W_SAVED]159160/* See if we are in the trap window. */161andcc %t_twinmask, %t_wim, %g0162bne trap_setup_user_spill ! yep we are163orn %g0, %t_twinmask, %g1 ! negate trap win mask into %g1164165/* Trap from user, but not into the invalid window.166* Calculate new umask. The way this works is,167* any window from the %wim at trap time until168* the window right before the one we are in now,169* is a user window. A diagram:170*171* 7 6 5 4 3 2 1 0 window number172* ---------------173* I L T mnemonic174*175* Window 'I' is the invalid window in our example,176* window 'L' is the window the user was in when177* the trap occurred, window T is the trap window178* we are in now. So therefore, windows 5, 4 and179* 3 are user windows. The following sequence180* computes the user winmask to represent this.181*/182subcc %t_wim, %t_twinmask, %g2183bneg,a 1f184sub %g2, 0x1, %g21851:186andn %g2, %t_twinmask, %g2187tsetup_patch3:188and %g2, 0xff, %g2 ! patched on 7win Sparcs189st %g2, [%curptr + TI_UWINMASK] ! store new umask190191jmpl %t_retpc + 0x8, %g0 ! return to caller192mov %t_kstack, %sp ! and onto kernel stack193194trap_setup_user_spill:195/* A spill occurred from either kernel or user mode196* and there exist some user windows to deal with.197* A mask of the currently valid user windows198* is in %g1 upon entry to here.199*/200201tsetup_patch4:202and %g1, 0xff, %g1 ! patched on 7win Sparcs, mask203srl %t_wim, 0x1, %g2 ! compute new %wim204tsetup_patch5:205sll %t_wim, 0x7, %t_wim ! patched on 7win Sparcs206or %t_wim, %g2, %g2 ! %g2 is new %wim207tsetup_patch6:208and %g2, 0xff, %g2 ! patched on 7win Sparcs209andn %g1, %g2, %g1 ! clear this bit in %g1210st %g1, [%curptr + TI_UWINMASK]211212save %g0, %g0, %g0213214wr %g2, 0x0, %wim215216/* Call MMU-architecture dependent stack checking217* routine.218*/219b tsetup_srmmu_stackchk220andcc %sp, 0x7, %g0221222/* Architecture specific stack checking routines. When either223* of these routines are called, the globals are free to use224* as they have been safely stashed on the new kernel stack225* pointer. Thus the definition below for simplicity.226*/227#define glob_tmp g1228229.globl tsetup_srmmu_stackchk230tsetup_srmmu_stackchk:231/* Check results of callers andcc %sp, 0x7, %g0 */232bne trap_setup_user_stack_is_bolixed233sethi %hi(PAGE_OFFSET), %glob_tmp234235cmp %glob_tmp, %sp236bleu,a 1f237LEON_PI( lda [%g0] ASI_LEON_MMUREGS, %glob_tmp) ! read MMU control238SUN_PI_( lda [%g0] ASI_M_MMUREGS, %glob_tmp) ! read MMU control239240trap_setup_user_stack_is_bolixed:241/* From user/kernel into invalid window w/bad user242* stack. Save bad user stack, and return to caller.243*/244SAVE_BOLIXED_USER_STACK(curptr, g3)245restore %g0, %g0, %g0246247jmpl %t_retpc + 0x8, %g0248mov %t_kstack, %sp2492501:251/* Clear the fault status and turn on the no_fault bit. */252or %glob_tmp, 0x2, %glob_tmp ! or in no_fault bit253LEON_PI(sta %glob_tmp, [%g0] ASI_LEON_MMUREGS) ! set it254SUN_PI_(sta %glob_tmp, [%g0] ASI_M_MMUREGS) ! set it255256/* Dump the registers and cross fingers. */257STORE_WINDOW(sp)258259/* Clear the no_fault bit and check the status. */260andn %glob_tmp, 0x2, %glob_tmp261LEON_PI(sta %glob_tmp, [%g0] ASI_LEON_MMUREGS)262SUN_PI_(sta %glob_tmp, [%g0] ASI_M_MMUREGS)263264mov AC_M_SFAR, %glob_tmp265LEON_PI(lda [%glob_tmp] ASI_LEON_MMUREGS, %g0)266SUN_PI_(lda [%glob_tmp] ASI_M_MMUREGS, %g0)267268mov AC_M_SFSR, %glob_tmp269LEON_PI(lda [%glob_tmp] ASI_LEON_MMUREGS, %glob_tmp)! save away status of winstore270SUN_PI_(lda [%glob_tmp] ASI_M_MMUREGS, %glob_tmp) ! save away status of winstore271272andcc %glob_tmp, 0x2, %g0 ! did we fault?273bne trap_setup_user_stack_is_bolixed ! failure274nop275276restore %g0, %g0, %g0277278jmpl %t_retpc + 0x8, %g0279mov %t_kstack, %sp280281282283