1 /* $Id: wuf.S,v 1.23 1996/04/25 06:09:18 davem Exp $ 2 * wuf.S: Window underflow trap handler for the Sparc. 3 * 4 * Copyright (C) 1995 David S. Miller 5 */ 6 7 #include <asm/cprefix.h> 8 #include <asm/contregs.h> 9 #include <asm/page.h> 10 #include <asm/ptrace.h> 11 #include <asm/psr.h> 12 #include <asm/smp.h> 13 #include <asm/asi.h> 14 #include <asm/winmacro.h> 15 #include <asm/asmmacro.h> 16 17 /* Just like the overflow handler we define macros for registers 18 * with fixed meanings in this routine. 19 */ 20 #define t_psr l0 21 #define t_pc l1 22 #define t_npc l2 23 #define t_wim l3 24 /* Don't touch the above registers or else you die horribly... */ 25 26 /* Now macros for the available scratch registers in this routine. */ 27 #define twin_tmp1 l4 28 #define twin_tmp2 l5 29 30 .text 31 .align 4 32 33 /* The trap entry point has executed the following: 34 * 35 * rd %psr, %l0 36 * rd %wim, %l3 37 * b fill_window_entry 38 * andcc %l0, PSR_PS, %g0 39 */ 40 41 /* Datum current->tss.uwinmask contains at all times a bitmask 42 * where if any user windows are active, at least one bit will 43 * be set in to mask. If no user windows are active, the bitmask 44 * will be all zeroes. 45 */ 46 47 /* To get an idea of what has just happened to cause this 48 * trap take a look at this diagram: 49 * 50 * 1 2 3 4 <-- Window number 51 * ---------- 52 * T O W I <-- Symbolic name 53 * 54 * O == the window that execution was in when 55 * the restore was attempted 56 * 57 * T == the trap itself has save'd us into this 58 * window 59 * 60 * W == this window is the one which is now invalid 61 * and must be made valid plus loaded from the 62 * stack 63 * 64 * I == this window will be the invalid one when we 65 * are done and return from trap if successful 66 */ 67 68 /* BEGINNING OF PATCH INSTRUCTIONS */ 69 70 /* On 7-window Sparc the boot code patches fnwin_patch1 71 * with the following instruction. 72 */ 73 .globl fnwin_patch1_7win, fnwin_patch2_7win 74 fnwin_patch1_7win: srl %t_wim, 6, %twin_tmp2 75 fnwin_patch2_7win: and %twin_tmp1, 0x7f, %twin_tmp1 76 /* END OF PATCH INSTRUCTIONS */ 77 78 .globl fill_window_entry, fnwin_patch1, fnwin_patch2 79 fill_window_entry: 80 /* LOCATION: Window 'T' */ 81 82 /* Compute what the new %wim is going to be if we retrieve 83 * the proper window off of the stack. 84 */ 85 sll %t_wim, 1, %twin_tmp1 86 fnwin_patch1: srl %t_wim, 7, %twin_tmp2 87 or %twin_tmp1, %twin_tmp2, %twin_tmp1 88 fnwin_patch2: and %twin_tmp1, 0xff, %twin_tmp1 89 90 wr %twin_tmp1, 0x0, %wim /* Make window 'I' invalid */ 91 WRITE_PAUSE 92 93 andcc %t_psr, PSR_PS, %g0 94 be fwin_from_user 95 restore %g0, %g0, %g0 /* Restore to window 'O' */ 96 97 /* Trapped from kernel, we trust that the kernel does not 98 * 'over restore' sorta speak and just grab the window 99 * from the stack and return. Easy enough. 100 */ 101 fwin_from_kernel: 102 /* LOCATION: Window 'O' */ 103 104 restore %g0, %g0, %g0 105 106 /* LOCATION: Window 'W' */ 107 108 LOAD_WINDOW(sp) /* Load it up */ 109 110 /* Spin the wheel... */ 111 save %g0, %g0, %g0 112 save %g0, %g0, %g0 113 /* I'd like to buy a vowel please... */ 114 115 /* LOCATION: Window 'T' */ 116 117 /* Now preserve the condition codes in %psr, pause, and 118 * return from trap. This is the simplest case of all. 119 */ 120 wr %t_psr, 0x0, %psr 121 WRITE_PAUSE 122 123 jmp %t_pc 124 rett %t_npc 125 126 fwin_from_user: 127 /* LOCATION: Window 'O' */ 128 129 restore %g0, %g0, %g0 /* Restore to window 'W' */ 130 131 /* LOCATION: Window 'W' */ 132 133 /* Branch to the architecture specific stack validation 134 * routine. They can be found below... 135 */ 136 .globl C_LABEL(fwin_mmu_patchme) 137 C_LABEL(fwin_mmu_patchme): b C_LABEL(sun4c_fwin_stackchk) 138 andcc %sp, 0x7, %g0 139 140 fwin_user_stack_is_bolixed: 141 /* LOCATION: Window 'W' */ 142 143 /* Place a pt_regs frame on the kernel stack, save back 144 * to the trap window and call c-code to deal with this. 145 */ 146 LOAD_CURRENT(l4, l5) 147 ld [%l4 + TASK_SAVED_KSTACK], %l5 148 149 /* Store globals into pt_regs frame. */ 150 STORE_PT_GLOBALS(l5) 151 STORE_PT_YREG(l5, g3) 152 153 /* Save kernel %sp in global while we change windows. */ 154 mov %l5, %g2 155 156 save %g0, %g0, %g0 157 158 /* LOCATION: Window 'O' */ 159 160 rd %psr, %g3 /* Read %psr in live user window */ 161 mov %fp, %g6 /* Save bogus frame pointer. */ 162 163 save %g0, %g0, %g0 164 165 /* LOCATION: Window 'T' */ 166 167 mov %g2, %sp /* Jump onto kernel %sp being held */ 168 169 /* Build rest of pt_regs. */ 170 STORE_PT_INS(sp) 171 STORE_PT_PRIV(sp, t_psr, t_pc, t_npc) 172 173 /* re-set trap time %wim value */ 174 wr %t_wim, 0x0, %wim 175 176 /* Fix users window mask and buffer save count. */ 177 mov 0x1, %g5 178 sll %g5, %g3, %g5 179 LOAD_CURRENT(twin_tmp1, g1) 180 st %g5, [%twin_tmp1 + THREAD_UMASK] ! one live user window still 181 st %g0, [%twin_tmp1 + THREAD_W_SAVED] ! no windows in the buffer 182 183 ENTER_SYSCALL 184 185 wr %t_psr, PSR_ET, %psr ! enable traps 186 WRITE_PAUSE 187 188 call C_LABEL(window_underflow_fault) 189 mov %g6, %o0 190 191 b ret_trap_entry 192 nop 193 194 fwin_user_stack_is_ok: 195 /* LOCATION: Window 'W' */ 196 197 /* The users stack area is kosher and mapped, load the 198 * window and fall through to the finish up routine. 199 */ 200 LOAD_WINDOW(sp) 201 202 /* Round and round she goes... */ 203 save %g0, %g0, %g0 /* Save to window 'O' */ 204 save %g0, %g0, %g0 /* Save to window 'T' */ 205 /* Where she'll trap nobody knows... */ 206 207 /* LOCATION: Window 'T' */ 208 209 fwin_user_finish_up: 210 /* LOCATION: Window 'T' */ 211 212 wr %t_psr, 0x0, %psr 213 WRITE_PAUSE 214 215 jmp %t_pc 216 rett %t_npc 217 218 /* Here come the architecture specific checks for stack. 219 * mappings. Note that unlike the window overflow handler 220 * we only need to check whether the user can read from 221 * the appropriate addresses. Also note that we are in 222 * an invalid window which will be loaded, and this means 223 * that until we actually load the window up we are free 224 * to use any of the local registers contained within. 225 * 226 * On success these routine branch to fwin_user_stack_is_ok 227 * if the area at %sp is user readable and the window still 228 * needs to be loaded, else fwin_user_finish_up if the 229 * routine has done the loading itself. On failure (bogus 230 * user stack) the routine shall branch to the label called 231 * fwin_user_stack_is_bolixed. 232 * 233 * Contrary to the arch-specific window overflow stack 234 * check routines in wof.S, these routines are free to use 235 * any of the local registers they want to as this window 236 * does not belong to anyone at this point, however the 237 * outs and ins are still verboten as they are part of 238 * 'someone elses' window possibly. 239 */ 240 241 .align 4 242 .globl C_LABEL(sun4c_fwin_stackchk) 243 C_LABEL(sun4c_fwin_stackchk): 244 /* LOCATION: Window 'W' */ 245 246 /* Caller did 'andcc %sp, 0x7, %g0' */ 247 be 1f 248 and %sp, 0xfff, %l0 ! delay slot 249 250 b fwin_user_stack_is_bolixed 251 nop 252 253 /* See if we have to check the sanity of one page or two */ 254 1: 255 add %l0, 0x38, %l0 256 sra %sp, 29, %l5 257 add %l5, 0x1, %l5 258 andncc %l5, 0x1, %g0 259 be 1f 260 andncc %l0, 0xff8, %g0 261 262 b fwin_user_stack_is_bolixed /* %sp is in vma hole, yuck */ 263 nop 264 265 1: 266 be sun4c_fwin_onepage /* Only one page to check */ 267 lda [%sp] ASI_PTE, %l1 268 sun4c_fwin_twopages: 269 add %sp, 0x38, %l0 270 sra %l0, 29, %l5 271 add %l5, 0x1, %l5 272 andncc %l5, 0x1, %g0 273 be 1f 274 lda [%l0] ASI_PTE, %l1 275 276 b fwin_user_stack_is_bolixed /* Second page in vma hole */ 277 nop 278 279 1: 280 srl %l1, 29, %l1 281 andcc %l1, 0x4, %g0 282 bne sun4c_fwin_onepage 283 lda [%sp] ASI_PTE, %l1 284 285 b fwin_user_stack_is_bolixed /* Second page has bad perms */ 286 nop 287 288 sun4c_fwin_onepage: 289 srl %l1, 29, %l1 290 andcc %l1, 0x4, %g0 291 bne fwin_user_stack_is_ok 292 nop 293 294 /* A page had bad page permissions, losing... */ 295 b fwin_user_stack_is_bolixed 296 nop 297 298 .globl C_LABEL(srmmu_fwin_stackchk) 299 C_LABEL(srmmu_fwin_stackchk): 300 /* LOCATION: Window 'W' */ 301 302 /* Caller did 'andcc %sp, 0x7, %g0' */ 303 bne fwin_user_stack_is_bolixed 304 nop 305 306 /* Check if the users stack is in kernel vma, then our 307 * trial and error technique below would succeed for 308 * the 'wrong' reason. 309 */ 310 sethi %hi(KERNBASE), %l5 ! delay slot for above 311 mov AC_M_SFSR, %l4 312 cmp %l5, %sp 313 bleu fwin_user_stack_is_bolixed 314 lda [%l4] ASI_M_MMUREGS, %g0 ! clear fault status 315 316 /* The technique is, turn off faults on this processor, 317 * just let the load rip, then check the sfsr to see if 318 * a fault did occur. Then we turn on fault traps again 319 * and branch conditionally based upon what happened. 320 */ 321 lda [%g0] ASI_M_MMUREGS, %l5 ! read mmu-ctrl reg 322 or %l5, 0x2, %l5 ! turn on no-fault bit 323 sta %l5, [%g0] ASI_M_MMUREGS ! store it 324 325 /* Cross fingers and go for it. */ 326 LOAD_WINDOW(sp) 327 328 /* A penny 'saved'... */ 329 save %g0, %g0, %g0 330 save %g0, %g0, %g0 331 /* Is a BADTRAP earned... */ 332 333 /* LOCATION: Window 'T' */ 334 335 lda [%g0] ASI_M_MMUREGS, %twin_tmp1 ! load mmu-ctrl again 336 andn %twin_tmp1, 0x2, %twin_tmp1 ! clear no-fault bit 337 sta %twin_tmp1, [%g0] ASI_M_MMUREGS ! store it 338 339 mov AC_M_SFAR, %twin_tmp2 340 lda [%twin_tmp2] ASI_M_MMUREGS, %g0 ! read fault address 341 342 mov AC_M_SFSR, %twin_tmp2 343 lda [%twin_tmp2] ASI_M_MMUREGS, %twin_tmp2 ! read fault status 344 andcc %twin_tmp2, 0x2, %g0 ! did fault occur? 345 be fwin_user_finish_up 346 nop 347 348 /* Did I ever tell you about my window lobotomy? 349 * anyways... fwin_user_stack_is_bolixed expects 350 * to be in window 'W' so make it happy or else 351 * we watchdog badly. 352 */ 353 restore %g0, %g0, %g0 354 b fwin_user_stack_is_bolixed ! oh well 355 restore %g0, %g0, %g0