1 /******************************************************************************
2  * arch/x86/hypercall.c
3  *
4  * Common x86 hypercall infrastructure.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Copyright (c) 2015,2016 Citrix Systems Ltd.
20  */
21 
22 #include <xen/hypercall.h>
23 
24 #define ARGS(x, n)                              \
25     [ __HYPERVISOR_ ## x ] = { n, n }
26 #define COMP(x, n, c)                           \
27     [ __HYPERVISOR_ ## x ] = { n, c }
28 
29 const hypercall_args_t hypercall_args_table[NR_hypercalls] =
30 {
31     ARGS(set_trap_table, 1),
32     ARGS(mmu_update, 4),
33     ARGS(set_gdt, 2),
34     ARGS(stack_switch, 2),
35     COMP(set_callbacks, 3, 4),
36     ARGS(fpu_taskswitch, 1),
37     ARGS(sched_op_compat, 2),
38     ARGS(platform_op, 1),
39     ARGS(set_debugreg, 2),
40     ARGS(get_debugreg, 1),
41     COMP(update_descriptor, 2, 4),
42     ARGS(memory_op, 2),
43     ARGS(multicall, 2),
44     COMP(update_va_mapping, 3, 4),
45     COMP(set_timer_op, 1, 2),
46     ARGS(event_channel_op_compat, 1),
47     ARGS(xen_version, 2),
48     ARGS(console_io, 3),
49     ARGS(physdev_op_compat, 1),
50 #ifdef CONFIG_GRANT_TABLE
51     ARGS(grant_table_op, 3),
52 #endif
53     ARGS(vm_assist, 2),
54     COMP(update_va_mapping_otherdomain, 4, 5),
55     ARGS(vcpu_op, 3),
56     COMP(set_segment_base, 2, 0),
57     ARGS(mmuext_op, 4),
58     ARGS(xsm_op, 1),
59     ARGS(nmi_op, 2),
60     ARGS(sched_op, 2),
61     ARGS(callback_op, 2),
62     ARGS(xenoprof_op, 2),
63     ARGS(event_channel_op, 2),
64     ARGS(physdev_op, 2),
65     ARGS(sysctl, 1),
66     ARGS(domctl, 1),
67     ARGS(kexec_op, 2),
68 #ifdef CONFIG_ARGO
69     ARGS(argo_op, 5),
70 #endif
71     ARGS(xenpmu_op, 2),
72 #ifdef CONFIG_HVM
73     ARGS(hvm_op, 2),
74     ARGS(dm_op, 3),
75 #endif
76 #ifdef CONFIG_HYPFS
77     ARGS(hypfs_op, 5),
78 #endif
79     ARGS(mca, 1),
80     ARGS(arch_1, 1),
81 };
82 
83 #undef COMP
84 #undef ARGS
85 
86 #define NEXT_ARG(fmt, args)                                                 \
87 ({                                                                          \
88     unsigned long __arg;                                                    \
89     switch ( *(fmt)++ )                                                     \
90     {                                                                       \
91     case 'i': __arg = (unsigned long)va_arg(args, unsigned int);  break;    \
92     case 'l': __arg = (unsigned long)va_arg(args, unsigned long); break;    \
93     case 'h': __arg = (unsigned long)va_arg(args, void *);        break;    \
94     default:  goto bad_fmt;                                                 \
95     }                                                                       \
96     __arg;                                                                  \
97 })
98 
hypercall_create_continuation(unsigned int op,const char * format,...)99 unsigned long hypercall_create_continuation(
100     unsigned int op, const char *format, ...)
101 {
102     struct vcpu *curr = current;
103     struct mc_state *mcs = &curr->mc_state;
104     const char *p = format;
105     unsigned long arg;
106     unsigned int i;
107     va_list args;
108 
109     curr->hcall_preempted = true;
110 
111     va_start(args, format);
112 
113     if ( mcs->flags & MCSF_in_multicall )
114     {
115         for ( i = 0; *p != '\0'; i++ )
116             mcs->call.args[i] = NEXT_ARG(p, args);
117     }
118     else
119     {
120         struct cpu_user_regs *regs = guest_cpu_user_regs();
121 
122         regs->rax = op;
123 
124         if ( !curr->hcall_compat )
125         {
126             for ( i = 0; *p != '\0'; i++ )
127             {
128                 arg = NEXT_ARG(p, args);
129                 switch ( i )
130                 {
131                 case 0: regs->rdi = arg; break;
132                 case 1: regs->rsi = arg; break;
133                 case 2: regs->rdx = arg; break;
134                 case 3: regs->r10 = arg; break;
135                 case 4: regs->r8  = arg; break;
136                 case 5: regs->r9  = arg; break;
137                 }
138             }
139         }
140         else
141         {
142             for ( i = 0; *p != '\0'; i++ )
143             {
144                 arg = NEXT_ARG(p, args);
145                 switch ( i )
146                 {
147                 case 0: regs->rbx = arg; break;
148                 case 1: regs->rcx = arg; break;
149                 case 2: regs->rdx = arg; break;
150                 case 3: regs->rsi = arg; break;
151                 case 4: regs->rdi = arg; break;
152                 case 5: regs->rbp = arg; break;
153                 }
154             }
155         }
156     }
157 
158     va_end(args);
159 
160     return op;
161 
162  bad_fmt:
163     va_end(args);
164     gprintk(XENLOG_ERR, "Bad hypercall continuation format '%c'\n", *p);
165     ASSERT_UNREACHABLE();
166     domain_crash(curr->domain);
167     return 0;
168 }
169 
170 #undef NEXT_ARG
171 
arch_hypercall_tasklet_result(struct vcpu * v,long res)172 void arch_hypercall_tasklet_result(struct vcpu *v, long res)
173 {
174     struct cpu_user_regs *regs = &v->arch.user_regs;
175 
176     regs->rax = res;
177 }
178 
hypercall_xlat_continuation(unsigned int * id,unsigned int nr,unsigned int mask,...)179 int hypercall_xlat_continuation(unsigned int *id, unsigned int nr,
180                                 unsigned int mask, ...)
181 {
182     int rc = 0;
183     struct mc_state *mcs = &current->mc_state;
184     struct cpu_user_regs *regs;
185     unsigned int i, cval = 0;
186     unsigned long nval = 0;
187     va_list args;
188 
189     ASSERT(nr <= ARRAY_SIZE(mcs->call.args));
190     ASSERT(!(mask >> nr));
191     ASSERT(!id || *id < nr);
192     ASSERT(!id || !(mask & (1U << *id)));
193 
194     va_start(args, mask);
195 
196     if ( mcs->flags & MCSF_in_multicall )
197     {
198         if ( !current->hcall_preempted )
199         {
200             va_end(args);
201             return 0;
202         }
203 
204         for ( i = 0; i < nr; ++i, mask >>= 1 )
205         {
206             if ( mask & 1 )
207             {
208                 nval = va_arg(args, unsigned long);
209                 cval = va_arg(args, unsigned int);
210                 if ( cval == nval )
211                     mask &= ~1U;
212                 else
213                     BUG_ON(nval == (unsigned int)nval);
214             }
215             else if ( id && *id == i )
216             {
217                 *id = mcs->call.args[i];
218                 id = NULL;
219             }
220             if ( (mask & 1) && mcs->call.args[i] == nval )
221             {
222                 mcs->call.args[i] = cval;
223                 ++rc;
224             }
225             else
226                 BUG_ON(mcs->call.args[i] != (unsigned int)mcs->call.args[i]);
227         }
228     }
229     else
230     {
231         regs = guest_cpu_user_regs();
232         for ( i = 0; i < nr; ++i, mask >>= 1 )
233         {
234             unsigned long *reg;
235 
236             switch ( i )
237             {
238             case 0: reg = &regs->rbx; break;
239             case 1: reg = &regs->rcx; break;
240             case 2: reg = &regs->rdx; break;
241             case 3: reg = &regs->rsi; break;
242             case 4: reg = &regs->rdi; break;
243             case 5: reg = &regs->rbp; break;
244             default: BUG(); reg = NULL; break;
245             }
246             if ( (mask & 1) )
247             {
248                 nval = va_arg(args, unsigned long);
249                 cval = va_arg(args, unsigned int);
250                 if ( cval == nval )
251                     mask &= ~1U;
252                 else
253                     BUG_ON(nval == (unsigned int)nval);
254             }
255             else if ( id && *id == i )
256             {
257                 *id = *reg;
258                 id = NULL;
259             }
260             if ( (mask & 1) && *reg == nval )
261             {
262                 *reg = cval;
263                 ++rc;
264             }
265             else
266                 BUG_ON(*reg != (unsigned int)*reg);
267         }
268     }
269 
270     va_end(args);
271 
272     return rc;
273 }
274 
275 #ifndef CONFIG_PV
276 /* Stub for arch_do_multicall_call */
arch_do_multicall_call(struct mc_state * mc)277 enum mc_disposition arch_do_multicall_call(struct mc_state *mc)
278 {
279     return mc_exit;
280 }
281 #endif
282 
283 /*
284  * Local variables:
285  * mode: C
286  * c-file-style: "BSD"
287  * c-basic-offset: 4
288  * tab-width: 4
289  * indent-tabs-mode: nil
290  * End:
291  */
292 
293