msi/tests: Drop workarounds for Windows 2000.
[wine.git] / dlls / ntoskrnl.exe / instr.c
blob67cdd327ee1a8d23af4323446ab8b1ec6eb9362a
1 /*
2 * Emulation of privileged instructions
4 * Copyright 1995 Alexandre Julliard
5 * Copyright 2005 Ivan Leo Puoti
6 * Copyright 2005 Laurent Pinchart
7 * Copyright 2014-2015 Sebastian Lackner
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winternl.h"
32 #define WIN32_NO_STATUS
33 #include "ddk/wdm.h"
34 #include "excpt.h"
35 #include "wine/debug.h"
36 #include "wine/exception.h"
38 #ifdef __i386__
40 WINE_DEFAULT_DEBUG_CHANNEL(int);
42 #include "pshpack1.h"
43 struct idtr
45 WORD limit;
46 BYTE *base;
48 #include "poppack.h"
50 static LDT_ENTRY idt[256];
52 static inline struct idtr get_idtr(void)
54 struct idtr ret;
55 #ifdef __GNUC__
56 __asm__( "sidtl %0" : "=m" (ret) );
57 #else
58 ret.base = (BYTE *)idt;
59 ret.limit = sizeof(idt) - 1;
60 #endif
61 return ret;
64 /* store an operand into a register */
65 static void store_reg_word( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int long_op )
67 switch((regmodrm >> 3) & 7)
69 case 0:
70 if (long_op) context->Eax = *(const DWORD *)addr;
71 else context->Eax = (context->Eax & 0xffff0000) | *(const WORD *)addr;
72 break;
73 case 1:
74 if (long_op) context->Ecx = *(const DWORD *)addr;
75 else context->Ecx = (context->Ecx & 0xffff0000) | *(const WORD *)addr;
76 break;
77 case 2:
78 if (long_op) context->Edx = *(const DWORD *)addr;
79 else context->Edx = (context->Edx & 0xffff0000) | *(const WORD *)addr;
80 break;
81 case 3:
82 if (long_op) context->Ebx = *(const DWORD *)addr;
83 else context->Ebx = (context->Ebx & 0xffff0000) | *(const WORD *)addr;
84 break;
85 case 4:
86 if (long_op) context->Esp = *(const DWORD *)addr;
87 else context->Esp = (context->Esp & 0xffff0000) | *(const WORD *)addr;
88 break;
89 case 5:
90 if (long_op) context->Ebp = *(const DWORD *)addr;
91 else context->Ebp = (context->Ebp & 0xffff0000) | *(const WORD *)addr;
92 break;
93 case 6:
94 if (long_op) context->Esi = *(const DWORD *)addr;
95 else context->Esi = (context->Esi & 0xffff0000) | *(const WORD *)addr;
96 break;
97 case 7:
98 if (long_op) context->Edi = *(const DWORD *)addr;
99 else context->Edi = (context->Edi & 0xffff0000) | *(const WORD *)addr;
100 break;
104 /* store an operand into a byte register */
105 static void store_reg_byte( CONTEXT *context, BYTE regmodrm, const BYTE *addr )
107 switch((regmodrm >> 3) & 7)
109 case 0: context->Eax = (context->Eax & 0xffffff00) | *addr; break;
110 case 1: context->Ecx = (context->Ecx & 0xffffff00) | *addr; break;
111 case 2: context->Edx = (context->Edx & 0xffffff00) | *addr; break;
112 case 3: context->Ebx = (context->Ebx & 0xffffff00) | *addr; break;
113 case 4: context->Eax = (context->Eax & 0xffff00ff) | (*addr << 8); break;
114 case 5: context->Ecx = (context->Ecx & 0xffff00ff) | (*addr << 8); break;
115 case 6: context->Edx = (context->Edx & 0xffff00ff) | (*addr << 8); break;
116 case 7: context->Ebx = (context->Ebx & 0xffff00ff) | (*addr << 8); break;
120 static DWORD *get_reg_address( CONTEXT *context, BYTE rm )
122 switch (rm & 7)
124 case 0: return &context->Eax;
125 case 1: return &context->Ecx;
126 case 2: return &context->Edx;
127 case 3: return &context->Ebx;
128 case 4: return &context->Esp;
129 case 5: return &context->Ebp;
130 case 6: return &context->Esi;
131 case 7: return &context->Edi;
133 return NULL;
137 /***********************************************************************
138 * INSTR_GetOperandAddr
140 * Return the address of an instruction operand (from the mod/rm byte).
142 static void *INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr,
143 int long_addr, int segprefix, int *len )
145 int mod, rm, base = 0, index = 0, ss = 0, off;
147 #define GET_VAL(val,type) \
148 { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
150 *len = 0;
151 GET_VAL( &mod, BYTE );
152 rm = mod & 7;
153 mod >>= 6;
155 if (mod == 3) return get_reg_address( context, rm );
157 if (long_addr)
159 if (rm == 4)
161 BYTE sib;
162 GET_VAL( &sib, BYTE );
163 rm = sib & 7;
164 ss = sib >> 6;
165 switch((sib >> 3) & 7)
167 case 0: index = context->Eax; break;
168 case 1: index = context->Ecx; break;
169 case 2: index = context->Edx; break;
170 case 3: index = context->Ebx; break;
171 case 4: index = 0; break;
172 case 5: index = context->Ebp; break;
173 case 6: index = context->Esi; break;
174 case 7: index = context->Edi; break;
178 switch(rm)
180 case 0: base = context->Eax; break;
181 case 1: base = context->Ecx; break;
182 case 2: base = context->Edx; break;
183 case 3: base = context->Ebx; break;
184 case 4: base = context->Esp; break;
185 case 5: base = context->Ebp; break;
186 case 6: base = context->Esi; break;
187 case 7: base = context->Edi; break;
189 switch (mod)
191 case 0:
192 if (rm == 5) /* special case: ds:(disp32) */
194 GET_VAL( &base, DWORD );
196 break;
198 case 1: /* 8-bit disp */
199 GET_VAL( &off, BYTE );
200 base += (signed char)off;
201 break;
203 case 2: /* 32-bit disp */
204 GET_VAL( &off, DWORD );
205 base += (signed long)off;
206 break;
209 else /* short address */
211 switch(rm)
213 case 0: /* ds:(bx,si) */
214 base = LOWORD(context->Ebx) + LOWORD(context->Esi);
215 break;
216 case 1: /* ds:(bx,di) */
217 base = LOWORD(context->Ebx) + LOWORD(context->Edi);
218 break;
219 case 2: /* ss:(bp,si) */
220 base = LOWORD(context->Ebp) + LOWORD(context->Esi);
221 break;
222 case 3: /* ss:(bp,di) */
223 base = LOWORD(context->Ebp) + LOWORD(context->Edi);
224 break;
225 case 4: /* ds:(si) */
226 base = LOWORD(context->Esi);
227 break;
228 case 5: /* ds:(di) */
229 base = LOWORD(context->Edi);
230 break;
231 case 6: /* ss:(bp) */
232 base = LOWORD(context->Ebp);
233 break;
234 case 7: /* ds:(bx) */
235 base = LOWORD(context->Ebx);
236 break;
239 switch(mod)
241 case 0:
242 if (rm == 6) /* special case: ds:(disp16) */
244 GET_VAL( &base, WORD );
246 break;
248 case 1: /* 8-bit disp */
249 GET_VAL( &off, BYTE );
250 base += (signed char)off;
251 break;
253 case 2: /* 16-bit disp */
254 GET_VAL( &off, WORD );
255 base += (signed short)off;
256 break;
258 base &= 0xffff;
260 /* FIXME: we assume that all segments have a base of 0 */
261 return (void *)(base + (index << ss));
262 #undef GET_VAL
266 /***********************************************************************
267 * emulate_instruction
269 * Emulate a privileged instruction.
270 * Returns exception continuation status.
272 static DWORD emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context )
274 static const char *reg_names[8] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
275 int prefix, segprefix, prefixlen, len, long_op, long_addr;
276 BYTE *instr;
278 long_op = long_addr = 1;
279 instr = (BYTE *)context->Eip;
280 if (!instr) return ExceptionContinueSearch;
282 /* First handle any possible prefix */
284 segprefix = -1; /* no prefix */
285 prefix = 1;
286 prefixlen = 0;
287 while(prefix)
289 switch(*instr)
291 case 0x2e:
292 segprefix = context->SegCs;
293 break;
294 case 0x36:
295 segprefix = context->SegSs;
296 break;
297 case 0x3e:
298 segprefix = context->SegDs;
299 break;
300 case 0x26:
301 segprefix = context->SegEs;
302 break;
303 case 0x64:
304 segprefix = context->SegFs;
305 break;
306 case 0x65:
307 segprefix = context->SegGs;
308 break;
309 case 0x66:
310 long_op = !long_op; /* opcode size prefix */
311 break;
312 case 0x67:
313 long_addr = !long_addr; /* addr size prefix */
314 break;
315 case 0xf0: /* lock */
316 break;
317 case 0xf2: /* repne */
318 break;
319 case 0xf3: /* repe */
320 break;
321 default:
322 prefix = 0; /* no more prefixes */
323 break;
325 if (prefix)
327 instr++;
328 prefixlen++;
332 /* Now look at the actual instruction */
334 switch(*instr)
336 case 0x0f: /* extended instruction */
337 switch(instr[1])
339 case 0x20: /* mov crX, Rd */
341 int reg = (instr[2] >> 3) & 7;
342 DWORD *data = get_reg_address( context, instr[2] );
343 TRACE( "mov cr%u,%s at 0x%08x\n", reg, reg_names[instr[2] & 7], context->Eip );
344 switch (reg)
346 case 0: *data = 0x10; break; /* FIXME: set more bits ? */
347 case 2: *data = 0; break;
348 case 3: *data = 0; break;
349 case 4: *data = 0; break;
350 default: return ExceptionContinueSearch;
352 context->Eip += prefixlen + 3;
353 return ExceptionContinueExecution;
355 case 0x21: /* mov drX, Rd */
357 int reg = (instr[2] >> 3) & 7;
358 DWORD *data = get_reg_address( context, instr[2] );
359 TRACE( "mov dr%u,%s at 0x%08x\n", reg, reg_names[instr[2] & 7], context->Eip );
360 switch (reg)
362 case 0: *data = context->Dr0; break;
363 case 1: *data = context->Dr1; break;
364 case 2: *data = context->Dr2; break;
365 case 3: *data = context->Dr3; break;
366 case 6: *data = context->Dr6; break;
367 case 7: *data = 0x400; break;
368 default: return ExceptionContinueSearch;
370 context->Eip += prefixlen + 3;
371 return ExceptionContinueExecution;
373 case 0x22: /* mov Rd, crX */
375 int reg = (instr[2] >> 3) & 7;
376 DWORD *data = get_reg_address( context, instr[2] );
377 TRACE( "mov %s,cr%u at 0x%08x, %s=%08x\n", reg_names[instr[2] & 7],
378 reg, context->Eip, reg_names[instr[2] & 7], *data );
379 switch (reg)
381 case 0: break;
382 case 2: break;
383 case 3: break;
384 case 4: break;
385 default: return ExceptionContinueSearch;
387 context->Eip += prefixlen + 3;
388 return ExceptionContinueExecution;
390 case 0x23: /* mov Rd, drX */
392 int reg = (instr[2] >> 3) & 7;
393 DWORD *data = get_reg_address( context, instr[2] );
394 TRACE( "mov %s,dr%u at 0x%08x %s=%08x\n", reg_names[instr[2] & 7],
395 reg, context->Eip, reg_names[instr[2] & 7], *data );
396 switch (reg)
398 case 0: context->Dr0 = *data; break;
399 case 1: context->Dr1 = *data; break;
400 case 2: context->Dr2 = *data; break;
401 case 3: context->Dr3 = *data; break;
402 case 6: context->Dr6 = *data; break;
403 case 7: context->Dr7 = *data; break;
404 default: return ExceptionContinueSearch;
406 context->Eip += prefixlen + 3;
407 return ExceptionContinueExecution;
410 break;
412 case 0x8a: /* mov Eb, Gb */
413 case 0x8b: /* mov Ev, Gv */
415 BYTE *data = INSTR_GetOperandAddr(context, instr + 1, long_addr,
416 segprefix, &len);
417 unsigned int data_size = (*instr == 0x8b) ? (long_op ? 4 : 2) : 1;
418 struct idtr idtr = get_idtr();
419 unsigned int offset = data - idtr.base;
421 if (offset <= idtr.limit + 1 - data_size)
423 idt[1].LimitLow = 0x100; /* FIXME */
424 idt[2].LimitLow = 0x11E; /* FIXME */
425 idt[3].LimitLow = 0x500; /* FIXME */
427 switch (*instr)
429 case 0x8a: store_reg_byte( context, instr[1], (BYTE *)idt + offset ); break;
430 case 0x8b: store_reg_word( context, instr[1], (BYTE *)idt + offset, long_op ); break;
432 context->Eip += prefixlen + len + 1;
433 return ExceptionContinueExecution;
435 break; /* Unable to emulate it */
438 case 0xfa: /* cli */
439 case 0xfb: /* sti */
440 context->Eip += prefixlen + 1;
441 return ExceptionContinueExecution;
443 return ExceptionContinueSearch; /* Unable to emulate it */
447 /***********************************************************************
448 * vectored_handler
450 * Vectored exception handler used to emulate protected instructions
451 * from 32-bit code.
453 LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs )
455 EXCEPTION_RECORD *record = ptrs->ExceptionRecord;
456 CONTEXT *context = ptrs->ContextRecord;
458 if ((record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
459 record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION))
461 if (emulate_instruction( record, context ) == ExceptionContinueExecution)
462 return EXCEPTION_CONTINUE_EXECUTION;
464 return EXCEPTION_CONTINUE_SEARCH;
467 #elif defined(__x86_64__) /* __i386__ */
469 WINE_DEFAULT_DEBUG_CHANNEL(int);
471 #define REX_B 1
472 #define REX_X 2
473 #define REX_R 4
474 #define REX_W 8
476 #define REGMODRM_MOD( regmodrm, rex ) ((regmodrm) >> 6)
477 #define REGMODRM_REG( regmodrm, rex ) (((regmodrm) >> 3) & 7) | (((rex) & REX_R) ? 8 : 0)
478 #define REGMODRM_RM( regmodrm, rex ) (((regmodrm) & 7) | (((rex) & REX_B) ? 8 : 0))
480 #define SIB_SS( sib, rex ) ((sib) >> 6)
481 #define SIB_INDEX( sib, rex ) (((sib) >> 3) & 7) | (((rex) & REX_X) ? 8 : 0)
482 #define SIB_BASE( sib, rex ) (((sib) & 7) | (((rex) & REX_B) ? 8 : 0))
484 /* keep in sync with dlls/ntdll/thread.c:thread_init */
485 static const BYTE *wine_user_shared_data = (BYTE *)0x7ffe0000;
486 static const BYTE *user_shared_data = (BYTE *)0xfffff78000000000;
488 static inline DWORD64 *get_int_reg( CONTEXT *context, int index )
490 return &context->Rax + index; /* index should be in range 0 .. 15 */
493 static inline int get_op_size( int long_op, int rex )
495 if (rex & REX_W)
496 return sizeof(DWORD64);
497 else if (long_op)
498 return sizeof(DWORD);
499 else
500 return sizeof(WORD);
503 /* store an operand into a register */
504 static void store_reg_word( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int long_op, int rex )
506 int index = REGMODRM_REG( regmodrm, rex );
507 BYTE *reg = (BYTE *)get_int_reg( context, index );
508 memcpy( reg, addr, get_op_size( long_op, rex ) );
511 /* store an operand into a byte register */
512 static void store_reg_byte( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int rex )
514 int index = REGMODRM_REG( regmodrm, rex );
515 BYTE *reg = (BYTE *)get_int_reg( context, index );
516 if (!rex && index >= 4 && index < 8) reg -= (4 * sizeof(DWORD64) - 1); /* special case: ah, ch, dh, bh */
517 *reg = *addr;
520 /***********************************************************************
521 * INSTR_GetOperandAddr
523 * Return the address of an instruction operand (from the mod/rm byte).
525 static BYTE *INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr,
526 int long_addr, int rex, int segprefix, int *len )
528 int mod, rm, ss = 0, off, have_sib = 0;
529 DWORD64 base = 0, index = 0;
531 #define GET_VAL( val, type ) \
532 { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
534 *len = 0;
535 GET_VAL( &mod, BYTE );
536 rm = REGMODRM_RM( mod, rex );
537 mod = REGMODRM_MOD( mod, rex );
539 if (mod == 3)
540 return (BYTE *)get_int_reg( context, rm );
542 if ((rm & 7) == 4)
544 BYTE sib;
545 int id;
547 GET_VAL( &sib, BYTE );
548 rm = SIB_BASE( sib, rex );
549 id = SIB_INDEX( sib, rex );
550 ss = SIB_SS( sib, rex );
552 index = (id != 4) ? *get_int_reg( context, id ) : 0;
553 if (!long_addr) index &= 0xffffffff;
554 have_sib = 1;
557 base = *get_int_reg( context, rm );
558 if (!long_addr) base &= 0xffffffff;
560 switch (mod)
562 case 0:
563 if (rm == 5) /* special case */
565 base = have_sib ? 0 : context->Rip;
566 if (!long_addr) base &= 0xffffffff;
567 GET_VAL( &off, DWORD );
568 base += (signed long)off;
570 break;
572 case 1: /* 8-bit disp */
573 GET_VAL( &off, BYTE );
574 base += (signed char)off;
575 break;
577 case 2: /* 32-bit disp */
578 GET_VAL( &off, DWORD );
579 base += (signed long)off;
580 break;
583 /* FIXME: we assume that all segments have a base of 0 */
584 return (BYTE *)(base + (index << ss));
585 #undef GET_VAL
589 /***********************************************************************
590 * emulate_instruction
592 * Emulate a privileged instruction.
593 * Returns exception continuation status.
595 static DWORD emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context )
597 static const char *reg_names[16] = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
598 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
599 int prefix, segprefix, prefixlen, len, long_op, long_addr, rex;
600 BYTE *instr;
602 long_op = long_addr = 1;
603 instr = (BYTE *)context->Rip;
604 if (!instr) return ExceptionContinueSearch;
606 /* First handle any possible prefix */
608 segprefix = -1; /* no seg prefix */
609 rex = 0; /* no rex prefix */
610 prefix = 1;
611 prefixlen = 0;
612 while(prefix)
614 switch(*instr)
616 case 0x2e:
617 segprefix = context->SegCs;
618 break;
619 case 0x36:
620 segprefix = context->SegSs;
621 break;
622 case 0x3e:
623 segprefix = context->SegDs;
624 break;
625 case 0x26:
626 segprefix = context->SegEs;
627 break;
628 case 0x64:
629 segprefix = context->SegFs;
630 break;
631 case 0x65:
632 segprefix = context->SegGs;
633 break;
634 case 0x66:
635 long_op = !long_op; /* opcode size prefix */
636 break;
637 case 0x67:
638 long_addr = !long_addr; /* addr size prefix */
639 break;
640 case 0x40: /* rex */
641 case 0x41:
642 case 0x42:
643 case 0x43:
644 case 0x44:
645 case 0x45:
646 case 0x46:
647 case 0x47:
648 case 0x48:
649 case 0x49:
650 case 0x4a:
651 case 0x4b:
652 case 0x4c:
653 case 0x4d:
654 case 0x4e:
655 case 0x4f:
656 rex = *instr;
657 break;
658 case 0xf0: /* lock */
659 break;
660 case 0xf2: /* repne */
661 break;
662 case 0xf3: /* repe */
663 break;
664 default:
665 prefix = 0; /* no more prefixes */
666 break;
668 if (prefix)
670 instr++;
671 prefixlen++;
675 /* Now look at the actual instruction */
677 switch(*instr)
679 case 0x0f: /* extended instruction */
680 switch(instr[1])
682 case 0x20: /* mov crX, Rd */
684 int reg = REGMODRM_REG( instr[2], rex );
685 int rm = REGMODRM_RM( instr[2], rex );
686 DWORD64 *data = get_int_reg( context, rm );
687 TRACE( "mov cr%u,%s at %lx\n", reg, reg_names[rm], context->Rip );
688 switch (reg)
690 case 0: *data = 0x10; break; /* FIXME: set more bits ? */
691 case 2: *data = 0; break;
692 case 3: *data = 0; break;
693 case 4: *data = 0; break;
694 case 8: *data = 0; break;
695 default: return ExceptionContinueSearch;
697 context->Rip += prefixlen + 3;
698 return ExceptionContinueExecution;
700 case 0x21: /* mov drX, Rd */
702 int reg = REGMODRM_REG( instr[2], rex );
703 int rm = REGMODRM_RM( instr[2], rex );
704 DWORD64 *data = get_int_reg( context, rm );
705 TRACE( "mov dr%u,%s at %lx\n", reg, reg_names[rm], context->Rip );
706 switch (reg)
708 case 0: *data = context->Dr0; break;
709 case 1: *data = context->Dr1; break;
710 case 2: *data = context->Dr2; break;
711 case 3: *data = context->Dr3; break;
712 case 4: /* dr4 and dr5 are obsolete aliases for dr6 and dr7 */
713 case 6: *data = context->Dr6; break;
714 case 5:
715 case 7: *data = 0x400; break;
716 default: return ExceptionContinueSearch;
718 context->Rip += prefixlen + 3;
719 return ExceptionContinueExecution;
721 case 0x22: /* mov Rd, crX */
723 int reg = REGMODRM_REG( instr[2], rex );
724 int rm = REGMODRM_RM( instr[2], rex );
725 DWORD64 *data = get_int_reg( context, rm );
726 TRACE( "mov %s,cr%u at %lx, %s=%lx\n", reg_names[rm], reg, context->Rip, reg_names[rm], *data );
727 switch (reg)
729 case 0: break;
730 case 2: break;
731 case 3: break;
732 case 4: break;
733 case 8: break;
734 default: return ExceptionContinueSearch;
736 context->Rip += prefixlen + 3;
737 return ExceptionContinueExecution;
739 case 0x23: /* mov Rd, drX */
741 int reg = REGMODRM_REG( instr[2], rex );
742 int rm = REGMODRM_RM( instr[2], rex );
743 DWORD64 *data = get_int_reg( context, rm );
744 TRACE( "mov %s,dr%u at %lx, %s=%lx\n", reg_names[rm], reg, context->Rip, reg_names[rm], *data );
745 switch (reg)
747 case 0: context->Dr0 = *data; break;
748 case 1: context->Dr1 = *data; break;
749 case 2: context->Dr2 = *data; break;
750 case 3: context->Dr3 = *data; break;
751 case 4: /* dr4 and dr5 are obsolete aliases for dr6 and dr7 */
752 case 6: context->Dr6 = *data; break;
753 case 5:
754 case 7: context->Dr7 = *data; break;
755 default: return ExceptionContinueSearch;
757 context->Rip += prefixlen + 3;
758 return ExceptionContinueExecution;
760 case 0xb6: /* movzx Eb, Gv */
761 case 0xb7: /* movzx Ew, Gv */
763 BYTE *data = INSTR_GetOperandAddr( context, instr + 2, long_addr,
764 rex, segprefix, &len );
765 unsigned int data_size = (instr[1] == 0xb7) ? 2 : 1;
766 SIZE_T offset = data - user_shared_data;
768 if (offset <= sizeof(KSHARED_USER_DATA) - data_size)
770 ULONGLONG temp = 0;
771 memcpy( &temp, wine_user_shared_data + offset, data_size );
772 store_reg_word( context, instr[2], (BYTE *)&temp, long_op, rex );
773 context->Rip += prefixlen + len + 2;
774 return ExceptionContinueExecution;
776 break; /* Unable to emulate it */
779 break; /* Unable to emulate it */
781 case 0x8a: /* mov Eb, Gb */
782 case 0x8b: /* mov Ev, Gv */
784 BYTE *data = INSTR_GetOperandAddr( context, instr + 1, long_addr,
785 rex, segprefix, &len );
786 unsigned int data_size = (*instr == 0x8b) ? get_op_size( long_op, rex ) : 1;
787 SIZE_T offset = data - user_shared_data;
789 if (offset <= sizeof(KSHARED_USER_DATA) - data_size)
791 switch (*instr)
793 case 0x8a: store_reg_byte( context, instr[1], wine_user_shared_data + offset, rex ); break;
794 case 0x8b: store_reg_word( context, instr[1], wine_user_shared_data + offset, long_op, rex ); break;
796 context->Rip += prefixlen + len + 1;
797 return ExceptionContinueExecution;
799 break; /* Unable to emulate it */
802 case 0xa0: /* mov Ob, AL */
803 case 0xa1: /* mov Ovqp, rAX */
805 BYTE *data = (BYTE *)(long_addr ? *(DWORD64 *)(instr + 1) : *(DWORD *)(instr + 1));
806 unsigned int data_size = (*instr == 0xa1) ? get_op_size( long_op, rex ) : 1;
807 SIZE_T offset = data - user_shared_data;
808 len = long_addr ? sizeof(DWORD64) : sizeof(DWORD);
810 if (offset <= sizeof(KSHARED_USER_DATA) - data_size)
812 memcpy( &context->Rax, wine_user_shared_data + offset, data_size );
813 context->Rip += prefixlen + len + 1;
814 return ExceptionContinueExecution;
816 break; /* Unable to emulate it */
819 case 0xfa: /* cli */
820 case 0xfb: /* sti */
821 context->Rip += prefixlen + 1;
822 return ExceptionContinueExecution;
824 return ExceptionContinueSearch; /* Unable to emulate it */
828 /***********************************************************************
829 * vectored_handler
831 * Vectored exception handler used to emulate protected instructions
832 * from 64-bit code.
834 LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs )
836 EXCEPTION_RECORD *record = ptrs->ExceptionRecord;
837 CONTEXT *context = ptrs->ContextRecord;
839 if (record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION ||
840 (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
841 record->ExceptionInformation[0] == EXCEPTION_READ_FAULT))
843 if (emulate_instruction( record, context ) == ExceptionContinueExecution)
845 TRACE( "next instruction rip=%lx\n", context->Rip );
846 TRACE( " rax=%016lx rbx=%016lx rcx=%016lx rdx=%016lx\n",
847 context->Rax, context->Rbx, context->Rcx, context->Rdx );
848 TRACE( " rsi=%016lx rdi=%016lx rbp=%016lx rsp=%016lx\n",
849 context->Rsi, context->Rdi, context->Rbp, context->Rsp );
850 TRACE( " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n",
851 context->R8, context->R9, context->R10, context->R11 );
852 TRACE( " r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n",
853 context->R12, context->R13, context->R14, context->R15 );
855 return EXCEPTION_CONTINUE_EXECUTION;
858 return EXCEPTION_CONTINUE_SEARCH;
861 #endif /* __x86_64__ */