/******************************************************************************
* asm-x86/guest/hypercall.h
*
* This program is free software; you can redistribute it and/or
* modify it under the terms and conditions of the GNU General Public
* License, version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; If not, see .
*
* Copyright (c) 2017 Citrix Systems Ltd.
*/
#ifndef __X86_XEN_HYPERCALL_H__
#define __X86_XEN_HYPERCALL_H__
#ifdef CONFIG_XEN_GUEST
#include
#include
#include
#include
#include
/*
* Hypercall primatives for 64bit
*
* Inputs: %rdi, %rsi, %rdx, %r10, %r8, %r9 (arguments 1-6)
*/
#define _hypercall64_1(type, hcall, a1) \
({ \
long res, tmp__; \
asm volatile ( \
"call hypercall_page + %c[offset]" \
: "=a" (res), "=D" (tmp__) \
: [offset] "i" (hcall * 32), \
"1" ((long)(a1)) \
: "memory" ); \
(type)res; \
})
#define _hypercall64_2(type, hcall, a1, a2) \
({ \
long res, tmp__; \
asm volatile ( \
"call hypercall_page + %c[offset]" \
: "=a" (res), "=D" (tmp__), "=S" (tmp__) \
: [offset] "i" (hcall * 32), \
"1" ((long)(a1)), "2" ((long)(a2)) \
: "memory" ); \
(type)res; \
})
#define _hypercall64_3(type, hcall, a1, a2, a3) \
({ \
long res, tmp__; \
asm volatile ( \
"call hypercall_page + %c[offset]" \
: "=a" (res), "=D" (tmp__), "=S" (tmp__), "=d" (tmp__) \
: [offset] "i" (hcall * 32), \
"1" ((long)(a1)), "2" ((long)(a2)), "3" ((long)(a3)) \
: "memory" ); \
(type)res; \
})
#define _hypercall64_4(type, hcall, a1, a2, a3, a4) \
({ \
long res, tmp__; \
register long _a4 asm ("r10") = ((long)(a4)); \
asm volatile ( \
"call hypercall_page + %c[offset]" \
: "=a" (res), "=D" (tmp__), "=S" (tmp__), "=d" (tmp__), \
"=&r" (tmp__) \
: [offset] "i" (hcall * 32), \
"1" ((long)(a1)), "2" ((long)(a2)), "3" ((long)(a3)), \
"4" (_a4) \
: "memory" ); \
(type)res; \
})
/*
* Primitive Hypercall wrappers
*/
static inline long xen_hypercall_sched_op(unsigned int cmd, void *arg)
{
return _hypercall64_2(long, __HYPERVISOR_sched_op, cmd, arg);
}
static inline long xen_hypercall_memory_op(unsigned int cmd, void *arg)
{
return _hypercall64_2(long, __HYPERVISOR_memory_op, cmd, arg);
}
static inline int xen_hypercall_vcpu_op(unsigned int cmd, unsigned int vcpu,
void *arg)
{
return _hypercall64_3(long, __HYPERVISOR_vcpu_op, cmd, vcpu, arg);
}
static inline long xen_hypercall_event_channel_op(unsigned int cmd, void *arg)
{
return _hypercall64_2(long, __HYPERVISOR_event_channel_op, cmd, arg);
}
static inline long xen_hypercall_grant_table_op(unsigned int cmd, void *arg,
unsigned int count)
{
return _hypercall64_3(long, __HYPERVISOR_grant_table_op, cmd, arg, count);
}
static inline long xen_hypercall_hvm_op(unsigned int op, void *arg)
{
return _hypercall64_2(long, __HYPERVISOR_hvm_op, op, arg);
}
/*
* Higher level hypercall helpers
*/
static inline void xen_hypercall_console_write(
const char *buf, unsigned int count)
{
(void)_hypercall64_3(long, __HYPERVISOR_console_io,
CONSOLEIO_write, count, buf);
}
static inline long xen_hypercall_shutdown(unsigned int reason)
{
struct sched_shutdown s = { .reason = reason };
return xen_hypercall_sched_op(SCHEDOP_shutdown, &s);
}
static inline long xen_hypercall_evtchn_send(evtchn_port_t port)
{
struct evtchn_send send = { .port = port };
return xen_hypercall_event_channel_op(EVTCHNOP_send, &send);
}
static inline long xen_hypercall_evtchn_unmask(evtchn_port_t port)
{
struct evtchn_unmask unmask = { .port = port };
return xen_hypercall_event_channel_op(EVTCHNOP_unmask, &unmask);
}
static inline long xen_hypercall_hvm_get_param(uint32_t index, uint64_t *value)
{
struct xen_hvm_param xhv = {
.domid = DOMID_SELF,
.index = index,
};
long ret = xen_hypercall_hvm_op(HVMOP_get_param, &xhv);
if ( ret == 0 )
*value = xhv.value;
return ret;
}
static inline long xen_hypercall_set_evtchn_upcall_vector(
unsigned int cpu, unsigned int vector)
{
struct xen_hvm_evtchn_upcall_vector a = {
.vcpu = cpu,
.vector = vector,
};
return xen_hypercall_hvm_op(HVMOP_set_evtchn_upcall_vector, &a);
}
#else /* CONFIG_XEN_GUEST */
#include
static inline void xen_hypercall_console_write(
const char *buf, unsigned int count)
{
ASSERT_UNREACHABLE();
}
static inline long xen_hypercall_shutdown(unsigned int reason)
{
ASSERT_UNREACHABLE();
return 0;
}
#endif /* CONFIG_XEN_GUEST */
#endif /* __X86_XEN_HYPERCALL_H__ */
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/