Commit 6410393a authored by Mikael Starvik's avatar Mikael Starvik Committed by Linus Torvalds

[PATCH] CRIS: Core kernel updates

Added profiler.
Optimized MMU refill handling.
Improved multiple interrupt handling.
Signed-off-by: default avatarMikael Starvik <starvik@axis.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 574f1884
#include <linux/config.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/arch/svinto.h>
/* Export shadow registers for the CPU I/O pins */
EXPORT_SYMBOL(genconfig_shadow);
EXPORT_SYMBOL(port_pa_data_shadow);
EXPORT_SYMBOL(port_pa_dir_shadow);
EXPORT_SYMBOL(port_pb_data_shadow);
EXPORT_SYMBOL(port_pb_dir_shadow);
EXPORT_SYMBOL(port_pb_config_shadow);
EXPORT_SYMBOL(port_g_data_shadow);
/* Cache flush functions */
EXPORT_SYMBOL(flush_etrax_cache);
EXPORT_SYMBOL(prepare_rx_descriptor);
/* $Id: entry.S,v 1.18 2004/05/11 12:28:25 starvik Exp $ /* $Id: entry.S,v 1.23 2004/10/19 13:07:37 starvik Exp $
* *
* linux/arch/cris/entry.S * linux/arch/cris/entry.S
* *
...@@ -7,6 +7,23 @@ ...@@ -7,6 +7,23 @@
* Authors: Bjorn Wesen (bjornw@axis.com) * Authors: Bjorn Wesen (bjornw@axis.com)
* *
* $Log: entry.S,v $ * $Log: entry.S,v $
* 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 * Revision 1.18 2004/05/11 12:28:25 starvik
* Merge of Linux 2.6.6 * Merge of Linux 2.6.6
* *
...@@ -238,6 +255,8 @@ ...@@ -238,6 +255,8 @@
#include <asm/errno.h> #include <asm/errno.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
#include <asm/arch/offset.h> #include <asm/arch/offset.h>
#include <asm/page.h>
#include <asm/pgtable.h>
;; functions exported from this file ;; functions exported from this file
...@@ -540,10 +559,62 @@ resume: ...@@ -540,10 +559,62 @@ resume:
;; from the other interrupt handlers. ;; from the other interrupt handlers.
mmu_bus_fault: mmu_bus_fault:
sbfs [$sp=$sp-16] ; push the internal CPU status ;; 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 ;; the first longword in the sbfs frame was the interrupted PC
;; which fits nicely with the "IRP" slot in pt_regs normally used to ;; 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 PMD_SHIFT, $r1 ; Get PMD index into PGD (bit 24-31)
move.d [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 PMD (bit 13-24)
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 $srp ; make a stackframe similar to pt_regs
push $dccr push $dccr
push $mof push $mof
...@@ -556,7 +627,7 @@ mmu_bus_fault: ...@@ -556,7 +627,7 @@ mmu_bus_fault:
move.d $sp, $r10 ; pt_regs argument to handle_mmu_bus_fault 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 ;; now we need to return through the normal path, we cannot just
;; do the RBFexit since we might have killed off the running ;; do the RBFexit since we might have killed off the running
...@@ -569,48 +640,20 @@ mmu_bus_fault: ...@@ -569,48 +640,20 @@ mmu_bus_fault:
nop nop
;; special handlers for breakpoint and NMI ;; 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: hwbreakpoint:
push $dccr push $dccr
di di
#if 1
push $r10 push $r10
push $r11 push $r11
move.d [hw_bp_trig_ptr],$r10 move.d [hw_bp_trig_ptr],$r10
move.d [$r10],$r11
cmp.d 42,$r11
beq 1f
nop
move $brp,$r11 move $brp,$r11
move.d $r11,[$r10+] move.d $r11,[$r10+]
move.d $r10,[hw_bp_trig_ptr] move.d $r10,[hw_bp_trig_ptr]
1: pop $r11 1: pop $r11
pop $r10 pop $r10
#endif
pop $dccr pop $dccr
retb retb
nop nop
#endif
IRQ1_interrupt: IRQ1_interrupt:
...@@ -719,29 +762,23 @@ multiple_interrupt: ...@@ -719,29 +762,23 @@ multiple_interrupt:
push $r10 ; push orig_r10 push $r10 ; push orig_r10
clear.d [$sp=$sp-4] ; frametype == 0, normal frame 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 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 [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: 1:
btst $r2, $r0 ; check for the irq given by bit r2 btst $r2, $r0 ; check for the irq given by bit r2
bmi _do_shortcut ; actually do the shortcut bpl 2f
nop 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 1, $r2 ; next vector bit
addq 4, $r1 ; next vector
cmp.b 32, $r2 cmp.b 32, $r2
bne 1b ; process all irq's up to and including number 31 bne 1b ; process all irq's up to and including number 31
nop moveq 0, $r9 ; make ret_from_intr realise we came from an ir
;; strange, we didn't get any set vector bits.. oh well, just return
ba _Rexit move.d $r0, [R_VECT_MASK_SET] ; Unblock all the IRQs
nop jump ret_from_intr
_do_shortcut:
test.d [$r1]
beq _Rexit
nop
jump [$r1] ; jump to the irq handlers shortcut
do_sigtrap: do_sigtrap:
;; ;;
...@@ -1079,6 +1116,8 @@ sys_call_table: ...@@ -1079,6 +1116,8 @@ sys_call_table:
.long sys_mq_timedreceive /* 280 */ .long sys_mq_timedreceive /* 280 */
.long sys_mq_notify .long sys_mq_notify
.long sys_mq_getsetattr .long sys_mq_getsetattr
.long sys_ni_syscall /* reserved for kexec */
.long sys_waitid
/* /*
* NOTE!! This doesn't have to be exact - we just have * NOTE!! This doesn't have to be exact - we just have
......
/* $Id: irq.c,v 1.1 2002/12/11 15:42:02 starvik Exp $ /* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $
* *
* linux/arch/cris/kernel/irq.c * linux/arch/cris/kernel/irq.c
* *
...@@ -23,12 +23,8 @@ irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq pro ...@@ -23,12 +23,8 @@ irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq pro
*/ */
void void
set_int_vector(int n, irqvectptr addr, irqvectptr saddr) set_int_vector(int n, irqvectptr addr)
{ {
/* remember the shortcut entry point, after the prologue */
irq_shortcuts[n] = saddr;
etrax_irv->v[n + 0x20] = (irqvectptr)addr; etrax_irv->v[n + 0x20] = (irqvectptr)addr;
} }
...@@ -106,17 +102,6 @@ static void (*interrupt[NR_IRQS])(void) = { ...@@ -106,17 +102,6 @@ static void (*interrupt[NR_IRQS])(void) = {
IRQ31_interrupt IRQ31_interrupt
}; };
static void (*sinterrupt[NR_IRQS])(void) = {
NULL, NULL, sIRQ2_interrupt, sIRQ3_interrupt,
sIRQ4_interrupt, sIRQ5_interrupt, sIRQ6_interrupt, sIRQ7_interrupt,
sIRQ8_interrupt, sIRQ9_interrupt, sIRQ10_interrupt, sIRQ11_interrupt,
sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL,
sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt,
sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt,
sIRQ24_interrupt, sIRQ25_interrupt, NULL, NULL, NULL, NULL, NULL,
sIRQ31_interrupt
};
static void (*bad_interrupt[NR_IRQS])(void) = { static void (*bad_interrupt[NR_IRQS])(void) = {
NULL, NULL, NULL, NULL,
NULL, bad_IRQ3_interrupt, NULL, bad_IRQ3_interrupt,
...@@ -137,12 +122,12 @@ static void (*bad_interrupt[NR_IRQS])(void) = { ...@@ -137,12 +122,12 @@ static void (*bad_interrupt[NR_IRQS])(void) = {
void arch_setup_irq(int irq) void arch_setup_irq(int irq)
{ {
set_int_vector(irq, interrupt[irq], sinterrupt[irq]); set_int_vector(irq, interrupt[irq]);
} }
void arch_free_irq(int irq) void arch_free_irq(int irq)
{ {
set_int_vector(irq, bad_interrupt[irq], 0); set_int_vector(irq, bad_interrupt[irq]);
} }
void weird_irq(void); void weird_irq(void);
...@@ -187,20 +172,20 @@ init_IRQ(void) ...@@ -187,20 +172,20 @@ init_IRQ(void)
/* set all etrax irq's to the bad handlers */ /* set all etrax irq's to the bad handlers */
for (i = 2; i < NR_IRQS; i++) for (i = 2; i < NR_IRQS; i++)
set_int_vector(i, bad_interrupt[i], 0); set_int_vector(i, bad_interrupt[i]);
/* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
set_int_vector(15, multiple_interrupt, 0); set_int_vector(15, multiple_interrupt);
/* 0 and 1 which are special breakpoint/NMI traps */ /* 0 and 1 which are special breakpoint/NMI traps */
set_int_vector(0, hwbreakpoint, 0); set_int_vector(0, hwbreakpoint);
set_int_vector(1, IRQ1_interrupt, 0); set_int_vector(1, IRQ1_interrupt);
/* and irq 14 which is the mmu bus fault handler */ /* and irq 14 which is the mmu bus fault handler */
set_int_vector(14, mmu_bus_fault, 0); set_int_vector(14, mmu_bus_fault);
/* setup the system-call trap, which is reached by BREAK 13 */ /* setup the system-call trap, which is reached by BREAK 13 */
......
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
*! Jul 21 1999 Bjorn Wesen eLinux port *! Jul 21 1999 Bjorn Wesen eLinux port
*! *!
*! $Log: kgdb.c,v $ *! $Log: kgdb.c,v $
*! Revision 1.5 2004/10/07 13:59:08 starvik
*! Corrected call to set_int_vector
*!
*! Revision 1.4 2003/04/09 05:20:44 starvik *! Revision 1.4 2003/04/09 05:20:44 starvik
*! Merge of Linux 2.5.67 *! Merge of Linux 2.5.67
*! *!
...@@ -68,7 +71,7 @@ ...@@ -68,7 +71,7 @@
*! *!
*!--------------------------------------------------------------------------- *!---------------------------------------------------------------------------
*! *!
*! $Id: kgdb.c,v 1.4 2003/04/09 05:20:44 starvik Exp $ *! $Id: kgdb.c,v 1.5 2004/10/07 13:59:08 starvik Exp $
*! *!
*! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
*! *!
...@@ -1557,7 +1560,7 @@ kgdb_init(void) ...@@ -1557,7 +1560,7 @@ kgdb_init(void)
/* could initialize debug port as well but it's done in head.S already... */ /* could initialize debug port as well but it's done in head.S already... */
/* breakpoint handler is now set in irq.c */ /* breakpoint handler is now set in irq.c */
set_int_vector(8, kgdb_handle_serial, 0); set_int_vector(8, kgdb_handle_serial);
enableDebugIRQ(); enableDebugIRQ();
} }
......
/* $Id: process.c,v 1.6 2004/05/11 12:28:25 starvik Exp $ /* $Id: process.c,v 1.9 2004/10/19 13:07:37 starvik Exp $
* *
* linux/arch/cris/kernel/process.c * linux/arch/cris/kernel/process.c
* *
...@@ -34,6 +34,15 @@ void default_idle(void) ...@@ -34,6 +34,15 @@ void default_idle(void)
#endif #endif
} }
/*
* Free current thread data structures etc..
*/
void exit_thread(void)
{
/* Nothing needs to be done. */
}
/* if the watchdog is enabled, we can simply disable interrupts and go /* if the watchdog is enabled, we can simply disable interrupts and go
* into an eternal loop, and the watchdog will reset the CPU after 0.1s * into an eternal loop, and the watchdog will reset the CPU after 0.1s
* if on the other hand the watchdog wasn't enabled, we just enable it and wait * if on the other hand the watchdog wasn't enabled, we just enable it and wait
...@@ -122,6 +131,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, ...@@ -122,6 +131,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
*childregs = *regs; /* struct copy of pt_regs */ *childregs = *regs; /* struct copy of pt_regs */
p->set_child_tid = p->clear_child_tid = NULL;
childregs->r10 = 0; /* child returns 0 after a fork/clone */ childregs->r10 = 0; /* child returns 0 after a fork/clone */
/* put the switch stack right below the pt_regs */ /* put the switch stack right below the pt_regs */
...@@ -212,13 +223,6 @@ asmlinkage int sys_execve(const char *fname, char **argv, char **envp, ...@@ -212,13 +223,6 @@ asmlinkage int sys_execve(const char *fname, char **argv, char **envp,
return error; return error;
} }
/*
* These bracket the sleeping functions..
*/
#define first_sched ((unsigned long)__sched_text_start)
#define last_sched ((unsigned long)__sched_text_end)
unsigned long get_wchan(struct task_struct *p) unsigned long get_wchan(struct task_struct *p)
{ {
#if 0 #if 0
...@@ -239,7 +243,7 @@ unsigned long get_wchan(struct task_struct *p) ...@@ -239,7 +243,7 @@ unsigned long get_wchan(struct task_struct *p)
if (ebp < stack_page || ebp > 8184+stack_page) if (ebp < stack_page || ebp > 8184+stack_page)
return 0; return 0;
eip = *(unsigned long *) (ebp+4); eip = *(unsigned long *) (ebp+4);
if (eip < first_sched || eip >= last_sched) if (!in_sched_functions(eip))
return eip; return eip;
ebp = *(unsigned long *) ebp; ebp = *(unsigned long *) ebp;
} while (count++ < 16); } while (count++ < 16);
......
...@@ -23,8 +23,37 @@ ...@@ -23,8 +23,37 @@
*/ */
#define DCCR_MASK 0x0000001f /* XNZVC */ #define DCCR_MASK 0x0000001f /* XNZVC */
extern inline long get_reg(struct task_struct *, unsigned int); /*
extern inline long put_reg(struct task_struct *, unsigned int, unsigned long); * Get contents of register REGNO in task TASK.
*/
inline long get_reg(struct task_struct *task, unsigned int regno)
{
/* USP is a special case, it's not in the pt_regs struct but
* in the tasks thread struct
*/
if (regno == PT_USP)
return task->thread.usp;
else if (regno < PT_MAX)
return ((unsigned long *)user_regs(task->thread_info))[regno];
else
return 0;
}
/*
* Write contents of register REGNO in task TASK.
*/
inline int put_reg(struct task_struct *task, unsigned int regno,
unsigned long data)
{
if (regno == PT_USP)
task->thread.usp = data;
else if (regno < PT_MAX)
((unsigned long *)user_regs(task->thread_info))[regno] = data;
else
return -1;
return 0;
}
/* /*
* Called by kernel/ptrace.c when detaching. * Called by kernel/ptrace.c when detaching.
...@@ -50,6 +79,7 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -50,6 +79,7 @@ sys_ptrace(long request, long pid, long addr, long data)
{ {
struct task_struct *child; struct task_struct *child;
int ret; int ret;
unsigned long __user *datap = (unsigned long __user *)data;
lock_kernel(); lock_kernel();
ret = -EPERM; ret = -EPERM;
...@@ -102,7 +132,7 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -102,7 +132,7 @@ sys_ptrace(long request, long pid, long addr, long data)
if (copied != sizeof(tmp)) if (copied != sizeof(tmp))
break; break;
ret = put_user(tmp,(unsigned long *) data); ret = put_user(tmp,datap);
break; break;
} }
...@@ -115,7 +145,7 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -115,7 +145,7 @@ sys_ptrace(long request, long pid, long addr, long data)
break; break;
tmp = get_reg(child, addr >> 2); tmp = get_reg(child, addr >> 2);
ret = put_user(tmp, (unsigned long *)data); ret = put_user(tmp, datap);
break; break;
} }
...@@ -176,7 +206,7 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -176,7 +206,7 @@ sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_KILL: case PTRACE_KILL:
ret = 0; ret = 0;
if (child->exit_state == EXIT_ZOMBIE) if (child->state == TASK_ZOMBIE)
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
...@@ -213,7 +243,7 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -213,7 +243,7 @@ sys_ptrace(long request, long pid, long addr, long data)
for (i = 0; i <= PT_MAX; i++) { for (i = 0; i <= PT_MAX; i++) {
tmp = get_reg(child, i); tmp = get_reg(child, i);
if (put_user(tmp, (unsigned long *) data)) { if (put_user(tmp, datap)) {
ret = -EFAULT; ret = -EFAULT;
goto out_tsk; goto out_tsk;
} }
...@@ -231,7 +261,7 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -231,7 +261,7 @@ sys_ptrace(long request, long pid, long addr, long data)
unsigned long tmp; unsigned long tmp;
for (i = 0; i <= PT_MAX; i++) { for (i = 0; i <= PT_MAX; i++) {
if (get_user(tmp, (unsigned long *) data)) { if (get_user(tmp, datap)) {
ret = -EFAULT; ret = -EFAULT;
goto out_tsk; goto out_tsk;
} }
......
...@@ -264,7 +264,6 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, ...@@ -264,7 +264,6 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
{ {
struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp(); struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp();
sigset_t set; sigset_t set;
stack_t st;
/* /*
* Since we stacked the signal on a dword boundary, * Since we stacked the signal on a dword boundary,
...@@ -288,11 +287,8 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, ...@@ -288,11 +287,8 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe; goto badframe;
if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
goto badframe; goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
do_sigaltstack(&st, NULL, rdusp());
return regs->r10; return regs->r10;
...@@ -388,9 +384,9 @@ static void setup_frame(int sig, struct k_sigaction *ka, ...@@ -388,9 +384,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
/* trampoline - the desired return ip is the retcode itself */ /* trampoline - the desired return ip is the retcode itself */
return_ip = (unsigned long)&frame->retcode; return_ip = (unsigned long)&frame->retcode;
/* This is movu.w __NR_sigreturn, r9; break 13; */ /* This is movu.w __NR_sigreturn, r9; break 13; */
err |= __put_user(0x9c5f, (short *)(frame->retcode+0)); err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0));
err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2)); err |= __put_user(__NR_sigreturn, (short __user*)(frame->retcode+2));
err |= __put_user(0xe93d, (short *)(frame->retcode+4)); err |= __put_user(0xe93d, (short __user*)(frame->retcode+4));
} }
if (err) if (err)
...@@ -448,9 +444,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -448,9 +444,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* trampoline - the desired return ip is the retcode itself */ /* trampoline - the desired return ip is the retcode itself */
return_ip = (unsigned long)&frame->retcode; return_ip = (unsigned long)&frame->retcode;
/* This is movu.w __NR_rt_sigreturn, r9; break 13; */ /* This is movu.w __NR_rt_sigreturn, r9; break 13; */
err |= __put_user(0x9c5f, (short *)(frame->retcode+0)); err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0));
err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode+2)); err |= __put_user(__NR_rt_sigreturn, (short __user*)(frame->retcode+2));
err |= __put_user(0xe93d, (short *)(frame->retcode+4)); err |= __put_user(0xe93d, (short __user*)(frame->retcode+4));
} }
if (err) if (err)
...@@ -482,10 +478,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -482,10 +478,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
extern inline void extern inline void
handle_signal(int canrestart, unsigned long sig, handle_signal(int canrestart, unsigned long sig,
siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs * regs)
{ {
struct k_sigaction *ka = &current->sighand->action[sig-1];
/* Are we from a system call? */ /* Are we from a system call? */
if (canrestart) { if (canrestart) {
/* If so, check system call restarting.. */ /* If so, check system call restarting.. */
...@@ -547,6 +542,7 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) ...@@ -547,6 +542,7 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
{ {
siginfo_t info; siginfo_t info;
int signr; int signr;
struct k_sigaction ka;
/* /*
* We want the common case to go fast, which * We want the common case to go fast, which
...@@ -560,10 +556,10 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) ...@@ -560,10 +556,10 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
if (!oldset) if (!oldset)
oldset = &current->blocked; oldset = &current->blocked;
signr = get_signal_to_deliver(&info, regs, NULL); signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) { if (signr > 0) {
/* Whee! Actually deliver the signal. */ /* Whee! Actually deliver the signal. */
handle_signal(canrestart, signr, &info, oldset, regs); handle_signal(canrestart, signr, &info, &ka, oldset, regs);
return 1; return 1;
} }
......
/* $Id: time.c,v 1.3 2004/06/01 05:38:42 starvik Exp $ /* $Id: time.c,v 1.5 2004/09/29 06:12:46 starvik Exp $
* *
* linux/arch/cris/arch-v10/kernel/time.c * linux/arch/cris/arch-v10/kernel/time.c
* *
...@@ -200,6 +200,8 @@ static long last_rtc_update = 0; ...@@ -200,6 +200,8 @@ static long last_rtc_update = 0;
//static unsigned short myjiff; /* used by our debug routine print_timestamp */ //static unsigned short myjiff; /* used by our debug routine print_timestamp */
extern void cris_do_profile(struct pt_regs *regs);
static inline irqreturn_t static inline irqreturn_t
timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
...@@ -227,9 +229,8 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -227,9 +229,8 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* call the real timer interrupt handler */ /* call the real timer interrupt handler */
do_timer(regs); do_timer(regs);
#ifndef CONFIG_SMP
update_process_times(user_mode(regs)); cris_do_profile(regs); /* Save profiling information */
#endif
/* /*
* If we have an externally synchronized Linux clock, then update * If we have an externally synchronized Linux clock, then update
......
...@@ -40,23 +40,25 @@ void ...@@ -40,23 +40,25 @@ void
handle_mmu_bus_fault(struct pt_regs *regs) handle_mmu_bus_fault(struct pt_regs *regs)
{ {
int cause; int cause;
#ifdef DEBUG
int select; int select;
#ifdef DEBUG
int index; int index;
int page_id; int page_id;
int acc, inv; int acc, inv;
#endif #endif
int miss, we, writeac; pgd_t* pgd = (pgd_t*)current_pgd;
pmd_t *pmd; pmd_t *pmd;
pte_t pte; pte_t pte;
int miss, we, writeac;
unsigned long address; unsigned long address;
unsigned long flags;
cause = *R_MMU_CAUSE; cause = *R_MMU_CAUSE;
address = cause & PAGE_MASK; /* get faulting address */ address = cause & PAGE_MASK; /* get faulting address */
select = *R_TLB_SELECT;
#ifdef DEBUG #ifdef DEBUG
select = *R_TLB_SELECT;
page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause);
acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause);
inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause);
...@@ -66,85 +68,31 @@ handle_mmu_bus_fault(struct pt_regs *regs) ...@@ -66,85 +68,31 @@ handle_mmu_bus_fault(struct pt_regs *regs)
we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause);
writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause); writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause);
/* 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.
*/
if(writeac)
regs->csrinstr &= ~(1 << 5);
D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n", D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
regs->irp, address, miss, inv, we, acc, index, page_id)); regs->irp, address, miss, inv, we, acc, index, page_id));
/* for a miss, we need to reload the TLB entry */ /* leave it to the MM system fault handler */
if (miss)
do_page_fault(address, regs, 0, writeac);
else
do_page_fault(address, regs, 1, we);
if (miss) { /* Reload TLB with new entry to avoid an extra miss exception.
/* see if the pte exists at all * do_page_fault may have flushed the TLB so we have to restore
* refer through current_pgd, dont use mm->pgd * the MMU registers.
*/ */
local_save_flags(flags);
pmd = (pmd_t *)(current_pgd + pgd_index(address)); local_irq_disable();
if (pmd_none(*pmd)) { pmd = (pmd_t *)(pgd + pgd_index(address));
do_page_fault(address, regs, 0, writeac); if (pmd_none(*pmd))
return;
}
if (pmd_bad(*pmd)) {
printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd);
pmd_clear(pmd);
return; return;
}
pte = *pte_offset_kernel(pmd, address); pte = *pte_offset_kernel(pmd, address);
if (!pte_present(pte)) { if (!pte_present(pte))
do_page_fault(address, regs, 0, writeac);
return; return;
} *R_TLB_SELECT = select;
*R_TLB_HI = cause;
#ifdef DEBUG
printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte));
if (pte_val(pte) & _PAGE_SILENT_WRITE)
printk("Silent-W ");
if (pte_val(pte) & _PAGE_KERNEL)
printk("Kernel ");
if (pte_val(pte) & _PAGE_SILENT_READ)
printk("Silent-R ");
if (pte_val(pte) & _PAGE_GLOBAL)
printk("Global ");
if (pte_val(pte) & _PAGE_PRESENT)
printk("Present ");
if (pte_val(pte) & _PAGE_ACCESSED)
printk("Accessed ");
if (pte_val(pte) & _PAGE_MODIFIED)
printk("Modified ");
if (pte_val(pte) & _PAGE_READ)
printk("Readable ");
if (pte_val(pte) & _PAGE_WRITE)
printk("Writeable ");
printk("\n");
#endif
/* load up the chosen TLB entry
* this assumes the pte format is the same as the TLB_LO layout.
*
* the write to R_TLB_LO also writes the vpn and page_id fields from
* R_MMU_CAUSE, which we in this case obviously want to keep
*/
*R_TLB_LO = pte_val(pte); *R_TLB_LO = pte_val(pte);
local_irq_restore(flags);
return;
}
/* leave it to the MM system fault handler */
do_page_fault(address, regs, 1, we);
} }
/* Called from arch/cris/mm/fault.c to find fixup code. */ /* Called from arch/cris/mm/fault.c to find fixup code. */
......
...@@ -65,7 +65,7 @@ void ...@@ -65,7 +65,7 @@ void
flush_tlb_mm(struct mm_struct *mm) flush_tlb_mm(struct mm_struct *mm)
{ {
int i; int i;
int page_id = mm->context; int page_id = mm->context.page_id;
unsigned long flags; unsigned long flags;
D(printk("tlb: flush mm context %d (%p)\n", page_id, mm)); D(printk("tlb: flush mm context %d (%p)\n", page_id, mm));
...@@ -103,7 +103,7 @@ flush_tlb_page(struct vm_area_struct *vma, ...@@ -103,7 +103,7 @@ flush_tlb_page(struct vm_area_struct *vma,
unsigned long addr) unsigned long addr)
{ {
struct mm_struct *mm = vma->vm_mm; struct mm_struct *mm = vma->vm_mm;
int page_id = mm->context; int page_id = mm->context.page_id;
int i; int i;
unsigned long flags; unsigned long flags;
...@@ -147,7 +147,7 @@ flush_tlb_range(struct vm_area_struct *vma, ...@@ -147,7 +147,7 @@ flush_tlb_range(struct vm_area_struct *vma,
unsigned long end) unsigned long end)
{ {
struct mm_struct *mm = vma->vm_mm; struct mm_struct *mm = vma->vm_mm;
int page_id = mm->context; int page_id = mm->context.page_id;
int i; int i;
unsigned long flags; unsigned long flags;
...@@ -208,6 +208,18 @@ dump_tlb_all(void) ...@@ -208,6 +208,18 @@ dump_tlb_all(void)
} }
#endif #endif
/*
* Initialize the context related info for a new mm_struct
* instance.
*/
int
init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
mm->context.page_id = NO_CONTEXT;
return 0;
}
/* called in schedule() just before actually doing the switch_to */ /* called in schedule() just before actually doing the switch_to */
void void
...@@ -231,6 +243,6 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, ...@@ -231,6 +243,6 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
D(printk("switching mmu_context to %d (%p)\n", next->context, next)); D(printk("switching mmu_context to %d (%p)\n", next->context, next));
*R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context); *R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context.page_id);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment