/root/src/xen/xen/arch/x86/hypercall.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | #define next_arg(fmt, args) ({ \ |
78 | 0 | unsigned long __arg; \ |
79 | 0 | switch ( *(fmt)++ ) \ |
80 | 0 | { \ |
81 | 0 | case 'i': __arg = (unsigned long)va_arg(args, unsigned int); break; \ |
82 | 0 | case 'l': __arg = (unsigned long)va_arg(args, unsigned long); break; \ |
83 | 0 | case 'h': __arg = (unsigned long)va_arg(args, void *); break; \ |
84 | 0 | default: __arg = 0; BUG(); \ |
85 | 0 | } \ |
86 | 0 | __arg; \ |
87 | 0 | }) |
88 | | |
89 | | unsigned long hypercall_create_continuation( |
90 | | unsigned int op, const char *format, ...) |
91 | 0 | { |
92 | 0 | struct vcpu *curr = current; |
93 | 0 | struct mc_state *mcs = &curr->mc_state; |
94 | 0 | const char *p = format; |
95 | 0 | unsigned long arg; |
96 | 0 | unsigned int i; |
97 | 0 | va_list args; |
98 | 0 |
|
99 | 0 | curr->hcall_preempted = true; |
100 | 0 |
|
101 | 0 | va_start(args, format); |
102 | 0 |
|
103 | 0 | if ( mcs->flags & MCSF_in_multicall ) |
104 | 0 | { |
105 | 0 | for ( i = 0; *p != '\0'; i++ ) |
106 | 0 | mcs->call.args[i] = next_arg(p, args); |
107 | 0 | } |
108 | 0 | else |
109 | 0 | { |
110 | 0 | struct cpu_user_regs *regs = guest_cpu_user_regs(); |
111 | 0 |
|
112 | 0 | regs->rax = op; |
113 | 0 |
|
114 | 0 | if ( !curr->hcall_compat ) |
115 | 0 | { |
116 | 0 | for ( i = 0; *p != '\0'; i++ ) |
117 | 0 | { |
118 | 0 | arg = next_arg(p, args); |
119 | 0 | switch ( i ) |
120 | 0 | { |
121 | 0 | case 0: regs->rdi = arg; break; |
122 | 0 | case 1: regs->rsi = arg; break; |
123 | 0 | case 2: regs->rdx = arg; break; |
124 | 0 | case 3: regs->r10 = arg; break; |
125 | 0 | case 4: regs->r8 = arg; break; |
126 | 0 | case 5: regs->r9 = arg; break; |
127 | 0 | } |
128 | 0 | } |
129 | 0 | } |
130 | 0 | else |
131 | 0 | { |
132 | 0 | for ( i = 0; *p != '\0'; i++ ) |
133 | 0 | { |
134 | 0 | arg = next_arg(p, args); |
135 | 0 | switch ( i ) |
136 | 0 | { |
137 | 0 | case 0: regs->rbx = arg; break; |
138 | 0 | case 1: regs->rcx = arg; break; |
139 | 0 | case 2: regs->rdx = arg; break; |
140 | 0 | case 3: regs->rsi = arg; break; |
141 | 0 | case 4: regs->rdi = arg; break; |
142 | 0 | case 5: regs->rbp = arg; break; |
143 | 0 | } |
144 | 0 | } |
145 | 0 | } |
146 | 0 | } |
147 | 0 |
|
148 | 0 | va_end(args); |
149 | 0 |
|
150 | 0 | return op; |
151 | 0 | } |
152 | | |
153 | | int hypercall_xlat_continuation(unsigned int *id, unsigned int nr, |
154 | | unsigned int mask, ...) |
155 | 0 | { |
156 | 0 | int rc = 0; |
157 | 0 | struct mc_state *mcs = ¤t->mc_state; |
158 | 0 | struct cpu_user_regs *regs; |
159 | 0 | unsigned int i, cval = 0; |
160 | 0 | unsigned long nval = 0; |
161 | 0 | va_list args; |
162 | 0 |
|
163 | 0 | ASSERT(nr <= ARRAY_SIZE(mcs->call.args)); |
164 | 0 | ASSERT(!(mask >> nr)); |
165 | 0 | ASSERT(!id || *id < nr); |
166 | 0 | ASSERT(!id || !(mask & (1U << *id))); |
167 | 0 |
|
168 | 0 | va_start(args, mask); |
169 | 0 |
|
170 | 0 | if ( mcs->flags & MCSF_in_multicall ) |
171 | 0 | { |
172 | 0 | if ( !current->hcall_preempted ) |
173 | 0 | { |
174 | 0 | va_end(args); |
175 | 0 | return 0; |
176 | 0 | } |
177 | 0 |
|
178 | 0 | for ( i = 0; i < nr; ++i, mask >>= 1 ) |
179 | 0 | { |
180 | 0 | if ( mask & 1 ) |
181 | 0 | { |
182 | 0 | nval = va_arg(args, unsigned long); |
183 | 0 | cval = va_arg(args, unsigned int); |
184 | 0 | if ( cval == nval ) |
185 | 0 | mask &= ~1U; |
186 | 0 | else |
187 | 0 | BUG_ON(nval == (unsigned int)nval); |
188 | 0 | } |
189 | 0 | else if ( id && *id == i ) |
190 | 0 | { |
191 | 0 | *id = mcs->call.args[i]; |
192 | 0 | id = NULL; |
193 | 0 | } |
194 | 0 | if ( (mask & 1) && mcs->call.args[i] == nval ) |
195 | 0 | { |
196 | 0 | mcs->call.args[i] = cval; |
197 | 0 | ++rc; |
198 | 0 | } |
199 | 0 | else |
200 | 0 | BUG_ON(mcs->call.args[i] != (unsigned int)mcs->call.args[i]); |
201 | 0 | } |
202 | 0 | } |
203 | 0 | else |
204 | 0 | { |
205 | 0 | regs = guest_cpu_user_regs(); |
206 | 0 | for ( i = 0; i < nr; ++i, mask >>= 1 ) |
207 | 0 | { |
208 | 0 | unsigned long *reg; |
209 | 0 |
|
210 | 0 | switch ( i ) |
211 | 0 | { |
212 | 0 | case 0: reg = ®s->rbx; break; |
213 | 0 | case 1: reg = ®s->rcx; break; |
214 | 0 | case 2: reg = ®s->rdx; break; |
215 | 0 | case 3: reg = ®s->rsi; break; |
216 | 0 | case 4: reg = ®s->rdi; break; |
217 | 0 | case 5: reg = ®s->rbp; break; |
218 | 0 | default: BUG(); reg = NULL; break; |
219 | 0 | } |
220 | 0 | if ( (mask & 1) ) |
221 | 0 | { |
222 | 0 | nval = va_arg(args, unsigned long); |
223 | 0 | cval = va_arg(args, unsigned int); |
224 | 0 | if ( cval == nval ) |
225 | 0 | mask &= ~1U; |
226 | 0 | else |
227 | 0 | BUG_ON(nval == (unsigned int)nval); |
228 | 0 | } |
229 | 0 | else if ( id && *id == i ) |
230 | 0 | { |
231 | 0 | *id = *reg; |
232 | 0 | id = NULL; |
233 | 0 | } |
234 | 0 | if ( (mask & 1) && *reg == nval ) |
235 | 0 | { |
236 | 0 | *reg = cval; |
237 | 0 | ++rc; |
238 | 0 | } |
239 | 0 | else |
240 | 0 | BUG_ON(*reg != (unsigned int)*reg); |
241 | 0 | } |
242 | 0 | } |
243 | 0 |
|
244 | 0 | va_end(args); |
245 | 0 |
|
246 | 0 | return rc; |
247 | 0 | } |
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 | | |