• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <sys/types.h>
2 #include <sys/ioctl.h>
3 #include "qemu-common.h"
4 
5 #ifdef CONFIG_KVM_GS_RESTORE
6 
7 #define INVALID_GS_REG  0xffff
8 #define KVM_GS_RESTORE_NODETECTED 0x1
9 #define KVM_GS_RESTORE_NO 0x2
10 #define KVM_GS_RESTORE_YES 0x3
11 int initial_gs = INVALID_GS_REG;
12 int gs_need_restore = KVM_GS_RESTORE_NODETECTED;
13 
restoregs(int gs)14 static void restoregs(int gs)
15 {
16     asm("movl %0, %%gs"::"r"(gs));
17 }
18 
_getgs()19 static unsigned int _getgs()
20 {
21     unsigned int gs = 0;
22     asm("movl %%gs,%0" :"=r"(gs):);
23     return gs;
24 }
25 
26 /* No fprintf or any system call before the gs is restored successfully */
check_and_restore_gs(void)27 static void check_and_restore_gs(void)
28 {
29     if (gs_need_restore == KVM_GS_RESTORE_NO)
30         return;
31 
32     restoregs(initial_gs);
33 }
34 
35 struct sigact_status
36 {
37     unsigned int sigaction:1;
38     __sighandler_t old_handler;
39     void (*old_sigaction) (int, siginfo_t *, void *);
40 };
41 static struct sigact_status o_sigact[SIGUNUSED];
42 
temp_sig_handler(int signum)43 static void temp_sig_handler(int signum)
44 {
45     /* !!! must restore gs firstly */
46     check_and_restore_gs();
47 
48     if (signum < SIGHUP || signum >= SIGUNUSED)
49     {
50         fprintf(stderr, "Invalid signal %x in temp_sig_handler\n", signum);
51         abort();
52     }
53 
54     if ( !o_sigact[signum].sigaction && o_sigact[signum].old_handler)
55         o_sigact[signum].old_handler(signum);
56     else
57     {
58         fprintf(stderr, "Invalid signal in temp_sig_handler: "
59              "signal %x sa_info %s!!\n",
60              signum, o_sigact[signum].sigaction ? "set":"not set" );
61          abort();
62     }
63 }
64 
temp_sig_sigaction(int signum,siginfo_t * info,void * ucontext)65 static void temp_sig_sigaction(int signum, siginfo_t *info, void *ucontext)
66 {
67     /* !!! must restore gs firstly */
68     check_and_restore_gs();
69 
70     if (signum < SIGHUP || signum >= SIGUNUSED)
71     {
72         fprintf(stderr, "Invalid signal %x in temp_sig_sigaction\n", signum);
73         abort();
74     }
75 
76     if ( o_sigact[signum].sigaction && o_sigact[signum].old_sigaction )
77         o_sigact[signum].old_sigaction(signum, info, ucontext);
78     else
79     {
80         fprintf(stderr, "Invalid signal in temp_sig_sigaction: "
81              "signal %x sa_info %s!!\n",
82              signum, o_sigact[signum].sigaction ? "set":"not set" );
83          abort();
84     }
85 }
86 
87 static int sig_taken = 0;
88 
take_signal_handler(void)89 static int take_signal_handler(void)
90 {
91     int i;
92 
93     if (gs_need_restore == KVM_GS_RESTORE_NO)
94         return 0;
95     if (sig_taken)
96         return 0;
97 
98     memset(o_sigact, 0, sizeof(o_sigact));
99 
100     /* SIGHUP is 1 in POSIX */
101     for (i = SIGHUP; i < SIGUNUSED; i++)
102     {
103         int sigret;
104         struct sigaction act, old_act;
105 
106         sigret = sigaction(i, NULL, &old_act);
107         if (sigret)
108             continue;
109         /* We don't need take the handler for default or ignore signals */
110         if ( !(old_act.sa_flags & SA_SIGINFO) &&
111                ((old_act.sa_handler == SIG_IGN ) ||
112                 (old_act.sa_handler == SIG_DFL)))
113             continue;
114 
115         memcpy(&act, &old_act, sizeof(struct sigaction));
116 
117         if (old_act.sa_flags & SA_SIGINFO)
118         {
119             o_sigact[i].old_sigaction = old_act.sa_sigaction;
120             o_sigact[i].sigaction = 1;
121             act.sa_sigaction = temp_sig_sigaction;
122         }
123         else
124         {
125             o_sigact[i].old_handler = old_act.sa_handler;
126             act.sa_handler = temp_sig_handler;
127         }
128 
129         sigaction(i, &act, NULL);
130         continue;
131     }
132     sig_taken = 1;
133     return 1;
134 }
135 
gs_base_pre_run(void)136 int gs_base_pre_run(void)
137 {
138     if (unlikely(initial_gs == INVALID_GS_REG) )
139     {
140         initial_gs = _getgs();
141         /*
142          * As 2.6.35-28 lucid will get correct gs but clobbered GS_BASE
143          * we have to always re-write the gs base
144          */
145         if (initial_gs == 0x0)
146             gs_need_restore = KVM_GS_RESTORE_NO;
147         else
148             gs_need_restore = KVM_GS_RESTORE_YES;
149     }
150 
151     take_signal_handler();
152     return 0;
153 }
154 
gs_base_post_run(void)155 int gs_base_post_run(void)
156 {
157     check_and_restore_gs();
158     return 0;
159 }
160 
161 /*
162  * ioctl may update errno, which is in thread local storage and
163  * requires gs register, we have to provide our own ioctl
164  * XXX should "call %%gs:$0x10" be replaced with call to vsyscall
165  * page, which is more generic and clean?
166  */
no_gs_ioctl(int fd,int type,void * arg)167 int no_gs_ioctl(int fd, int type, void *arg)
168 {
169     int ret=0;
170 
171     asm(
172       "movl %3, %%edx;\n"
173       "movl %2, %%ecx;\n"
174       "movl %1, %%ebx;\n"
175       "movl $0x36, %%eax;\n"
176       "call *%%gs:0x10;\n"
177       "movl %%eax, %0\n"
178       : "=m"(ret)
179       :"m"(fd),"m"(type),"m"(arg)
180       :"%edx","%ecx","%eax","%ebx"
181       );
182 
183     return ret;
184 }
185 
186 #endif
187 
188