diff options
Diffstat (limited to 'arch/sh/kernel/process_32.c')
-rw-r--r-- | arch/sh/kernel/process_32.c | 114 |
1 files changed, 23 insertions, 91 deletions
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index d8af889366a4..856010f9ebc9 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c | |||
@@ -25,17 +25,15 @@ | |||
25 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
26 | #include <linux/ftrace.h> | 26 | #include <linux/ftrace.h> |
27 | #include <linux/preempt.h> | 27 | #include <linux/preempt.h> |
28 | #include <linux/hw_breakpoint.h> | ||
28 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
29 | #include <asm/mmu_context.h> | 30 | #include <asm/mmu_context.h> |
30 | #include <asm/pgalloc.h> | 31 | #include <asm/pgalloc.h> |
31 | #include <asm/system.h> | 32 | #include <asm/system.h> |
32 | #include <asm/ubc.h> | ||
33 | #include <asm/fpu.h> | 33 | #include <asm/fpu.h> |
34 | #include <asm/syscalls.h> | 34 | #include <asm/syscalls.h> |
35 | #include <asm/watchdog.h> | 35 | #include <asm/watchdog.h> |
36 | 36 | ||
37 | int ubc_usercnt = 0; | ||
38 | |||
39 | #ifdef CONFIG_32BIT | 37 | #ifdef CONFIG_32BIT |
40 | static void watchdog_trigger_immediate(void) | 38 | static void watchdog_trigger_immediate(void) |
41 | { | 39 | { |
@@ -147,21 +145,34 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
147 | } | 145 | } |
148 | EXPORT_SYMBOL(kernel_thread); | 146 | EXPORT_SYMBOL(kernel_thread); |
149 | 147 | ||
148 | void start_thread(struct pt_regs *regs, unsigned long new_pc, | ||
149 | unsigned long new_sp) | ||
150 | { | ||
151 | set_fs(USER_DS); | ||
152 | |||
153 | regs->pr = 0; | ||
154 | regs->sr = SR_FD; | ||
155 | regs->pc = new_pc; | ||
156 | regs->regs[15] = new_sp; | ||
157 | |||
158 | free_thread_xstate(current); | ||
159 | } | ||
160 | EXPORT_SYMBOL(start_thread); | ||
161 | |||
150 | /* | 162 | /* |
151 | * Free current thread data structures etc.. | 163 | * Free current thread data structures etc.. |
152 | */ | 164 | */ |
153 | void exit_thread(void) | 165 | void exit_thread(void) |
154 | { | 166 | { |
155 | if (current->thread.ubc_pc) { | ||
156 | current->thread.ubc_pc = 0; | ||
157 | ubc_usercnt -= 1; | ||
158 | } | ||
159 | } | 167 | } |
160 | 168 | ||
161 | void flush_thread(void) | 169 | void flush_thread(void) |
162 | { | 170 | { |
163 | #if defined(CONFIG_SH_FPU) | ||
164 | struct task_struct *tsk = current; | 171 | struct task_struct *tsk = current; |
172 | |||
173 | flush_ptrace_hw_breakpoint(tsk); | ||
174 | |||
175 | #if defined(CONFIG_SH_FPU) | ||
165 | /* Forget lazy FPU state */ | 176 | /* Forget lazy FPU state */ |
166 | clear_fpu(tsk, task_pt_regs(tsk)); | 177 | clear_fpu(tsk, task_pt_regs(tsk)); |
167 | clear_used_math(); | 178 | clear_used_math(); |
@@ -209,11 +220,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
209 | { | 220 | { |
210 | struct thread_info *ti = task_thread_info(p); | 221 | struct thread_info *ti = task_thread_info(p); |
211 | struct pt_regs *childregs; | 222 | struct pt_regs *childregs; |
223 | |||
212 | #if defined(CONFIG_SH_DSP) | 224 | #if defined(CONFIG_SH_DSP) |
213 | struct task_struct *tsk = current; | 225 | struct task_struct *tsk = current; |
214 | #endif | ||
215 | 226 | ||
216 | #if defined(CONFIG_SH_DSP) | ||
217 | if (is_dsp_enabled(tsk)) { | 227 | if (is_dsp_enabled(tsk)) { |
218 | /* We can use the __save_dsp or just copy the struct: | 228 | /* We can use the __save_dsp or just copy the struct: |
219 | * __save_dsp(p); | 229 | * __save_dsp(p); |
@@ -244,53 +254,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
244 | p->thread.sp = (unsigned long) childregs; | 254 | p->thread.sp = (unsigned long) childregs; |
245 | p->thread.pc = (unsigned long) ret_from_fork; | 255 | p->thread.pc = (unsigned long) ret_from_fork; |
246 | 256 | ||
247 | p->thread.ubc_pc = 0; | 257 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); |
248 | 258 | ||
249 | return 0; | 259 | return 0; |
250 | } | 260 | } |
251 | 261 | ||
252 | /* Tracing by user break controller. */ | ||
253 | static void ubc_set_tracing(int asid, unsigned long pc) | ||
254 | { | ||
255 | #if defined(CONFIG_CPU_SH4A) | ||
256 | unsigned long val; | ||
257 | |||
258 | val = (UBC_CBR_ID_INST | UBC_CBR_RW_READ | UBC_CBR_CE); | ||
259 | val |= (UBC_CBR_AIE | UBC_CBR_AIV_SET(asid)); | ||
260 | |||
261 | ctrl_outl(val, UBC_CBR0); | ||
262 | ctrl_outl(pc, UBC_CAR0); | ||
263 | ctrl_outl(0x0, UBC_CAMR0); | ||
264 | ctrl_outl(0x0, UBC_CBCR); | ||
265 | |||
266 | val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE); | ||
267 | ctrl_outl(val, UBC_CRR0); | ||
268 | |||
269 | /* Read UBC register that we wrote last, for checking update */ | ||
270 | val = ctrl_inl(UBC_CRR0); | ||
271 | |||
272 | #else /* CONFIG_CPU_SH4A */ | ||
273 | ctrl_outl(pc, UBC_BARA); | ||
274 | |||
275 | #ifdef CONFIG_MMU | ||
276 | ctrl_outb(asid, UBC_BASRA); | ||
277 | #endif | ||
278 | |||
279 | ctrl_outl(0, UBC_BAMRA); | ||
280 | |||
281 | if (current_cpu_data.type == CPU_SH7729 || | ||
282 | current_cpu_data.type == CPU_SH7710 || | ||
283 | current_cpu_data.type == CPU_SH7712 || | ||
284 | current_cpu_data.type == CPU_SH7203){ | ||
285 | ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); | ||
286 | ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); | ||
287 | } else { | ||
288 | ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA); | ||
289 | ctrl_outw(BRCR_PCBA, UBC_BRCR); | ||
290 | } | ||
291 | #endif /* CONFIG_CPU_SH4A */ | ||
292 | } | ||
293 | |||
294 | /* | 262 | /* |
295 | * switch_to(x,y) should switch tasks from x to y. | 263 | * switch_to(x,y) should switch tasks from x to y. |
296 | * | 264 | * |
@@ -304,7 +272,7 @@ __switch_to(struct task_struct *prev, struct task_struct *next) | |||
304 | 272 | ||
305 | /* we're going to use this soon, after a few expensive things */ | 273 | /* we're going to use this soon, after a few expensive things */ |
306 | if (next->fpu_counter > 5) | 274 | if (next->fpu_counter > 5) |
307 | prefetch(&next_t->fpu.hard); | 275 | prefetch(next_t->xstate); |
308 | 276 | ||
309 | #ifdef CONFIG_MMU | 277 | #ifdef CONFIG_MMU |
310 | /* | 278 | /* |
@@ -316,32 +284,13 @@ __switch_to(struct task_struct *prev, struct task_struct *next) | |||
316 | : "r" (task_thread_info(next))); | 284 | : "r" (task_thread_info(next))); |
317 | #endif | 285 | #endif |
318 | 286 | ||
319 | /* If no tasks are using the UBC, we're done */ | ||
320 | if (ubc_usercnt == 0) | ||
321 | /* If no tasks are using the UBC, we're done */; | ||
322 | else if (next->thread.ubc_pc && next->mm) { | ||
323 | int asid = 0; | ||
324 | #ifdef CONFIG_MMU | ||
325 | asid |= cpu_asid(smp_processor_id(), next->mm); | ||
326 | #endif | ||
327 | ubc_set_tracing(asid, next->thread.ubc_pc); | ||
328 | } else { | ||
329 | #if defined(CONFIG_CPU_SH4A) | ||
330 | ctrl_outl(UBC_CBR_INIT, UBC_CBR0); | ||
331 | ctrl_outl(UBC_CRR_INIT, UBC_CRR0); | ||
332 | #else | ||
333 | ctrl_outw(0, UBC_BBRA); | ||
334 | ctrl_outw(0, UBC_BBRB); | ||
335 | #endif | ||
336 | } | ||
337 | |||
338 | /* | 287 | /* |
339 | * If the task has used fpu the last 5 timeslices, just do a full | 288 | * If the task has used fpu the last 5 timeslices, just do a full |
340 | * restore of the math state immediately to avoid the trap; the | 289 | * restore of the math state immediately to avoid the trap; the |
341 | * chances of needing FPU soon are obviously high now | 290 | * chances of needing FPU soon are obviously high now |
342 | */ | 291 | */ |
343 | if (next->fpu_counter > 5) | 292 | if (next->fpu_counter > 5) |
344 | fpu_state_restore(task_pt_regs(next)); | 293 | __fpu_state_restore(); |
345 | 294 | ||
346 | return prev; | 295 | return prev; |
347 | } | 296 | } |
@@ -434,20 +383,3 @@ unsigned long get_wchan(struct task_struct *p) | |||
434 | 383 | ||
435 | return pc; | 384 | return pc; |
436 | } | 385 | } |
437 | |||
438 | asmlinkage void break_point_trap(void) | ||
439 | { | ||
440 | /* Clear tracing. */ | ||
441 | #if defined(CONFIG_CPU_SH4A) | ||
442 | ctrl_outl(UBC_CBR_INIT, UBC_CBR0); | ||
443 | ctrl_outl(UBC_CRR_INIT, UBC_CRR0); | ||
444 | #else | ||
445 | ctrl_outw(0, UBC_BBRA); | ||
446 | ctrl_outw(0, UBC_BBRB); | ||
447 | ctrl_outl(0, UBC_BRCR); | ||
448 | #endif | ||
449 | current->thread.ubc_pc = 0; | ||
450 | ubc_usercnt -= 1; | ||
451 | |||
452 | force_sig(SIGTRAP, current); | ||
453 | } | ||