diff options
author | Ley Foon Tan <lftan@altera.com> | 2014-11-06 02:19:47 -0500 |
---|---|---|
committer | Ley Foon Tan <lftan@altera.com> | 2014-12-07 23:55:53 -0500 |
commit | 71995e4d004f6afbc86cc4a80c4a281f6c00b07f (patch) | |
tree | 68139e7bb9dfee02e23384224e2fa20082e55653 | |
parent | cbd15b3fadc27e81a6e8a3d38ce13cde5ce7cb71 (diff) |
nios2: Process management
This patch adds support for thread creation and context switching.
Signed-off-by: Ley Foon Tan <lftan@altera.com>
-rw-r--r-- | arch/nios2/include/asm/mmu_context.h | 66 | ||||
-rw-r--r-- | arch/nios2/include/asm/processor.h | 103 | ||||
-rw-r--r-- | arch/nios2/include/asm/switch_to.h | 31 | ||||
-rw-r--r-- | arch/nios2/include/asm/thread_info.h | 120 | ||||
-rw-r--r-- | arch/nios2/kernel/process.c | 258 | ||||
-rw-r--r-- | arch/nios2/mm/mmu_context.c | 116 |
6 files changed, 694 insertions, 0 deletions
diff --git a/arch/nios2/include/asm/mmu_context.h b/arch/nios2/include/asm/mmu_context.h new file mode 100644 index 000000000000..294b4b1f81d4 --- /dev/null +++ b/arch/nios2/include/asm/mmu_context.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> | ||
3 | * Copyright (C) 1996, 1997, 1998, 1999 by Ralf Baechle | ||
4 | * Copyright (C) 1999 Silicon Graphics, Inc. | ||
5 | * | ||
6 | * based on MIPS asm/mmu_context.h | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | |||
13 | #ifndef _ASM_NIOS2_MMU_CONTEXT_H | ||
14 | #define _ASM_NIOS2_MMU_CONTEXT_H | ||
15 | |||
16 | #include <asm-generic/mm_hooks.h> | ||
17 | |||
18 | extern void mmu_context_init(void); | ||
19 | extern unsigned long get_pid_from_context(mm_context_t *ctx); | ||
20 | |||
21 | /* | ||
22 | * For the fast tlb miss handlers, we keep a pointer to the current pgd. | ||
23 | * processor. | ||
24 | */ | ||
25 | extern pgd_t *pgd_current; | ||
26 | |||
27 | static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) | ||
28 | { | ||
29 | } | ||
30 | |||
31 | /* | ||
32 | * Initialize the context related info for a new mm_struct instance. | ||
33 | * | ||
34 | * Set all new contexts to 0, that way the generation will never match | ||
35 | * the currently running generation when this context is switched in. | ||
36 | */ | ||
37 | static inline int init_new_context(struct task_struct *tsk, | ||
38 | struct mm_struct *mm) | ||
39 | { | ||
40 | mm->context = 0; | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | /* | ||
45 | * Destroy context related info for an mm_struct that is about | ||
46 | * to be put to rest. | ||
47 | */ | ||
48 | static inline void destroy_context(struct mm_struct *mm) | ||
49 | { | ||
50 | } | ||
51 | |||
52 | void switch_mm(struct mm_struct *prev, struct mm_struct *next, | ||
53 | struct task_struct *tsk); | ||
54 | |||
55 | static inline void deactivate_mm(struct task_struct *tsk, | ||
56 | struct mm_struct *mm) | ||
57 | { | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * After we have set current->mm to a new value, this activates | ||
62 | * the context for the new mm so we see the new mappings. | ||
63 | */ | ||
64 | void activate_mm(struct mm_struct *prev, struct mm_struct *next); | ||
65 | |||
66 | #endif /* _ASM_NIOS2_MMU_CONTEXT_H */ | ||
diff --git a/arch/nios2/include/asm/processor.h b/arch/nios2/include/asm/processor.h new file mode 100644 index 000000000000..3bd349473b06 --- /dev/null +++ b/arch/nios2/include/asm/processor.h | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Altera Corporation | ||
3 | * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> | ||
4 | * Copyright (C) 2004 Microtronix Datacom Ltd | ||
5 | * Copyright (C) 2001 Ken Hill (khill@microtronix.com) | ||
6 | * Vic Phillips (vic@microtronix.com) | ||
7 | * | ||
8 | * based on SPARC asm/processor_32.h which is: | ||
9 | * | ||
10 | * Copyright (C) 1994 David S. Miller | ||
11 | * | ||
12 | * This file is subject to the terms and conditions of the GNU General Public | ||
13 | * License. See the file "COPYING" in the main directory of this archive | ||
14 | * for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef _ASM_NIOS2_PROCESSOR_H | ||
18 | #define _ASM_NIOS2_PROCESSOR_H | ||
19 | |||
20 | #include <asm/ptrace.h> | ||
21 | #include <asm/registers.h> | ||
22 | #include <asm/page.h> | ||
23 | |||
24 | #define NIOS2_FLAG_KTHREAD 0x00000001 /* task is a kernel thread */ | ||
25 | |||
26 | #define NIOS2_OP_NOP 0x1883a | ||
27 | #define NIOS2_OP_BREAK 0x3da03a | ||
28 | |||
29 | #ifdef __KERNEL__ | ||
30 | |||
31 | #define STACK_TOP TASK_SIZE | ||
32 | #define STACK_TOP_MAX STACK_TOP | ||
33 | |||
34 | #endif /* __KERNEL__ */ | ||
35 | |||
36 | /* Kuser helpers is mapped to this user space address */ | ||
37 | #define KUSER_BASE 0x1000 | ||
38 | #define KUSER_SIZE (PAGE_SIZE) | ||
39 | #ifndef __ASSEMBLY__ | ||
40 | |||
41 | /* | ||
42 | * Default implementation of macro that returns current | ||
43 | * instruction pointer ("program counter"). | ||
44 | */ | ||
45 | #define current_text_addr() ({ __label__ _l; _l: &&_l; }) | ||
46 | |||
47 | # define TASK_SIZE 0x7FFF0000UL | ||
48 | # define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) | ||
49 | |||
50 | /* The Nios processor specific thread struct. */ | ||
51 | struct thread_struct { | ||
52 | struct pt_regs *kregs; | ||
53 | |||
54 | /* Context switch saved kernel state. */ | ||
55 | unsigned long ksp; | ||
56 | unsigned long kpsr; | ||
57 | }; | ||
58 | |||
59 | #define INIT_MMAP \ | ||
60 | { &init_mm, (0), (0), __pgprot(0x0), VM_READ | VM_WRITE | VM_EXEC } | ||
61 | |||
62 | # define INIT_THREAD { \ | ||
63 | .kregs = NULL, \ | ||
64 | .ksp = 0, \ | ||
65 | .kpsr = 0, \ | ||
66 | } | ||
67 | |||
68 | extern void start_thread(struct pt_regs *regs, unsigned long pc, | ||
69 | unsigned long sp); | ||
70 | |||
71 | struct task_struct; | ||
72 | |||
73 | /* Free all resources held by a thread. */ | ||
74 | static inline void release_thread(struct task_struct *dead_task) | ||
75 | { | ||
76 | } | ||
77 | |||
78 | /* Free current thread data structures etc.. */ | ||
79 | static inline void exit_thread(void) | ||
80 | { | ||
81 | } | ||
82 | |||
83 | /* Return saved PC of a blocked thread. */ | ||
84 | #define thread_saved_pc(tsk) ((tsk)->thread.kregs->ea) | ||
85 | |||
86 | extern unsigned long get_wchan(struct task_struct *p); | ||
87 | |||
88 | /* Prepare to copy thread state - unlazy all lazy status */ | ||
89 | #define prepare_to_copy(tsk) do { } while (0) | ||
90 | |||
91 | #define task_pt_regs(p) \ | ||
92 | ((struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1) | ||
93 | |||
94 | /* Used by procfs */ | ||
95 | #define KSTK_EIP(tsk) ((tsk)->thread.kregs->ea) | ||
96 | #define KSTK_ESP(tsk) ((tsk)->thread.kregs->sp) | ||
97 | |||
98 | #define cpu_relax() barrier() | ||
99 | #define cpu_relax_lowlatency() cpu_relax() | ||
100 | |||
101 | #endif /* __ASSEMBLY__ */ | ||
102 | |||
103 | #endif /* _ASM_NIOS2_PROCESSOR_H */ | ||
diff --git a/arch/nios2/include/asm/switch_to.h b/arch/nios2/include/asm/switch_to.h new file mode 100644 index 000000000000..c47b3f4afbcd --- /dev/null +++ b/arch/nios2/include/asm/switch_to.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 Microtronix Datacom Ltd. | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | */ | ||
8 | #ifndef _ASM_NIOS2_SWITCH_TO_H | ||
9 | #define _ASM_NIOS2_SWITCH_TO_H | ||
10 | |||
11 | /* | ||
12 | * switch_to(n) should switch tasks to task ptr, first checking that | ||
13 | * ptr isn't the current task, in which case it does nothing. This | ||
14 | * also clears the TS-flag if the task we switched to has used the | ||
15 | * math co-processor latest. | ||
16 | */ | ||
17 | #define switch_to(prev, next, last) \ | ||
18 | { \ | ||
19 | void *_last; \ | ||
20 | __asm__ __volatile__ ( \ | ||
21 | "mov r4, %1\n" \ | ||
22 | "mov r5, %2\n" \ | ||
23 | "call resume\n" \ | ||
24 | "mov %0,r4\n" \ | ||
25 | : "=r" (_last) \ | ||
26 | : "r" (prev), "r" (next) \ | ||
27 | : "r4", "r5", "r7", "r8", "ra"); \ | ||
28 | (last) = _last; \ | ||
29 | } | ||
30 | |||
31 | #endif /* _ASM_NIOS2_SWITCH_TO_H */ | ||
diff --git a/arch/nios2/include/asm/thread_info.h b/arch/nios2/include/asm/thread_info.h new file mode 100644 index 000000000000..1f266575beb5 --- /dev/null +++ b/arch/nios2/include/asm/thread_info.h | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * NiosII low-level thread information | ||
3 | * | ||
4 | * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> | ||
5 | * Copyright (C) 2004 Microtronix Datacom Ltd. | ||
6 | * | ||
7 | * Based on asm/thread_info_no.h from m68k which is: | ||
8 | * | ||
9 | * Copyright (C) 2002 David Howells <dhowells@redhat.com> | ||
10 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | ||
12 | * License. See the file "COPYING" in the main directory of this archive | ||
13 | * for more details. | ||
14 | */ | ||
15 | |||
16 | #ifndef _ASM_NIOS2_THREAD_INFO_H | ||
17 | #define _ASM_NIOS2_THREAD_INFO_H | ||
18 | |||
19 | #ifdef __KERNEL__ | ||
20 | |||
21 | /* | ||
22 | * Size of the kernel stack for each process. | ||
23 | */ | ||
24 | #define THREAD_SIZE_ORDER 1 | ||
25 | #define THREAD_SIZE 8192 /* 2 * PAGE_SIZE */ | ||
26 | |||
27 | #ifndef __ASSEMBLY__ | ||
28 | |||
29 | typedef struct { | ||
30 | unsigned long seg; | ||
31 | } mm_segment_t; | ||
32 | |||
33 | /* | ||
34 | * low level task data that entry.S needs immediate access to | ||
35 | * - this struct should fit entirely inside of one cache line | ||
36 | * - this struct shares the supervisor stack pages | ||
37 | * - if the contents of this structure are changed, the assembly constants | ||
38 | * must also be changed | ||
39 | */ | ||
40 | struct thread_info { | ||
41 | struct task_struct *task; /* main task structure */ | ||
42 | struct exec_domain *exec_domain; /* execution domain */ | ||
43 | unsigned long flags; /* low level flags */ | ||
44 | __u32 cpu; /* current CPU */ | ||
45 | int preempt_count; /* 0 => preemptable,<0 => BUG */ | ||
46 | mm_segment_t addr_limit; /* thread address space: | ||
47 | 0-0x7FFFFFFF for user-thead | ||
48 | 0-0xFFFFFFFF for kernel-thread | ||
49 | */ | ||
50 | struct restart_block restart_block; | ||
51 | struct pt_regs *regs; | ||
52 | }; | ||
53 | |||
54 | /* | ||
55 | * macros/functions for gaining access to the thread information structure | ||
56 | * | ||
57 | * preempt_count needs to be 1 initially, until the scheduler is functional. | ||
58 | */ | ||
59 | #define INIT_THREAD_INFO(tsk) \ | ||
60 | { \ | ||
61 | .task = &tsk, \ | ||
62 | .exec_domain = &default_exec_domain, \ | ||
63 | .flags = 0, \ | ||
64 | .cpu = 0, \ | ||
65 | .preempt_count = INIT_PREEMPT_COUNT, \ | ||
66 | .addr_limit = KERNEL_DS, \ | ||
67 | .restart_block = { \ | ||
68 | .fn = do_no_restart_syscall, \ | ||
69 | }, \ | ||
70 | } | ||
71 | |||
72 | #define init_thread_info (init_thread_union.thread_info) | ||
73 | #define init_stack (init_thread_union.stack) | ||
74 | |||
75 | /* how to get the thread information struct from C */ | ||
76 | static inline struct thread_info *current_thread_info(void) | ||
77 | { | ||
78 | register unsigned long sp asm("sp"); | ||
79 | |||
80 | return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); | ||
81 | } | ||
82 | #endif /* !__ASSEMBLY__ */ | ||
83 | |||
84 | /* | ||
85 | * thread information flags | ||
86 | * - these are process state flags that various assembly files may need to | ||
87 | * access | ||
88 | * - pending work-to-be-done flags are in LSW | ||
89 | * - other flags in MSW | ||
90 | */ | ||
91 | #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ | ||
92 | #define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ | ||
93 | #define TIF_SIGPENDING 2 /* signal pending */ | ||
94 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ | ||
95 | #define TIF_MEMDIE 4 /* is terminating due to OOM killer */ | ||
96 | #define TIF_SECCOMP 5 /* secure computing */ | ||
97 | #define TIF_SYSCALL_AUDIT 6 /* syscall auditing active */ | ||
98 | #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ | ||
99 | |||
100 | #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling | ||
101 | TIF_NEED_RESCHED */ | ||
102 | |||
103 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) | ||
104 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) | ||
105 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) | ||
106 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | ||
107 | #define _TIF_SECCOMP (1 << TIF_SECCOMP) | ||
108 | #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) | ||
109 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) | ||
110 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) | ||
111 | |||
112 | /* work to do on interrupt/exception return */ | ||
113 | #define _TIF_WORK_MASK 0x0000FFFE | ||
114 | |||
115 | /* work to do on any return to u-space */ | ||
116 | # define _TIF_ALLWORK_MASK 0x0000FFFF | ||
117 | |||
118 | #endif /* __KERNEL__ */ | ||
119 | |||
120 | #endif /* _ASM_NIOS2_THREAD_INFO_H */ | ||
diff --git a/arch/nios2/kernel/process.c b/arch/nios2/kernel/process.c new file mode 100644 index 000000000000..0e075b5ad2a5 --- /dev/null +++ b/arch/nios2/kernel/process.c | |||
@@ -0,0 +1,258 @@ | |||
1 | /* | ||
2 | * Architecture-dependent parts of process handling. | ||
3 | * | ||
4 | * Copyright (C) 2013 Altera Corporation | ||
5 | * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> | ||
6 | * Copyright (C) 2009 Wind River Systems Inc | ||
7 | * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com | ||
8 | * Copyright (C) 2004 Microtronix Datacom Ltd | ||
9 | * | ||
10 | * This file is subject to the terms and conditions of the GNU General Public | ||
11 | * License. See the file "COPYING" in the main directory of this archive | ||
12 | * for more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/export.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/tick.h> | ||
18 | #include <linux/uaccess.h> | ||
19 | |||
20 | #include <asm/unistd.h> | ||
21 | #include <asm/traps.h> | ||
22 | #include <asm/cpuinfo.h> | ||
23 | |||
24 | asmlinkage void ret_from_fork(void); | ||
25 | asmlinkage void ret_from_kernel_thread(void); | ||
26 | |||
27 | void (*pm_power_off)(void) = NULL; | ||
28 | EXPORT_SYMBOL(pm_power_off); | ||
29 | |||
30 | void arch_cpu_idle(void) | ||
31 | { | ||
32 | local_irq_enable(); | ||
33 | } | ||
34 | |||
35 | /* | ||
36 | * The development boards have no way to pull a board reset. Just jump to the | ||
37 | * cpu reset address and let the boot loader or the code in head.S take care of | ||
38 | * resetting peripherals. | ||
39 | */ | ||
40 | void machine_restart(char *__unused) | ||
41 | { | ||
42 | pr_notice("Machine restart (%08x)...\n", cpuinfo.reset_addr); | ||
43 | local_irq_disable(); | ||
44 | __asm__ __volatile__ ( | ||
45 | "jmp %0\n\t" | ||
46 | : | ||
47 | : "r" (cpuinfo.reset_addr) | ||
48 | : "r4"); | ||
49 | } | ||
50 | |||
51 | void machine_halt(void) | ||
52 | { | ||
53 | pr_notice("Machine halt...\n"); | ||
54 | local_irq_disable(); | ||
55 | for (;;) | ||
56 | ; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * There is no way to power off the development boards. So just spin for now. If | ||
61 | * we ever have a way of resetting a board using a GPIO we should add that here. | ||
62 | */ | ||
63 | void machine_power_off(void) | ||
64 | { | ||
65 | pr_notice("Machine power off...\n"); | ||
66 | local_irq_disable(); | ||
67 | for (;;) | ||
68 | ; | ||
69 | } | ||
70 | |||
71 | void show_regs(struct pt_regs *regs) | ||
72 | { | ||
73 | pr_notice("\n"); | ||
74 | show_regs_print_info(KERN_DEFAULT); | ||
75 | |||
76 | pr_notice("r1: %08lx r2: %08lx r3: %08lx r4: %08lx\n", | ||
77 | regs->r1, regs->r2, regs->r3, regs->r4); | ||
78 | |||
79 | pr_notice("r5: %08lx r6: %08lx r7: %08lx r8: %08lx\n", | ||
80 | regs->r5, regs->r6, regs->r7, regs->r8); | ||
81 | |||
82 | pr_notice("r9: %08lx r10: %08lx r11: %08lx r12: %08lx\n", | ||
83 | regs->r9, regs->r10, regs->r11, regs->r12); | ||
84 | |||
85 | pr_notice("r13: %08lx r14: %08lx r15: %08lx\n", | ||
86 | regs->r13, regs->r14, regs->r15); | ||
87 | |||
88 | pr_notice("ra: %08lx fp: %08lx sp: %08lx gp: %08lx\n", | ||
89 | regs->ra, regs->fp, regs->sp, regs->gp); | ||
90 | |||
91 | pr_notice("ea: %08lx estatus: %08lx\n", | ||
92 | regs->ea, regs->estatus); | ||
93 | } | ||
94 | |||
95 | void flush_thread(void) | ||
96 | { | ||
97 | set_fs(USER_DS); | ||
98 | } | ||
99 | |||
100 | int copy_thread(unsigned long clone_flags, | ||
101 | unsigned long usp, unsigned long arg, struct task_struct *p) | ||
102 | { | ||
103 | struct pt_regs *childregs = task_pt_regs(p); | ||
104 | struct pt_regs *regs; | ||
105 | struct switch_stack *stack; | ||
106 | struct switch_stack *childstack = | ||
107 | ((struct switch_stack *)childregs) - 1; | ||
108 | |||
109 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
110 | memset(childstack, 0, | ||
111 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); | ||
112 | |||
113 | childstack->r16 = usp; /* fn */ | ||
114 | childstack->r17 = arg; | ||
115 | childstack->ra = (unsigned long) ret_from_kernel_thread; | ||
116 | childregs->estatus = STATUS_PIE; | ||
117 | childregs->sp = (unsigned long) childstack; | ||
118 | |||
119 | p->thread.ksp = (unsigned long) childstack; | ||
120 | p->thread.kregs = childregs; | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | regs = current_pt_regs(); | ||
125 | *childregs = *regs; | ||
126 | childregs->r2 = 0; /* Set the return value for the child. */ | ||
127 | childregs->r7 = 0; | ||
128 | |||
129 | stack = ((struct switch_stack *) regs) - 1; | ||
130 | *childstack = *stack; | ||
131 | childstack->ra = (unsigned long)ret_from_fork; | ||
132 | p->thread.kregs = childregs; | ||
133 | p->thread.ksp = (unsigned long) childstack; | ||
134 | |||
135 | if (usp) | ||
136 | childregs->sp = usp; | ||
137 | |||
138 | /* Initialize tls register. */ | ||
139 | if (clone_flags & CLONE_SETTLS) | ||
140 | childstack->r23 = regs->r8; | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Generic dumping code. Used for panic and debug. | ||
147 | */ | ||
148 | void dump(struct pt_regs *fp) | ||
149 | { | ||
150 | unsigned long *sp; | ||
151 | unsigned char *tp; | ||
152 | int i; | ||
153 | |||
154 | pr_emerg("\nCURRENT PROCESS:\n\n"); | ||
155 | pr_emerg("COMM=%s PID=%d\n", current->comm, current->pid); | ||
156 | |||
157 | if (current->mm) { | ||
158 | pr_emerg("TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", | ||
159 | (int) current->mm->start_code, | ||
160 | (int) current->mm->end_code, | ||
161 | (int) current->mm->start_data, | ||
162 | (int) current->mm->end_data, | ||
163 | (int) current->mm->end_data, | ||
164 | (int) current->mm->brk); | ||
165 | pr_emerg("USER-STACK=%08x KERNEL-STACK=%08x\n\n", | ||
166 | (int) current->mm->start_stack, | ||
167 | (int)(((unsigned long) current) + THREAD_SIZE)); | ||
168 | } | ||
169 | |||
170 | pr_emerg("PC: %08lx\n", fp->ea); | ||
171 | pr_emerg("SR: %08lx SP: %08lx\n", | ||
172 | (long) fp->estatus, (long) fp); | ||
173 | |||
174 | pr_emerg("r1: %08lx r2: %08lx r3: %08lx\n", | ||
175 | fp->r1, fp->r2, fp->r3); | ||
176 | |||
177 | pr_emerg("r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", | ||
178 | fp->r4, fp->r5, fp->r6, fp->r7); | ||
179 | pr_emerg("r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", | ||
180 | fp->r8, fp->r9, fp->r10, fp->r11); | ||
181 | pr_emerg("r12: %08lx r13: %08lx r14: %08lx r15: %08lx\n", | ||
182 | fp->r12, fp->r13, fp->r14, fp->r15); | ||
183 | pr_emerg("or2: %08lx ra: %08lx fp: %08lx sp: %08lx\n", | ||
184 | fp->orig_r2, fp->ra, fp->fp, fp->sp); | ||
185 | pr_emerg("\nUSP: %08x TRAPFRAME: %08x\n", | ||
186 | (unsigned int) fp->sp, (unsigned int) fp); | ||
187 | |||
188 | pr_emerg("\nCODE:"); | ||
189 | tp = ((unsigned char *) fp->ea) - 0x20; | ||
190 | for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { | ||
191 | if ((i % 0x10) == 0) | ||
192 | pr_emerg("\n%08x: ", (int) (tp + i)); | ||
193 | pr_emerg("%08x ", (int) *sp++); | ||
194 | } | ||
195 | pr_emerg("\n"); | ||
196 | |||
197 | pr_emerg("\nKERNEL STACK:"); | ||
198 | tp = ((unsigned char *) fp) - 0x40; | ||
199 | for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { | ||
200 | if ((i % 0x10) == 0) | ||
201 | pr_emerg("\n%08x: ", (int) (tp + i)); | ||
202 | pr_emerg("%08x ", (int) *sp++); | ||
203 | } | ||
204 | pr_emerg("\n"); | ||
205 | pr_emerg("\n"); | ||
206 | |||
207 | pr_emerg("\nUSER STACK:"); | ||
208 | tp = (unsigned char *) (fp->sp - 0x10); | ||
209 | for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { | ||
210 | if ((i % 0x10) == 0) | ||
211 | pr_emerg("\n%08x: ", (int) (tp + i)); | ||
212 | pr_emerg("%08x ", (int) *sp++); | ||
213 | } | ||
214 | pr_emerg("\n\n"); | ||
215 | } | ||
216 | |||
217 | unsigned long get_wchan(struct task_struct *p) | ||
218 | { | ||
219 | unsigned long fp, pc; | ||
220 | unsigned long stack_page; | ||
221 | int count = 0; | ||
222 | |||
223 | if (!p || p == current || p->state == TASK_RUNNING) | ||
224 | return 0; | ||
225 | |||
226 | stack_page = (unsigned long)p; | ||
227 | fp = ((struct switch_stack *)p->thread.ksp)->fp; /* ;dgt2 */ | ||
228 | do { | ||
229 | if (fp < stack_page+sizeof(struct task_struct) || | ||
230 | fp >= 8184+stack_page) /* ;dgt2;tmp */ | ||
231 | return 0; | ||
232 | pc = ((unsigned long *)fp)[1]; | ||
233 | if (!in_sched_functions(pc)) | ||
234 | return pc; | ||
235 | fp = *(unsigned long *) fp; | ||
236 | } while (count++ < 16); /* ;dgt2;tmp */ | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * Do necessary setup to start up a newly executed thread. | ||
242 | * Will startup in user mode (status_extension = 0). | ||
243 | */ | ||
244 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) | ||
245 | { | ||
246 | memset((void *) regs, 0, sizeof(struct pt_regs)); | ||
247 | regs->estatus = ESTATUS_EPIE | ESTATUS_EU; | ||
248 | regs->ea = pc; | ||
249 | regs->sp = sp; | ||
250 | } | ||
251 | |||
252 | #include <linux/elfcore.h> | ||
253 | |||
254 | /* Fill in the FPU structure for a core dump. */ | ||
255 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) | ||
256 | { | ||
257 | return 0; /* Nios2 has no FPU and thus no FPU registers */ | ||
258 | } | ||
diff --git a/arch/nios2/mm/mmu_context.c b/arch/nios2/mm/mmu_context.c new file mode 100644 index 000000000000..45d6b9c58d67 --- /dev/null +++ b/arch/nios2/mm/mmu_context.c | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * MMU context handling. | ||
3 | * | ||
4 | * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> | ||
5 | * Copyright (C) 2009 Wind River Systems Inc | ||
6 | * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/mm.h> | ||
14 | |||
15 | #include <asm/cpuinfo.h> | ||
16 | #include <asm/mmu_context.h> | ||
17 | #include <asm/tlb.h> | ||
18 | |||
19 | /* The pids position and mask in context */ | ||
20 | #define PID_SHIFT 0 | ||
21 | #define PID_BITS (cpuinfo.tlb_pid_num_bits) | ||
22 | #define PID_MASK ((1UL << PID_BITS) - 1) | ||
23 | |||
24 | /* The versions position and mask in context */ | ||
25 | #define VERSION_BITS (32 - PID_BITS) | ||
26 | #define VERSION_SHIFT (PID_SHIFT + PID_BITS) | ||
27 | #define VERSION_MASK ((1UL << VERSION_BITS) - 1) | ||
28 | |||
29 | /* Return the version part of a context */ | ||
30 | #define CTX_VERSION(c) (((c) >> VERSION_SHIFT) & VERSION_MASK) | ||
31 | |||
32 | /* Return the pid part of a context */ | ||
33 | #define CTX_PID(c) (((c) >> PID_SHIFT) & PID_MASK) | ||
34 | |||
35 | /* Value of the first context (version 1, pid 0) */ | ||
36 | #define FIRST_CTX ((1UL << VERSION_SHIFT) | (0 << PID_SHIFT)) | ||
37 | |||
38 | static mm_context_t next_mmu_context; | ||
39 | |||
40 | /* | ||
41 | * Initialize MMU context management stuff. | ||
42 | */ | ||
43 | void __init mmu_context_init(void) | ||
44 | { | ||
45 | /* We need to set this here because the value depends on runtime data | ||
46 | * from cpuinfo */ | ||
47 | next_mmu_context = FIRST_CTX; | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * Set new context (pid), keep way | ||
52 | */ | ||
53 | static void set_context(mm_context_t context) | ||
54 | { | ||
55 | set_mmu_pid(CTX_PID(context)); | ||
56 | } | ||
57 | |||
58 | static mm_context_t get_new_context(void) | ||
59 | { | ||
60 | /* Return the next pid */ | ||
61 | next_mmu_context += (1UL << PID_SHIFT); | ||
62 | |||
63 | /* If the pid field wraps around we increase the version and | ||
64 | * flush the tlb */ | ||
65 | if (unlikely(CTX_PID(next_mmu_context) == 0)) { | ||
66 | /* Version is incremented since the pid increment above | ||
67 | * overflows info version */ | ||
68 | flush_cache_all(); | ||
69 | flush_tlb_all(); | ||
70 | } | ||
71 | |||
72 | /* If the version wraps we start over with the first generation, we do | ||
73 | * not need to flush the tlb here since it's always done above */ | ||
74 | if (unlikely(CTX_VERSION(next_mmu_context) == 0)) | ||
75 | next_mmu_context = FIRST_CTX; | ||
76 | |||
77 | return next_mmu_context; | ||
78 | } | ||
79 | |||
80 | void switch_mm(struct mm_struct *prev, struct mm_struct *next, | ||
81 | struct task_struct *tsk) | ||
82 | { | ||
83 | unsigned long flags; | ||
84 | |||
85 | local_irq_save(flags); | ||
86 | |||
87 | /* If the process context we are swapping in has a different context | ||
88 | * generation then we have it should get a new generation/pid */ | ||
89 | if (unlikely(CTX_VERSION(next->context) != | ||
90 | CTX_VERSION(next_mmu_context))) | ||
91 | next->context = get_new_context(); | ||
92 | |||
93 | /* Save the current pgd so the fast tlb handler can find it */ | ||
94 | pgd_current = next->pgd; | ||
95 | |||
96 | /* Set the current context */ | ||
97 | set_context(next->context); | ||
98 | |||
99 | local_irq_restore(flags); | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * After we have set current->mm to a new value, this activates | ||
104 | * the context for the new mm so we see the new mappings. | ||
105 | */ | ||
106 | void activate_mm(struct mm_struct *prev, struct mm_struct *next) | ||
107 | { | ||
108 | next->context = get_new_context(); | ||
109 | set_context(next->context); | ||
110 | pgd_current = next->pgd; | ||
111 | } | ||
112 | |||
113 | unsigned long get_pid_from_context(mm_context_t *context) | ||
114 | { | ||
115 | return CTX_PID((*context)); | ||
116 | } | ||