Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 104409
b: refs/heads/master
c: e743590
h: refs/heads/master
i:
  104407: a07ab34
v: v3
  • Loading branch information
Jeremy Fitzhardinge authored and Ingo Molnar committed Jul 16, 2008
1 parent 01798fb commit 89e8388
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 49 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ca15f20f1126f897500ade892a2d598a08da1b56
refs/heads/master: e74359028d5489a281fb2c379a47b1d3cb14526e
170 changes: 122 additions & 48 deletions trunk/include/asm-x86/xen/hypercall.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,83 +40,157 @@
#include <xen/interface/sched.h>
#include <xen/interface/physdev.h>

/*
* The hypercall asms have to meet several constraints:
* - Work on 32- and 64-bit.
* The two architectures put their arguments in different sets of
* registers.
*
* - Work around asm syntax quirks
* It isn't possible to specify one of the rNN registers in a
* constraint, so we use explicit register variables to get the
* args into the right place.
*
* - Mark all registers as potentially clobbered
* Even unused parameters can be clobbered by the hypervisor, so we
* need to make sure gcc knows it.
*
* - Avoid compiler bugs.
* This is the tricky part. Because x86_32 has such a constrained
* register set, gcc versions below 4.3 have trouble generating
* code when all the arg registers and memory are trashed by the
* asm. There are syntactically simpler ways of achieving the
* semantics below, but they cause the compiler to crash.
*
* The only combination I found which works is:
* - assign the __argX variables first
* - list all actually used parameters as "+r" (__argX)
* - clobber the rest
*
* The result certainly isn't pretty, and it really shows up cpp's
* weakness as as macro language. Sorry. (But let's just give thanks
* there aren't more than 5 arguments...)
*/

extern struct { char _entry[32]; } hypercall_page[];

#define __HYPERCALL "call hypercall_page+%c[offset]"
#define __HYPERCALL_ENTRY(x) \
[offset] "i" (__HYPERVISOR_##x * sizeof(hypercall_page[0]))

#ifdef CONFIG_X86_32
#define __HYPERCALL_RETREG "eax"
#define __HYPERCALL_ARG1REG "ebx"
#define __HYPERCALL_ARG2REG "ecx"
#define __HYPERCALL_ARG3REG "edx"
#define __HYPERCALL_ARG4REG "esi"
#define __HYPERCALL_ARG5REG "edi"
#else
#define __HYPERCALL_RETREG "rax"
#define __HYPERCALL_ARG1REG "rdi"
#define __HYPERCALL_ARG2REG "rsi"
#define __HYPERCALL_ARG3REG "rdx"
#define __HYPERCALL_ARG4REG "r10"
#define __HYPERCALL_ARG5REG "r8"
#endif

#define __HYPERCALL_DECLS \
register unsigned long __res asm(__HYPERCALL_RETREG); \
register unsigned long __arg1 asm(__HYPERCALL_ARG1REG) = __arg1; \
register unsigned long __arg2 asm(__HYPERCALL_ARG2REG) = __arg2; \
register unsigned long __arg3 asm(__HYPERCALL_ARG3REG) = __arg3; \
register unsigned long __arg4 asm(__HYPERCALL_ARG4REG) = __arg4; \
register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5;

#define __HYPERCALL_0PARAM "=r" (__res)
#define __HYPERCALL_1PARAM __HYPERCALL_0PARAM, "+r" (__arg1)
#define __HYPERCALL_2PARAM __HYPERCALL_1PARAM, "+r" (__arg2)
#define __HYPERCALL_3PARAM __HYPERCALL_2PARAM, "+r" (__arg3)
#define __HYPERCALL_4PARAM __HYPERCALL_3PARAM, "+r" (__arg4)
#define __HYPERCALL_5PARAM __HYPERCALL_4PARAM, "+r" (__arg5)

#define __HYPERCALL_0ARG()
#define __HYPERCALL_1ARG(a1) \
__HYPERCALL_0ARG() __arg1 = (unsigned long)(a1);
#define __HYPERCALL_2ARG(a1,a2) \
__HYPERCALL_1ARG(a1) __arg2 = (unsigned long)(a2);
#define __HYPERCALL_3ARG(a1,a2,a3) \
__HYPERCALL_2ARG(a1,a2) __arg3 = (unsigned long)(a3);
#define __HYPERCALL_4ARG(a1,a2,a3,a4) \
__HYPERCALL_3ARG(a1,a2,a3) __arg4 = (unsigned long)(a4);
#define __HYPERCALL_5ARG(a1,a2,a3,a4,a5) \
__HYPERCALL_4ARG(a1,a2,a3,a4) __arg5 = (unsigned long)(a5);

#define __HYPERCALL_CLOBBER5 "memory"
#define __HYPERCALL_CLOBBER4 __HYPERCALL_CLOBBER5, __HYPERCALL_ARG5REG
#define __HYPERCALL_CLOBBER3 __HYPERCALL_CLOBBER4, __HYPERCALL_ARG4REG
#define __HYPERCALL_CLOBBER2 __HYPERCALL_CLOBBER3, __HYPERCALL_ARG3REG
#define __HYPERCALL_CLOBBER1 __HYPERCALL_CLOBBER2, __HYPERCALL_ARG2REG
#define __HYPERCALL_CLOBBER0 __HYPERCALL_CLOBBER1, __HYPERCALL_ARG1REG

#define _hypercall0(type, name) \
({ \
long __res; \
asm volatile ( \
"call %[call]" \
: "=a" (__res) \
: [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
: "memory" ); \
__HYPERCALL_DECLS; \
__HYPERCALL_0ARG(); \
asm volatile (__HYPERCALL \
: __HYPERCALL_0PARAM \
: __HYPERCALL_ENTRY(name) \
: __HYPERCALL_CLOBBER0); \
(type)__res; \
})

#define _hypercall1(type, name, a1) \
({ \
long __res, __ign1; \
asm volatile ( \
"call %[call]" \
: "=a" (__res), "=b" (__ign1) \
: "1" ((long)(a1)), \
[call] "m" (hypercall_page[__HYPERVISOR_##name]) \
: "memory" ); \
__HYPERCALL_DECLS; \
__HYPERCALL_1ARG(a1); \
asm volatile (__HYPERCALL \
: __HYPERCALL_1PARAM \
: __HYPERCALL_ENTRY(name) \
: __HYPERCALL_CLOBBER1); \
(type)__res; \
})

#define _hypercall2(type, name, a1, a2) \
({ \
long __res, __ign1, __ign2; \
asm volatile ( \
"call %[call]" \
: "=a" (__res), "=b" (__ign1), "=c" (__ign2) \
: "1" ((long)(a1)), "2" ((long)(a2)), \
[call] "m" (hypercall_page[__HYPERVISOR_##name]) \
: "memory" ); \
__HYPERCALL_DECLS; \
__HYPERCALL_2ARG(a1, a2); \
asm volatile (__HYPERCALL \
: __HYPERCALL_2PARAM \
: __HYPERCALL_ENTRY(name) \
: __HYPERCALL_CLOBBER2); \
(type)__res; \
})

#define _hypercall3(type, name, a1, a2, a3) \
({ \
long __res, __ign1, __ign2, __ign3; \
asm volatile ( \
"call %[call]" \
: "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
"=d" (__ign3) \
: "1" ((long)(a1)), "2" ((long)(a2)), \
"3" ((long)(a3)), \
[call] "m" (hypercall_page[__HYPERVISOR_##name]) \
: "memory" ); \
__HYPERCALL_DECLS; \
__HYPERCALL_3ARG(a1, a2, a3); \
asm volatile (__HYPERCALL \
: __HYPERCALL_3PARAM \
: __HYPERCALL_ENTRY(name) \
: __HYPERCALL_CLOBBER3); \
(type)__res; \
})

#define _hypercall4(type, name, a1, a2, a3, a4) \
({ \
long __res, __ign1, __ign2, __ign3, __ign4; \
asm volatile ( \
"call %[call]" \
: "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
"=d" (__ign3), "=S" (__ign4) \
: "1" ((long)(a1)), "2" ((long)(a2)), \
"3" ((long)(a3)), "4" ((long)(a4)), \
[call] "m" (hypercall_page[__HYPERVISOR_##name]) \
: "memory" ); \
__HYPERCALL_DECLS; \
__HYPERCALL_4ARG(a1, a2, a3, a4); \
asm volatile (__HYPERCALL \
: __HYPERCALL_4PARAM \
: __HYPERCALL_ENTRY(name) \
: __HYPERCALL_CLOBBER4); \
(type)__res; \
})

#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
({ \
long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \
asm volatile ( \
"call %[call]" \
: "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
"=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \
: "1" ((long)(a1)), "2" ((long)(a2)), \
"3" ((long)(a3)), "4" ((long)(a4)), \
"5" ((long)(a5)), \
[call] "m" (hypercall_page[__HYPERVISOR_##name]) \
: "memory" ); \
__HYPERCALL_DECLS; \
__HYPERCALL_5ARG(a1, a2, a3, a4, a5); \
asm volatile (__HYPERCALL \
: __HYPERCALL_5PARAM \
: __HYPERCALL_ENTRY(name) \
: __HYPERCALL_CLOBBER5); \
(type)__res; \
})

Expand Down

0 comments on commit 89e8388

Please sign in to comment.