Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/ia64/xen/xcom_hcall.c
10817 views
1
/*
2
* This program is free software; you can redistribute it and/or modify
3
* it under the terms of the GNU General Public License as published by
4
* the Free Software Foundation; either version 2 of the License, or
5
* (at your option) any later version.
6
*
7
* This program is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
* GNU General Public License for more details.
11
*
12
* You should have received a copy of the GNU General Public License
13
* along with this program; if not, write to the Free Software
14
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15
*
16
* Tristan Gingold <[email protected]>
17
*
18
* Copyright (c) 2007
19
* Isaku Yamahata <yamahata at valinux co jp>
20
* VA Linux Systems Japan K.K.
21
* consolidate mini and inline version.
22
*/
23
24
#include <linux/module.h>
25
#include <xen/interface/xen.h>
26
#include <xen/interface/memory.h>
27
#include <xen/interface/grant_table.h>
28
#include <xen/interface/callback.h>
29
#include <xen/interface/vcpu.h>
30
#include <asm/xen/hypervisor.h>
31
#include <asm/xen/xencomm.h>
32
33
/* Xencomm notes:
34
* This file defines hypercalls to be used by xencomm. The hypercalls simply
35
* create inlines or mini descriptors for pointers and then call the raw arch
36
* hypercall xencomm_arch_hypercall_XXX
37
*
38
* If the arch wants to directly use these hypercalls, simply define macros
39
* in asm/xen/hypercall.h, eg:
40
* #define HYPERVISOR_sched_op xencomm_hypercall_sched_op
41
*
42
* The arch may also define HYPERVISOR_xxx as a function and do more operations
43
* before/after doing the hypercall.
44
*
45
* Note: because only inline or mini descriptors are created these functions
46
* must only be called with in kernel memory parameters.
47
*/
48
49
int
50
xencomm_hypercall_console_io(int cmd, int count, char *str)
51
{
52
/* xen early printk uses console io hypercall before
53
* xencomm initialization. In that case, we just ignore it.
54
*/
55
if (!xencomm_is_initialized())
56
return 0;
57
58
return xencomm_arch_hypercall_console_io
59
(cmd, count, xencomm_map_no_alloc(str, count));
60
}
61
EXPORT_SYMBOL_GPL(xencomm_hypercall_console_io);
62
63
int
64
xencomm_hypercall_event_channel_op(int cmd, void *op)
65
{
66
struct xencomm_handle *desc;
67
desc = xencomm_map_no_alloc(op, sizeof(struct evtchn_op));
68
if (desc == NULL)
69
return -EINVAL;
70
71
return xencomm_arch_hypercall_event_channel_op(cmd, desc);
72
}
73
EXPORT_SYMBOL_GPL(xencomm_hypercall_event_channel_op);
74
75
int
76
xencomm_hypercall_xen_version(int cmd, void *arg)
77
{
78
struct xencomm_handle *desc;
79
unsigned int argsize;
80
81
switch (cmd) {
82
case XENVER_version:
83
/* do not actually pass an argument */
84
return xencomm_arch_hypercall_xen_version(cmd, 0);
85
case XENVER_extraversion:
86
argsize = sizeof(struct xen_extraversion);
87
break;
88
case XENVER_compile_info:
89
argsize = sizeof(struct xen_compile_info);
90
break;
91
case XENVER_capabilities:
92
argsize = sizeof(struct xen_capabilities_info);
93
break;
94
case XENVER_changeset:
95
argsize = sizeof(struct xen_changeset_info);
96
break;
97
case XENVER_platform_parameters:
98
argsize = sizeof(struct xen_platform_parameters);
99
break;
100
case XENVER_get_features:
101
argsize = (arg == NULL) ? 0 : sizeof(struct xen_feature_info);
102
break;
103
104
default:
105
printk(KERN_DEBUG
106
"%s: unknown version op %d\n", __func__, cmd);
107
return -ENOSYS;
108
}
109
110
desc = xencomm_map_no_alloc(arg, argsize);
111
if (desc == NULL)
112
return -EINVAL;
113
114
return xencomm_arch_hypercall_xen_version(cmd, desc);
115
}
116
EXPORT_SYMBOL_GPL(xencomm_hypercall_xen_version);
117
118
int
119
xencomm_hypercall_physdev_op(int cmd, void *op)
120
{
121
unsigned int argsize;
122
123
switch (cmd) {
124
case PHYSDEVOP_apic_read:
125
case PHYSDEVOP_apic_write:
126
argsize = sizeof(struct physdev_apic);
127
break;
128
case PHYSDEVOP_alloc_irq_vector:
129
case PHYSDEVOP_free_irq_vector:
130
argsize = sizeof(struct physdev_irq);
131
break;
132
case PHYSDEVOP_irq_status_query:
133
argsize = sizeof(struct physdev_irq_status_query);
134
break;
135
136
default:
137
printk(KERN_DEBUG
138
"%s: unknown physdev op %d\n", __func__, cmd);
139
return -ENOSYS;
140
}
141
142
return xencomm_arch_hypercall_physdev_op
143
(cmd, xencomm_map_no_alloc(op, argsize));
144
}
145
146
static int
147
xencommize_grant_table_op(struct xencomm_mini **xc_area,
148
unsigned int cmd, void *op, unsigned int count,
149
struct xencomm_handle **desc)
150
{
151
struct xencomm_handle *desc1;
152
unsigned int argsize;
153
154
switch (cmd) {
155
case GNTTABOP_map_grant_ref:
156
argsize = sizeof(struct gnttab_map_grant_ref);
157
break;
158
case GNTTABOP_unmap_grant_ref:
159
argsize = sizeof(struct gnttab_unmap_grant_ref);
160
break;
161
case GNTTABOP_setup_table:
162
{
163
struct gnttab_setup_table *setup = op;
164
165
argsize = sizeof(*setup);
166
167
if (count != 1)
168
return -EINVAL;
169
desc1 = __xencomm_map_no_alloc
170
(xen_guest_handle(setup->frame_list),
171
setup->nr_frames *
172
sizeof(*xen_guest_handle(setup->frame_list)),
173
*xc_area);
174
if (desc1 == NULL)
175
return -EINVAL;
176
(*xc_area)++;
177
set_xen_guest_handle(setup->frame_list, (void *)desc1);
178
break;
179
}
180
case GNTTABOP_dump_table:
181
argsize = sizeof(struct gnttab_dump_table);
182
break;
183
case GNTTABOP_transfer:
184
argsize = sizeof(struct gnttab_transfer);
185
break;
186
case GNTTABOP_copy:
187
argsize = sizeof(struct gnttab_copy);
188
break;
189
case GNTTABOP_query_size:
190
argsize = sizeof(struct gnttab_query_size);
191
break;
192
default:
193
printk(KERN_DEBUG "%s: unknown hypercall grant table op %d\n",
194
__func__, cmd);
195
BUG();
196
}
197
198
*desc = __xencomm_map_no_alloc(op, count * argsize, *xc_area);
199
if (*desc == NULL)
200
return -EINVAL;
201
(*xc_area)++;
202
203
return 0;
204
}
205
206
int
207
xencomm_hypercall_grant_table_op(unsigned int cmd, void *op,
208
unsigned int count)
209
{
210
int rc;
211
struct xencomm_handle *desc;
212
XENCOMM_MINI_ALIGNED(xc_area, 2);
213
214
rc = xencommize_grant_table_op(&xc_area, cmd, op, count, &desc);
215
if (rc)
216
return rc;
217
218
return xencomm_arch_hypercall_grant_table_op(cmd, desc, count);
219
}
220
EXPORT_SYMBOL_GPL(xencomm_hypercall_grant_table_op);
221
222
int
223
xencomm_hypercall_sched_op(int cmd, void *arg)
224
{
225
struct xencomm_handle *desc;
226
unsigned int argsize;
227
228
switch (cmd) {
229
case SCHEDOP_yield:
230
case SCHEDOP_block:
231
argsize = 0;
232
break;
233
case SCHEDOP_shutdown:
234
argsize = sizeof(struct sched_shutdown);
235
break;
236
case SCHEDOP_poll:
237
{
238
struct sched_poll *poll = arg;
239
struct xencomm_handle *ports;
240
241
argsize = sizeof(struct sched_poll);
242
ports = xencomm_map_no_alloc(xen_guest_handle(poll->ports),
243
sizeof(*xen_guest_handle(poll->ports)));
244
245
set_xen_guest_handle(poll->ports, (void *)ports);
246
break;
247
}
248
default:
249
printk(KERN_DEBUG "%s: unknown sched op %d\n", __func__, cmd);
250
return -ENOSYS;
251
}
252
253
desc = xencomm_map_no_alloc(arg, argsize);
254
if (desc == NULL)
255
return -EINVAL;
256
257
return xencomm_arch_hypercall_sched_op(cmd, desc);
258
}
259
EXPORT_SYMBOL_GPL(xencomm_hypercall_sched_op);
260
261
int
262
xencomm_hypercall_multicall(void *call_list, int nr_calls)
263
{
264
int rc;
265
int i;
266
struct multicall_entry *mce;
267
struct xencomm_handle *desc;
268
XENCOMM_MINI_ALIGNED(xc_area, nr_calls * 2);
269
270
for (i = 0; i < nr_calls; i++) {
271
mce = (struct multicall_entry *)call_list + i;
272
273
switch (mce->op) {
274
case __HYPERVISOR_update_va_mapping:
275
case __HYPERVISOR_mmu_update:
276
/* No-op on ia64. */
277
break;
278
case __HYPERVISOR_grant_table_op:
279
rc = xencommize_grant_table_op
280
(&xc_area,
281
mce->args[0], (void *)mce->args[1],
282
mce->args[2], &desc);
283
if (rc)
284
return rc;
285
mce->args[1] = (unsigned long)desc;
286
break;
287
case __HYPERVISOR_memory_op:
288
default:
289
printk(KERN_DEBUG
290
"%s: unhandled multicall op entry op %lu\n",
291
__func__, mce->op);
292
return -ENOSYS;
293
}
294
}
295
296
desc = xencomm_map_no_alloc(call_list,
297
nr_calls * sizeof(struct multicall_entry));
298
if (desc == NULL)
299
return -EINVAL;
300
301
return xencomm_arch_hypercall_multicall(desc, nr_calls);
302
}
303
EXPORT_SYMBOL_GPL(xencomm_hypercall_multicall);
304
305
int
306
xencomm_hypercall_callback_op(int cmd, void *arg)
307
{
308
unsigned int argsize;
309
switch (cmd) {
310
case CALLBACKOP_register:
311
argsize = sizeof(struct callback_register);
312
break;
313
case CALLBACKOP_unregister:
314
argsize = sizeof(struct callback_unregister);
315
break;
316
default:
317
printk(KERN_DEBUG
318
"%s: unknown callback op %d\n", __func__, cmd);
319
return -ENOSYS;
320
}
321
322
return xencomm_arch_hypercall_callback_op
323
(cmd, xencomm_map_no_alloc(arg, argsize));
324
}
325
326
static int
327
xencommize_memory_reservation(struct xencomm_mini *xc_area,
328
struct xen_memory_reservation *mop)
329
{
330
struct xencomm_handle *desc;
331
332
desc = __xencomm_map_no_alloc(xen_guest_handle(mop->extent_start),
333
mop->nr_extents *
334
sizeof(*xen_guest_handle(mop->extent_start)),
335
xc_area);
336
if (desc == NULL)
337
return -EINVAL;
338
339
set_xen_guest_handle(mop->extent_start, (void *)desc);
340
return 0;
341
}
342
343
int
344
xencomm_hypercall_memory_op(unsigned int cmd, void *arg)
345
{
346
GUEST_HANDLE(xen_pfn_t) extent_start_va[2] = { {NULL}, {NULL} };
347
struct xen_memory_reservation *xmr = NULL;
348
int rc;
349
struct xencomm_handle *desc;
350
unsigned int argsize;
351
XENCOMM_MINI_ALIGNED(xc_area, 2);
352
353
switch (cmd) {
354
case XENMEM_increase_reservation:
355
case XENMEM_decrease_reservation:
356
case XENMEM_populate_physmap:
357
xmr = (struct xen_memory_reservation *)arg;
358
set_xen_guest_handle(extent_start_va[0],
359
xen_guest_handle(xmr->extent_start));
360
361
argsize = sizeof(*xmr);
362
rc = xencommize_memory_reservation(xc_area, xmr);
363
if (rc)
364
return rc;
365
xc_area++;
366
break;
367
368
case XENMEM_maximum_ram_page:
369
argsize = 0;
370
break;
371
372
case XENMEM_add_to_physmap:
373
argsize = sizeof(struct xen_add_to_physmap);
374
break;
375
376
default:
377
printk(KERN_DEBUG "%s: unknown memory op %d\n", __func__, cmd);
378
return -ENOSYS;
379
}
380
381
desc = xencomm_map_no_alloc(arg, argsize);
382
if (desc == NULL)
383
return -EINVAL;
384
385
rc = xencomm_arch_hypercall_memory_op(cmd, desc);
386
387
switch (cmd) {
388
case XENMEM_increase_reservation:
389
case XENMEM_decrease_reservation:
390
case XENMEM_populate_physmap:
391
set_xen_guest_handle(xmr->extent_start,
392
xen_guest_handle(extent_start_va[0]));
393
break;
394
}
395
396
return rc;
397
}
398
EXPORT_SYMBOL_GPL(xencomm_hypercall_memory_op);
399
400
int
401
xencomm_hypercall_suspend(unsigned long srec)
402
{
403
struct sched_shutdown arg;
404
405
arg.reason = SHUTDOWN_suspend;
406
407
return xencomm_arch_hypercall_sched_op(
408
SCHEDOP_shutdown, xencomm_map_no_alloc(&arg, sizeof(arg)));
409
}
410
411
long
412
xencomm_hypercall_vcpu_op(int cmd, int cpu, void *arg)
413
{
414
unsigned int argsize;
415
switch (cmd) {
416
case VCPUOP_register_runstate_memory_area: {
417
struct vcpu_register_runstate_memory_area *area =
418
(struct vcpu_register_runstate_memory_area *)arg;
419
argsize = sizeof(*arg);
420
set_xen_guest_handle(area->addr.h,
421
(void *)xencomm_map_no_alloc(area->addr.v,
422
sizeof(area->addr.v)));
423
break;
424
}
425
426
default:
427
printk(KERN_DEBUG "%s: unknown vcpu op %d\n", __func__, cmd);
428
return -ENOSYS;
429
}
430
431
return xencomm_arch_hypercall_vcpu_op(cmd, cpu,
432
xencomm_map_no_alloc(arg, argsize));
433
}
434
435
long
436
xencomm_hypercall_opt_feature(void *arg)
437
{
438
return xencomm_arch_hypercall_opt_feature(
439
xencomm_map_no_alloc(arg,
440
sizeof(struct xen_ia64_opt_feature)));
441
}
442
443