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