root/arch/ppc/kernel/misc.S

/* [previous][next][first][last][top][bottom][index][help] */
   1 /*
   2  * This module contains the PowerPC interrupt fielders
   3  * set of code at specific locations, based on function
   4  */
   5 
   6 #include <linux/sys.h>
   7 #include "ppc_asm.tmpl"
   8 
   9 /* Keep track of low-level exceptions - rather crude, but informative */        
  10 #define STATS
  11 
  12 /*
  13  * Increment a [64 bit] statistic counter
  14  * Uses R2, R3
  15  */
  16 #define BUMP(ctr) \
  17         lis     r2,ctr@h; \
  18         ori     r2,r2,ctr@l; \
  19         lwz     r3,4(r2); \
  20         addic   r3,r3,1; \
  21         stw     r3,4(r2); \
  22         lwz     r3,0(r2); \
  23         addze   r3,r3; \
  24         stw     r3,0(r2)
  25 
  26 /* This instruction is not implemented on the PPC 603 */
  27 #define tlbia \
  28         li      r4,32; \
  29         mtspr   CTR,r4; \
  30         li      r4,0; \
  31 0:      tlbie   r4; \
  32         addi    r4,r4,0x1000; \
  33         bdnz    0b
  34         
  35 _TEXT()
  36 
  37 /*
  38  * Disable interrupts
  39  *      rc = _disable_interrupts()
  40  */
  41 _GLOBAL(_disable_interrupts)
  42         mfmsr   r0              /* Get current interrupt state */
  43         rlwinm  r3,r0,16+1,32-1,31      /* Extract old value of 'EE' */
  44         li      r4,0            /* Need [unsigned] value of MSR_EE */
  45         ori     r4,r4,MSR_EE    /* Set to turn off bit */
  46         andc    r0,r0,r4        /* Clears bit in (r4) */
  47         mtmsr   r0              /* Update machine state */
  48         blr                     /* Done */
  49 
  50 /*
  51  * Enable interrupts
  52  *      _enable_interrupts(int state)
  53  * turns on interrupts if state = 1.
  54  */
  55 _GLOBAL(_enable_interrupts)
  56         mfmsr   r0              /* Get current state */
  57         rlwimi  r0,r3,16-1,32-16,32-16  /* Insert bit */
  58         mtmsr   r0              /* Update machine state */
  59         blr
  60 
  61 /*
  62  * Get 'flags' (aka machine status register)
  63  *      __save_flags(long *ptr)
  64  */
  65 _GLOBAL(__save_flags)
  66         mfmsr   r0              /* Get current state */
  67         stw     r0,0(r3)
  68         mr      r3,r0
  69         blr
  70 
  71 /*
  72  * Restore 'flags'
  73  *      __restore_flags(long val)
  74  */
  75 _GLOBAL(__restore_flags)
  76         mtmsr   r3
  77         isync
  78         blr
  79 
  80 /*
  81  * Disable interrupts - like an 80x86
  82  *      cli()
  83  */
  84 _GLOBAL(cli)
  85         mfmsr   r0              /* Get current interrupt state */
  86         rlwinm  r3,r0,16+1,32-1,31      /* Extract old value of 'EE' */
  87         li      r4,0            /* Need [unsigned] value of MSR_EE */
  88         ori     r4,r4,MSR_EE    /* Set to turn off bit */
  89         andc    r0,r0,r4        /* Clears bit in (r4) */
  90         mtmsr   r0              /* Update machine state */
  91         blr                     /* Done */
  92 
  93 /*
  94  * Enable interrupts - like an 80x86
  95  *      sti()
  96  */
  97 _GLOBAL(sti)
  98         mfmsr   r0              /* Get current state */
  99         ori     r0,r0,MSR_EE    /* Turn on 'EE' bit */
 100         mtmsr   r0              /* Update machine state */
 101         blr
 102 
 103 /*
 104  * Flush MMU TLB
 105  */
 106 _GLOBAL(_tlbia)
 107         tlbia
 108         BUMP(__TLBIAs)
 109         blr     
 110 
 111 /*
 112  * Flush MMU TLB for a particular address
 113  */
 114 _GLOBAL(_tlbie)
 115         tlbie   r3
 116         BUMP(__TLBIEs)
 117         blr     
 118 
 119 /*
 120  * Atomic [test&set] exchange
 121  *
 122  *      void *xchg_u32(void *ptr, unsigned long val)
 123  * Changes the memory location '*ptr' to be val and returns
 124  * the previous value stored there.
 125  */
 126 _GLOBAL(xchg_u32)
 127         mr      r5,r3           /* Save pointer */
 128 10:     lwarx   r3,0,r5         /* Fetch old value & reserve */
 129         stwcx.  r4,0,r5         /* Update with new value */
 130         bne-    10b             /* Retry if "reservation" (i.e. lock) lost */
 131         blr
 132 
 133 /*
 134  * Delay for a specific # of "loops"
 135  *      __delay(int loops)
 136  */
 137 _GLOBAL(__delay)
 138         mtctr   r3
 139 00:     addi    r3,r3,0         /* NOP */
 140         bdnz    00b
 141         blr
 142 
 143 /*
 144  * Delay for a number of microseconds
 145  *      udelay(int usecs)
 146  */
 147 _GLOBAL(udelay)
 148 00:     li      r0,86   /* Instructions / microsecond? */
 149         mtctr   r0
 150 10:     addi    r0,r0,0 /* NOP */
 151         bdnz    10b
 152         subic.  r3,r3,1
 153         bne     00b
 154         blr
 155 
 156 /*
 157  * Atomically increment [intr_count]
 158  */
 159 _GLOBAL(start_bh_atomic)
 160         lis     r3,intr_count@h
 161         ori     r3,r3,intr_count@l
 162 10:     lwarx   r4,0,r3
 163         addi    r4,r4,1
 164         stwcx.  r4,0,r3
 165         bne-    10b
 166         blr
 167 
 168 /*
 169  * Atomically decrement [intr_count]
 170  */
 171 _GLOBAL(end_bh_atomic)
 172         lis     r3,intr_count@h
 173         ori     r3,r3,intr_count@l
 174 10:     lwarx   r4,0,r3
 175         subic   r4,r4,1
 176         stwcx.  r4,0,r3
 177         bne-    10b
 178         blr
 179 
 180 /*
 181  *extern inline int find_first_zero_bit(void * vaddr, unsigned size)
 182  *{
 183  *      unsigned long res;
 184  *      unsigned long *p;
 185  *      unsigned long *addr = vaddr;
 186  *
 187  *      if (!size)
 188  *              return 0;
 189  *      __asm__ __volatile__ ("    moveq #-1,d0\n\t"
 190  *                            "1:"
 191  *                            "    cmpl  %1@+,d0\n\t"
 192  *                            "    bne   2f\n\t"
 193  *                            "    subql #1,%0\n\t"
 194  *                            "    bne   1b\n\t"
 195  *                            "    bra   5f\n\t"
 196  *                            "2:"
 197  *                            "    movel %1@-,d0\n\t"
 198  *                            "    notl  d0\n\t"
 199  *                            "    bfffo d0{#0,#0},%0\n\t"
 200  *                            "5:"
 201  *                            : "=d" (res), "=a" (p)
 202  *                            : "0" ((size + 31) >> 5), "1" (addr)
 203  *                            : "d0");
 204  *      return ((p - addr) << 5) + res;
 205  *}
 206  */
 207 _GLOBAL(find_first_zero_bit)
 208         li      r5,0            /* bit # */
 209         subi    r3,r3,4         /* Adjust pointer for auto-increment */
 210 00:     lwzu    r0,4(r3)        /* Get next word */
 211         not.    r7,r0           /* Complement to find ones */
 212         beq     10f             /* Jump if all ones */
 213 02:     andi.   r7,r0,1         /* Check low-order bit */
 214         beq     20f             /* All done when zero found */
 215         srawi   r0,r0,1
 216         addi    r5,r5,1
 217         b       02b
 218 10:     addi    r5,r5,32        /* Update bit # */
 219         subic.  r4,r4,32        /* Any more? */
 220         bgt     00b
 221 20:     mr      r3,r5           /* Compute result */    
 222         blr
 223  
 224 /*
 225  *static inline int find_next_zero_bit (void *vaddr, int size,
 226  *                                    int offset)
 227  *{
 228  *      unsigned long *addr = vaddr;
 229  *      unsigned long *p = addr + (offset >> 5);
 230  *      int set = 0, bit = offset & 31, res;
 231  *
 232  *      if (bit) {
 233  *              // Look for zero in first longword 
 234  *              __asm__("bfffo %1{#0,#0},%0"
 235  *                      : "=d" (set)
 236  *                      : "d" (~*p << bit));
 237  *              if (set < (32 - bit))
 238  *                      return set + offset;
 239  *                set = 32 - bit;
 240  *              p++;
 241  *      }
 242  *      // No zero yet, search remaining full bytes for a zero 
 243  *      res = find_first_zero_bit (p, size - 32 * (p - addr));
 244  *      return (offset + set + res);
 245  *}
 246  */
 247 _GLOBAL(find_next_zero_bit)
 248         addi    r5,r5,1         /* bump offset to start */
 249         srawi   r6,r5,5         /* word offset */
 250         add     r6,r6,r6        /* byte offset */
 251         add     r6,r6,r6        /* byte offset */
 252         add     r3,r3,r6        /* compute byte position */
 253         sub     r4,r4,r5        /* adjust size by starting index */
 254         andi.   r0,r5,0x1F      /* offset in current word? */
 255         beq     10f             /* at start of word */
 256         lwz     r0,0(r3)        /* get word */
 257         sraw    r0,r0,r5        /* shift right */
 258         not.    r7,r0
 259         beq     07f             /* jump if only ones remain */
 260 05:     andi.   r7,r0,1         /* found zero? */
 261         beq     90f             /* yes - all done */
 262         srawi   r0,r0,1
 263         addi    r5,r5,1
 264         b       05b
 265 07:     andi.   r6,r5,0x1F
 266         subfic  r0,r6,32
 267         add     r5,r5,r0
 268         sub     r4,r4,r0
 269         b       20f
 270 10:     subi    r3,r3,4         /* Adjust pointer for auto-increment */
 271 20:     lwzu    r0,4(r3)        /* Get next word */
 272         not.    r7,r0           /* Complement to find ones */
 273         beq     40f             /* Jump if all ones */
 274 30:     andi.   r7,r0,1         /* Check low-order bit */
 275         beq     90f             /* All done when zero found */
 276         srawi   r0,r0,1
 277         addi    r5,r5,1
 278         b       30b
 279 40:     addi    r5,r5,32        /* Update bit # */
 280         subic.  r4,r4,32        /* Any more? */
 281         bgt     20b
 282 90:     mr      r3,r5           /* Compute result */    
 283         blr
 284  
 285 /*
 286  *
 287  * ffz = Find First Zero in word. Undefined if no zero exists,
 288  * so code should check against ~0UL first..
 289  *
 290  *extern inline unsigned long ffz(unsigned long word)
 291  *{
 292  *      __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
 293  *                            : "=d" (word)
 294  *                            : "d" (~(word)));
 295  *      return word;
 296  *}
 297  */
 298 _GLOBAL(ffz)
 299         mr      r4,r3
 300         li      r3,0
 301 10:     andi.   r0,r4,1         /* Find the zero we know is there */
 302         srawi   r4,r4,1
 303         beq     90f
 304         addi    r3,r3,1
 305         b       10b
 306 90:     blr
 307 
 308 /*
 309  * Extended precision shifts
 310  *
 311  * R3/R4 has 64 bit value
 312  * R5    has shift count
 313  * result in R3/R4
 314  *
 315  *  ashrdi3:     XXXYYY/ZZZAAA -> SSSXXX/YYYZZZ
 316  *  ashldi3:     XXXYYY/ZZZAAA -> YYYZZZ/AAA000
 317  */
 318 _GLOBAL(__ashrdi3)
 319         li      r6,32
 320         sub     r6,r6,r5
 321         slw     r7,r3,r6        /* isolate YYY */
 322         srw     r4,r4,r5        /* isolate ZZZ */
 323         or      r4,r4,r7        /* YYYZZZ */
 324         sraw    r3,r3,r5        /* SSSXXX */
 325         blr
 326         
 327 _GLOBAL(__ashldi3)
 328         li      r6,32
 329         sub     r6,r6,r5
 330         srw     r7,r4,r6        /* isolate ZZZ */
 331         slw     r4,r4,r5        /* AAA000 */
 332         slw     r3,r3,r5        /* YYY--- */
 333         or      r3,r3,r7        /* YYYZZZ */
 334         blr
 335         
 336 _GLOBAL(abort)
 337         .long   0
 338 
 339 _GLOBAL(bzero)
 340 #define bufp r3
 341 #define len  r4
 342 #define pat  r5
 343 /* R3 has buffer */
 344 /* R4 has length */
 345 /* R5 has pattern */
 346         cmpi    0,len,0         /* Exit if len <= 0 */
 347         ble     99f
 348         andi.   r0,bufp,3       /* Must be on longword boundary */
 349         bne     10f             /* Use byte loop if not aligned */
 350         andi.   r0,len,3        /* Check for overrage */
 351         subi    bufp,bufp,4     /* Adjust pointer */
 352         srawi   len,len,2       /* Divide by 4 */
 353         blt     99f             /* If negative - bug out! */
 354         mtspr   CTR,len         /* Set up counter */
 355         li      pat,0
 356 00:     stwu    pat,4(bufp)     /* Store value */
 357         bdnz    00b             /* Loop [based on counter] */
 358         mr      len,r0          /* Get remainder (bytes) */
 359 10:     cmpi    0,len,0         /* Any bytes left */
 360         ble     99f             /* No - all done */
 361         mtspr   CTR,len         /* Set up counter */
 362         subi    bufp,bufp,1     /* Adjust pointer */
 363         li      pat,0
 364 20:     stbu    pat,1(bufp)     /* Store value */
 365         bdnz    20b             /* Loop [based on counter] */
 366 99:     blr
 367 
 368 _GLOBAL(abs)
 369         cmpi    0,r3,0
 370         bge     10f
 371         neg     r3,r3
 372 10:     blr
 373 
 374 /*
 375  * Compute IP checksums
 376  *   _ip_fast_csum(buf, len) -- Optimized for IP header
 377  *   _ip_compute_csum(buf, len)
 378  */
 379 
 380 _GLOBAL(_ip_fast_csum)
 381         li      r0,0
 382         addic   r0,r0,0         /* Clear initial carry */
 383         lwz     r4,0(r3)
 384         lwz     r5,4(r3)
 385         adde    r0,r0,r4
 386         lwz     r4,8(r3)
 387         adde    r0,r0,r5
 388         lwz     r5,12(r3)
 389         adde    r0,r0,r4
 390         lwz     r4,16(r3)
 391         adde    r0,r0,r5
 392         adde    r0,r0,r4
 393         mr      r3,r0
 394         andi.   r3,r3,0xFFFF
 395         srwi    r0,r0,16
 396         adde    r3,r3,r0
 397         andis.  r0,r3,1
 398         beq     10f
 399         addi    r3,r3,1
 400 10:     not     r3,r3
 401         andi.   r3,r3,0xFFFF
 402         blr
 403 
 404 _GLOBAL(_ip_compute_csum)
 405         li      r0,0
 406         addic   r0,r0,0
 407 finish_ip_csum: 
 408         subi    r3,r3,4
 409         andi.   r5,r3,2         /* Align buffer to longword boundary */
 410         beq     10f
 411         lhz     r5,4(r3)
 412         adde    r0,r0,r5
 413         addi    r3,r3,2
 414         subi    r4,r4,2
 415 10:     cmpi    0,r4,16         /* unrolled loop - 16 bytes at a time */
 416         blt     20f
 417         lwz     r5,4(r3)
 418         lwz     r6,8(r3)
 419         adde    r0,r0,r5
 420         lwz     r5,12(r3)
 421         adde    r0,r0,r6
 422         lwzu    r6,16(r3)
 423         adde    r0,r0,r5
 424         adde    r0,r0,r6
 425         subi    r4,r4,16
 426         b       10b
 427 20:     cmpi    0,r4,4
 428         blt     30f
 429         lwzu    r5,4(r3)
 430         adde    r0,r0,r5
 431         subi    r4,r4,4
 432         b       20b
 433 30:     cmpi    0,r4,2
 434         blt     40f
 435         lhz     r5,4(r3)
 436         addi    r3,r3,2
 437         adde    r0,r0,r5
 438         subi    r4,r4,2
 439 40:     cmpi    0,r4,1
 440         bne     50f
 441         lbz     r5,4(r3)
 442         slwi    r5,r5,8         /* Upper byte of word */
 443         adde    r0,r0,r5
 444 50:     mr      r3,r0
 445         andi.   r3,r3,0xFFFF
 446         srwi    r0,r0,16
 447         adde    r3,r3,r0
 448         andis.  r0,r3,1
 449         beq     60f
 450         addi    r3,r3,1
 451 60:     not     r3,r3
 452         andi.   r3,r3,0xFFFF
 453         blr
 454 
 455 _GLOBAL(_udp_check)
 456         addc    r0,r5,r6        /* Add in header fields */
 457         adde    r0,r0,r7
 458         b       finish_ip_csum  
 459 #if 0
 460 _GLOBAL(_tcp_check)
 461         addc    r0,r5,r6        /* Add in header fields */
 462         adde    r0,r0,r7
 463         b       finish_ip_csum  
 464 #endif
 465 _GLOBAL(_get_SP)
 466         mr      r3,r1           /* Close enough */
 467         blr     
 468 
 469 /* Why isn't this a) automatic, b) written in 'C'? */   
 470         .data
 471         .align 4
 472         .globl  sys_call_table
 473 sys_call_table:
 474         .long sys_setup         /* 0 */
 475         .long sys_exit
 476         .long sys_fork
 477         .long sys_read
 478         .long sys_write
 479         .long sys_open                  /* 5 */
 480         .long sys_close
 481         .long sys_waitpid
 482         .long sys_creat
 483         .long sys_link
 484         .long sys_unlink                /* 10 */
 485         .long sys_execve
 486         .long sys_chdir
 487         .long sys_time
 488         .long sys_mknod
 489         .long sys_chmod         /* 15 */
 490         .long sys_chown
 491         .long sys_break
 492         .long sys_stat
 493         .long sys_lseek
 494         .long sys_getpid                /* 20 */
 495         .long sys_mount
 496         .long sys_umount
 497         .long sys_setuid
 498         .long sys_getuid
 499         .long sys_stime         /* 25 */
 500         .long sys_ptrace
 501         .long sys_alarm
 502         .long sys_fstat
 503         .long sys_pause
 504         .long sys_utime         /* 30 */
 505         .long sys_stty
 506         .long sys_gtty
 507         .long sys_access
 508         .long sys_nice
 509         .long sys_ftime         /* 35 */
 510         .long sys_sync
 511         .long sys_kill
 512         .long sys_rename
 513         .long sys_mkdir
 514         .long sys_rmdir         /* 40 */
 515         .long sys_dup
 516         .long sys_pipe
 517         .long sys_times
 518         .long sys_prof
 519         .long sys_brk                   /* 45 */
 520         .long sys_setgid
 521         .long sys_getgid
 522         .long sys_signal
 523         .long sys_geteuid
 524         .long sys_getegid               /* 50 */
 525         .long sys_acct
 526         .long sys_phys
 527         .long sys_lock
 528         .long sys_ioctl
 529         .long sys_fcntl         /* 55 */
 530         .long sys_mpx
 531         .long sys_setpgid
 532         .long sys_ulimit
 533         .long sys_olduname
 534         .long sys_umask         /* 60 */
 535         .long sys_chroot
 536         .long sys_ustat
 537         .long sys_dup2
 538         .long sys_getppid
 539         .long sys_getpgrp               /* 65 */
 540         .long sys_setsid
 541         .long sys_sigaction
 542         .long sys_sgetmask
 543         .long sys_ssetmask
 544         .long sys_setreuid              /* 70 */
 545         .long sys_setregid
 546         .long sys_sigsuspend
 547         .long sys_sigpending
 548         .long sys_sethostname
 549         .long sys_setrlimit             /* 75 */
 550         .long sys_getrlimit
 551         .long sys_getrusage
 552         .long sys_gettimeofday
 553         .long sys_settimeofday
 554         .long sys_getgroups             /* 80 */
 555         .long sys_setgroups
 556         .long sys_select
 557         .long sys_symlink
 558         .long sys_lstat
 559         .long sys_readlink              /* 85 */
 560         .long sys_uselib
 561         .long sys_swapon
 562         .long sys_reboot
 563 /*      .long sys_readdir*/
 564         .long old_readdir
 565         .long sys_mmap                  /* 90 */
 566         .long sys_munmap
 567         .long sys_truncate
 568         .long sys_ftruncate
 569         .long sys_fchmod
 570         .long sys_fchown                /* 95 */
 571         .long sys_getpriority
 572         .long sys_setpriority
 573         .long sys_profil
 574         .long sys_statfs
 575         .long sys_fstatfs               /* 100 */
 576         .long sys_ioperm
 577         .long sys_socketcall
 578         .long sys_syslog
 579         .long sys_setitimer
 580         .long sys_getitimer             /* 105 */
 581         .long sys_newstat
 582         .long sys_newlstat
 583         .long sys_newfstat
 584         .long sys_uname
 585         .long sys_iopl                  /* 110 */
 586         .long sys_vhangup
 587         .long sys_idle
 588         .long sys_vm86
 589         .long sys_wait4
 590         .long sys_swapoff               /* 115 */
 591         .long sys_sysinfo
 592         .long sys_ipc
 593         .long sys_fsync
 594         .long sys_sigreturn
 595         .long sys_clone         /* 120 */
 596         .long sys_setdomainname
 597         .long sys_newuname
 598         .long sys_modify_ldt
 599         .long sys_adjtimex
 600         .long sys_mprotect              /* 125 */
 601         .long sys_sigprocmask
 602         .long sys_create_module
 603         .long sys_init_module
 604         .long sys_delete_module
 605         .long sys_get_kernel_syms       /* 130 */
 606         .long sys_quotactl
 607         .long sys_getpgid
 608         .long sys_fchdir
 609         .long sys_bdflush
 610         .long sys_sysfs         /* 135 */
 611         .long sys_personality
 612         .long 0                         /* for afs_syscall */
 613         .long sys_setfsuid
 614         .long sys_setfsgid
 615         .long sys_llseek                /* 140 */
 616         .long sys_getdents
 617         .long sys_newselect
 618         .long sys_flock
 619         .long sys_msync
 620         .space (NR_syscalls-144)*4
 621 
 622         .data
 623 #if 0
 624         .globl  floppy_track_buffer
 625 floppy_track_buffer:
 626         .space  512*2*38                /* Space for one entire cylinder! */    
 627 #endif

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