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