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 ARGS(grant_table_op, 3),
51 ARGS(vm_assist, 2),
52 COMP(update_va_mapping_otherdomain, 4, 5),
53 ARGS(vcpu_op, 3),
54 COMP(set_segment_base, 2, 0),
55 ARGS(mmuext_op, 4),
56 ARGS(xsm_op, 1),
57 ARGS(nmi_op, 2),
58 ARGS(sched_op, 2),
59 ARGS(callback_op, 2),
60 ARGS(xenoprof_op, 2),
61 ARGS(event_channel_op, 2),
62 ARGS(physdev_op, 2),
63 ARGS(hvm_op, 2),
64 ARGS(sysctl, 1),
65 ARGS(domctl, 1),
66 ARGS(kexec_op, 2),
67 ARGS(tmem_op, 1),
68 ARGS(xenpmu_op, 2),
69 ARGS(dm_op, 3),
70 ARGS(mca, 1),
71 ARGS(arch_1, 1),
72 };
73
74 #undef COMP
75 #undef ARGS
76
77 #define next_arg(fmt, args) ({ \
78 unsigned long __arg; \
79 switch ( *(fmt)++ ) \
80 { \
81 case 'i': __arg = (unsigned long)va_arg(args, unsigned int); break; \
82 case 'l': __arg = (unsigned long)va_arg(args, unsigned long); break; \
83 case 'h': __arg = (unsigned long)va_arg(args, void *); break; \
84 default: __arg = 0; BUG(); \
85 } \
86 __arg; \
87 })
88
hypercall_create_continuation(unsigned int op,const char * format,...)89 unsigned long hypercall_create_continuation(
90 unsigned int op, const char *format, ...)
91 {
92 struct vcpu *curr = current;
93 struct mc_state *mcs = &curr->mc_state;
94 const char *p = format;
95 unsigned long arg;
96 unsigned int i;
97 va_list args;
98
99 curr->hcall_preempted = true;
100
101 va_start(args, format);
102
103 if ( mcs->flags & MCSF_in_multicall )
104 {
105 for ( i = 0; *p != '\0'; i++ )
106 mcs->call.args[i] = next_arg(p, args);
107 }
108 else
109 {
110 struct cpu_user_regs *regs = guest_cpu_user_regs();
111
112 regs->rax = op;
113
114 if ( !curr->hcall_compat )
115 {
116 for ( i = 0; *p != '\0'; i++ )
117 {
118 arg = next_arg(p, args);
119 switch ( i )
120 {
121 case 0: regs->rdi = arg; break;
122 case 1: regs->rsi = arg; break;
123 case 2: regs->rdx = arg; break;
124 case 3: regs->r10 = arg; break;
125 case 4: regs->r8 = arg; break;
126 case 5: regs->r9 = arg; break;
127 }
128 }
129 }
130 else
131 {
132 for ( i = 0; *p != '\0'; i++ )
133 {
134 arg = next_arg(p, args);
135 switch ( i )
136 {
137 case 0: regs->rbx = arg; break;
138 case 1: regs->rcx = arg; break;
139 case 2: regs->rdx = arg; break;
140 case 3: regs->rsi = arg; break;
141 case 4: regs->rdi = arg; break;
142 case 5: regs->rbp = arg; break;
143 }
144 }
145 }
146 }
147
148 va_end(args);
149
150 return op;
151 }
152
hypercall_xlat_continuation(unsigned int * id,unsigned int nr,unsigned int mask,...)153 int hypercall_xlat_continuation(unsigned int *id, unsigned int nr,
154 unsigned int mask, ...)
155 {
156 int rc = 0;
157 struct mc_state *mcs = ¤t->mc_state;
158 struct cpu_user_regs *regs;
159 unsigned int i, cval = 0;
160 unsigned long nval = 0;
161 va_list args;
162
163 ASSERT(nr <= ARRAY_SIZE(mcs->call.args));
164 ASSERT(!(mask >> nr));
165 ASSERT(!id || *id < nr);
166 ASSERT(!id || !(mask & (1U << *id)));
167
168 va_start(args, mask);
169
170 if ( mcs->flags & MCSF_in_multicall )
171 {
172 if ( !current->hcall_preempted )
173 {
174 va_end(args);
175 return 0;
176 }
177
178 for ( i = 0; i < nr; ++i, mask >>= 1 )
179 {
180 if ( mask & 1 )
181 {
182 nval = va_arg(args, unsigned long);
183 cval = va_arg(args, unsigned int);
184 if ( cval == nval )
185 mask &= ~1U;
186 else
187 BUG_ON(nval == (unsigned int)nval);
188 }
189 else if ( id && *id == i )
190 {
191 *id = mcs->call.args[i];
192 id = NULL;
193 }
194 if ( (mask & 1) && mcs->call.args[i] == nval )
195 {
196 mcs->call.args[i] = cval;
197 ++rc;
198 }
199 else
200 BUG_ON(mcs->call.args[i] != (unsigned int)mcs->call.args[i]);
201 }
202 }
203 else
204 {
205 regs = guest_cpu_user_regs();
206 for ( i = 0; i < nr; ++i, mask >>= 1 )
207 {
208 unsigned long *reg;
209
210 switch ( i )
211 {
212 case 0: reg = ®s->rbx; break;
213 case 1: reg = ®s->rcx; break;
214 case 2: reg = ®s->rdx; break;
215 case 3: reg = ®s->rsi; break;
216 case 4: reg = ®s->rdi; break;
217 case 5: reg = ®s->rbp; break;
218 default: BUG(); reg = NULL; break;
219 }
220 if ( (mask & 1) )
221 {
222 nval = va_arg(args, unsigned long);
223 cval = va_arg(args, unsigned int);
224 if ( cval == nval )
225 mask &= ~1U;
226 else
227 BUG_ON(nval == (unsigned int)nval);
228 }
229 else if ( id && *id == i )
230 {
231 *id = *reg;
232 id = NULL;
233 }
234 if ( (mask & 1) && *reg == nval )
235 {
236 *reg = cval;
237 ++rc;
238 }
239 else
240 BUG_ON(*reg != (unsigned int)*reg);
241 }
242 }
243
244 va_end(args);
245
246 return rc;
247 }
248
249 /*
250 * Local variables:
251 * mode: C
252 * c-file-style: "BSD"
253 * c-basic-offset: 4
254 * tab-width: 4
255 * indent-tabs-mode: nil
256 * End:
257 */
258
259