blob: a0ff565f762c4c8d6ac71f29661c39fb317e0849 [file] [log] [blame]
Jun Nakajimabb0140b2011-05-27 18:24:21 -07001#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
11int initial_gs = INVALID_GS_REG;
12int gs_need_restore = KVM_GS_RESTORE_NODETECTED;
13
14static void restoregs(int gs)
15{
16 asm("movl %0, %%gs"::"r"(gs));
17}
18
19static 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 */
27static 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
35static struct sigaction old_alarm_act, old_gio_act, old_pipe_act,old_usr1_act, old_chld_act;
36static 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
68static int sig_taken = 0;
69static 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
93int 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
112int 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 */
124int 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