• 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 static struct sigaction old_alarm_act, old_gio_act, old_pipe_act,old_usr1_act, old_chld_act;
temp_sig_handler(int host_signum)36 static void temp_sig_handler(int host_signum)
37 {
38     /* !!! must restore gs firstly */
39     check_and_restore_gs();
40     switch (host_signum)
41     {
42     case SIGALRM:
43         old_alarm_act.sa_handler(host_signum);
44         break;
45 
46     case SIGIO:
47         old_gio_act.sa_handler(host_signum);
48         break;
49 
50     case SIGUSR1:
51         old_usr1_act.sa_handler(host_signum);
52         break;
53 
54     case SIGPIPE:
55         old_pipe_act.sa_handler(host_signum);
56         break;
57 
58     case SIGCHLD:
59         old_chld_act.sa_handler(host_signum);
60         break;
61 
62     default:
63         fprintf(stderr, "Not take signal %x!!\n", host_signum);
64         break;
65     }
66 }
67 
68 static int sig_taken = 0;
take_signal_handler(void)69 static int take_signal_handler(void)
70 {
71     struct sigaction act;
72     int ret;
73 
74     if (gs_need_restore == KVM_GS_RESTORE_NO)
75         return 0;
76     if (sig_taken)
77         return 0;
78 
79     sig_taken = 1;
80     sigfillset(&act.sa_mask);
81     act.sa_flags = 0;
82     act.sa_handler = temp_sig_handler;
83     /* Did we missed any other signal ? */
84     sigaction(SIGALRM, &act, &old_alarm_act);
85     sigaction(SIGIO, &act, &old_gio_act);
86     sigaction(SIGUSR1, &act, &old_usr1_act);
87     sigaction(SIGPIPE, &act, &old_pipe_act);
88     act.sa_flags = SA_NOCLDSTOP;
89     sigaction(SIGCHLD, &act, &old_chld_act);
90     return 1;
91 }
92 
gs_base_pre_run(void)93 int gs_base_pre_run(void)
94 {
95     if (unlikely(initial_gs == INVALID_GS_REG) )
96     {
97         initial_gs = _getgs();
98         /*
99          * As 2.6.35-28 lucid will get correct gs but clobbered GS_BASE
100          * we have to always re-write the gs base
101          */
102         if (initial_gs == 0x0)
103             gs_need_restore = KVM_GS_RESTORE_NO;
104         else
105             gs_need_restore = KVM_GS_RESTORE_YES;
106     }
107 
108     take_signal_handler();
109     return 0;
110 }
111 
gs_base_post_run(void)112 int gs_base_post_run(void)
113 {
114     check_and_restore_gs();
115     return 0;
116 }
117 
118 /*
119  * ioctl may update errno, which is in thread local storage and
120  * requires gs register, we have to provide our own ioctl
121  * XXX should "call %%gs:$0x10" be replaced with call to vsyscall
122  * page, which is more generic and clean?
123  */
no_gs_ioctl(int fd,int type,void * arg)124 int no_gs_ioctl(int fd, int type, void *arg)
125 {
126     int ret=0;
127 
128     asm(
129       "movl %3, %%edx;\n"
130       "movl %2, %%ecx;\n"
131       "movl %1, %%ebx;\n"
132       "movl $0x36, %%eax;\n"
133       "call *%%gs:0x10;\n"
134       "movl %%eax, %0\n"
135       : "=m"(ret)
136       :"m"(fd),"m"(type),"m"(arg)
137       :"%edx","%ecx","%eax","%ebx"
138       );
139 
140     return ret;
141 }
142 
143 #endif
144 
145