Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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 <tristan.gingold@bull.net>
 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
 49int
 50xencomm_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}
 61EXPORT_SYMBOL_GPL(xencomm_hypercall_console_io);
 62
 63int
 64xencomm_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}
 73EXPORT_SYMBOL_GPL(xencomm_hypercall_event_channel_op);
 74
 75int
 76xencomm_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}
116EXPORT_SYMBOL_GPL(xencomm_hypercall_xen_version);
117
118int
119xencomm_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
146static int
147xencommize_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
206int
207xencomm_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}
220EXPORT_SYMBOL_GPL(xencomm_hypercall_grant_table_op);
221
222int
223xencomm_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}
259EXPORT_SYMBOL_GPL(xencomm_hypercall_sched_op);
260
261int
262xencomm_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}
303EXPORT_SYMBOL_GPL(xencomm_hypercall_multicall);
304
305int
306xencomm_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
326static int
327xencommize_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
343int
344xencomm_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}
398EXPORT_SYMBOL_GPL(xencomm_hypercall_memory_op);
399
400int
401xencomm_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
411long
412xencomm_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
435long
436xencomm_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}