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