diff options
author | Greentime Hu <greentime@andestech.com> | 2017-10-24 03:47:50 -0400 |
---|---|---|
committer | Greentime Hu <greentime@andestech.com> | 2018-02-21 21:44:32 -0500 |
commit | a15e9ffa877852e529db33cc615c132bad2fc60a (patch) | |
tree | c6a8f4eb446a368a79327835de1051031327e3d2 /arch/nds32/kernel | |
parent | 7de9cf474083bfbba469f72dc208f7b51747632d (diff) |
nds32: Process management
This patch includes copy_thread(), start_thread() implementation and cpu_context
structure definition. nds32 uses $r25 to get current task_struct.
Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/nds32/kernel')
-rw-r--r-- | arch/nds32/kernel/process.c | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/arch/nds32/kernel/process.c b/arch/nds32/kernel/process.c new file mode 100644 index 000000000000..65fda986e55f --- /dev/null +++ b/arch/nds32/kernel/process.c | |||
@@ -0,0 +1,208 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (C) 2005-2017 Andes Technology Corporation | ||
3 | |||
4 | #include <linux/sched.h> | ||
5 | #include <linux/sched/debug.h> | ||
6 | #include <linux/sched/task_stack.h> | ||
7 | #include <linux/delay.h> | ||
8 | #include <linux/kallsyms.h> | ||
9 | #include <linux/uaccess.h> | ||
10 | #include <asm/elf.h> | ||
11 | #include <asm/proc-fns.h> | ||
12 | #include <linux/ptrace.h> | ||
13 | #include <linux/reboot.h> | ||
14 | |||
15 | extern void setup_mm_for_reboot(char mode); | ||
16 | #ifdef CONFIG_PROC_FS | ||
17 | struct proc_dir_entry *proc_dir_cpu; | ||
18 | EXPORT_SYMBOL(proc_dir_cpu); | ||
19 | #endif | ||
20 | |||
21 | extern inline void arch_reset(char mode) | ||
22 | { | ||
23 | if (mode == 's') { | ||
24 | /* Use cpu handler, jump to 0 */ | ||
25 | cpu_reset(0); | ||
26 | } | ||
27 | } | ||
28 | |||
29 | void (*pm_power_off) (void); | ||
30 | EXPORT_SYMBOL(pm_power_off); | ||
31 | |||
32 | static char reboot_mode_nds32 = 'h'; | ||
33 | |||
34 | int __init reboot_setup(char *str) | ||
35 | { | ||
36 | reboot_mode_nds32 = str[0]; | ||
37 | return 1; | ||
38 | } | ||
39 | |||
40 | static int cpub_pwroff(void) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | __setup("reboot=", reboot_setup); | ||
46 | |||
47 | void machine_halt(void) | ||
48 | { | ||
49 | cpub_pwroff(); | ||
50 | } | ||
51 | |||
52 | EXPORT_SYMBOL(machine_halt); | ||
53 | |||
54 | void machine_power_off(void) | ||
55 | { | ||
56 | if (pm_power_off) | ||
57 | pm_power_off(); | ||
58 | } | ||
59 | |||
60 | EXPORT_SYMBOL(machine_power_off); | ||
61 | |||
62 | void machine_restart(char *cmd) | ||
63 | { | ||
64 | /* | ||
65 | * Clean and disable cache, and turn off interrupts | ||
66 | */ | ||
67 | cpu_proc_fin(); | ||
68 | |||
69 | /* | ||
70 | * Tell the mm system that we are going to reboot - | ||
71 | * we may need it to insert some 1:1 mappings so that | ||
72 | * soft boot works. | ||
73 | */ | ||
74 | setup_mm_for_reboot(reboot_mode_nds32); | ||
75 | |||
76 | /* Execute kernel restart handler call chain */ | ||
77 | do_kernel_restart(cmd); | ||
78 | |||
79 | /* | ||
80 | * Now call the architecture specific reboot code. | ||
81 | */ | ||
82 | arch_reset(reboot_mode_nds32); | ||
83 | |||
84 | /* | ||
85 | * Whoops - the architecture was unable to reboot. | ||
86 | * Tell the user! | ||
87 | */ | ||
88 | mdelay(1000); | ||
89 | pr_info("Reboot failed -- System halted\n"); | ||
90 | while (1) ; | ||
91 | } | ||
92 | |||
93 | EXPORT_SYMBOL(machine_restart); | ||
94 | |||
95 | void show_regs(struct pt_regs *regs) | ||
96 | { | ||
97 | printk("PC is at %pS\n", (void *)instruction_pointer(regs)); | ||
98 | printk("LP is at %pS\n", (void *)regs->lp); | ||
99 | pr_info("pc : [<%08lx>] lp : [<%08lx>] %s\n" | ||
100 | "sp : %08lx fp : %08lx gp : %08lx\n", | ||
101 | instruction_pointer(regs), | ||
102 | regs->lp, print_tainted(), regs->sp, regs->fp, regs->gp); | ||
103 | pr_info("r25: %08lx r24: %08lx\n", regs->uregs[25], regs->uregs[24]); | ||
104 | |||
105 | pr_info("r23: %08lx r22: %08lx r21: %08lx r20: %08lx\n", | ||
106 | regs->uregs[23], regs->uregs[22], | ||
107 | regs->uregs[21], regs->uregs[20]); | ||
108 | pr_info("r19: %08lx r18: %08lx r17: %08lx r16: %08lx\n", | ||
109 | regs->uregs[19], regs->uregs[18], | ||
110 | regs->uregs[17], regs->uregs[16]); | ||
111 | pr_info("r15: %08lx r14: %08lx r13: %08lx r12: %08lx\n", | ||
112 | regs->uregs[15], regs->uregs[14], | ||
113 | regs->uregs[13], regs->uregs[12]); | ||
114 | pr_info("r11: %08lx r10: %08lx r9 : %08lx r8 : %08lx\n", | ||
115 | regs->uregs[11], regs->uregs[10], | ||
116 | regs->uregs[9], regs->uregs[8]); | ||
117 | pr_info("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", | ||
118 | regs->uregs[7], regs->uregs[6], regs->uregs[5], regs->uregs[4]); | ||
119 | pr_info("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", | ||
120 | regs->uregs[3], regs->uregs[2], regs->uregs[1], regs->uregs[0]); | ||
121 | pr_info(" IRQs o%s Segment %s\n", | ||
122 | interrupts_enabled(regs) ? "n" : "ff", | ||
123 | segment_eq(get_fs(), get_ds())? "kernel" : "user"); | ||
124 | } | ||
125 | |||
126 | EXPORT_SYMBOL(show_regs); | ||
127 | |||
128 | void flush_thread(void) | ||
129 | { | ||
130 | } | ||
131 | |||
132 | DEFINE_PER_CPU(struct task_struct *, __entry_task); | ||
133 | |||
134 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | ||
135 | int copy_thread(unsigned long clone_flags, unsigned long stack_start, | ||
136 | unsigned long stk_sz, struct task_struct *p) | ||
137 | { | ||
138 | struct pt_regs *childregs = task_pt_regs(p); | ||
139 | |||
140 | memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); | ||
141 | |||
142 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
143 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
144 | /* kernel thread fn */ | ||
145 | p->thread.cpu_context.r6 = stack_start; | ||
146 | /* kernel thread argument */ | ||
147 | p->thread.cpu_context.r7 = stk_sz; | ||
148 | } else { | ||
149 | *childregs = *current_pt_regs(); | ||
150 | if (stack_start) | ||
151 | childregs->sp = stack_start; | ||
152 | /* child get zero as ret. */ | ||
153 | childregs->uregs[0] = 0; | ||
154 | childregs->osp = 0; | ||
155 | if (clone_flags & CLONE_SETTLS) | ||
156 | childregs->uregs[25] = childregs->uregs[3]; | ||
157 | } | ||
158 | /* cpu context switching */ | ||
159 | p->thread.cpu_context.pc = (unsigned long)ret_from_fork; | ||
160 | p->thread.cpu_context.sp = (unsigned long)childregs; | ||
161 | |||
162 | #ifdef CONFIG_HWZOL | ||
163 | childregs->lb = 0; | ||
164 | childregs->le = 0; | ||
165 | childregs->lc = 0; | ||
166 | #endif | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * fill in the fpe structure for a core dump... | ||
173 | */ | ||
174 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpu) | ||
175 | { | ||
176 | int fpvalid = 0; | ||
177 | return fpvalid; | ||
178 | } | ||
179 | |||
180 | EXPORT_SYMBOL(dump_fpu); | ||
181 | |||
182 | unsigned long get_wchan(struct task_struct *p) | ||
183 | { | ||
184 | unsigned long fp, lr; | ||
185 | unsigned long stack_start, stack_end; | ||
186 | int count = 0; | ||
187 | |||
188 | if (!p || p == current || p->state == TASK_RUNNING) | ||
189 | return 0; | ||
190 | |||
191 | if (IS_ENABLED(CONFIG_FRAME_POINTER)) { | ||
192 | stack_start = (unsigned long)end_of_stack(p); | ||
193 | stack_end = (unsigned long)task_stack_page(p) + THREAD_SIZE; | ||
194 | |||
195 | fp = thread_saved_fp(p); | ||
196 | do { | ||
197 | if (fp < stack_start || fp > stack_end) | ||
198 | return 0; | ||
199 | lr = ((unsigned long *)fp)[0]; | ||
200 | if (!in_sched_functions(lr)) | ||
201 | return lr; | ||
202 | fp = *(unsigned long *)(fp + 4); | ||
203 | } while (count++ < 16); | ||
204 | } | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | EXPORT_SYMBOL(get_wchan); | ||