root/arch/sparc/kernel/rirq.S

/* [previous][next][first][last][top][bottom][index][help] */
   1 /* rirq.S: Needed to return from an interrupt on SMP with no
   2  *         locks held or released.
   3  *
   4  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
   5  */
   6 
   7 #include <asm/cprefix.h>
   8 #include <asm/page.h>
   9 #include <asm/ptrace.h>
  10 #include <asm/psr.h>
  11 #include <asm/asi.h>
  12 #include <asm/smp.h>
  13 #include <asm/contregs.h>
  14 #include <asm/winmacro.h>
  15 #include <asm/asmmacro.h>
  16 
  17 #define t_psr     l0
  18 #define t_pc      l1
  19 #define t_npc     l2
  20 #define t_wim     l3
  21 #define twin_tmp1 l4
  22 #define twin_tmp2 l5
  23 #define twin_tmp3 l6
  24 
  25         /* 7 WINDOW SPARC PATCH INSTRUCTIONS */
  26         .globl  rirq_7win_patch1, rirq_7win_patch2, rirq_7win_patch3
  27         .globl  rirq_7win_patch4, rirq_7win_patch5
  28 rirq_7win_patch1:       srl     %t_wim, 0x6, %twin_tmp2
  29 rirq_7win_patch2:       and     %twin_tmp2, 0x7f, %twin_tmp2
  30 rirq_7win_patch3:       srl     %g1, 7, %g2
  31 rirq_7win_patch4:       srl     %g2, 6, %g2
  32 rirq_7win_patch5:       and     %g1, 0x7f, %g1
  33         /* END OF PATCH INSTRUCTIONS */
  34 
  35         .globl  ret_irq_entry, rirq_patch1, rirq_patch2
  36         .globl  rirq_patch3, rirq_patch4, rirq_patch5
  37 ret_irq_entry:
  38         ld      [%sp + REGWIN_SZ + PT_PSR], %t_psr
  39         andcc   %t_psr, PSR_PS, %g0
  40         bne     ret_irq_kernel
  41          nop
  42 
  43 ret_irq_user:
  44         wr      %t_psr, 0x0, %psr
  45         WRITE_PAUSE
  46 
  47         LOAD_CURRENT(twin_tmp2, twin_tmp1)
  48         ld      [%twin_tmp2 + THREAD_W_SAVED], %twin_tmp1
  49         orcc    %g0, %twin_tmp1, %g0
  50         be      ret_irq_nobufwins
  51          nop
  52 
  53         /* User has toasty windows, must grab klock. */
  54         ENTER_SYSCALL
  55 
  56         wr      %t_psr, PSR_ET, %psr
  57         WRITE_PAUSE
  58 
  59         mov     1, %o1
  60         call    C_LABEL(try_to_clear_window_buffer)
  61          add    %sp, REGWIN_SZ, %o0
  62 
  63         /* We have klock, so we must return just like a normal trap. */
  64         b       ret_trap_entry
  65          nop
  66 
  67 ret_irq_nobufwins:
  68         /* Load up the user's out registers so we can pull
  69          * a window from the stack, if necessary.
  70          */
  71         LOAD_PT_INS(sp)
  72 
  73         /* If there are already live user windows in the
  74          * set we can return from trap safely.
  75          */
  76         ld      [%twin_tmp2 + THREAD_UMASK], %twin_tmp1
  77         orcc    %g0, %twin_tmp1, %g0
  78         bne     ret_irq_userwins_ok
  79          nop
  80         
  81                 /* Calculate new %wim, we have to pull a register
  82                  * window from the users stack.
  83                  */
  84 ret_irq_pull_one_window:
  85                 rd      %wim, %t_wim
  86                 sll     %t_wim, 0x1, %twin_tmp1
  87 rirq_patch1:    srl     %t_wim, 0x7, %twin_tmp2
  88                 or      %twin_tmp2, %twin_tmp1, %twin_tmp2
  89 rirq_patch2:    and     %twin_tmp2, 0xff, %twin_tmp2
  90 
  91                 wr      %twin_tmp2, 0x0, %wim
  92                 WRITE_PAUSE
  93 
  94                                 /* Here comes the architecture specific 
  95                                  * branch to the user stack checking routine
  96                                  * for return from traps.
  97                                  */
  98                                 .globl  C_LABEL(rirq_mmu_patchme)
  99 C_LABEL(rirq_mmu_patchme):      b       C_LABEL(sun4c_reti_stackchk)
 100                                  andcc  %fp, 0x7, %g0   
 101 
 102 ret_irq_userwins_ok:
 103         LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc)
 104         or      %t_pc, %t_npc, %g2
 105         andcc   %g2, 0x3, %g0
 106         bne     ret_irq_unaligned_pc
 107          nop
 108 
 109         LOAD_PT_YREG(sp, g1)
 110         LOAD_PT_GLOBALS(sp)
 111 
 112         wr      %t_psr, 0x0, %psr
 113         WRITE_PAUSE
 114 
 115         jmp     %t_pc
 116         rett    %t_npc
 117         
 118 ret_irq_unaligned_pc:
 119         add     %sp, REGWIN_SZ, %o0
 120         ld      [%sp + REGWIN_SZ + PT_PC], %o1
 121         ld      [%sp + REGWIN_SZ + PT_NPC], %o2
 122         ld      [%sp + REGWIN_SZ + PT_PSR], %o3
 123 
 124         wr      %t_wim, 0x0, %wim               ! or else...
 125         WRITE_PAUSE
 126 
 127         /* User has unaligned crap, must grab klock. */
 128         ENTER_SYSCALL
 129 
 130         wr      %t_psr, PSR_ET, %psr
 131         WRITE_PAUSE
 132 
 133         call    C_LABEL(do_memaccess_unaligned)
 134          nop
 135 
 136         /* We have klock, so we must return just like a normal trap. */
 137         b       ret_trap_entry
 138          nop
 139 
 140 ret_irq_kernel:
 141         wr      %t_psr, 0x0, %psr
 142         WRITE_PAUSE
 143 
 144                 /* Will the rett land us in the invalid window? */
 145                 mov     2, %g1
 146                 sll     %g1, %t_psr, %g1
 147 rirq_patch3:    srl     %g1, 8, %g2
 148                 or      %g1, %g2, %g1
 149                 rd      %wim, %g2
 150                 andcc   %g2, %g1, %g0
 151                 be      1f              ! Nope, just return from the trap
 152                  nop
 153 
 154                 /* We have to grab a window before returning. */
 155                 sll     %g2, 0x1, %g1
 156 rirq_patch4:    srl     %g2, 7,  %g2
 157                 or      %g1, %g2, %g1
 158 rirq_patch5:    and     %g1, 0xff, %g1
 159 
 160         wr      %g1, 0x0, %wim
 161         WRITE_PAUSE
 162 
 163         restore %g0, %g0, %g0
 164         LOAD_WINDOW(sp)
 165         save    %g0, %g0, %g0
 166 
 167         /* Reload the entire frame in case this is from a
 168          * kernel system call or whatever...
 169          */
 170 1:
 171         LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
 172 
 173         wr      %t_psr, 0x0, %psr
 174         WRITE_PAUSE
 175 
 176         jmp     %t_pc
 177         rett    %t_npc
 178 
 179 ret_irq_user_stack_is_bolixed:
 180         wr      %t_wim, 0x0, %wim
 181         WRITE_PAUSE
 182 
 183         /* User has a toasty window, must grab klock. */
 184         ENTER_SYSCALL
 185 
 186         wr      %t_psr, PSR_ET, %psr
 187         WRITE_PAUSE
 188 
 189         call    C_LABEL(window_ret_fault)
 190          add    %sp, REGWIN_SZ, %o0
 191 
 192         /* We have klock, so we must return just like a normal trap. */
 193         b       ret_trap_entry
 194          nop
 195 
 196         .globl  C_LABEL(sun4c_reti_stackchk)
 197 C_LABEL(sun4c_reti_stackchk):
 198         be      1f
 199          and    %fp, 0xfff, %g1         ! delay slot
 200 
 201         b       ret_irq_user_stack_is_bolixed
 202          nop
 203 
 204         /* See if we have to check the sanity of one page or two */
 205 1:
 206         add     %g1, 0x38, %g1
 207         sra     %fp, 29, %g2
 208         add     %g2, 0x1, %g2
 209         andncc  %g2, 0x1, %g0
 210         be      1f
 211          andncc %g1, 0xff8, %g0
 212 
 213         /* %sp is in vma hole, yuck */
 214         b       ret_irq_user_stack_is_bolixed
 215          nop
 216 
 217 1:
 218         be      sun4c_reti_onepage      /* Only one page to check */
 219          lda    [%fp] ASI_PTE, %g2
 220 
 221 sun4c_reti_twopages:
 222         add     %fp, 0x38, %g1
 223         sra     %g1, 29, %g2
 224         add     %g2, 0x1, %g2
 225         andncc  %g2, 0x1, %g0
 226         be      1f
 227          lda    [%g1] ASI_PTE, %g2
 228 
 229         /* Second page is in vma hole */
 230         b       ret_irq_user_stack_is_bolixed
 231          nop
 232 
 233 1:
 234         srl     %g2, 29, %g2
 235         andcc   %g2, 0x4, %g0
 236         bne     sun4c_reti_onepage
 237          lda    [%fp] ASI_PTE, %g2
 238 
 239         /* Second page has bad perms */
 240         b       ret_irq_user_stack_is_bolixed
 241          nop
 242 
 243 sun4c_reti_onepage:
 244         srl     %g2, 29, %g2
 245         andcc   %g2, 0x4, %g0
 246         bne     1f
 247          nop
 248 
 249         /* A page had bad page permissions, losing... */
 250         b       ret_irq_user_stack_is_bolixed
 251          nop
 252 
 253         /* Whee, things are ok, load the window and continue. */
 254 1:
 255         restore %g0, %g0, %g0
 256 
 257         LOAD_WINDOW(sp)
 258 
 259         save    %g0, %g0, %g0
 260         b       ret_irq_userwins_ok
 261          nop
 262 
 263         .globl  C_LABEL(srmmu_reti_stackchk)
 264 C_LABEL(srmmu_reti_stackchk):
 265         bne     ret_irq_user_stack_is_bolixed
 266          sethi  %hi(KERNBASE), %g1
 267         cmp     %g1, %fp
 268         bleu    ret_irq_user_stack_is_bolixed
 269          mov    AC_M_SFSR, %g1
 270         lda     [%g1] ASI_M_MMUREGS, %g0
 271 
 272         lda     [%g0] ASI_M_MMUREGS, %g1
 273         or      %g1, 0x2, %g1
 274         sta     %g1, [%g0] ASI_M_MMUREGS
 275 
 276         restore %g0, %g0, %g0
 277 
 278         LOAD_WINDOW(sp)
 279 
 280         save    %g0, %g0, %g0
 281 
 282         andn    %g1, 0x2, %g1
 283         sta     %g1, [%g0] ASI_M_MMUREGS
 284 
 285         mov     AC_M_SFAR, %g2
 286         lda     [%g2] ASI_M_MMUREGS, %g2
 287 
 288         mov     AC_M_SFSR, %g1
 289         lda     [%g1] ASI_M_MMUREGS, %g1
 290         andcc   %g1, 0x2, %g0
 291         bne     ret_irq_user_stack_is_bolixed
 292          nop
 293 
 294         b       ret_irq_userwins_ok
 295          nop

/* [previous][next][first][last][top][bottom][index][help] */