ia64/xen-unstable

changeset 14732:97453bb714b9

hvm: Fix EFLAGS setting in MMIO decoder/emulator.
Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
author kfraser@localhost.localdomain
date Thu Apr 05 08:44:55 2007 +0100 (2007-04-05)
parents 94dfb13cbbed
children d9b670f76f51
files xen/arch/x86/hvm/io.c
line diff
     1.1 --- a/xen/arch/x86/hvm/io.c	Thu Apr 05 08:43:21 2007 +0100
     1.2 +++ b/xen/arch/x86/hvm/io.c	Thu Apr 05 08:44:55 2007 +0100
     1.3 @@ -289,25 +289,11 @@ static void set_reg_value (int size, int
     1.4  
     1.5  long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs);
     1.6  
     1.7 -static inline void set_eflags_CF(int size, unsigned long v1,
     1.8 -                                 unsigned long v2, struct cpu_user_regs *regs)
     1.9 -{
    1.10 -    unsigned long mask;
    1.11 -
    1.12 -    if ( size == BYTE_64 )
    1.13 -        size = BYTE;
    1.14 -    ASSERT((size <= sizeof(mask)) && (size > 0));
    1.15 -
    1.16 -    mask = ~0UL >> (8 * (sizeof(mask) - size));
    1.17 -
    1.18 -    if ((v1 & mask) > (v2 & mask))
    1.19 -        regs->eflags |= X86_EFLAGS_CF;
    1.20 -    else
    1.21 -        regs->eflags &= ~X86_EFLAGS_CF;
    1.22 -}
    1.23 -
    1.24 -static inline void set_eflags_OF(int size, unsigned long v1,
    1.25 -                                 unsigned long v2, unsigned long v3,
    1.26 +static inline void set_eflags_CF(int size,
    1.27 +                                 unsigned int instr,
    1.28 +                                 unsigned long result,
    1.29 +                                 unsigned long src,
    1.30 +                                 unsigned long dst,
    1.31                                   struct cpu_user_regs *regs)
    1.32  {
    1.33      unsigned long mask;
    1.34 @@ -318,19 +304,62 @@ static inline void set_eflags_OF(int siz
    1.35  
    1.36      mask = ~0UL >> (8 * (sizeof(mask) - size));
    1.37  
    1.38 -    if ((v3 ^ v2) & (v3 ^ v1) & mask)
    1.39 -        regs->eflags |= X86_EFLAGS_OF;
    1.40 +    if ( instr == INSTR_ADD )
    1.41 +    {
    1.42 +        /* CF=1 <==> result is less than the augend and addend) */
    1.43 +        if ( (result & mask) < (dst & mask) )
    1.44 +        {
    1.45 +            ASSERT((result & mask) < (src & mask));
    1.46 +            regs->eflags |= X86_EFLAGS_CF;
    1.47 +        }
    1.48 +    }
    1.49 +    else
    1.50 +    {
    1.51 +        ASSERT( instr == INSTR_CMP || instr == INSTR_SUB );
    1.52 +        if ( (src & mask) > (dst & mask) )
    1.53 +            regs->eflags |= X86_EFLAGS_CF;
    1.54 +    }
    1.55  }
    1.56  
    1.57 -static inline void set_eflags_AF(int size, unsigned long v1,
    1.58 -                                 unsigned long v2, unsigned long v3,
    1.59 +static inline void set_eflags_OF(int size,
    1.60 +                                 unsigned int instr,
    1.61 +                                 unsigned long result,
    1.62 +                                 unsigned long src,
    1.63 +                                 unsigned long dst,
    1.64                                   struct cpu_user_regs *regs)
    1.65  {
    1.66 -    if ((v1 ^ v2 ^ v3) & 0x10)
    1.67 +    unsigned long mask;
    1.68 +
    1.69 +    if ( size == BYTE_64 )
    1.70 +        size = BYTE;
    1.71 +    ASSERT((size <= sizeof(mask)) && (size > 0));
    1.72 +
    1.73 +    mask =  1UL << ((8*size) - 1);
    1.74 +
    1.75 +    if ( instr == INSTR_ADD )
    1.76 +    {
    1.77 +        if ((src ^ result) & (dst ^ result) & mask);
    1.78 +            regs->eflags |= X86_EFLAGS_OF;
    1.79 +    }
    1.80 +    else
    1.81 +    {
    1.82 +        ASSERT(instr == INSTR_CMP || instr == INSTR_SUB);
    1.83 +        if ((dst ^ src) & (dst ^ result) & mask)
    1.84 +            regs->eflags |= X86_EFLAGS_OF;
    1.85 +    }
    1.86 +}
    1.87 +
    1.88 +static inline void set_eflags_AF(int size,
    1.89 +                                 unsigned long result,
    1.90 +                                 unsigned long src,
    1.91 +                                 unsigned long dst,
    1.92 +                                 struct cpu_user_regs *regs)
    1.93 +{
    1.94 +    if ((result ^ src ^ dst) & 0x10)
    1.95          regs->eflags |= X86_EFLAGS_AF;
    1.96  }
    1.97  
    1.98 -static inline void set_eflags_ZF(int size, unsigned long v1,
    1.99 +static inline void set_eflags_ZF(int size, unsigned long result,
   1.100                                   struct cpu_user_regs *regs)
   1.101  {
   1.102      unsigned long mask;
   1.103 @@ -341,11 +370,11 @@ static inline void set_eflags_ZF(int siz
   1.104  
   1.105      mask = ~0UL >> (8 * (sizeof(mask) - size));
   1.106  
   1.107 -    if ((v1 & mask) == 0)
   1.108 +    if ((result & mask) == 0)
   1.109          regs->eflags |= X86_EFLAGS_ZF;
   1.110  }
   1.111  
   1.112 -static inline void set_eflags_SF(int size, unsigned long v1,
   1.113 +static inline void set_eflags_SF(int size, unsigned long result,
   1.114                                   struct cpu_user_regs *regs)
   1.115  {
   1.116      unsigned long mask;
   1.117 @@ -354,9 +383,9 @@ static inline void set_eflags_SF(int siz
   1.118          size = BYTE;
   1.119      ASSERT((size <= sizeof(mask)) && (size > 0));
   1.120  
   1.121 -    mask = ~0UL >> (8 * (sizeof(mask) - size));
   1.122 +    mask = 1UL << ((8*size) - 1);
   1.123  
   1.124 -    if (v1 & mask)
   1.125 +    if (result & mask)
   1.126          regs->eflags |= X86_EFLAGS_SF;
   1.127  }
   1.128  
   1.129 @@ -379,10 +408,10 @@ static char parity_table[256] = {
   1.130      1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
   1.131  };
   1.132  
   1.133 -static inline void set_eflags_PF(int size, unsigned long v1,
   1.134 +static inline void set_eflags_PF(int size, unsigned long result,
   1.135                                   struct cpu_user_regs *regs)
   1.136  {
   1.137 -    if (parity_table[v1 & 0xFF])
   1.138 +    if (parity_table[result & 0xFF])
   1.139          regs->eflags |= X86_EFLAGS_PF;
   1.140  }
   1.141  
   1.142 @@ -585,6 +614,17 @@ static void hvm_mmio_assist(struct cpu_u
   1.143              diff = (unsigned long) p->data & value;
   1.144              set_reg_value(size, index, 0, regs, diff);
   1.145          }
   1.146 +
   1.147 +        /*
   1.148 +         * The OF and CF flags are cleared; the SF, ZF, and PF
   1.149 +         * flags are set according to the result. The state of
   1.150 +         * the AF flag is undefined.
   1.151 +         */
   1.152 +        regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|
   1.153 +                          X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF);
   1.154 +        set_eflags_ZF(size, diff, regs);
   1.155 +        set_eflags_SF(size, diff, regs);
   1.156 +        set_eflags_PF(size, diff, regs);
   1.157          break;
   1.158  
   1.159      case INSTR_ADD:
   1.160 @@ -603,12 +643,16 @@ static void hvm_mmio_assist(struct cpu_u
   1.161          }
   1.162  
   1.163          /*
   1.164 -         * The OF and CF flags are cleared; the SF, ZF, and PF
   1.165 -         * flags are set according to the result. The state of
   1.166 -         * the AF flag is undefined.
   1.167 +         * The CF, OF, SF, ZF, AF, and PF flags are set according
   1.168 +         * to the result
   1.169           */
   1.170 -        regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|
   1.171 +        regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|X86_EFLAGS_AF|
   1.172                            X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF);
   1.173 +        set_eflags_CF(size, mmio_opp->instr, diff, value,
   1.174 +                      (unsigned long) p->data, regs);
   1.175 +        set_eflags_OF(size, mmio_opp->instr, diff, value,
   1.176 +                      (unsigned long) p->data, regs);
   1.177 +        set_eflags_AF(size, diff, value, (unsigned long) p->data, regs);
   1.178          set_eflags_ZF(size, diff, regs);
   1.179          set_eflags_SF(size, diff, regs);
   1.180          set_eflags_PF(size, diff, regs);
   1.181 @@ -691,8 +735,20 @@ static void hvm_mmio_assist(struct cpu_u
   1.182           */
   1.183          regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|X86_EFLAGS_AF|
   1.184                            X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF);
   1.185 -        set_eflags_CF(size, value, (unsigned long) p->data, regs);
   1.186 -        set_eflags_OF(size, diff, value, (unsigned long) p->data, regs);
   1.187 +        if ( src & (REGISTER | IMMEDIATE) )
   1.188 +        {
   1.189 +            set_eflags_CF(size, mmio_opp->instr, diff, value,
   1.190 +                          (unsigned long) p->data, regs);
   1.191 +            set_eflags_OF(size, mmio_opp->instr, diff, value,
   1.192 +                          (unsigned long) p->data, regs);
   1.193 +        }
   1.194 +        else
   1.195 +        {
   1.196 +            set_eflags_CF(size, mmio_opp->instr, diff,
   1.197 +                          (unsigned long) p->data, value, regs);
   1.198 +            set_eflags_OF(size, mmio_opp->instr, diff,
   1.199 +                          (unsigned long) p->data, value, regs);
   1.200 +        }
   1.201          set_eflags_AF(size, diff, value, (unsigned long) p->data, regs);
   1.202          set_eflags_ZF(size, diff, regs);
   1.203          set_eflags_SF(size, diff, regs);