KVM: pvmmu breakage with gcc 4.3.0
Subsystems (3)
Some pvmmu functions store their commands on stack, and newer GCC versions conclude that these commands are unused.
So stick an inline asm statement to convince the compiler otherwise.
arch/x86/kernel/kvm.c +6 -0
@@ -55,6 +55,12 @@ static void kvm_mmu_op(void *buffer, unsigned len)int r;unsigned long a1, a2; +/* +* GCC 4.3.0 concludes that on-stack kvm_mmu_op* is unused and +* optimizes its initialization away. +*/ + asm ("" : :"p" (buffer)); + do { a1 = __pa(buffer); a2 = 0; /* on i386 __pa() always returns <4G */
Quoted 5 lines · Marcelo Tosatti
Some pvmmu functions store their commands on stack, and newer GCC versions conclude that these commands are unused.
So stick an inline asm statement to convince the compiler otherwise.
I think a better fix is to add a "memory " clobber to the hypercalls. This isn't really a GCC bug since it doesn't realize that hypercalls can touch memory.
See the attached patch.
Avi: please push this for 2.6.26 if possible.
Regards,
Anthony Liguori
Quoted 21 lines
Signed-off-by Marcelo Tosatti <[email protected]>arch/x86/kernel/kvm.c +6
-1@@ -55,6 +55,12 @@ static void kvm_mmu_op(void *buffer, unsigned len)int r;unsigned long a1, a2; +/* +* GCC 4.3.0 concludes that on-stack kvm_mmu_op* is unused and +* optimizes its initialization away. +*/ + asm ("" : :"p" (buffer)); + do { a1 = __pa(buffer); a2 = 0; /* on i386 __pa() always returns <4G */ --
Quoted 4 lines
To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Subject: [PATCH] Add memory clobber to hypercalls
Cc: Avi Kivity <[email protected]>
Cc: Marcelo Tosatti <[email protected]>
Hypercalls can modify arbitrary regions of memory. Make sure to indicate this in the clobber list. This fixes a hang when using KVM_GUEST kernel built with GCC 4.3.0.
This was originally spotted and analyzed by Marcelo.
include/asm-x86/kvm_para.h +10 -5
@@ -71,7 +71,8 @@ static inline long kvm_hypercall0(unsigned int nr)long ret; asm volatile(KVM_HYPERCALL : "=a"(ret) - : "a"(nr)); + : "a"(nr) + : "memory");return ret; }
@@ -80,7 +81,8 @@ static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)long ret; asm volatile(KVM_HYPERCALL : "=a"(ret) - : "a"(nr), "b"(p1)); + : "a"(nr), "b"(p1) + : "memory");return ret; }
@@ -90,7 +92,8 @@ static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,long ret; asm volatile(KVM_HYPERCALL : "=a"(ret) - : "a"(nr), "b"(p1), "c"(p2)); + : "a"(nr), "b"(p1), "c"(p2) + : "memory");return ret; }
@@ -100,7 +103,8 @@ static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,long ret; asm volatile(KVM_HYPERCALL : "=a"(ret) - : "a"(nr), "b"(p1), "c"(p2), "d"(p3)); + : "a"(nr), "b"(p1), "c"(p2), "d"(p3) + : "memory");return ret; }
@@ -111,7 +115,8 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,long ret; asm volatile(KVM_HYPERCALL : "=a"(ret) - : "a"(nr), "b"(p1), "c"(p2), "d"(p3), "S"(p4)); + : "a"(nr), "b"(p1), "c"(p2), "d"(p3), "S"(p4) + : "memory");return ret; }
Am Donnerstag, 26. Juni 2008 schrieb Anthony Liguori:
Quoted 10 lines
Quoted 5 lines · Marcelo Tosatti
Some pvmmu functions store their commands on stack, and newer GCC versions conclude that these commands are unused.
So stick an inline asm statement to convince the compiler otherwise.
I think a better fix is to add a "memory " clobber to the hypercalls. This isn't really a GCC bug since it doesn't realize that hypercalls can touch memory.
Thats what we do on asm-s390/kvm_para.h. Our hypercalls do have a memory clobber.
Quoted 1 line · Anthony Liguori
I think a better fix is to add a "memory " clobber to the hypercalls.
This should definitely be done, but I don't see that this is a sure way to get that initializers that are otherwise unreferenced to be stored in their locations. IOW, it appears to me that GCC might still decide to optimize them away, because it doesn't see that the values can be used.
Now, Marcelo's patch appears to have been the result of a misunderstanding. I meant to tell him that a simpler "p" notation was *not* enough to make the problem go away. I thought a better approach was to have __pa do something along the lines of
({ char *__buf = (char*)buffer; asm ("" : : "o"(*__buf)); ... })
to make it clear that physical addresses are used.
Anyhow, for now, it appears that a "memory" clobber is not only required for correct semantics, but also enough to fix the problem. Let's just hope GCC doesn't get too smart.
Signature · 4 lines
Alexandre Oliva http://www.lsd.ic.unicamp.br/~oliva/
Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org}
FSFLA Board Member ¡Sé Libre! => http://www.fsfla.org/
Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org}Quoted 8 lines · Alexandre Oliva
I thought a better approach
was to have__pado something along the lines of({ char
*__buf= (char*)buffer; asm ("" : : "o"(*__buf)); ... })to make it clear that physical addresses are used.
I agree, I think such a patch is important for future-proofing Linux against increasing gcc optimization capabilities.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 13 lines · Marcelo Tosatti
Some pvmmu functions store their commands on stack, and newer GCC versions conclude that these commands are unused.
So stick an inline asm statement to convince the compiler otherwise.
Signed-off-by Marcelo Tosatti <[email protected]>arch/x86/kernel/kvm.c +0
-0
arch/x86/kernel/kvm.c static void kvm_mmu_op(void *buffer, unsigned len) · line 64
Quoted 10 lines
arch/x86/kernel/kvm.c +6
-0@@ -55,6 +55,12 @@ static void kvm_mmu_op(void *buffer, unsigned len)int r;unsigned long a1, a2; +/* +* GCC 4.3.0 concludes that on-stack kvm_mmu_op* is unused and +* optimizes its initialization away. +*/ + asm ("" : :"p" (buffer)); +
I don't think "p" should force the contents into memory? Perhaps "m"(*(char *)buffer)?
Anthony, I don't see why a memory clobber would tell gcc that the variables is actually used. The problem is with the void * -> unsigned long cast (__pa), once that happens gcc loses track. It's probably needed anyway since hypercalls _do_ clobber memory.
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
Quoted 27 lines · Avi Kivity
Quoted 13 lines · Marcelo Tosatti
Some pvmmu functions store their commands on stack, and newer GCC versions conclude that these commands are unused.
So stick an inline asm statement to convince the compiler otherwise.
Signed-off-by Marcelo Tosatti <[email protected]>arch/x86/kernel/kvm.c +0
-0arch/x86/kernel/kvm.c static void kvm_mmu_op(void *buffer, unsigned len) · line 64
Quoted 10 lines
arch/x86/kernel/kvm.c +6
-0@@ -55,6 +55,12 @@ static void kvm_mmu_op(void *buffer, unsigned len)int r;unsigned long a1, a2; +/* +* GCC 4.3.0 concludes that on-stack kvm_mmu_op* is unused and +* optimizes its initialization away. +*/ + asm ("" : :"p" (buffer)); +I don't think "p" should force the contents into memory? Perhaps "m"(*(char *)buffer)?
Quoted 1 line
Anthony, I don't see why a memory clobber would tell gcc that the variables is actually used.
It doesn't, but it seems to me that it should force GCC to assume everything is live. It's a big stick to hit the problem with but it seems like the right thing semantically.
Quoted 2 lines
The problem is with the void * -> unsigned long cast (
__pa), once
that happens gcc loses track. It's probably needed anyway since hypercalls _do_ clobber memory.
Right, it's not telling GCC that we touch a particular variable, but rather that we may have touched any variable.
Regards,
Anthony Liguori
Quoted 28 lines · Anthony Liguori
Quoted 27 lines · Avi Kivity
Quoted 13 lines · Marcelo Tosatti
Some pvmmu functions store their commands on stack, and newer GCC versions conclude that these commands are unused.
So stick an inline asm statement to convince the compiler otherwise.
Signed-off-by Marcelo Tosatti <[email protected]>arch/x86/kernel/kvm.c +0
-0arch/x86/kernel/kvm.c static void kvm_mmu_op(void *buffer, unsigned len) · line 64
Quoted 10 lines
arch/x86/kernel/kvm.c +6
-0@@ -55,6 +55,12 @@ static void kvm_mmu_op(void *buffer, unsigned len)int r;unsigned long a1, a2; +/* +* GCC 4.3.0 concludes that on-stack kvm_mmu_op* is unused and +* optimizes its initialization away. +*/ + asm ("" : :"p" (buffer)); +I don't think "p" should force the contents into memory? Perhaps "m"(*(char *)buffer)?
Quoted 4 lines
Quoted 1 line
Anthony, I don't see why a memory clobber would tell gcc that the variables is actually used.
It doesn't, but it seems to me that it should force GCC to assume everything is live. It's a big stick to hit the problem with but it seems like the right thing semantically.
In general the right stick to hit a compiler with is 'volatile,' which should tell the compiler that outside forces are in play. Without really digging into the code I don't want to suggest just where this should be used, but clearly Christian had the same thought.
Quoted 5 lines
Quoted 2 lines
The problem is with the void * -> unsigned long cast (
__pa), once
that happens gcc loses track. It's probably needed anyway since hypercalls _do_ clobber memory.Right, it's not telling GCC that we touch a particular variable, but rather that we may have touched any variable.
Signature · 3 lines
Bill Davidsen <[email protected]> "We have more to fear from the bungling of the incompetent than from the machinations of the wicked." - from Slashdot
Am Donnerstag, 26. Juni 2008 schrieb Avi Kivity:
Quoted 7 lines
I don't think "p" should force the contents into memory? Perhaps "m"(*(char *)buffer)?
Anthony, I don't see why a memory clobber would tell gcc that the variables is actually used. The problem is with the void * -> unsigned long cast (
__pa), once that happens gcc loses track. It's probably needed anyway since hypercalls _do_ clobber memory.
I I think about that again, the correct solution should be to use 2 input constraints for parameters together with the memory clobber on hypercall.
I think something like the following covers all cases:
static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1), "m"(*(char *) p1)
: "memory" );
return ret;
}The address and the memory content of p1 (if it is a pointer) is not ommitted by gcc. Furthermore, the memory clobbering nature of a hypercall is specified as well.
Christian
Quoted 22 lines · Christian Borntraeger
Am Donnerstag, 26. Juni 2008 schrieb Avi Kivity:
Quoted 4 lines
I don't think "p" should force the contents into memory? Perhaps "m"(*(char *)buffer)?
Anthony, I don't see why a memory clobber would tell gcc that the variables is actually used. The problem is with the void * -> unsigned long cast (
__pa), once that happens gcc loses track. It's probably needed anyway since hypercalls _do_ clobber memory.I I think about that again, the correct solution should be to use 2 input constraints for parameters together with the memory clobber on hypercall.
I think something like the following covers all cases:
static inline long
kvm_hypercall1(unsigned int nr, unsigned long p1){ long ret; asm volatile(KVM_HYPERCALL : "=a"(ret) : "a"(nr), "b"(p1), "m"(*(char *) p1) : "memory" ); return ret; }
Quoted 2 lines
The address and the memory content of p1 (if it is a pointer) is not ommitted by gcc. Furthermore, the memory clobbering nature of a hypercall is specified as well.
Isn't that redundant though? Shouldn't a memory clobber force GCC to assume that anything that's reachable is live?
Regards,
Anthony Liguori
Quoted 2 lines
Christian
Quoted 12 lines · Christian Borntraeger
Am Donnerstag, 26. Juni 2008 schrieb Avi Kivity:
Quoted 4 lines
I don't think "p" should force the contents into memory? Perhaps "m"(*(char *)buffer)?
Anthony, I don't see why a memory clobber would tell gcc that the variables is actually used. The problem is with the void * -> unsigned long cast (
__pa), once that happens gcc loses track. It's probably needed anyway since hypercalls _do_ clobber memory.I I think about that again, the correct solution should be to use 2 input constraints for parameters together with the memory clobber on hypercall.
I think something like the following covers all cases:
static inline long
kvm_hypercall1(unsigned int nr, unsigned long p1)
Quoted 9 lines
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1), "m"(*(char *) p1)
: "memory" );
return ret;
}I don't know exactly what the rules are when you cast from pointer to unsigned long. What I'm concerned about is that if there are a few layers of indirection, GCC won't be able to propagate the liveness of the pointer p1. It has to be able to figure out that p1 here was really that point on the stack. From the perspective of being conservative, it certainly can't hurt, but I'm not sure it solves the problem by itself.
This is why I think the "memory" constraint is really the right solution. That should force GCC to be very conservative about syncing everything to memory.
Regards,
Anthony Liguori
Quoted 8 lines
The address and the memory content of p1 (if it is a pointer) is not ommitted by gcc. Furthermore, the memory clobbering nature of a hypercall is specified as well.
Christian
--
To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Am Donnerstag, 26. Juni 2008 schrieb Anthony Liguori:
Quoted 35 lines
Quoted 17 lines · Christian Borntraeger
Am Donnerstag, 26. Juni 2008 schrieb Avi Kivity:
Quoted 8 lines
I don't think "p" should force the contents into memory? Perhaps "m"(*(char *)buffer)?
Anthony, I don't see why a memory clobber would tell gcc that the variables is actually used. The problem is with the void * -> unsigned long cast (
__pa), once that happens gcc loses track. It's probably needed anyway since hypercalls _do_ clobber memory.I I think about that again, the correct solution should be to use 2 input constraints for parameters together with the memory clobber on hypercall.
I think something like the following covers all cases:
static inline long
kvm_hypercall1(unsigned int nr, unsigned long p1)Quoted 9 lines
{ long ret; asm volatile(KVM_HYPERCALL : "=a"(ret) : "a"(nr), "b"(p1), "m"(*(char *) p1) : "memory" ); return ret; }I don't know exactly what the rules are when you cast from pointer to unsigned long. What I'm concerned about is that if there are a few layers of indirection, GCC won't be able to propagate the liveness of the pointer p1. It has to be able to figure out that p1 here was really that point on the stack. From the perspective of being conservative, it certainly can't hurt, but I'm not sure it solves the problem by itself.
Quoted 3 lines
This is why I think the "memory" constraint is really the right solution. That should force GCC to be very conservative about syncing everything to memory.
The thing is, that your patch has "memory" in the clobber list. I dont know if clobber constraints give any guarantees about input constraints. Thats why I think that "b" plus "m" as input constraints are better. Does gcc actually accept "memory" as input contraint?
I think I have to ask our compiler developers, but in 5 minutes I will be offline until monday...
Quoted 22 lines · Christian Borntraeger
Am Donnerstag, 26. Juni 2008 schrieb Avi Kivity:
Quoted 4 lines
I don't think "p" should force the contents into memory? Perhaps "m"(*(char *)buffer)?
Anthony, I don't see why a memory clobber would tell gcc that the variables is actually used. The problem is with the void * -> unsigned long cast (
__pa), once that happens gcc loses track. It's probably needed anyway since hypercalls _do_ clobber memory.I I think about that again, the correct solution should be to use 2 input constraints for parameters together with the memory clobber on hypercall.
I think something like the following covers all cases:
static inline long
kvm_hypercall1(unsigned int nr, unsigned long p1){ long ret; asm volatile(KVM_HYPERCALL : "=a"(ret) : "a"(nr), "b"(p1), "m"(*(char *) p1) : "memory" ); return ret; }
Quoted 2 lines
The address and the memory content of p1 (if it is a pointer) is not ommitted by gcc. Furthermore, the memory clobbering nature of a hypercall is specified as well.
That only works if p1 is a virtual address. x86 (and ppc) hypercalls use physical addresses.
Signature · 1 line
error compiling committee.c: too many arguments to function