Scott Parish
2005-Jun-09  10:29 UTC
[Xen-devel] [patch] do_multicall_call abi violation? (x86_64)
Booting dom0 and running xend spews quite a number of:
 (XEN) (file=multicall.c, line=50) Error writing result back to multicall block.
To jump right to the end of a long story, i think that
do_multicall_call() is in x86_64 abi violation. 
   #define do_multicall_call(_call)                         \
       do {                                                 \
           __asm__ __volatile__ (                           \
               "movq  "STR(MULTICALL_op)"(%0),%%rax; "     
\
     ...
               "movq  "STR(MULTICALL_arg4)"(%0),%%r8; "    
\
               "callq *(%%rax); "                           \
               "movq  %%rax,"STR(MULTICALL_result)"(%0); " 
\
               : : "b" (_call)                              \
               : "rax", "rdi", "rsi",
"rdx", "rcx", "r8");  \
       } while ( 0 )
The abi says the following (v0.95, page 16):
       Registers %rbp, %rbx and %r12 through %r15 "belong" to the
       calling function and the called function is required to preserve
       their values. In other words, a called function must preserve
       these registers'' values for its caller. Remaining registers
       "belong" to the called function. If a calling function wants to
       preserve such a register value across a function call, it must
       save the value in its local stack frame.
do_multicall_call() is doing a call, who does who knows what with
registers, but doesn''t advertise clobbering all the abi''s
volatile
registers.
I tried searching for documentation, as it seems to me that gcc should
have some magic flag since it has to know the abi anyway, but i
couldn''t
find anything. Assuming that this isn''t a compiler bug and there
aren''t
any such flags, the attached patch should make things abi compliant, and
fixes the problem i was seeing.
-----
If you''re curious the exact connection between the abi violation and
the error messages...
do_multicall() looks somewhat like (pseudo-code):
   do_multicall(...) {
      if ( asm("inline-asm-1") )
         return;
 
      do_multicall_call();
      if ( asm("inline-asm-2") ) {
         printk("Error");
         return;
      }
the result of inline-asm-1 is in some register X. the "if" turns into
a
jnz on X to a "ret". gcc realizes if we didn''t jump, then X
has to be 0,
so it''s going to use that value for initialization of the __pu_err in
inline-asm-2.
the problem is that the call in do_multicall_call() stomps on X, as it
isn''t advertised to clobber X.
inline-asm-2 is the __put_user code, which uses the fixup/exception-
table trick:
		"1:	mov"itype" %"rtype"1,%2\n"			\
		"2:\n"							\
		".section .fixup,\"ax\"\n"				\
		"3:	mov %3,%0\n"					\
		"	jmp 2b\n"					\
		".previous\n"						\
		".section __ex_table,\"a\"\n"				\
		"	"__FIXUP_ALIGN"\n"				\
		"	"__FIXUP_WORD" 1b,3b\n"				\
		".previous"						\
		: "=r"(err)						\
		: ltype (x), "m"(__m(addr)), "i"(errret),
"0"(err))
so "err" (in register X) is uninitialized if we don''t fault.
finally
depending on what the call did with X if could be a non-zero value.
sRp
-- 
Scott Parish
Signed-off-by: srparish@us.ibm.com
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel