debuggers.hg
changeset 16445:81aa410fa662
i386: adjustment to segment fixup code.
Clean up and support more instructions.
Signed-off-by: Jan Beulich <jbeulich@novell.com>
Clean up and support more instructions.
Signed-off-by: Jan Beulich <jbeulich@novell.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Wed Nov 21 11:49:41 2007 +0000 (2007-11-21) |
parents | 8c305873f2b8 |
children | 6301c3b6e1ba |
files | xen/arch/x86/x86_32/seg_fixup.c |
line diff
1.1 --- a/xen/arch/x86/x86_32/seg_fixup.c Wed Nov 21 11:38:51 2007 +0000 1.2 +++ b/xen/arch/x86/x86_32/seg_fixup.c Wed Nov 21 11:49:41 2007 +0000 1.3 @@ -42,7 +42,7 @@ 1.4 #define O OPCODE_BYTE 1.5 #define M HAS_MODRM 1.6 1.7 -static unsigned char insn_decode[256] = { 1.8 +static const unsigned char insn_decode[256] = { 1.9 /* 0x00 - 0x0F */ 1.10 O|M, O|M, O|M, O|M, X, X, X, X, 1.11 O|M, O|M, O|M, O|M, X, X, X, X, 1.12 @@ -69,7 +69,7 @@ static unsigned char insn_decode[256] = 1.13 X, X, X, X, X, X, X, X, 1.14 /* 0x80 - 0x8F */ 1.15 O|M|1, O|M|4, O|M|1, O|M|1, O|M, O|M, O|M, O|M, 1.16 - O|M, O|M, O|M, O|M, O|M, O|M, O|M, X, 1.17 + O|M, O|M, O|M, O|M, O|M, X|M, O|M, O|M, 1.18 /* 0x90 - 0x9F */ 1.19 X, X, X, X, X, X, X, X, 1.20 X, X, X, X, X, X, X, X, 1.21 @@ -89,17 +89,17 @@ static unsigned char insn_decode[256] = 1.22 X, X, X, X, X, X, X, X, 1.23 X, X, X, X, X, X, X, X, 1.24 /* 0xF0 - 0xFF */ 1.25 - X, X, X, X, X, X, X, X, 1.26 + X, X, X, X, X, X, O|M, O|M, 1.27 X, X, X, X, X, X, O|M, O|M 1.28 }; 1.29 1.30 -static unsigned char twobyte_decode[256] = { 1.31 +static const unsigned char twobyte_decode[256] = { 1.32 /* 0x00 - 0x0F */ 1.33 X, X, X, X, X, X, X, X, 1.34 X, X, X, X, X, X, X, X, 1.35 /* 0x10 - 0x1F */ 1.36 X, X, X, X, X, X, X, X, 1.37 - X, X, X, X, X, X, X, X, 1.38 + O|M, X, X, X, X, X, X, X, 1.39 /* 0x20 - 0x2F */ 1.40 X, X, X, X, X, X, X, X, 1.41 X, X, X, X, X, X, X, X, 1.42 @@ -122,16 +122,16 @@ static unsigned char twobyte_decode[256] 1.43 X, X, X, X, X, X, X, X, 1.44 X, X, X, X, X, X, X, X, 1.45 /* 0x90 - 0x9F */ 1.46 - X, X, X, X, X, X, X, X, 1.47 - X, X, X, X, X, X, X, X, 1.48 + O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M, 1.49 + O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M, 1.50 /* 0xA0 - 0xAF */ 1.51 - X, X, X, X, X, X, X, X, 1.52 - X, X, X, X, X, X, X, X, 1.53 + X, X, X, O|M, O|M|1, O|M, O|M, X, 1.54 + X, X, X, O|M, O|M|1, O|M, X, O|M, 1.55 /* 0xB0 - 0xBF */ 1.56 - X, X, X, X, X, X, X, X, 1.57 - X, X, X, X, X, X, X, X, 1.58 + X, X, X, O|M, X, X, O|M, O|M, 1.59 + X, X, O|M|1, O|M, O|M, O|M, O|M, O|M, 1.60 /* 0xC0 - 0xCF */ 1.61 - X, X, X, X, X, X, X, X, 1.62 + O|M, O|M, X, O|M, X, X, X, O|M, 1.63 X, X, X, X, X, X, X, X, 1.64 /* 0xD0 - 0xDF */ 1.65 X, X, X, X, X, X, X, X, 1.66 @@ -155,22 +155,22 @@ static unsigned char twobyte_decode[256] 1.67 */ 1.68 static int get_baselimit(u16 seg, unsigned long *base, unsigned long *limit) 1.69 { 1.70 - struct vcpu *d = current; 1.71 - unsigned long *table, a, b; 1.72 - int ldt = !!(seg & 4); 1.73 - int idx = (seg >> 3) & 8191; 1.74 + struct vcpu *curr = current; 1.75 + uint32_t *table, a, b; 1.76 + int ldt = !!(seg & 4); 1.77 + int idx = (seg >> 3) & 8191; 1.78 1.79 /* Get base and check limit. */ 1.80 if ( ldt ) 1.81 { 1.82 - table = (unsigned long *)LDT_VIRT_START(d); 1.83 - if ( idx >= d->arch.guest_context.ldt_ents ) 1.84 + table = (uint32_t *)LDT_VIRT_START(curr); 1.85 + if ( idx >= curr->arch.guest_context.ldt_ents ) 1.86 goto fail; 1.87 } 1.88 else /* gdt */ 1.89 { 1.90 - table = (unsigned long *)GDT_VIRT_START(d); 1.91 - if ( idx >= d->arch.guest_context.gdt_ents ) 1.92 + table = (uint32_t *)GDT_VIRT_START(curr); 1.93 + if ( idx >= curr->arch.guest_context.gdt_ents ) 1.94 goto fail; 1.95 } 1.96 1.97 @@ -225,29 +225,29 @@ static int linearise_address(u16 seg, un 1.98 1.99 static int fixup_seg(u16 seg, unsigned long offset) 1.100 { 1.101 - struct vcpu *d = current; 1.102 - unsigned long *table, a, b, base, limit; 1.103 - int ldt = !!(seg & 4); 1.104 - int idx = (seg >> 3) & 8191; 1.105 + struct vcpu *curr = current; 1.106 + uint32_t *table, a, b, base, limit; 1.107 + int ldt = !!(seg & 4); 1.108 + int idx = (seg >> 3) & 8191; 1.109 1.110 /* Get base and check limit. */ 1.111 if ( ldt ) 1.112 { 1.113 - table = (unsigned long *)LDT_VIRT_START(d); 1.114 - if ( idx >= d->arch.guest_context.ldt_ents ) 1.115 + table = (uint32_t *)LDT_VIRT_START(curr); 1.116 + if ( idx >= curr->arch.guest_context.ldt_ents ) 1.117 { 1.118 dprintk(XENLOG_DEBUG, "Segment %04x out of LDT range (%ld)\n", 1.119 - seg, d->arch.guest_context.ldt_ents); 1.120 + seg, curr->arch.guest_context.ldt_ents); 1.121 goto fail; 1.122 } 1.123 } 1.124 else /* gdt */ 1.125 { 1.126 - table = (unsigned long *)GDT_VIRT_START(d); 1.127 - if ( idx >= d->arch.guest_context.gdt_ents ) 1.128 + table = (uint32_t *)GDT_VIRT_START(curr); 1.129 + if ( idx >= curr->arch.guest_context.gdt_ents ) 1.130 { 1.131 dprintk(XENLOG_DEBUG, "Segment %04x out of GDT range (%ld)\n", 1.132 - seg, d->arch.guest_context.gdt_ents); 1.133 + seg, curr->arch.guest_context.gdt_ents); 1.134 goto fail; 1.135 } 1.136 } 1.137 @@ -265,7 +265,7 @@ static int fixup_seg(u16 seg, unsigned l 1.138 _SEGMENT_G|_SEGMENT_CODE|_SEGMENT_DPL)) != 1.139 (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB|_SEGMENT_G|_SEGMENT_DPL) ) 1.140 { 1.141 - dprintk(XENLOG_DEBUG, "Bad segment %08lx:%08lx\n", a, b); 1.142 + dprintk(XENLOG_DEBUG, "Bad segment %08x:%08x\n", a, b); 1.143 goto fail; 1.144 } 1.145 1.146 @@ -295,8 +295,7 @@ static int fixup_seg(u16 seg, unsigned l 1.147 } 1.148 } 1.149 1.150 - dprintk(XENLOG_DEBUG, "None of the above! " 1.151 - "(%08lx:%08lx, %08lx, %08lx, %08lx)\n", 1.152 + dprintk(XENLOG_DEBUG, "None of the above! (%08x:%08x, %08x, %08x, %08x)\n", 1.153 a, b, base, limit, base+limit); 1.154 1.155 fail: 1.156 @@ -318,18 +317,15 @@ static int fixup_seg(u16 seg, unsigned l 1.157 */ 1.158 int gpf_emulate_4gb(struct cpu_user_regs *regs) 1.159 { 1.160 - struct vcpu *d = current; 1.161 - struct trap_info *ti; 1.162 - struct trap_bounce *tb; 1.163 - u8 modrm, mod, reg, rm, decode; 1.164 - void *memreg; 1.165 - unsigned long offset; 1.166 - u8 disp8; 1.167 - u32 disp32 = 0; 1.168 + struct vcpu *curr = current; 1.169 + u8 modrm, mod, rm, decode; 1.170 + const u32 *base, *index = NULL; 1.171 + unsigned long offset; 1.172 + s8 disp8; 1.173 + s32 disp32 = 0; 1.174 u8 *eip; /* ptr to instruction start */ 1.175 u8 *pb, b; /* ptr into instr. / current instr. byte */ 1.176 - int gs_override = 0; 1.177 - int twobyte = 0; 1.178 + int gs_override = 0, scale = 0, twobyte = 0; 1.179 1.180 /* WARNING: We only work for ring-3 segments. */ 1.181 if ( unlikely(vm86_mode(regs)) || unlikely(!ring_3(regs)) ) 1.182 @@ -360,6 +356,9 @@ int gpf_emulate_4gb(struct cpu_user_regs 1.183 goto fail; 1.184 } 1.185 1.186 + if ( twobyte ) 1.187 + break; 1.188 + 1.189 switch ( b ) 1.190 { 1.191 case 0x67: /* Address-size override */ 1.192 @@ -378,6 +377,9 @@ int gpf_emulate_4gb(struct cpu_user_regs 1.193 case 0x65: /* GS override */ 1.194 gs_override = 1; 1.195 break; 1.196 + case 0x0f: /* Not really a prefix byte */ 1.197 + twobyte = 1; 1.198 + break; 1.199 default: /* Not a prefix byte */ 1.200 goto done_prefix; 1.201 } 1.202 @@ -390,32 +392,10 @@ int gpf_emulate_4gb(struct cpu_user_regs 1.203 goto fail; 1.204 } 1.205 1.206 - decode = insn_decode[b]; /* opcode byte */ 1.207 + decode = (!twobyte ? insn_decode : twobyte_decode)[b]; 1.208 pb++; 1.209 - if ( decode == 0 && b == 0x0f ) 1.210 - { 1.211 - twobyte = 1; 1.212 1.213 - if ( get_user(b, pb) ) 1.214 - { 1.215 - dprintk(XENLOG_DEBUG, 1.216 - "Fault while accessing byte %ld of instruction\n", 1.217 - (long)(pb-eip)); 1.218 - goto page_fault; 1.219 - } 1.220 - 1.221 - if ( (pb - eip) >= 15 ) 1.222 - { 1.223 - dprintk(XENLOG_DEBUG, "Too many opcode bytes for a " 1.224 - "legal instruction\n"); 1.225 - goto fail; 1.226 - } 1.227 - 1.228 - decode = twobyte_decode[b]; 1.229 - pb++; 1.230 - } 1.231 - 1.232 - if ( decode == 0 ) 1.233 + if ( !(decode & OPCODE_BYTE) ) 1.234 { 1.235 dprintk(XENLOG_DEBUG, "Unsupported %sopcode %02x\n", 1.236 twobyte ? "two byte " : "", b); 1.237 @@ -425,12 +405,12 @@ int gpf_emulate_4gb(struct cpu_user_regs 1.238 if ( !(decode & HAS_MODRM) ) 1.239 { 1.240 /* Must be a <disp32>, or bail. */ 1.241 - if ( (decode & 7) != 4 ) 1.242 + if ( (decode & INSN_SUFFIX_BYTES) != 4 ) 1.243 goto fail; 1.244 1.245 if ( get_user(offset, (u32 *)pb) ) 1.246 { 1.247 - dprintk(XENLOG_DEBUG, "Fault while extracting <disp32>.\n"); 1.248 + dprintk(XENLOG_DEBUG, "Fault while extracting <moffs32>.\n"); 1.249 goto page_fault; 1.250 } 1.251 pb += 4; 1.252 @@ -451,29 +431,39 @@ int gpf_emulate_4gb(struct cpu_user_regs 1.253 pb++; 1.254 1.255 mod = (modrm >> 6) & 3; 1.256 - reg = (modrm >> 3) & 7; 1.257 rm = (modrm >> 0) & 7; 1.258 1.259 if ( rm == 4 ) 1.260 { 1.261 - dprintk(XENLOG_DEBUG, "FIXME: Add decoding for the SIB byte.\n"); 1.262 - goto fixme; 1.263 + u8 sib; 1.264 + 1.265 + if ( get_user(sib, pb) ) 1.266 + { 1.267 + dprintk(XENLOG_DEBUG, "Fault while extracting sib byte\n"); 1.268 + goto page_fault; 1.269 + } 1.270 + 1.271 + pb++; 1.272 + 1.273 + rm = sib & 7; 1.274 + if ( (sib & 0x38) != 0x20 ) 1.275 + index = decode_register((sib >> 3) & 7, regs, 0); 1.276 + scale = sib >> 6; 1.277 } 1.278 1.279 /* Decode R/M field. */ 1.280 - memreg = decode_register(rm, regs, 0); 1.281 + base = decode_register(rm, regs, 0); 1.282 1.283 /* Decode Mod field. */ 1.284 - switch ( modrm >> 6 ) 1.285 + switch ( mod ) 1.286 { 1.287 case 0: 1.288 - disp32 = 0; 1.289 if ( rm == 5 ) /* disp32 rather than (EBP) */ 1.290 { 1.291 - memreg = NULL; 1.292 + base = NULL; 1.293 if ( get_user(disp32, (u32 *)pb) ) 1.294 { 1.295 - dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n"); 1.296 + dprintk(XENLOG_DEBUG, "Fault while extracting <base32>.\n"); 1.297 goto page_fault; 1.298 } 1.299 pb += 4; 1.300 @@ -487,13 +477,13 @@ int gpf_emulate_4gb(struct cpu_user_regs 1.301 goto page_fault; 1.302 } 1.303 pb++; 1.304 - disp32 = (disp8 & 0x80) ? (disp8 | ~0xff) : disp8;; 1.305 + disp32 = disp8; 1.306 break; 1.307 1.308 case 2: 1.309 if ( get_user(disp32, (u32 *)pb) ) 1.310 { 1.311 - dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n"); 1.312 + dprintk(XENLOG_DEBUG, "Fault while extracting <disp32>.\n"); 1.313 goto page_fault; 1.314 } 1.315 pb += 4; 1.316 @@ -505,8 +495,10 @@ int gpf_emulate_4gb(struct cpu_user_regs 1.317 } 1.318 1.319 offset = disp32; 1.320 - if ( memreg != NULL ) 1.321 - offset += *(u32 *)memreg; 1.322 + if ( base != NULL ) 1.323 + offset += *base; 1.324 + if ( index != NULL ) 1.325 + offset += *index << scale; 1.326 1.327 skip_modrm: 1.328 if ( !fixup_seg((u16)regs->gs, offset) ) 1.329 @@ -516,10 +508,11 @@ int gpf_emulate_4gb(struct cpu_user_regs 1.330 perfc_incr(seg_fixups); 1.331 1.332 /* If requested, give a callback on otherwise unused vector 15. */ 1.333 - if ( VM_ASSIST(d->domain, VMASST_TYPE_4gb_segments_notify) ) 1.334 + if ( VM_ASSIST(curr->domain, VMASST_TYPE_4gb_segments_notify) ) 1.335 { 1.336 - ti = &d->arch.guest_context.trap_ctxt[15]; 1.337 - tb = &d->arch.trap_bounce; 1.338 + struct trap_info *ti = &curr->arch.guest_context.trap_ctxt[15]; 1.339 + struct trap_bounce *tb = &curr->arch.trap_bounce; 1.340 + 1.341 tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE; 1.342 tb->error_code = pb - eip; 1.343 tb->cs = ti->cs; 1.344 @@ -530,13 +523,6 @@ int gpf_emulate_4gb(struct cpu_user_regs 1.345 1.346 return EXCRET_fault_fixed; 1.347 1.348 - fixme: 1.349 - dprintk(XENLOG_DEBUG, "Undecodable instruction " 1.350 - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " 1.351 - "caused GPF(0) at %04x:%08x\n", 1.352 - eip[0], eip[1], eip[2], eip[3], 1.353 - eip[4], eip[5], eip[6], eip[7], 1.354 - regs->cs, regs->eip); 1.355 fail: 1.356 return 0; 1.357