-/* $Id: entry.S,v 1.18 2004/05/11 12:28:25 starvik Exp $
+/* $Id: entry.S,v 1.28 2005/06/20 05:06:30 starvik Exp $
*
* linux/arch/cris/entry.S
*
* Authors: Bjorn Wesen (bjornw@axis.com)
*
* $Log: entry.S,v $
+ * Revision 1.28 2005/06/20 05:06:30 starvik
+ * Remove unnecessary diff to kernel.org tree
+ *
+ * Revision 1.27 2005/03/04 08:16:16 starvik
+ * Merge of Linux 2.6.11.
+ *
+ * Revision 1.26 2005/01/11 13:49:47 starvik
+ * Added NMI handler.
+ *
+ * Revision 1.25 2004/12/27 11:18:32 starvik
+ * Merge of Linux 2.6.10 (not functional yet).
+ *
+ * Revision 1.24 2004/12/22 10:41:23 starvik
+ * Updates to make v10 compile with the latest SMP aware generic code (even
+ * though v10 will never have SMP).
+ *
+ * Revision 1.23 2004/10/19 13:07:37 starvik
+ * Merge of Linux 2.6.9
+ *
+ * Revision 1.22 2004/06/21 10:29:55 starvik
+ * Merge of Linux 2.6.7
+ *
+ * Revision 1.21 2004/06/09 05:30:27 starvik
+ * Clean up multiple interrupt handling.
+ * Prevent interrupts from interrupting each other.
+ * Handle all active interrupts.
+ *
+ * Revision 1.20 2004/06/08 08:55:32 starvik
+ * Removed unused code
+ *
+ * Revision 1.19 2004/06/04 11:56:15 starvik
+ * Implemented page table lookup for refills in assembler for improved performance.
+ *
* Revision 1.18 2004/05/11 12:28:25 starvik
* Merge of Linux 2.6.6
*
*
*/
-#include <linux/config.h>
#include <linux/linkage.h>
#include <linux/sys.h>
#include <asm/unistd.h>
#include <asm/arch/sv_addr_ag.h>
#include <asm/errno.h>
#include <asm/thread_info.h>
-#include <asm/arch/offset.h>
-
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
;; functions exported from this file
.globl system_call
#ifdef CONFIG_PREEMPT
; Check if preemptive kernel scheduling should be done
_resume_kernel:
+ di
; Load current task struct
movs.w -8192, $r0 ; THREAD_SIZE = 8192
and.d $sp, $r0
bpl _Rexit
nop
; Ok, lets's do some preemptive kernel scheduling
- move.d PREEMPT_ACTIVE, $r10
- move.d $r10, [$r0+TI_preempt_count] ; Mark as active
- ei
- jsr schedule
- clear.d [$r0+TI_preempt_count] ; Mark as inactive
- di
+ jsr preempt_schedule_irq
; Load new task struct
movs.w -8192, $r0 ; THREAD_SIZE = 8192
and.d $sp, $r0
;; It needs to stack the CPU status and overall is different
;; from the other interrupt handlers.
-mmu_bus_fault:
- sbfs [$sp=$sp-16] ; push the internal CPU status
+mmu_bus_fault:
+ ;; For refills we try to do a quick page table lookup. If it is
+ ;; a real fault we let the mm subsystem handle it.
+
;; the first longword in the sbfs frame was the interrupted PC
;; which fits nicely with the "IRP" slot in pt_regs normally used to
- ;; contain the return address. used by Oops to print kernel errors..
+ ;; contain the return address. used by Oops to print kernel errors.
+ sbfs [$sp=$sp-16] ; push the internal CPU status
+ push $dccr
+ di
+ subq 2*4, $sp
+ movem $r1, [$sp]
+ move.d [R_MMU_CAUSE], $r1
+ ;; ETRAX 100LX TR89 bugfix: if the second half of an unaligned
+ ;; write causes a MMU-fault, it will not be restarted correctly.
+ ;; This could happen if a write crosses a page-boundary and the
+ ;; second page is not yet COW'ed or even loaded. The workaround
+ ;; is to clear the unaligned bit in the CPU status record, so
+ ;; that the CPU will rerun both the first and second halves of
+ ;; the instruction. This will not have any sideeffects unless
+ ;; the first half goes to any device or memory that can't be
+ ;; written twice, and which is mapped through the MMU.
+ ;;
+ ;; We only need to do this for writes.
+ btstq 8, $r1 ; Write access?
+ bpl 1f
+ nop
+ move.d [$sp+16], $r0 ; Clear unaligned bit in csrinstr
+ and.d ~(1<<5), $r0
+ move.d $r0, [$sp+16]
+1: btstq 12, $r1 ; Refill?
+ bpl 2f
+ lsrq 24, $r1 ; Get PGD index (bit 24-31)
+ move.d [per_cpu__current_pgd], $r0 ; PGD for the current process
+ move.d [$r0+$r1.d], $r0 ; Get PMD
+ beq 2f
+ nop
+ and.w PAGE_MASK, $r0 ; Remove PMD flags
+ move.d [R_MMU_CAUSE], $r1
+ lsrq PAGE_SHIFT, $r1
+ and.d 0x7ff, $r1 ; Get PTE index into PGD (bit 13-23)
+ move.d [$r0+$r1.d], $r1 ; Get PTE
+ beq 2f
+ nop
+ ;; Store in TLB
+ move.d $r1, [R_TLB_LO]
+ ;; Return
+ movem [$sp+], $r1
+ pop $dccr
+ rbf [$sp+] ; return by popping the CPU status
+
+2: ; PMD or PTE missing, let the mm subsystem fix it up.
+ movem [$sp+], $r1
+ pop $dccr
+
+ ; Ok, not that easy, pass it on to the mm subsystem
+ ; The MMU status record is now on the stack
push $srp ; make a stackframe similar to pt_regs
push $dccr
push $mof
move.d $sp, $r10 ; pt_regs argument to handle_mmu_bus_fault
- jsr handle_mmu_bus_fault ; in arch/cris/mm/fault.c
+ jsr handle_mmu_bus_fault ; in arch/cris/arch-v10/mm/fault.c
;; now we need to return through the normal path, we cannot just
;; do the RBFexit since we might have killed off the running
nop
;; special handlers for breakpoint and NMI
-#if 0
hwbreakpoint:
push $dccr
di
- push $r10
- push $r11
- push $r12
- push $r13
- clearf b
- move $brp,$r11
- move.d [hw_bp_msg],$r10
- jsr printk
- setf b
- pop $r13
- pop $r12
- pop $r11
- pop $r10
- pop $dccr
- retb
- nop
-#else
-hwbreakpoint:
- push $dccr
- di
-#if 1
push $r10
push $r11
move.d [hw_bp_trig_ptr],$r10
- move.d [$r10],$r11
- cmp.d 42,$r11
- beq 1f
- nop
move $brp,$r11
move.d $r11,[$r10+]
move.d $r10,[hw_bp_trig_ptr]
1: pop $r11
pop $r10
-#endif
pop $dccr
retb
nop
-#endif
IRQ1_interrupt:
-
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
-;; If we receive a watchdog interrupt while it is not expected, then set
-;; up a canonical frame and dump register contents before dying.
-
;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
move $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
push $srp
push $r10 ; push orig_r10
clear.d [$sp=$sp-4] ; frametype == 0, normal frame
-;; We don't check that we actually were bit by the watchdog as opposed to
-;; an external NMI, since there is currently no handler for external NMI.
-
+ move.d [R_IRQ_MASK0_RD], $r1 ; External NMI or watchdog?
+ and.d 0x80000000, $r1
+ beq wdog
+ move.d $sp, $r10
+ jsr handle_nmi
+ setf m ; Enable NMI again
+ retb ; Return from NMI
+ nop
+wdog:
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
;; Check if we're waiting for reset to happen, as signalled by
;; hard_reset_now setting cause_of_death to a magic value. If so, just
;; get stuck until reset happens.
push $r10 ; push orig_r10
clear.d [$sp=$sp-4] ; frametype == 0, normal frame
- move.d irq_shortcuts + 8, $r1
moveq 2, $r2 ; first bit we care about is the timer0 irq
move.d [R_VECT_MASK_RD], $r0; read the irq bits that triggered the multiple irq
+ move.d $r0, [R_VECT_MASK_CLR] ; Block all active IRQs
1:
btst $r2, $r0 ; check for the irq given by bit r2
- bmi _do_shortcut ; actually do the shortcut
- nop
+ bpl 2f
+ move.d $r2, $r10 ; First argument to do_IRQ
+ move.d $sp, $r11 ; second argument to do_IRQ
+ jsr do_IRQ
+2:
addq 1, $r2 ; next vector bit
- addq 4, $r1 ; next vector
cmp.b 32, $r2
bne 1b ; process all irq's up to and including number 31
- nop
-
- ;; strange, we didn't get any set vector bits.. oh well, just return
+ moveq 0, $r9 ; make ret_from_intr realise we came from an ir
- ba _Rexit
- nop
-
-_do_shortcut:
- test.d [$r1]
- beq _Rexit
- nop
- jump [$r1] ; jump to the irq handlers shortcut
+ move.d $r0, [R_VECT_MASK_SET] ; Unblock all the IRQs
+ jump ret_from_intr
do_sigtrap:
;;
.long sys_mq_timedreceive /* 280 */
.long sys_mq_notify
.long sys_mq_getsetattr
-
+ .long sys_ni_syscall /* reserved for kexec */
+ .long sys_waitid
+ .long sys_ni_syscall /* 285 */ /* available */
+ .long sys_add_key
+ .long sys_request_key
+ .long sys_keyctl
+
/*
* NOTE!! This doesn't have to be exact - we just have
* to make sure we have _enough_ of the "sys_ni_syscall"