# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1175010980 -3600
# Node ID d4ddaff75afd0231e5d832d591196b32f8a7ecc7
# Parent 681ed46676a6a6988fa1d0c2e550af65673fb82c
hvm: Fix undefined bit shifting in mmio emulation path
In functions set_eflags_* (xen/arch/x86/hvm/io.c), if the first
argument "size" equals sizeof(long), the following code will produce
unintended and invalid result:
unsigned long mask = (1 << (8 * size)) - 1;
In ANSI C, if the shift amount is greater or equal to the width of the
data type, the result is undefined. Specifically on x86, a bit mask is
applied to the shift amount, so that more significant bits are
ignored. So the above expression results 0x0 instead of the intended
~0UL.
This patch fixes this issue. Because size=0 is not a valid parameter,
rewriting the code using right shift avoids an additional condition
check.
Signed-off-by: Qing He <qing.he@xxxxxxxxx>
---
xen/arch/x86/hvm/io.c | 28 ++++++++++++++++++++++++----
1 files changed, 24 insertions(+), 4 deletions(-)
diff -r 681ed46676a6 -r d4ddaff75afd xen/arch/x86/hvm/io.c
--- a/xen/arch/x86/hvm/io.c Tue Mar 27 16:45:37 2007 +0100
+++ b/xen/arch/x86/hvm/io.c Tue Mar 27 16:56:20 2007 +0100
@@ -292,7 +292,11 @@ static inline void set_eflags_CF(int siz
static inline void set_eflags_CF(int size, unsigned long v1,
unsigned long v2, struct cpu_user_regs *regs)
{
- unsigned long mask = (1 << (8 * size)) - 1;
+ unsigned long mask;
+
+ ASSERT((size <= sizeof(mask)) && (size > 0));
+
+ mask = ~0UL >> (8 * (sizeof(mask) - size));
if ((v1 & mask) > (v2 & mask))
regs->eflags |= X86_EFLAGS_CF;
@@ -303,7 +307,13 @@ static inline void set_eflags_OF(int siz
static inline void set_eflags_OF(int size, unsigned long v1,
unsigned long v2, unsigned long v3, struct
cpu_user_regs *regs)
{
- if ((v3 ^ v2) & (v3 ^ v1) & (1 << ((8 * size) - 1)))
+ unsigned long mask;
+
+ ASSERT((size <= sizeof(mask)) && (size > 0));
+
+ mask = ~0UL >> (8 * (sizeof(mask) - size));
+
+ if ((v3 ^ v2) & (v3 ^ v1) & mask)
regs->eflags |= X86_EFLAGS_OF;
}
@@ -317,7 +327,11 @@ static inline void set_eflags_ZF(int siz
static inline void set_eflags_ZF(int size, unsigned long v1,
struct cpu_user_regs *regs)
{
- unsigned long mask = (1 << (8 * size)) - 1;
+ unsigned long mask;
+
+ ASSERT((size <= sizeof(mask)) && (size > 0));
+
+ mask = ~0UL >> (8 * (sizeof(mask) - size));
if ((v1 & mask) == 0)
regs->eflags |= X86_EFLAGS_ZF;
@@ -326,7 +340,13 @@ static inline void set_eflags_SF(int siz
static inline void set_eflags_SF(int size, unsigned long v1,
struct cpu_user_regs *regs)
{
- if (v1 & (1 << ((8 * size) - 1)))
+ unsigned long mask;
+
+ ASSERT((size <= sizeof(mask)) && (size > 0));
+
+ mask = ~0UL >> (8 * (sizeof(mask) - size));
+
+ if (v1 & mask)
regs->eflags |= X86_EFLAGS_SF;
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|