direct-io.hg

changeset 14589:d4ddaff75afd

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@intel.com>
author kfraser@localhost.localdomain
date Tue Mar 27 16:56:20 2007 +0100 (2007-03-27)
parents 681ed46676a6
children c1bfe329f7ff
files xen/arch/x86/hvm/io.c
line diff
     1.1 --- a/xen/arch/x86/hvm/io.c	Tue Mar 27 16:45:37 2007 +0100
     1.2 +++ b/xen/arch/x86/hvm/io.c	Tue Mar 27 16:56:20 2007 +0100
     1.3 @@ -292,7 +292,11 @@ extern long get_reg_value(int size, int 
     1.4  static inline void set_eflags_CF(int size, unsigned long v1,
     1.5                                   unsigned long v2, struct cpu_user_regs *regs)
     1.6  {
     1.7 -    unsigned long mask = (1 << (8 * size)) - 1;
     1.8 +    unsigned long mask;
     1.9 +    
    1.10 +    ASSERT((size <= sizeof(mask)) && (size > 0));
    1.11 +
    1.12 +    mask = ~0UL >> (8 * (sizeof(mask) - size));
    1.13  
    1.14      if ((v1 & mask) > (v2 & mask))
    1.15          regs->eflags |= X86_EFLAGS_CF;
    1.16 @@ -303,7 +307,13 @@ static inline void set_eflags_CF(int siz
    1.17  static inline void set_eflags_OF(int size, unsigned long v1,
    1.18                                   unsigned long v2, unsigned long v3, struct cpu_user_regs *regs)
    1.19  {
    1.20 -    if ((v3 ^ v2) & (v3 ^ v1) & (1 << ((8 * size) - 1)))
    1.21 +    unsigned long mask;
    1.22 +
    1.23 +    ASSERT((size <= sizeof(mask)) && (size > 0));
    1.24 +
    1.25 +    mask = ~0UL >> (8 * (sizeof(mask) - size));
    1.26 +    
    1.27 +    if ((v3 ^ v2) & (v3 ^ v1) & mask)
    1.28          regs->eflags |= X86_EFLAGS_OF;
    1.29  }
    1.30  
    1.31 @@ -317,7 +327,11 @@ static inline void set_eflags_AF(int siz
    1.32  static inline void set_eflags_ZF(int size, unsigned long v1,
    1.33                                   struct cpu_user_regs *regs)
    1.34  {
    1.35 -    unsigned long mask = (1 << (8 * size)) - 1;
    1.36 +    unsigned long mask;
    1.37 +    
    1.38 +    ASSERT((size <= sizeof(mask)) && (size > 0));
    1.39 +
    1.40 +    mask = ~0UL >> (8 * (sizeof(mask) - size));
    1.41  
    1.42      if ((v1 & mask) == 0)
    1.43          regs->eflags |= X86_EFLAGS_ZF;
    1.44 @@ -326,7 +340,13 @@ static inline void set_eflags_ZF(int siz
    1.45  static inline void set_eflags_SF(int size, unsigned long v1,
    1.46                                   struct cpu_user_regs *regs)
    1.47  {
    1.48 -    if (v1 & (1 << ((8 * size) - 1)))
    1.49 +    unsigned long mask;
    1.50 +    
    1.51 +    ASSERT((size <= sizeof(mask)) && (size > 0));
    1.52 +
    1.53 +    mask = ~0UL >> (8 * (sizeof(mask) - size));
    1.54 +
    1.55 +    if (v1 & mask)
    1.56          regs->eflags |= X86_EFLAGS_SF;
    1.57  }
    1.58