Skip to contentSkip to conversation

Fix g2h() for 32-bit targets on 64-bit hosts

PATCH In review Benjamin Herrenschmidt 2 participants 6 messages Aug 3, 2016

lore
Share & tools
lore
#0 lore raw

PATCH 2/2 Fix g2h() for 32-bit targets on 64-bit hosts

The current constructs ends up cropping the host address to 32-bit which crashes for me running 32-bit ppc programs on an x86_64.

---

Not sure who to CC for this...

 include/exec/cpu_ldst.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/exec/cpu_ldst.h +1 -1
index 6eb5fe8..0164535 100644
@@ -49,7 +49,7 @@
 
 #if defined(CONFIG_USER_ONLY)
 /* All direct uses of g2h and h2g need to go away for usermode softmmu.  */
-#define g2h(x) ((void *)((unsigned long)(target_ulong)(x) + guest_base))
+#define g2h(x) ((void *)(guest_base + (unsigned long)(target_ulong)(x)))
 
 #if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS
 #define h2g_valid(x) 1
#1 lore raw
Quoted 16 lines · Benjamin Herrenschmidt

The current constructs ends up cropping the host address to 32-bit which crashes for me running 32-bit ppc programs on an x86_64.

---

Not sure who to CC for this...

 include/exec/cpu_ldst.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/exec/cpu_ldst.h +0 -0
index 6eb5fe8..0164535 100644

include/exec/cpu_ldst.h line 52

Quoted 5 lines
include/exec/cpu_ldst.h +1 -1
@@ -49,7 +49,7 @@
 
 #if defined(CONFIG_USER_ONLY)
 /* All direct uses of g2h and h2g need to go away for usermode softmmu.  */
-#define g2h(x) ((void *)((unsigned long)(target_ulong)(x) + guest_base))
+#define g2h(x) ((void *)(guest_base + (unsigned long)(target_ulong)(x)))

I'm confused. Is this just swapping the order of the operands to '+'? I wouldn't expect that to make any difference because typecast has higher precedence than '+'...

I run 32-bit (ARM) programs on x86-64 a lot so I would be surprised if g2h() was broken like this.

thanks
-- PMM

#2 lore raw
Quoted 5 lines · Peter Maydell
Quoted 5 lines

index 6eb5fe8..0164535 100644

include/exec/cpu_ldst.h +0 -0
@@ -49,7 +49,7 @@
 
Quoted 8 lines

include/exec/cpu_ldst.h line 52

Quoted 4 lines
include/exec/cpu_ldst.h +1 -1
   #if defined(CONFIG_USER_ONLY)
   /* All direct uses of g2h and h2g need to go away for usermode softmmu.  */
-#define g2h(x) ((void *)((unsigned long)(target_ulong)(x) + guest_base))
+#define g2h(x) ((void *)(guest_base + (unsigned long)(target_ulong)(x)))

I'm confused. Is this just swapping the order of the operands to '+'? I wouldn't expect that to make any difference because typecast has higher precedence than '+'...

The typecast to target_ulong which is 32-bits :-)

Quoted 2 lines
Quoted 1 line

I run 32-bit (ARM) programs on x86-64 a lot so I would be surprised

if g2h() was broken like this.

I had a pretty clear breakage case, and this along with patch 1 fixed it.

Cheers,
Ben.

#3 lore raw
Quoted 7 lines · Benjamin Herrenschmidt

Quoted 4 lines

I'm confused. Is this just swapping the order of the operands to '+'?
I wouldn't expect that to make any difference because typecast has higher precedence than '+'...

The typecast to target_ulong which is 32-bits :-)

But you are right, this isn't the breakage. Patch 1/2 is sufficient to fix it, though I didn't realize it at first.

"vaddr" is actually a typedef, so the whole tlb_vaddr_to_host() turned into a cast of guest_base to vaddr...

The g2h part was just me being tired. It's true though that target_ulong is going to be 32-bits which I don't like but type promotion makes it work.

So drop that patch and stick to patch 1/2 which is the real fix.

As to why you don't hit the bug on ARM, well, maybe you don't many helpers using tlb_vaddr_to_host ? Also address randomization makes things hit or miss here ...

Cheers,
Ben.

#4 lore raw
Quoted 12 lines · Benjamin Herrenschmidt
Quoted 7 lines · Benjamin Herrenschmidt
Quoted 5 lines

I'm confused. Is this just swapping the order of the operands to '+'?
I wouldn't expect that to make any difference because typecast has higher precedence than '+'...

The typecast to target_ulong which is 32-bits :-)

But you are right, this isn't the breakage. Patch 1/2 is sufficient to fix it, though I didn't realize it at first.

Quoted 6 lines

"vaddr" is actually a typedef, so the whole tlb_vaddr_to_host() turned into a cast of guest_base to vaddr...

The g2h part was just me being tired. It's true though that target_ulong is going to be 32-bits which I don't like but type promotion makes it work.

The cast to target_ulong is deliberate -- guest addresses should be that size and type, which is why we cast to it. Then we cast to unsigned long to zero-extend them to the size of a host address, before adding the guest_base. See commit 8d9dde9429d2b5b5 which added that cast to fix a problem where there was otherwise accidental sign extension in some uses of 32-bit-guest-on-64-bit-host.

Quoted 5 lines

So drop that patch and stick to patch 1/2 which is the real fix.

As to why you don't hit the bug on ARM, well, maybe you don't many helpers using tlb_vaddr_to_host ? Also address randomization makes things hit or miss here ...

The only uses of tlb_vaddr_to_host in the tree are
(a) in a not-CONFIG_USER_ONLY codepath on target-arm
(b) in target-s390x, which is a 64-bit guest

thanks
-- PMM

#5 lore raw
Quoted 7 lines · Peter Maydell
Quoted 3 lines

As to why you don't hit the bug on ARM, well, maybe you don't many helpers using tlb_vaddr_to_host ? Also address randomization makes things hit or miss here ...

The only uses of tlb_vaddr_to_host in the tree are
(a) in a not-CONFIG_USER_ONLY codepath on target-arm
(b) in target-s390x, which is a 64-bit guest

  (c) a few new helpers using it on ppc that are in David's ppc-for-2.8 branch :-)

Now we can put the fix in his branch if you prefer but it's a pretty trivial one so I would suggest just sticking it in.

Cheers,
Ben