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 = ¤t->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 = ®s->rbx; break;
239 case 1: reg = ®s->rcx; break;
240 case 2: reg = ®s->rdx; break;
241 case 3: reg = ®s->rsi; break;
242 case 4: reg = ®s->rdi; break;
243 case 5: reg = ®s->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