Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | | |
| 2 | | skeleton.sa 3.2 4/26/91 |
| 3 | | |
| 4 | | This file contains code that is system dependent and will |
| 5 | | need to be modified to install the FPSP. |
| 6 | | |
| 7 | | Each entry point for exception 'xxxx' begins with a 'jmp fpsp_xxxx'. |
| 8 | | Put any target system specific handling that must be done immediately |
| 9 | | before the jump instruction. If there no handling necessary, then |
| 10 | | the 'fpsp_xxxx' handler entry point should be placed in the exception |
| 11 | | table so that the 'jmp' can be eliminated. If the FPSP determines that the |
| 12 | | exception is one that must be reported then there will be a |
| 13 | | return from the package by a 'jmp real_xxxx'. At that point |
| 14 | | the machine state will be identical to the state before |
| 15 | | the FPSP was entered. In particular, whatever condition |
| 16 | | that caused the exception will still be pending when the FPSP |
| 17 | | package returns. Thus, there will be system specific code |
| 18 | | to handle the exception. |
| 19 | | |
| 20 | | If the exception was completely handled by the package, then |
| 21 | | the return will be via a 'jmp fpsp_done'. Unless there is |
| 22 | | OS specific work to be done (such as handling a context switch or |
| 23 | | interrupt) the user program can be resumed via 'rte'. |
| 24 | | |
| 25 | | In the following skeleton code, some typical 'real_xxxx' handling |
| 26 | | code is shown. This code may need to be moved to an appropriate |
| 27 | | place in the target system, or rewritten. |
| 28 | | |
| 29 | |
| 30 | | Copyright (C) Motorola, Inc. 1990 |
| 31 | | All Rights Reserved |
| 32 | | |
Matt Waddel | e00d82d | 2006-02-11 17:55:48 -0800 | [diff] [blame] | 33 | | For details on the license for this file, please see the |
| 34 | | file, README, in this same directory. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 35 | |
| 36 | | |
| 37 | | Modified for Linux-1.3.x by Jes Sorensen (jds@kom.auc.dk) |
| 38 | | |
| 39 | |
| 40 | #include <linux/linkage.h> |
| 41 | #include <asm/entry.h> |
Sam Ravnborg | 0013a85 | 2005-09-09 20:57:26 +0200 | [diff] [blame] | 42 | #include <asm/asm-offsets.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 43 | |
| 44 | |SKELETON idnt 2,1 | Motorola 040 Floating Point Software Package |
| 45 | |
| 46 | |section 15 |
| 47 | | |
| 48 | | The following counters are used for standalone testing |
| 49 | | |
| 50 | |
| 51 | |section 8 |
| 52 | |
| 53 | #include "fpsp.h" |
| 54 | |
| 55 | |xref b1238_fix |
| 56 | |
| 57 | | |
| 58 | | Divide by Zero exception |
| 59 | | |
| 60 | | All dz exceptions are 'real', hence no fpsp_dz entry point. |
| 61 | | |
| 62 | .global dz |
| 63 | .global real_dz |
| 64 | dz: |
| 65 | real_dz: |
| 66 | link %a6,#-LOCAL_SIZE |
| 67 | fsave -(%sp) |
| 68 | bclrb #E1,E_BYTE(%a6) |
| 69 | frestore (%sp)+ |
| 70 | unlk %a6 |
| 71 | |
| 72 | SAVE_ALL_INT |
| 73 | GET_CURRENT(%d0) |
| 74 | movel %sp,%sp@- | stack frame pointer argument |
| 75 | bsrl trap_c |
| 76 | addql #4,%sp |
| 77 | bral ret_from_exception |
| 78 | |
| 79 | | |
| 80 | | Inexact exception |
| 81 | | |
| 82 | | All inexact exceptions are real, but the 'real' handler |
| 83 | | will probably want to clear the pending exception. |
| 84 | | The provided code will clear the E3 exception (if pending), |
| 85 | | otherwise clear the E1 exception. The frestore is not really |
| 86 | | necessary for E1 exceptions. |
| 87 | | |
| 88 | | Code following the 'inex' label is to handle bug #1232. In this |
| 89 | | bug, if an E1 snan, ovfl, or unfl occurred, and the process was |
| 90 | | swapped out before taking the exception, the exception taken on |
| 91 | | return was inex, rather than the correct exception. The snan, ovfl, |
| 92 | | and unfl exception to be taken must not have been enabled. The |
| 93 | | fix is to check for E1, and the existence of one of snan, ovfl, |
| 94 | | or unfl bits set in the fpsr. If any of these are set, branch |
| 95 | | to the appropriate handler for the exception in the fpsr. Note |
| 96 | | that this fix is only for d43b parts, and is skipped if the |
| 97 | | version number is not $40. |
| 98 | | |
| 99 | | |
| 100 | .global real_inex |
| 101 | .global inex |
| 102 | inex: |
| 103 | link %a6,#-LOCAL_SIZE |
| 104 | fsave -(%sp) |
| 105 | cmpib #VER_40,(%sp) |test version number |
| 106 | bnes not_fmt40 |
| 107 | fmovel %fpsr,-(%sp) |
| 108 | btstb #E1,E_BYTE(%a6) |test for E1 set |
| 109 | beqs not_b1232 |
| 110 | btstb #snan_bit,2(%sp) |test for snan |
| 111 | beq inex_ckofl |
| 112 | addl #4,%sp |
| 113 | frestore (%sp)+ |
| 114 | unlk %a6 |
| 115 | bra snan |
| 116 | inex_ckofl: |
| 117 | btstb #ovfl_bit,2(%sp) |test for ovfl |
| 118 | beq inex_ckufl |
| 119 | addl #4,%sp |
| 120 | frestore (%sp)+ |
| 121 | unlk %a6 |
| 122 | bra ovfl |
| 123 | inex_ckufl: |
| 124 | btstb #unfl_bit,2(%sp) |test for unfl |
| 125 | beq not_b1232 |
| 126 | addl #4,%sp |
| 127 | frestore (%sp)+ |
| 128 | unlk %a6 |
| 129 | bra unfl |
| 130 | |
| 131 | | |
| 132 | | We do not have the bug 1232 case. Clean up the stack and call |
| 133 | | real_inex. |
| 134 | | |
| 135 | not_b1232: |
| 136 | addl #4,%sp |
| 137 | frestore (%sp)+ |
| 138 | unlk %a6 |
| 139 | |
| 140 | real_inex: |
| 141 | |
| 142 | link %a6,#-LOCAL_SIZE |
| 143 | fsave -(%sp) |
| 144 | not_fmt40: |
| 145 | bclrb #E3,E_BYTE(%a6) |clear and test E3 flag |
| 146 | beqs inex_cke1 |
| 147 | | |
| 148 | | Clear dirty bit on dest resister in the frame before branching |
| 149 | | to b1238_fix. |
| 150 | | |
| 151 | moveml %d0/%d1,USER_DA(%a6) |
| 152 | bfextu CMDREG1B(%a6){#6:#3},%d0 |get dest reg no |
| 153 | bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit |
| 154 | bsrl b1238_fix |test for bug1238 case |
| 155 | moveml USER_DA(%a6),%d0/%d1 |
| 156 | bras inex_done |
| 157 | inex_cke1: |
| 158 | bclrb #E1,E_BYTE(%a6) |
| 159 | inex_done: |
| 160 | frestore (%sp)+ |
| 161 | unlk %a6 |
| 162 | |
| 163 | SAVE_ALL_INT |
| 164 | GET_CURRENT(%d0) |
| 165 | movel %sp,%sp@- | stack frame pointer argument |
| 166 | bsrl trap_c |
| 167 | addql #4,%sp |
| 168 | bral ret_from_exception |
| 169 | |
| 170 | | |
| 171 | | Overflow exception |
| 172 | | |
| 173 | |xref fpsp_ovfl |
| 174 | .global real_ovfl |
| 175 | .global ovfl |
| 176 | ovfl: |
| 177 | jmp fpsp_ovfl |
| 178 | real_ovfl: |
| 179 | |
| 180 | link %a6,#-LOCAL_SIZE |
| 181 | fsave -(%sp) |
| 182 | bclrb #E3,E_BYTE(%a6) |clear and test E3 flag |
| 183 | bnes ovfl_done |
| 184 | bclrb #E1,E_BYTE(%a6) |
| 185 | ovfl_done: |
| 186 | frestore (%sp)+ |
| 187 | unlk %a6 |
| 188 | |
| 189 | SAVE_ALL_INT |
| 190 | GET_CURRENT(%d0) |
| 191 | movel %sp,%sp@- | stack frame pointer argument |
| 192 | bsrl trap_c |
| 193 | addql #4,%sp |
| 194 | bral ret_from_exception |
| 195 | |
| 196 | | |
| 197 | | Underflow exception |
| 198 | | |
| 199 | |xref fpsp_unfl |
| 200 | .global real_unfl |
| 201 | .global unfl |
| 202 | unfl: |
| 203 | jmp fpsp_unfl |
| 204 | real_unfl: |
| 205 | |
| 206 | link %a6,#-LOCAL_SIZE |
| 207 | fsave -(%sp) |
| 208 | bclrb #E3,E_BYTE(%a6) |clear and test E3 flag |
| 209 | bnes unfl_done |
| 210 | bclrb #E1,E_BYTE(%a6) |
| 211 | unfl_done: |
| 212 | frestore (%sp)+ |
| 213 | unlk %a6 |
| 214 | |
| 215 | SAVE_ALL_INT |
| 216 | GET_CURRENT(%d0) |
| 217 | movel %sp,%sp@- | stack frame pointer argument |
| 218 | bsrl trap_c |
| 219 | addql #4,%sp |
| 220 | bral ret_from_exception |
| 221 | |
| 222 | | |
| 223 | | Signalling NAN exception |
| 224 | | |
| 225 | |xref fpsp_snan |
| 226 | .global real_snan |
| 227 | .global snan |
| 228 | snan: |
| 229 | jmp fpsp_snan |
| 230 | real_snan: |
| 231 | link %a6,#-LOCAL_SIZE |
| 232 | fsave -(%sp) |
| 233 | bclrb #E1,E_BYTE(%a6) |snan is always an E1 exception |
| 234 | frestore (%sp)+ |
| 235 | unlk %a6 |
| 236 | |
| 237 | SAVE_ALL_INT |
| 238 | GET_CURRENT(%d0) |
| 239 | movel %sp,%sp@- | stack frame pointer argument |
| 240 | bsrl trap_c |
| 241 | addql #4,%sp |
| 242 | bral ret_from_exception |
| 243 | |
| 244 | | |
| 245 | | Operand Error exception |
| 246 | | |
| 247 | |xref fpsp_operr |
| 248 | .global real_operr |
| 249 | .global operr |
| 250 | operr: |
| 251 | jmp fpsp_operr |
| 252 | real_operr: |
| 253 | link %a6,#-LOCAL_SIZE |
| 254 | fsave -(%sp) |
| 255 | bclrb #E1,E_BYTE(%a6) |operr is always an E1 exception |
| 256 | frestore (%sp)+ |
| 257 | unlk %a6 |
| 258 | |
| 259 | SAVE_ALL_INT |
| 260 | GET_CURRENT(%d0) |
| 261 | movel %sp,%sp@- | stack frame pointer argument |
| 262 | bsrl trap_c |
| 263 | addql #4,%sp |
| 264 | bral ret_from_exception |
| 265 | |
| 266 | |
| 267 | | |
| 268 | | BSUN exception |
| 269 | | |
| 270 | | This sample handler simply clears the nan bit in the FPSR. |
| 271 | | |
| 272 | |xref fpsp_bsun |
| 273 | .global real_bsun |
| 274 | .global bsun |
| 275 | bsun: |
| 276 | jmp fpsp_bsun |
| 277 | real_bsun: |
| 278 | link %a6,#-LOCAL_SIZE |
| 279 | fsave -(%sp) |
| 280 | bclrb #E1,E_BYTE(%a6) |bsun is always an E1 exception |
| 281 | fmovel %FPSR,-(%sp) |
| 282 | bclrb #nan_bit,(%sp) |
| 283 | fmovel (%sp)+,%FPSR |
| 284 | frestore (%sp)+ |
| 285 | unlk %a6 |
| 286 | |
| 287 | SAVE_ALL_INT |
| 288 | GET_CURRENT(%d0) |
| 289 | movel %sp,%sp@- | stack frame pointer argument |
| 290 | bsrl trap_c |
| 291 | addql #4,%sp |
| 292 | bral ret_from_exception |
| 293 | |
| 294 | | |
| 295 | | F-line exception |
| 296 | | |
| 297 | | A 'real' F-line exception is one that the FPSP isn't supposed to |
| 298 | | handle. E.g. an instruction with a co-processor ID that is not 1. |
| 299 | | |
| 300 | | |
| 301 | |xref fpsp_fline |
| 302 | .global real_fline |
| 303 | .global fline |
| 304 | fline: |
| 305 | jmp fpsp_fline |
| 306 | real_fline: |
| 307 | |
| 308 | SAVE_ALL_INT |
| 309 | GET_CURRENT(%d0) |
| 310 | movel %sp,%sp@- | stack frame pointer argument |
| 311 | bsrl trap_c |
| 312 | addql #4,%sp |
| 313 | bral ret_from_exception |
| 314 | |
| 315 | | |
| 316 | | Unsupported data type exception |
| 317 | | |
| 318 | |xref fpsp_unsupp |
| 319 | .global real_unsupp |
| 320 | .global unsupp |
| 321 | unsupp: |
| 322 | jmp fpsp_unsupp |
| 323 | real_unsupp: |
| 324 | link %a6,#-LOCAL_SIZE |
| 325 | fsave -(%sp) |
| 326 | bclrb #E1,E_BYTE(%a6) |unsupp is always an E1 exception |
| 327 | frestore (%sp)+ |
| 328 | unlk %a6 |
| 329 | |
| 330 | SAVE_ALL_INT |
| 331 | GET_CURRENT(%d0) |
| 332 | movel %sp,%sp@- | stack frame pointer argument |
| 333 | bsrl trap_c |
| 334 | addql #4,%sp |
| 335 | bral ret_from_exception |
| 336 | |
| 337 | | |
| 338 | | Trace exception |
| 339 | | |
| 340 | .global real_trace |
| 341 | real_trace: |
| 342 | | |
| 343 | bral trap |
| 344 | |
| 345 | | |
| 346 | | fpsp_fmt_error --- exit point for frame format error |
| 347 | | |
| 348 | | The fpu stack frame does not match the frames existing |
| 349 | | or planned at the time of this writing. The fpsp is |
| 350 | | unable to handle frame sizes not in the following |
| 351 | | version:size pairs: |
| 352 | | |
| 353 | | {4060, 4160} - busy frame |
| 354 | | {4028, 4130} - unimp frame |
| 355 | | {4000, 4100} - idle frame |
| 356 | | |
| 357 | | This entry point simply holds an f-line illegal value. |
| 358 | | Replace this with a call to your kernel panic code or |
| 359 | | code to handle future revisions of the fpu. |
| 360 | | |
| 361 | .global fpsp_fmt_error |
| 362 | fpsp_fmt_error: |
| 363 | |
| 364 | .long 0xf27f0000 |f-line illegal |
| 365 | |
| 366 | | |
| 367 | | fpsp_done --- FPSP exit point |
| 368 | | |
| 369 | | The exception has been handled by the package and we are ready |
| 370 | | to return to user mode, but there may be OS specific code |
| 371 | | to execute before we do. If there is, do it now. |
| 372 | | |
| 373 | | |
| 374 | |
| 375 | .global fpsp_done |
| 376 | fpsp_done: |
| 377 | btst #0x5,%sp@ | supervisor bit set in saved SR? |
| 378 | beq .Lnotkern |
| 379 | rte |
| 380 | .Lnotkern: |
| 381 | SAVE_ALL_INT |
| 382 | GET_CURRENT(%d0) |
Roman Zippel | 3b66a1e | 2005-11-13 16:06:59 -0800 | [diff] [blame] | 383 | | deliver signals, reschedule etc.. |
| 384 | jra ret_from_exception |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 385 | |
| 386 | | |
| 387 | | mem_write --- write to user or supervisor address space |
| 388 | | |
| 389 | | Writes to memory while in supervisor mode. copyout accomplishes |
| 390 | | this via a 'moves' instruction. copyout is a UNIX SVR3 (and later) function. |
| 391 | | If you don't have copyout, use the local copy of the function below. |
| 392 | | |
| 393 | | a0 - supervisor source address |
| 394 | | a1 - user destination address |
| 395 | | d0 - number of bytes to write (maximum count is 12) |
| 396 | | |
| 397 | | The supervisor source address is guaranteed to point into the supervisor |
| 398 | | stack. The result is that a UNIX |
| 399 | | process is allowed to sleep as a consequence of a page fault during |
| 400 | | copyout. The probability of a page fault is exceedingly small because |
| 401 | | the 68040 always reads the destination address and thus the page |
| 402 | | faults should have already been handled. |
| 403 | | |
| 404 | | If the EXC_SR shows that the exception was from supervisor space, |
| 405 | | then just do a dumb (and slow) memory move. In a UNIX environment |
| 406 | | there shouldn't be any supervisor mode floating point exceptions. |
| 407 | | |
| 408 | .global mem_write |
| 409 | mem_write: |
| 410 | btstb #5,EXC_SR(%a6) |check for supervisor state |
| 411 | beqs user_write |
| 412 | super_write: |
| 413 | moveb (%a0)+,(%a1)+ |
| 414 | subql #1,%d0 |
| 415 | bnes super_write |
| 416 | rts |
| 417 | user_write: |
| 418 | movel %d1,-(%sp) |preserve d1 just in case |
| 419 | movel %d0,-(%sp) |
| 420 | movel %a1,-(%sp) |
| 421 | movel %a0,-(%sp) |
| 422 | jsr copyout |
| 423 | addw #12,%sp |
| 424 | movel (%sp)+,%d1 |
| 425 | rts |
| 426 | | |
| 427 | | mem_read --- read from user or supervisor address space |
| 428 | | |
| 429 | | Reads from memory while in supervisor mode. copyin accomplishes |
| 430 | | this via a 'moves' instruction. copyin is a UNIX SVR3 (and later) function. |
| 431 | | If you don't have copyin, use the local copy of the function below. |
| 432 | | |
| 433 | | The FPSP calls mem_read to read the original F-line instruction in order |
| 434 | | to extract the data register number when the 'Dn' addressing mode is |
| 435 | | used. |
| 436 | | |
| 437 | |Input: |
| 438 | | a0 - user source address |
| 439 | | a1 - supervisor destination address |
| 440 | | d0 - number of bytes to read (maximum count is 12) |
| 441 | | |
| 442 | | Like mem_write, mem_read always reads with a supervisor |
| 443 | | destination address on the supervisor stack. Also like mem_write, |
| 444 | | the EXC_SR is checked and a simple memory copy is done if reading |
| 445 | | from supervisor space is indicated. |
| 446 | | |
| 447 | .global mem_read |
| 448 | mem_read: |
| 449 | btstb #5,EXC_SR(%a6) |check for supervisor state |
| 450 | beqs user_read |
| 451 | super_read: |
| 452 | moveb (%a0)+,(%a1)+ |
| 453 | subql #1,%d0 |
| 454 | bnes super_read |
| 455 | rts |
| 456 | user_read: |
| 457 | movel %d1,-(%sp) |preserve d1 just in case |
| 458 | movel %d0,-(%sp) |
| 459 | movel %a1,-(%sp) |
| 460 | movel %a0,-(%sp) |
| 461 | jsr copyin |
| 462 | addw #12,%sp |
| 463 | movel (%sp)+,%d1 |
| 464 | rts |
| 465 | |
| 466 | | |
| 467 | | Use these routines if your kernel doesn't have copyout/copyin equivalents. |
| 468 | | Assumes that D0/D1/A0/A1 are scratch registers. copyout overwrites DFC, |
| 469 | | and copyin overwrites SFC. |
| 470 | | |
| 471 | copyout: |
| 472 | movel 4(%sp),%a0 | source |
| 473 | movel 8(%sp),%a1 | destination |
| 474 | movel 12(%sp),%d0 | count |
| 475 | subl #1,%d0 | dec count by 1 for dbra |
| 476 | movel #1,%d1 |
| 477 | |
| 478 | | DFC is already set |
| 479 | | movec %d1,%DFC | set dfc for user data space |
| 480 | moreout: |
| 481 | moveb (%a0)+,%d1 | fetch supervisor byte |
| 482 | out_ea: |
| 483 | movesb %d1,(%a1)+ | write user byte |
| 484 | dbf %d0,moreout |
| 485 | rts |
| 486 | |
| 487 | copyin: |
| 488 | movel 4(%sp),%a0 | source |
| 489 | movel 8(%sp),%a1 | destination |
| 490 | movel 12(%sp),%d0 | count |
| 491 | subl #1,%d0 | dec count by 1 for dbra |
| 492 | movel #1,%d1 |
| 493 | | SFC is already set |
| 494 | | movec %d1,%SFC | set sfc for user space |
| 495 | morein: |
| 496 | in_ea: |
| 497 | movesb (%a0)+,%d1 | fetch user byte |
| 498 | moveb %d1,(%a1)+ | write supervisor byte |
| 499 | dbf %d0,morein |
| 500 | rts |
| 501 | |
| 502 | .section .fixup,#alloc,#execinstr |
| 503 | .even |
| 504 | 1: |
| 505 | jbra fpsp040_die |
| 506 | |
| 507 | .section __ex_table,#alloc |
| 508 | .align 4 |
| 509 | |
| 510 | .long in_ea,1b |
| 511 | .long out_ea,1b |
| 512 | |
| 513 | |end |