Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
windows.c
Go to the documentation of this file.
1 /* windows.c: Routines to deal with register window management
2  * at the C-code level.
3  *
4  * Copyright (C) 1995 David S. Miller ([email protected])
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 
13 #include <asm/uaccess.h>
14 
15 /* Do save's until all user register windows are out of the cpu. */
17 {
18  register int ctr asm("g5");
19 
20  ctr = 0;
21  __asm__ __volatile__(
22  "\n1:\n\t"
23  "ld [%%g6 + %2], %%g4\n\t"
24  "orcc %%g0, %%g4, %%g0\n\t"
25  "add %0, 1, %0\n\t"
26  "bne 1b\n\t"
27  " save %%sp, -64, %%sp\n"
28  "2:\n\t"
29  "subcc %0, 1, %0\n\t"
30  "bne 2b\n\t"
31  " restore %%g0, %%g0, %%g0\n"
32  : "=&r" (ctr)
33  : "0" (ctr),
34  "i" ((const unsigned long)TI_UWINMASK)
35  : "g4", "cc");
36 }
37 
38 static inline void shift_window_buffer(int first_win, int last_win, struct thread_info *tp)
39 {
40  int i;
41 
42  for(i = first_win; i < last_win; i++) {
43  tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1];
44  memcpy(&tp->reg_window[i], &tp->reg_window[i+1], sizeof(struct reg_window32));
45  }
46 }
47 
48 /* Place as many of the user's current register windows
49  * on the stack that we can. Even if the %sp is unaligned
50  * we still copy the window there, the only case that we don't
51  * succeed is if the %sp points to a bum mapping altogether.
52  * setup_frame() and do_sigreturn() use this before shifting
53  * the user stack around. Future instruction and hardware
54  * bug workaround routines will need this functionality as
55  * well.
56  */
58 {
59  struct thread_info *tp = current_thread_info();
60  int window;
61 
63  if(!tp->w_saved)
64  return;
65 
66  /* Ok, there is some dirty work to do. */
67  for(window = tp->w_saved - 1; window >= 0; window--) {
68  unsigned long sp = tp->rwbuf_stkptrs[window];
69 
70  /* Ok, let it rip. */
71  if (copy_to_user((char __user *) sp, &tp->reg_window[window],
72  sizeof(struct reg_window32)))
73  continue;
74 
75  shift_window_buffer(window, tp->w_saved - 1, tp);
76  tp->w_saved--;
77  }
78 }
79 
80 #if 0
81 /* An optimization. */
82 static inline void copy_aligned_window(void *dest, const void *src)
83 {
84  __asm__ __volatile__("ldd [%1], %%g2\n\t"
85  "ldd [%1 + 0x8], %%g4\n\t"
86  "std %%g2, [%0]\n\t"
87  "std %%g4, [%0 + 0x8]\n\t"
88  "ldd [%1 + 0x10], %%g2\n\t"
89  "ldd [%1 + 0x18], %%g4\n\t"
90  "std %%g2, [%0 + 0x10]\n\t"
91  "std %%g4, [%0 + 0x18]\n\t"
92  "ldd [%1 + 0x20], %%g2\n\t"
93  "ldd [%1 + 0x28], %%g4\n\t"
94  "std %%g2, [%0 + 0x20]\n\t"
95  "std %%g4, [%0 + 0x28]\n\t"
96  "ldd [%1 + 0x30], %%g2\n\t"
97  "ldd [%1 + 0x38], %%g4\n\t"
98  "std %%g2, [%0 + 0x30]\n\t"
99  "std %%g4, [%0 + 0x38]\n\t" : :
100  "r" (dest), "r" (src) :
101  "g2", "g3", "g4", "g5");
102 }
103 #endif
104 
105 /* Try to push the windows in a threads window buffer to the
106  * user stack. Unaligned %sp's are not allowed here.
107  */
108 
110 {
111  struct thread_info *tp = current_thread_info();
112  int window;
113 
115  for(window = 0; window < tp->w_saved; window++) {
116  unsigned long sp = tp->rwbuf_stkptrs[window];
117 
118  if ((sp & 7) ||
119  copy_to_user((char __user *) sp, &tp->reg_window[window],
120  sizeof(struct reg_window32)))
121  do_exit(SIGILL);
122  }
123  tp->w_saved = 0;
124 }