ia64/xen-unstable
changeset 14732:97453bb714b9
hvm: Fix EFLAGS setting in MMIO decoder/emulator.
Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
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);