• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/sparc/kernel/
1/* windows.c: Routines to deal with register window management
2 *            at the C-code level.
3 *
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 */
6
7#include <linux/kernel.h>
8#include <linux/sched.h>
9#include <linux/string.h>
10#include <linux/mm.h>
11#include <linux/smp.h>
12#include <linux/smp_lock.h>
13
14#include <asm/uaccess.h>
15
16/* Do save's until all user register windows are out of the cpu. */
17void flush_user_windows(void)
18{
19	register int ctr asm("g5");
20
21	ctr = 0;
22	__asm__ __volatile__(
23		"\n1:\n\t"
24		"ld	[%%g6 + %2], %%g4\n\t"
25		"orcc	%%g0, %%g4, %%g0\n\t"
26		"add	%0, 1, %0\n\t"
27		"bne	1b\n\t"
28		" save	%%sp, -64, %%sp\n"
29		"2:\n\t"
30		"subcc	%0, 1, %0\n\t"
31		"bne	2b\n\t"
32		" restore %%g0, %%g0, %%g0\n"
33	: "=&r" (ctr)
34	: "0" (ctr),
35	  "i" ((const unsigned long)TI_UWINMASK)
36	: "g4", "cc");
37}
38
39static inline void shift_window_buffer(int first_win, int last_win, struct thread_info *tp)
40{
41	int i;
42
43	for(i = first_win; i < last_win; i++) {
44		tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1];
45		memcpy(&tp->reg_window[i], &tp->reg_window[i+1], sizeof(struct reg_window32));
46	}
47}
48
49void synchronize_user_stack(void)
50{
51	struct thread_info *tp = current_thread_info();
52	int window;
53
54	flush_user_windows();
55	if(!tp->w_saved)
56		return;
57
58	/* Ok, there is some dirty work to do. */
59	for(window = tp->w_saved - 1; window >= 0; window--) {
60		unsigned long sp = tp->rwbuf_stkptrs[window];
61
62		/* Ok, let it rip. */
63		if (copy_to_user((char __user *) sp, &tp->reg_window[window],
64				 sizeof(struct reg_window32)))
65			continue;
66
67		shift_window_buffer(window, tp->w_saved - 1, tp);
68		tp->w_saved--;
69	}
70}
71
72
73/* Try to push the windows in a threads window buffer to the
74 * user stack.  Unaligned %sp's are not allowed here.
75 */
76
77void try_to_clear_window_buffer(struct pt_regs *regs, int who)
78{
79	struct thread_info *tp = current_thread_info();
80	int window;
81
82	flush_user_windows();
83	for(window = 0; window < tp->w_saved; window++) {
84		unsigned long sp = tp->rwbuf_stkptrs[window];
85
86		if ((sp & 7) ||
87		    copy_to_user((char __user *) sp, &tp->reg_window[window],
88				 sizeof(struct reg_window32)))
89			do_exit(SIGILL);
90	}
91	tp->w_saved = 0;
92}
93