0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/sched.h>
0010 #include <linux/string.h>
0011 #include <linux/mm.h>
0012 #include <linux/smp.h>
0013
0014 #include <asm/cacheflush.h>
0015 #include <linux/uaccess.h>
0016
0017 #include "kernel.h"
0018
0019
0020 void flush_user_windows(void)
0021 {
0022 register int ctr asm("g5");
0023
0024 ctr = 0;
0025 __asm__ __volatile__(
0026 "\n1:\n\t"
0027 "ld [%%g6 + %2], %%g4\n\t"
0028 "orcc %%g0, %%g4, %%g0\n\t"
0029 "add %0, 1, %0\n\t"
0030 "bne 1b\n\t"
0031 " save %%sp, -64, %%sp\n"
0032 "2:\n\t"
0033 "subcc %0, 1, %0\n\t"
0034 "bne 2b\n\t"
0035 " restore %%g0, %%g0, %%g0\n"
0036 : "=&r" (ctr)
0037 : "0" (ctr),
0038 "i" ((const unsigned long)TI_UWINMASK)
0039 : "g4", "cc");
0040 }
0041
0042 static inline void shift_window_buffer(int first_win, int last_win, struct thread_info *tp)
0043 {
0044 int i;
0045
0046 for(i = first_win; i < last_win; i++) {
0047 tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1];
0048 memcpy(&tp->reg_window[i], &tp->reg_window[i+1], sizeof(struct reg_window32));
0049 }
0050 }
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 void synchronize_user_stack(void)
0062 {
0063 struct thread_info *tp = current_thread_info();
0064 int window;
0065
0066 flush_user_windows();
0067 if(!tp->w_saved)
0068 return;
0069
0070
0071 for(window = tp->w_saved - 1; window >= 0; window--) {
0072 unsigned long sp = tp->rwbuf_stkptrs[window];
0073
0074
0075 if (copy_to_user((char __user *) sp, &tp->reg_window[window],
0076 sizeof(struct reg_window32)))
0077 continue;
0078
0079 shift_window_buffer(window, tp->w_saved - 1, tp);
0080 tp->w_saved--;
0081 }
0082 }
0083
0084 #if 0
0085
0086 static inline void copy_aligned_window(void *dest, const void *src)
0087 {
0088 __asm__ __volatile__("ldd [%1], %%g2\n\t"
0089 "ldd [%1 + 0x8], %%g4\n\t"
0090 "std %%g2, [%0]\n\t"
0091 "std %%g4, [%0 + 0x8]\n\t"
0092 "ldd [%1 + 0x10], %%g2\n\t"
0093 "ldd [%1 + 0x18], %%g4\n\t"
0094 "std %%g2, [%0 + 0x10]\n\t"
0095 "std %%g4, [%0 + 0x18]\n\t"
0096 "ldd [%1 + 0x20], %%g2\n\t"
0097 "ldd [%1 + 0x28], %%g4\n\t"
0098 "std %%g2, [%0 + 0x20]\n\t"
0099 "std %%g4, [%0 + 0x28]\n\t"
0100 "ldd [%1 + 0x30], %%g2\n\t"
0101 "ldd [%1 + 0x38], %%g4\n\t"
0102 "std %%g2, [%0 + 0x30]\n\t"
0103 "std %%g4, [%0 + 0x38]\n\t" : :
0104 "r" (dest), "r" (src) :
0105 "g2", "g3", "g4", "g5");
0106 }
0107 #endif
0108
0109
0110
0111
0112
0113 void try_to_clear_window_buffer(struct pt_regs *regs, int who)
0114 {
0115 struct thread_info *tp = current_thread_info();
0116 int window;
0117
0118 flush_user_windows();
0119 for(window = 0; window < tp->w_saved; window++) {
0120 unsigned long sp = tp->rwbuf_stkptrs[window];
0121
0122 if ((sp & 7) ||
0123 copy_to_user((char __user *) sp, &tp->reg_window[window],
0124 sizeof(struct reg_window32))) {
0125 force_exit_sig(SIGILL);
0126 return;
0127 }
0128 }
0129 tp->w_saved = 0;
0130 }