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
26 #define NONAMELESSUNION
30 #define WIN32_NO_STATUS
33 #include "wine/debug.h"
35 #define KSHARED_USER_DATA_PAGE_SIZE 0x1000
37 #define CR0_PE 0x00000001 /* Protected Mode */
38 #define CR0_ET 0x00000010 /* Extension Type */
39 #define CR0_NE 0x00000020 /* Numeric Error */
40 #define CR0_WP 0x00010000 /* Write Protect */
41 #define CR0_AM 0x00040000 /* Alignment Mask */
42 #define CR0_PG 0x80000000 /* Paging */
53 WINE_DEFAULT_DEBUG_CHANNEL(int);
63 static LDT_ENTRY idt
[256];
65 static inline struct idtr
get_idtr(void)
69 __asm__( "sidtl %0" : "=m" (ret
) );
71 ret
.base
= (BYTE
*)idt
;
72 ret
.limit
= sizeof(idt
) - 1;
77 /* store an operand into a register */
78 static void store_reg_word( CONTEXT
*context
, BYTE regmodrm
, const BYTE
*addr
, int long_op
)
80 switch((regmodrm
>> 3) & 7)
83 if (long_op
) context
->Eax
= *(const DWORD
*)addr
;
84 else context
->Eax
= (context
->Eax
& 0xffff0000) | *(const WORD
*)addr
;
87 if (long_op
) context
->Ecx
= *(const DWORD
*)addr
;
88 else context
->Ecx
= (context
->Ecx
& 0xffff0000) | *(const WORD
*)addr
;
91 if (long_op
) context
->Edx
= *(const DWORD
*)addr
;
92 else context
->Edx
= (context
->Edx
& 0xffff0000) | *(const WORD
*)addr
;
95 if (long_op
) context
->Ebx
= *(const DWORD
*)addr
;
96 else context
->Ebx
= (context
->Ebx
& 0xffff0000) | *(const WORD
*)addr
;
99 if (long_op
) context
->Esp
= *(const DWORD
*)addr
;
100 else context
->Esp
= (context
->Esp
& 0xffff0000) | *(const WORD
*)addr
;
103 if (long_op
) context
->Ebp
= *(const DWORD
*)addr
;
104 else context
->Ebp
= (context
->Ebp
& 0xffff0000) | *(const WORD
*)addr
;
107 if (long_op
) context
->Esi
= *(const DWORD
*)addr
;
108 else context
->Esi
= (context
->Esi
& 0xffff0000) | *(const WORD
*)addr
;
111 if (long_op
) context
->Edi
= *(const DWORD
*)addr
;
112 else context
->Edi
= (context
->Edi
& 0xffff0000) | *(const WORD
*)addr
;
117 /* store an operand into a byte register */
118 static void store_reg_byte( CONTEXT
*context
, BYTE regmodrm
, const BYTE
*addr
)
120 switch((regmodrm
>> 3) & 7)
122 case 0: context
->Eax
= (context
->Eax
& 0xffffff00) | *addr
; break;
123 case 1: context
->Ecx
= (context
->Ecx
& 0xffffff00) | *addr
; break;
124 case 2: context
->Edx
= (context
->Edx
& 0xffffff00) | *addr
; break;
125 case 3: context
->Ebx
= (context
->Ebx
& 0xffffff00) | *addr
; break;
126 case 4: context
->Eax
= (context
->Eax
& 0xffff00ff) | (*addr
<< 8); break;
127 case 5: context
->Ecx
= (context
->Ecx
& 0xffff00ff) | (*addr
<< 8); break;
128 case 6: context
->Edx
= (context
->Edx
& 0xffff00ff) | (*addr
<< 8); break;
129 case 7: context
->Ebx
= (context
->Ebx
& 0xffff00ff) | (*addr
<< 8); break;
133 static DWORD
*get_reg_address( CONTEXT
*context
, BYTE rm
)
137 case 0: return &context
->Eax
;
138 case 1: return &context
->Ecx
;
139 case 2: return &context
->Edx
;
140 case 3: return &context
->Ebx
;
141 case 4: return &context
->Esp
;
142 case 5: return &context
->Ebp
;
143 case 6: return &context
->Esi
;
144 case 7: return &context
->Edi
;
150 /***********************************************************************
151 * INSTR_GetOperandAddr
153 * Return the address of an instruction operand (from the mod/rm byte).
155 static void *INSTR_GetOperandAddr( CONTEXT
*context
, BYTE
*instr
,
156 int long_addr
, int segprefix
, int *len
)
158 int mod
, rm
, base
= 0, index
= 0, ss
= 0, off
;
160 #define GET_VAL(val,type) \
161 { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
164 GET_VAL( &mod
, BYTE
);
168 if (mod
== 3) return get_reg_address( context
, rm
);
175 GET_VAL( &sib
, BYTE
);
178 switch((sib
>> 3) & 7)
180 case 0: index
= context
->Eax
; break;
181 case 1: index
= context
->Ecx
; break;
182 case 2: index
= context
->Edx
; break;
183 case 3: index
= context
->Ebx
; break;
184 case 4: index
= 0; break;
185 case 5: index
= context
->Ebp
; break;
186 case 6: index
= context
->Esi
; break;
187 case 7: index
= context
->Edi
; break;
193 case 0: base
= context
->Eax
; break;
194 case 1: base
= context
->Ecx
; break;
195 case 2: base
= context
->Edx
; break;
196 case 3: base
= context
->Ebx
; break;
197 case 4: base
= context
->Esp
; break;
198 case 5: base
= context
->Ebp
; break;
199 case 6: base
= context
->Esi
; break;
200 case 7: base
= context
->Edi
; break;
205 if (rm
== 5) /* special case: ds:(disp32) */
207 GET_VAL( &base
, DWORD
);
211 case 1: /* 8-bit disp */
212 GET_VAL( &off
, BYTE
);
213 base
+= (signed char)off
;
216 case 2: /* 32-bit disp */
217 GET_VAL( &off
, DWORD
);
218 base
+= (signed long)off
;
222 else /* short address */
226 case 0: /* ds:(bx,si) */
227 base
= LOWORD(context
->Ebx
) + LOWORD(context
->Esi
);
229 case 1: /* ds:(bx,di) */
230 base
= LOWORD(context
->Ebx
) + LOWORD(context
->Edi
);
232 case 2: /* ss:(bp,si) */
233 base
= LOWORD(context
->Ebp
) + LOWORD(context
->Esi
);
235 case 3: /* ss:(bp,di) */
236 base
= LOWORD(context
->Ebp
) + LOWORD(context
->Edi
);
238 case 4: /* ds:(si) */
239 base
= LOWORD(context
->Esi
);
241 case 5: /* ds:(di) */
242 base
= LOWORD(context
->Edi
);
244 case 6: /* ss:(bp) */
245 base
= LOWORD(context
->Ebp
);
247 case 7: /* ds:(bx) */
248 base
= LOWORD(context
->Ebx
);
255 if (rm
== 6) /* special case: ds:(disp16) */
257 GET_VAL( &base
, WORD
);
261 case 1: /* 8-bit disp */
262 GET_VAL( &off
, BYTE
);
263 base
+= (signed char)off
;
266 case 2: /* 16-bit disp */
267 GET_VAL( &off
, WORD
);
268 base
+= (signed short)off
;
273 /* FIXME: we assume that all segments have a base of 0 */
274 return (void *)(base
+ (index
<< ss
));
279 /***********************************************************************
280 * emulate_instruction
282 * Emulate a privileged instruction.
283 * Returns exception continuation status.
285 static DWORD
emulate_instruction( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
287 static const char *reg_names
[8] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
288 int prefix
, segprefix
, prefixlen
, len
, long_op
, long_addr
;
291 long_op
= long_addr
= 1;
292 instr
= (BYTE
*)context
->Eip
;
293 if (!instr
) return ExceptionContinueSearch
;
295 /* First handle any possible prefix */
297 segprefix
= -1; /* no prefix */
305 segprefix
= context
->SegCs
;
308 segprefix
= context
->SegSs
;
311 segprefix
= context
->SegDs
;
314 segprefix
= context
->SegEs
;
317 segprefix
= context
->SegFs
;
320 segprefix
= context
->SegGs
;
323 long_op
= !long_op
; /* opcode size prefix */
326 long_addr
= !long_addr
; /* addr size prefix */
328 case 0xf0: /* lock */
330 case 0xf2: /* repne */
332 case 0xf3: /* repe */
335 prefix
= 0; /* no more prefixes */
345 /* Now look at the actual instruction */
349 case 0x0f: /* extended instruction */
352 case 0x20: /* mov crX, Rd */
354 int reg
= (instr
[2] >> 3) & 7;
355 DWORD
*data
= get_reg_address( context
, instr
[2] );
356 TRACE( "mov cr%u,%s at 0x%08lx\n", reg
, reg_names
[instr
[2] & 7], context
->Eip
);
359 case 0: *data
= CR0_PE
|CR0_ET
|CR0_NE
|CR0_WP
|CR0_AM
|CR0_PG
; break;
360 case 2: *data
= 0; break;
361 case 3: *data
= 0; break;
362 case 4: *data
= 0; break;
363 default: return ExceptionContinueSearch
;
365 context
->Eip
+= prefixlen
+ 3;
366 return ExceptionContinueExecution
;
368 case 0x21: /* mov drX, Rd */
370 int reg
= (instr
[2] >> 3) & 7;
371 DWORD
*data
= get_reg_address( context
, instr
[2] );
372 TRACE( "mov dr%u,%s at 0x%08lx\n", reg
, reg_names
[instr
[2] & 7], context
->Eip
);
375 case 0: *data
= context
->Dr0
; break;
376 case 1: *data
= context
->Dr1
; break;
377 case 2: *data
= context
->Dr2
; break;
378 case 3: *data
= context
->Dr3
; break;
379 case 6: *data
= context
->Dr6
; break;
380 case 7: *data
= 0x400; break;
381 default: return ExceptionContinueSearch
;
383 context
->Eip
+= prefixlen
+ 3;
384 return ExceptionContinueExecution
;
386 case 0x22: /* mov Rd, crX */
388 int reg
= (instr
[2] >> 3) & 7;
389 DWORD
*data
= get_reg_address( context
, instr
[2] );
390 TRACE( "mov %s,cr%u at 0x%08lx, %s=%08lx\n", reg_names
[instr
[2] & 7],
391 reg
, context
->Eip
, reg_names
[instr
[2] & 7], *data
);
398 default: return ExceptionContinueSearch
;
400 context
->Eip
+= prefixlen
+ 3;
401 return ExceptionContinueExecution
;
403 case 0x23: /* mov Rd, drX */
405 int reg
= (instr
[2] >> 3) & 7;
406 DWORD
*data
= get_reg_address( context
, instr
[2] );
407 TRACE( "mov %s,dr%u at 0x%08lx %s=%08lx\n", reg_names
[instr
[2] & 7],
408 reg
, context
->Eip
, reg_names
[instr
[2] & 7], *data
);
411 case 0: context
->Dr0
= *data
; break;
412 case 1: context
->Dr1
= *data
; break;
413 case 2: context
->Dr2
= *data
; break;
414 case 3: context
->Dr3
= *data
; break;
415 case 6: context
->Dr6
= *data
; break;
416 case 7: context
->Dr7
= *data
; break;
417 default: return ExceptionContinueSearch
;
419 context
->Eip
+= prefixlen
+ 3;
420 return ExceptionContinueExecution
;
425 case 0x8a: /* mov Eb, Gb */
426 case 0x8b: /* mov Ev, Gv */
428 BYTE
*data
= INSTR_GetOperandAddr(context
, instr
+ 1, long_addr
,
430 unsigned int data_size
= (*instr
== 0x8b) ? (long_op
? 4 : 2) : 1;
431 struct idtr idtr
= get_idtr();
432 unsigned int offset
= data
- idtr
.base
;
434 if (offset
<= idtr
.limit
+ 1 - data_size
)
436 idt
[1].LimitLow
= 0x100; /* FIXME */
437 idt
[2].LimitLow
= 0x11E; /* FIXME */
438 idt
[3].LimitLow
= 0x500; /* FIXME */
442 case 0x8a: store_reg_byte( context
, instr
[1], (BYTE
*)idt
+ offset
); break;
443 case 0x8b: store_reg_word( context
, instr
[1], (BYTE
*)idt
+ offset
, long_op
); break;
445 context
->Eip
+= prefixlen
+ len
+ 1;
446 return ExceptionContinueExecution
;
448 break; /* Unable to emulate it */
453 context
->Eip
+= prefixlen
+ 1;
454 return ExceptionContinueExecution
;
456 return ExceptionContinueSearch
; /* Unable to emulate it */
460 /***********************************************************************
463 * Vectored exception handler used to emulate protected instructions
466 LONG CALLBACK
vectored_handler( EXCEPTION_POINTERS
*ptrs
)
468 EXCEPTION_RECORD
*record
= ptrs
->ExceptionRecord
;
469 CONTEXT
*context
= ptrs
->ContextRecord
;
471 if ((record
->ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
||
472 record
->ExceptionCode
== EXCEPTION_PRIV_INSTRUCTION
))
474 if (emulate_instruction( record
, context
) == ExceptionContinueExecution
)
475 return EXCEPTION_CONTINUE_EXECUTION
;
477 return EXCEPTION_CONTINUE_SEARCH
;
480 #elif defined(__x86_64__) /* __i386__ */
482 WINE_DEFAULT_DEBUG_CHANNEL(int);
489 #define MSR_LSTAR 0xc0000082
491 #define REGMODRM_MOD( regmodrm, rex ) ((regmodrm) >> 6)
492 #define REGMODRM_REG( regmodrm, rex ) (((regmodrm) >> 3) & 7) | (((rex) & REX_R) ? 8 : 0)
493 #define REGMODRM_RM( regmodrm, rex ) (((regmodrm) & 7) | (((rex) & REX_B) ? 8 : 0))
495 #define SIB_SS( sib, rex ) ((sib) >> 6)
496 #define SIB_INDEX( sib, rex ) (((sib) >> 3) & 7) | (((rex) & REX_X) ? 8 : 0)
497 #define SIB_BASE( sib, rex ) (((sib) & 7) | (((rex) & REX_B) ? 8 : 0))
499 /* keep in sync with dlls/ntdll/thread.c:thread_init */
500 static const BYTE
*wine_user_shared_data
= (BYTE
*)0x7ffe0000;
501 static const BYTE
*user_shared_data
= (BYTE
*)0xfffff78000000000;
503 static inline DWORD64
*get_int_reg( CONTEXT
*context
, int index
)
505 return &context
->Rax
+ index
; /* index should be in range 0 .. 15 */
508 static inline int get_op_size( int long_op
, int rex
)
511 return sizeof(DWORD64
);
513 return sizeof(DWORD
);
518 /* store an operand into a register */
519 static void store_reg_word( CONTEXT
*context
, BYTE regmodrm
, const BYTE
*addr
, int long_op
, int rex
,
522 int index
= REGMODRM_REG( regmodrm
, rex
);
523 BYTE
*reg
= (BYTE
*)get_int_reg( context
, index
);
524 int op_size
= get_op_size( long_op
, rex
);
530 memcpy( reg
, addr
, op_size
);
533 for (i
= 0; i
< op_size
; ++i
)
537 for (i
= 0; i
< op_size
; ++i
)
543 /* store an operand into a byte register */
544 static void store_reg_byte( CONTEXT
*context
, BYTE regmodrm
, const BYTE
*addr
, int rex
, enum instr_op op
)
546 int index
= REGMODRM_REG( regmodrm
, rex
);
547 BYTE
*reg
= (BYTE
*)get_int_reg( context
, index
);
548 if (!rex
&& index
>= 4 && index
< 8) reg
-= (4 * sizeof(DWORD64
) - 1); /* special case: ah, ch, dh, bh */
564 /***********************************************************************
565 * INSTR_GetOperandAddr
567 * Return the address of an instruction operand (from the mod/rm byte).
569 static BYTE
*INSTR_GetOperandAddr( CONTEXT
*context
, BYTE
*instr
, int addl_instr_len
,
570 int long_addr
, int rex
, int segprefix
, int *len
)
572 int mod
, rm
, ss
= 0, off
, have_sib
= 0;
573 DWORD64 base
= 0, index
= 0;
575 #define GET_VAL( val, type ) \
576 { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
579 GET_VAL( &mod
, BYTE
);
580 rm
= REGMODRM_RM( mod
, rex
);
581 mod
= REGMODRM_MOD( mod
, rex
);
584 return (BYTE
*)get_int_reg( context
, rm
);
591 GET_VAL( &sib
, BYTE
);
592 rm
= SIB_BASE( sib
, rex
);
593 id
= SIB_INDEX( sib
, rex
);
594 ss
= SIB_SS( sib
, rex
);
596 index
= (id
!= 4) ? *get_int_reg( context
, id
) : 0;
597 if (!long_addr
) index
&= 0xffffffff;
601 base
= *get_int_reg( context
, rm
);
602 if (!long_addr
) base
&= 0xffffffff;
607 if (rm
== 5) /* special case */
609 base
= have_sib
? 0 : context
->Rip
;
610 if (!long_addr
) base
&= 0xffffffff;
611 GET_VAL( &off
, DWORD
);
612 base
+= (signed long)off
;
613 base
+= (signed long)*len
+ (signed long)addl_instr_len
;
617 case 1: /* 8-bit disp */
618 GET_VAL( &off
, BYTE
);
619 base
+= (signed char)off
;
622 case 2: /* 32-bit disp */
623 GET_VAL( &off
, DWORD
);
624 base
+= (signed long)off
;
628 /* FIXME: we assume that all segments have a base of 0 */
629 return (BYTE
*)(base
+ (index
<< ss
));
634 static void fake_syscall_function(void)
640 /***********************************************************************
641 * emulate_instruction
643 * Emulate a privileged instruction.
644 * Returns exception continuation status.
646 static DWORD
emulate_instruction( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
648 static const char *reg_names
[16] = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
649 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
650 int prefix
, segprefix
, prefixlen
, len
, long_op
, long_addr
, rex
;
653 long_op
= long_addr
= 1;
654 instr
= (BYTE
*)context
->Rip
;
655 if (!instr
) return ExceptionContinueSearch
;
657 /* First handle any possible prefix */
659 segprefix
= -1; /* no seg prefix */
660 rex
= 0; /* no rex prefix */
668 segprefix
= context
->SegCs
;
671 segprefix
= context
->SegSs
;
674 segprefix
= context
->SegDs
;
677 segprefix
= context
->SegEs
;
680 segprefix
= context
->SegFs
;
683 segprefix
= context
->SegGs
;
686 long_op
= !long_op
; /* opcode size prefix */
689 long_addr
= !long_addr
; /* addr size prefix */
709 case 0xf0: /* lock */
711 case 0xf2: /* repne */
713 case 0xf3: /* repe */
716 prefix
= 0; /* no more prefixes */
726 /* Now look at the actual instruction */
730 case 0x0f: /* extended instruction */
733 case 0x20: /* mov crX, Rd */
735 int reg
= REGMODRM_REG( instr
[2], rex
);
736 int rm
= REGMODRM_RM( instr
[2], rex
);
737 DWORD64
*data
= get_int_reg( context
, rm
);
738 TRACE( "mov cr%u,%s at %Ix\n", reg
, reg_names
[rm
], context
->Rip
);
741 case 0: *data
= 0x10; break; /* FIXME: set more bits ? */
742 case 2: *data
= 0; break;
743 case 3: *data
= 0; break;
744 case 4: *data
= 0; break;
745 case 8: *data
= 0; break;
746 default: return ExceptionContinueSearch
;
748 context
->Rip
+= prefixlen
+ 3;
749 return ExceptionContinueExecution
;
751 case 0x21: /* mov drX, Rd */
753 int reg
= REGMODRM_REG( instr
[2], rex
);
754 int rm
= REGMODRM_RM( instr
[2], rex
);
755 DWORD64
*data
= get_int_reg( context
, rm
);
756 TRACE( "mov dr%u,%s at %Ix\n", reg
, reg_names
[rm
], context
->Rip
);
759 case 0: *data
= context
->Dr0
; break;
760 case 1: *data
= context
->Dr1
; break;
761 case 2: *data
= context
->Dr2
; break;
762 case 3: *data
= context
->Dr3
; break;
763 case 4: /* dr4 and dr5 are obsolete aliases for dr6 and dr7 */
764 case 6: *data
= context
->Dr6
; break;
766 case 7: *data
= 0x400; break;
767 default: return ExceptionContinueSearch
;
769 context
->Rip
+= prefixlen
+ 3;
770 return ExceptionContinueExecution
;
772 case 0x22: /* mov Rd, crX */
774 int reg
= REGMODRM_REG( instr
[2], rex
);
775 int rm
= REGMODRM_RM( instr
[2], rex
);
776 DWORD64
*data
= get_int_reg( context
, rm
);
777 TRACE( "mov %s,cr%u at %Ix, %s=%Ix\n", reg_names
[rm
], reg
, context
->Rip
, reg_names
[rm
], *data
);
785 default: return ExceptionContinueSearch
;
787 context
->Rip
+= prefixlen
+ 3;
788 return ExceptionContinueExecution
;
790 case 0x23: /* mov Rd, drX */
792 int reg
= REGMODRM_REG( instr
[2], rex
);
793 int rm
= REGMODRM_RM( instr
[2], rex
);
794 DWORD64
*data
= get_int_reg( context
, rm
);
795 TRACE( "mov %s,dr%u at %Ix, %s=%Ix\n", reg_names
[rm
], reg
, context
->Rip
, reg_names
[rm
], *data
);
798 case 0: context
->Dr0
= *data
; break;
799 case 1: context
->Dr1
= *data
; break;
800 case 2: context
->Dr2
= *data
; break;
801 case 3: context
->Dr3
= *data
; break;
802 case 4: /* dr4 and dr5 are obsolete aliases for dr6 and dr7 */
803 case 6: context
->Dr6
= *data
; break;
805 case 7: context
->Dr7
= *data
; break;
806 default: return ExceptionContinueSearch
;
808 context
->Rip
+= prefixlen
+ 3;
809 return ExceptionContinueExecution
;
811 case 0x32: /* rdmsr */
813 ULONG reg
= context
->Rcx
;
814 TRACE("rdmsr CR 0x%08lx\n", reg
);
819 ULONG_PTR syscall_address
= (ULONG_PTR
)fake_syscall_function
;
820 context
->Rdx
= (ULONG
)(syscall_address
>> 32);
821 context
->Rax
= (ULONG
)syscall_address
;
825 FIXME("reg %#lx, returning 0.\n", reg
);
830 context
->Rip
+= prefixlen
+ 2;
831 return ExceptionContinueExecution
;
833 case 0xb6: /* movzx Eb, Gv */
834 case 0xb7: /* movzx Ew, Gv */
836 BYTE
*data
= INSTR_GetOperandAddr( context
, instr
+ 2, prefixlen
+ 2, long_addr
,
837 rex
, segprefix
, &len
);
838 unsigned int data_size
= (instr
[1] == 0xb7) ? 2 : 1;
839 SIZE_T offset
= data
- user_shared_data
;
841 if (offset
<= KSHARED_USER_DATA_PAGE_SIZE
- data_size
)
845 TRACE("USD offset %#x at %p.\n", (unsigned int)offset
, (void *)context
->Rip
);
846 memcpy( &temp
, wine_user_shared_data
+ offset
, data_size
);
847 store_reg_word( context
, instr
[2], (BYTE
*)&temp
, long_op
, rex
, INSTR_OP_MOV
);
848 context
->Rip
+= prefixlen
+ len
+ 2;
849 return ExceptionContinueExecution
;
851 break; /* Unable to emulate it */
854 break; /* Unable to emulate it */
856 case 0x8a: /* mov Eb, Gb */
857 case 0x8b: /* mov Ev, Gv */
858 case 0x0b: /* or Ev, Gv */
859 case 0x33: /* xor Ev, Gv */
861 BYTE
*data
= INSTR_GetOperandAddr( context
, instr
+ 1, prefixlen
+ 1, long_addr
,
862 rex
, segprefix
, &len
);
863 unsigned int data_size
= (*instr
== 0x8b) ? get_op_size( long_op
, rex
) : 1;
864 SIZE_T offset
= data
- user_shared_data
;
866 if (offset
<= KSHARED_USER_DATA_PAGE_SIZE
- data_size
)
868 TRACE("USD offset %#x at %p.\n", (unsigned int)offset
, (void *)context
->Rip
);
872 store_reg_byte( context
, instr
[1], wine_user_shared_data
+ offset
,
876 store_reg_word( context
, instr
[1], wine_user_shared_data
+ offset
,
877 long_op
, rex
, INSTR_OP_MOV
);
880 store_reg_word( context
, instr
[1], wine_user_shared_data
+ offset
,
881 long_op
, rex
, INSTR_OP_OR
);
884 store_reg_word( context
, instr
[1], wine_user_shared_data
+ offset
,
885 long_op
, rex
, INSTR_OP_XOR
);
888 context
->Rip
+= prefixlen
+ len
+ 1;
889 return ExceptionContinueExecution
;
891 break; /* Unable to emulate it */
894 case 0xa0: /* mov Ob, AL */
895 case 0xa1: /* mov Ovqp, rAX */
897 BYTE
*data
= (BYTE
*)(long_addr
? *(DWORD64
*)(instr
+ 1) : *(DWORD
*)(instr
+ 1));
898 unsigned int data_size
= (*instr
== 0xa1) ? get_op_size( long_op
, rex
) : 1;
899 SIZE_T offset
= data
- user_shared_data
;
900 len
= long_addr
? sizeof(DWORD64
) : sizeof(DWORD
);
902 if (offset
<= KSHARED_USER_DATA_PAGE_SIZE
- data_size
)
904 TRACE("USD offset %#x at %p.\n", (unsigned int)offset
, (void *)context
->Rip
);
905 memcpy( &context
->Rax
, wine_user_shared_data
+ offset
, data_size
);
906 context
->Rip
+= prefixlen
+ len
+ 1;
907 return ExceptionContinueExecution
;
909 break; /* Unable to emulate it */
914 context
->Rip
+= prefixlen
+ 1;
915 return ExceptionContinueExecution
;
917 return ExceptionContinueSearch
; /* Unable to emulate it */
921 /***********************************************************************
924 * Vectored exception handler used to emulate protected instructions
927 LONG CALLBACK
vectored_handler( EXCEPTION_POINTERS
*ptrs
)
929 EXCEPTION_RECORD
*record
= ptrs
->ExceptionRecord
;
930 CONTEXT
*context
= ptrs
->ContextRecord
;
932 if (record
->ExceptionCode
== EXCEPTION_PRIV_INSTRUCTION
||
933 (record
->ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
&&
934 record
->ExceptionInformation
[0] == EXCEPTION_READ_FAULT
))
936 if (emulate_instruction( record
, context
) == ExceptionContinueExecution
)
938 TRACE( "next instruction rip=%Ix\n", context
->Rip
);
939 TRACE( " rax=%016Ix rbx=%016Ix rcx=%016Ix rdx=%016Ix\n",
940 context
->Rax
, context
->Rbx
, context
->Rcx
, context
->Rdx
);
941 TRACE( " rsi=%016Ix rdi=%016Ix rbp=%016Ix rsp=%016Ix\n",
942 context
->Rsi
, context
->Rdi
, context
->Rbp
, context
->Rsp
);
943 TRACE( " r8=%016Ix r9=%016Ix r10=%016Ix r11=%016Ix\n",
944 context
->R8
, context
->R9
, context
->R10
, context
->R11
);
945 TRACE( " r12=%016Ix r13=%016Ix r14=%016Ix r15=%016Ix\n",
946 context
->R12
, context
->R13
, context
->R14
, context
->R15
);
948 return EXCEPTION_CONTINUE_EXECUTION
;
951 return EXCEPTION_CONTINUE_SEARCH
;
954 #endif /* __x86_64__ */