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"
34 #include "wine/exception.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(int);
48 static LDT_ENTRY idt
[256];
50 static inline struct idtr
get_idtr(void)
54 __asm__( "sidtl %0" : "=m" (ret
) );
56 ret
.base
= (BYTE
*)idt
;
57 ret
.limit
= sizeof(idt
) - 1;
62 /* store an operand into a register */
63 static void store_reg_word( CONTEXT
*context
, BYTE regmodrm
, const BYTE
*addr
, int long_op
)
65 switch((regmodrm
>> 3) & 7)
68 if (long_op
) context
->Eax
= *(const DWORD
*)addr
;
69 else context
->Eax
= (context
->Eax
& 0xffff0000) | *(const WORD
*)addr
;
72 if (long_op
) context
->Ecx
= *(const DWORD
*)addr
;
73 else context
->Ecx
= (context
->Ecx
& 0xffff0000) | *(const WORD
*)addr
;
76 if (long_op
) context
->Edx
= *(const DWORD
*)addr
;
77 else context
->Edx
= (context
->Edx
& 0xffff0000) | *(const WORD
*)addr
;
80 if (long_op
) context
->Ebx
= *(const DWORD
*)addr
;
81 else context
->Ebx
= (context
->Ebx
& 0xffff0000) | *(const WORD
*)addr
;
84 if (long_op
) context
->Esp
= *(const DWORD
*)addr
;
85 else context
->Esp
= (context
->Esp
& 0xffff0000) | *(const WORD
*)addr
;
88 if (long_op
) context
->Ebp
= *(const DWORD
*)addr
;
89 else context
->Ebp
= (context
->Ebp
& 0xffff0000) | *(const WORD
*)addr
;
92 if (long_op
) context
->Esi
= *(const DWORD
*)addr
;
93 else context
->Esi
= (context
->Esi
& 0xffff0000) | *(const WORD
*)addr
;
96 if (long_op
) context
->Edi
= *(const DWORD
*)addr
;
97 else context
->Edi
= (context
->Edi
& 0xffff0000) | *(const WORD
*)addr
;
102 /* store an operand into a byte register */
103 static void store_reg_byte( CONTEXT
*context
, BYTE regmodrm
, const BYTE
*addr
)
105 switch((regmodrm
>> 3) & 7)
107 case 0: context
->Eax
= (context
->Eax
& 0xffffff00) | *addr
; break;
108 case 1: context
->Ecx
= (context
->Ecx
& 0xffffff00) | *addr
; break;
109 case 2: context
->Edx
= (context
->Edx
& 0xffffff00) | *addr
; break;
110 case 3: context
->Ebx
= (context
->Ebx
& 0xffffff00) | *addr
; break;
111 case 4: context
->Eax
= (context
->Eax
& 0xffff00ff) | (*addr
<< 8); break;
112 case 5: context
->Ecx
= (context
->Ecx
& 0xffff00ff) | (*addr
<< 8); break;
113 case 6: context
->Edx
= (context
->Edx
& 0xffff00ff) | (*addr
<< 8); break;
114 case 7: context
->Ebx
= (context
->Ebx
& 0xffff00ff) | (*addr
<< 8); break;
118 static DWORD
*get_reg_address( CONTEXT
*context
, BYTE rm
)
122 case 0: return &context
->Eax
;
123 case 1: return &context
->Ecx
;
124 case 2: return &context
->Edx
;
125 case 3: return &context
->Ebx
;
126 case 4: return &context
->Esp
;
127 case 5: return &context
->Ebp
;
128 case 6: return &context
->Esi
;
129 case 7: return &context
->Edi
;
135 /***********************************************************************
136 * INSTR_GetOperandAddr
138 * Return the address of an instruction operand (from the mod/rm byte).
140 static void *INSTR_GetOperandAddr( CONTEXT
*context
, BYTE
*instr
,
141 int long_addr
, int segprefix
, int *len
)
143 int mod
, rm
, base
= 0, index
= 0, ss
= 0, off
;
145 #define GET_VAL(val,type) \
146 { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
149 GET_VAL( &mod
, BYTE
);
153 if (mod
== 3) return get_reg_address( context
, rm
);
160 GET_VAL( &sib
, BYTE
);
163 switch((sib
>> 3) & 7)
165 case 0: index
= context
->Eax
; break;
166 case 1: index
= context
->Ecx
; break;
167 case 2: index
= context
->Edx
; break;
168 case 3: index
= context
->Ebx
; break;
169 case 4: index
= 0; break;
170 case 5: index
= context
->Ebp
; break;
171 case 6: index
= context
->Esi
; break;
172 case 7: index
= context
->Edi
; break;
178 case 0: base
= context
->Eax
; break;
179 case 1: base
= context
->Ecx
; break;
180 case 2: base
= context
->Edx
; break;
181 case 3: base
= context
->Ebx
; break;
182 case 4: base
= context
->Esp
; break;
183 case 5: base
= context
->Ebp
; break;
184 case 6: base
= context
->Esi
; break;
185 case 7: base
= context
->Edi
; break;
190 if (rm
== 5) /* special case: ds:(disp32) */
192 GET_VAL( &base
, DWORD
);
196 case 1: /* 8-bit disp */
197 GET_VAL( &off
, BYTE
);
198 base
+= (signed char)off
;
201 case 2: /* 32-bit disp */
202 GET_VAL( &off
, DWORD
);
203 base
+= (signed long)off
;
207 else /* short address */
211 case 0: /* ds:(bx,si) */
212 base
= LOWORD(context
->Ebx
) + LOWORD(context
->Esi
);
214 case 1: /* ds:(bx,di) */
215 base
= LOWORD(context
->Ebx
) + LOWORD(context
->Edi
);
217 case 2: /* ss:(bp,si) */
218 base
= LOWORD(context
->Ebp
) + LOWORD(context
->Esi
);
220 case 3: /* ss:(bp,di) */
221 base
= LOWORD(context
->Ebp
) + LOWORD(context
->Edi
);
223 case 4: /* ds:(si) */
224 base
= LOWORD(context
->Esi
);
226 case 5: /* ds:(di) */
227 base
= LOWORD(context
->Edi
);
229 case 6: /* ss:(bp) */
230 base
= LOWORD(context
->Ebp
);
232 case 7: /* ds:(bx) */
233 base
= LOWORD(context
->Ebx
);
240 if (rm
== 6) /* special case: ds:(disp16) */
242 GET_VAL( &base
, WORD
);
246 case 1: /* 8-bit disp */
247 GET_VAL( &off
, BYTE
);
248 base
+= (signed char)off
;
251 case 2: /* 16-bit disp */
252 GET_VAL( &off
, WORD
);
253 base
+= (signed short)off
;
258 /* FIXME: we assume that all segments have a base of 0 */
259 return (void *)(base
+ (index
<< ss
));
264 /***********************************************************************
265 * emulate_instruction
267 * Emulate a privileged instruction.
268 * Returns exception continuation status.
270 static DWORD
emulate_instruction( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
272 static const char *reg_names
[8] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
273 int prefix
, segprefix
, prefixlen
, len
, long_op
, long_addr
;
276 long_op
= long_addr
= 1;
277 instr
= (BYTE
*)context
->Eip
;
278 if (!instr
) return ExceptionContinueSearch
;
280 /* First handle any possible prefix */
282 segprefix
= -1; /* no prefix */
290 segprefix
= context
->SegCs
;
293 segprefix
= context
->SegSs
;
296 segprefix
= context
->SegDs
;
299 segprefix
= context
->SegEs
;
302 segprefix
= context
->SegFs
;
305 segprefix
= context
->SegGs
;
308 long_op
= !long_op
; /* opcode size prefix */
311 long_addr
= !long_addr
; /* addr size prefix */
313 case 0xf0: /* lock */
315 case 0xf2: /* repne */
317 case 0xf3: /* repe */
320 prefix
= 0; /* no more prefixes */
330 /* Now look at the actual instruction */
334 case 0x0f: /* extended instruction */
337 case 0x20: /* mov crX, Rd */
339 int reg
= (instr
[2] >> 3) & 7;
340 DWORD
*data
= get_reg_address( context
, instr
[2] );
341 TRACE( "mov cr%u,%s at 0x%08x\n", reg
, reg_names
[instr
[2] & 7], context
->Eip
);
344 case 0: *data
= 0x10; break; /* FIXME: set more bits ? */
345 case 2: *data
= 0; break;
346 case 3: *data
= 0; break;
347 case 4: *data
= 0; break;
348 default: return ExceptionContinueSearch
;
350 context
->Eip
+= prefixlen
+ 3;
351 return ExceptionContinueExecution
;
353 case 0x21: /* mov drX, Rd */
355 int reg
= (instr
[2] >> 3) & 7;
356 DWORD
*data
= get_reg_address( context
, instr
[2] );
357 TRACE( "mov dr%u,%s at 0x%08x\n", reg
, reg_names
[instr
[2] & 7], context
->Eip
);
360 case 0: *data
= context
->Dr0
; break;
361 case 1: *data
= context
->Dr1
; break;
362 case 2: *data
= context
->Dr2
; break;
363 case 3: *data
= context
->Dr3
; break;
364 case 6: *data
= context
->Dr6
; break;
365 case 7: *data
= 0x400; break;
366 default: return ExceptionContinueSearch
;
368 context
->Eip
+= prefixlen
+ 3;
369 return ExceptionContinueExecution
;
371 case 0x22: /* mov Rd, crX */
373 int reg
= (instr
[2] >> 3) & 7;
374 DWORD
*data
= get_reg_address( context
, instr
[2] );
375 TRACE( "mov %s,cr%u at 0x%08x, %s=%08x\n", reg_names
[instr
[2] & 7],
376 reg
, context
->Eip
, reg_names
[instr
[2] & 7], *data
);
383 default: return ExceptionContinueSearch
;
385 context
->Eip
+= prefixlen
+ 3;
386 return ExceptionContinueExecution
;
388 case 0x23: /* mov Rd, drX */
390 int reg
= (instr
[2] >> 3) & 7;
391 DWORD
*data
= get_reg_address( context
, instr
[2] );
392 TRACE( "mov %s,dr%u at 0x%08x %s=%08x\n", reg_names
[instr
[2] & 7],
393 reg
, context
->Eip
, reg_names
[instr
[2] & 7], *data
);
396 case 0: context
->Dr0
= *data
; break;
397 case 1: context
->Dr1
= *data
; break;
398 case 2: context
->Dr2
= *data
; break;
399 case 3: context
->Dr3
= *data
; break;
400 case 6: context
->Dr6
= *data
; break;
401 case 7: context
->Dr7
= *data
; break;
402 default: return ExceptionContinueSearch
;
404 context
->Eip
+= prefixlen
+ 3;
405 return ExceptionContinueExecution
;
410 case 0x8a: /* mov Eb, Gb */
411 case 0x8b: /* mov Ev, Gv */
413 BYTE
*data
= INSTR_GetOperandAddr(context
, instr
+ 1, long_addr
,
415 unsigned int data_size
= (*instr
== 0x8b) ? (long_op
? 4 : 2) : 1;
416 struct idtr idtr
= get_idtr();
417 unsigned int offset
= data
- idtr
.base
;
419 if (offset
<= idtr
.limit
+ 1 - data_size
)
421 idt
[1].LimitLow
= 0x100; /* FIXME */
422 idt
[2].LimitLow
= 0x11E; /* FIXME */
423 idt
[3].LimitLow
= 0x500; /* FIXME */
427 case 0x8a: store_reg_byte( context
, instr
[1], (BYTE
*)idt
+ offset
); break;
428 case 0x8b: store_reg_word( context
, instr
[1], (BYTE
*)idt
+ offset
, long_op
); break;
430 context
->Eip
+= prefixlen
+ len
+ 1;
431 return ExceptionContinueExecution
;
433 break; /* Unable to emulate it */
438 context
->Eip
+= prefixlen
+ 1;
439 return ExceptionContinueExecution
;
441 return ExceptionContinueSearch
; /* Unable to emulate it */
445 /***********************************************************************
448 * Vectored exception handler used to emulate protected instructions
451 LONG CALLBACK
vectored_handler( EXCEPTION_POINTERS
*ptrs
)
453 EXCEPTION_RECORD
*record
= ptrs
->ExceptionRecord
;
454 CONTEXT
*context
= ptrs
->ContextRecord
;
456 if ((record
->ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
||
457 record
->ExceptionCode
== EXCEPTION_PRIV_INSTRUCTION
))
459 if (emulate_instruction( record
, context
) == ExceptionContinueExecution
)
460 return EXCEPTION_CONTINUE_EXECUTION
;
462 return EXCEPTION_CONTINUE_SEARCH
;
465 #elif defined(__x86_64__) /* __i386__ */
467 WINE_DEFAULT_DEBUG_CHANNEL(int);
474 #define MSR_LSTAR 0xc0000082
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
)
496 return sizeof(DWORD64
);
498 return sizeof(DWORD
);
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 */
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
, int addl_instr_len
,
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); }
535 GET_VAL( &mod
, BYTE
);
536 rm
= REGMODRM_RM( mod
, rex
);
537 mod
= REGMODRM_MOD( mod
, rex
);
540 return (BYTE
*)get_int_reg( context
, rm
);
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;
557 base
= *get_int_reg( context
, rm
);
558 if (!long_addr
) base
&= 0xffffffff;
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
;
569 base
+= (signed long)*len
+ (signed long)addl_instr_len
;
573 case 1: /* 8-bit disp */
574 GET_VAL( &off
, BYTE
);
575 base
+= (signed char)off
;
578 case 2: /* 32-bit disp */
579 GET_VAL( &off
, DWORD
);
580 base
+= (signed long)off
;
584 /* FIXME: we assume that all segments have a base of 0 */
585 return (BYTE
*)(base
+ (index
<< ss
));
590 static void fake_syscall_function(void)
596 static void update_shared_data(void)
598 struct _KUSER_SHARED_DATA
*shared_data
= (struct _KUSER_SHARED_DATA
*)wine_user_shared_data
;
600 shared_data
->u
.TickCountQuad
= GetTickCount64();
601 shared_data
->u
.TickCount
.High2Time
= shared_data
->u
.TickCount
.High1Time
;
605 /***********************************************************************
606 * emulate_instruction
608 * Emulate a privileged instruction.
609 * Returns exception continuation status.
611 static DWORD
emulate_instruction( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
613 static const char *reg_names
[16] = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
614 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
615 int prefix
, segprefix
, prefixlen
, len
, long_op
, long_addr
, rex
;
618 long_op
= long_addr
= 1;
619 instr
= (BYTE
*)context
->Rip
;
620 if (!instr
) return ExceptionContinueSearch
;
622 /* First handle any possible prefix */
624 segprefix
= -1; /* no seg prefix */
625 rex
= 0; /* no rex prefix */
633 segprefix
= context
->SegCs
;
636 segprefix
= context
->SegSs
;
639 segprefix
= context
->SegDs
;
642 segprefix
= context
->SegEs
;
645 segprefix
= context
->SegFs
;
648 segprefix
= context
->SegGs
;
651 long_op
= !long_op
; /* opcode size prefix */
654 long_addr
= !long_addr
; /* addr size prefix */
674 case 0xf0: /* lock */
676 case 0xf2: /* repne */
678 case 0xf3: /* repe */
681 prefix
= 0; /* no more prefixes */
691 /* Now look at the actual instruction */
695 case 0x0f: /* extended instruction */
698 case 0x20: /* mov crX, Rd */
700 int reg
= REGMODRM_REG( instr
[2], rex
);
701 int rm
= REGMODRM_RM( instr
[2], rex
);
702 DWORD64
*data
= get_int_reg( context
, rm
);
703 TRACE( "mov cr%u,%s at %lx\n", reg
, reg_names
[rm
], context
->Rip
);
706 case 0: *data
= 0x10; break; /* FIXME: set more bits ? */
707 case 2: *data
= 0; break;
708 case 3: *data
= 0; break;
709 case 4: *data
= 0; break;
710 case 8: *data
= 0; break;
711 default: return ExceptionContinueSearch
;
713 context
->Rip
+= prefixlen
+ 3;
714 return ExceptionContinueExecution
;
716 case 0x21: /* mov drX, Rd */
718 int reg
= REGMODRM_REG( instr
[2], rex
);
719 int rm
= REGMODRM_RM( instr
[2], rex
);
720 DWORD64
*data
= get_int_reg( context
, rm
);
721 TRACE( "mov dr%u,%s at %lx\n", reg
, reg_names
[rm
], context
->Rip
);
724 case 0: *data
= context
->Dr0
; break;
725 case 1: *data
= context
->Dr1
; break;
726 case 2: *data
= context
->Dr2
; break;
727 case 3: *data
= context
->Dr3
; break;
728 case 4: /* dr4 and dr5 are obsolete aliases for dr6 and dr7 */
729 case 6: *data
= context
->Dr6
; break;
731 case 7: *data
= 0x400; break;
732 default: return ExceptionContinueSearch
;
734 context
->Rip
+= prefixlen
+ 3;
735 return ExceptionContinueExecution
;
737 case 0x22: /* mov Rd, crX */
739 int reg
= REGMODRM_REG( instr
[2], rex
);
740 int rm
= REGMODRM_RM( instr
[2], rex
);
741 DWORD64
*data
= get_int_reg( context
, rm
);
742 TRACE( "mov %s,cr%u at %lx, %s=%lx\n", reg_names
[rm
], reg
, context
->Rip
, reg_names
[rm
], *data
);
750 default: return ExceptionContinueSearch
;
752 context
->Rip
+= prefixlen
+ 3;
753 return ExceptionContinueExecution
;
755 case 0x23: /* mov Rd, drX */
757 int reg
= REGMODRM_REG( instr
[2], rex
);
758 int rm
= REGMODRM_RM( instr
[2], rex
);
759 DWORD64
*data
= get_int_reg( context
, rm
);
760 TRACE( "mov %s,dr%u at %lx, %s=%lx\n", reg_names
[rm
], reg
, context
->Rip
, reg_names
[rm
], *data
);
763 case 0: context
->Dr0
= *data
; break;
764 case 1: context
->Dr1
= *data
; break;
765 case 2: context
->Dr2
= *data
; break;
766 case 3: context
->Dr3
= *data
; break;
767 case 4: /* dr4 and dr5 are obsolete aliases for dr6 and dr7 */
768 case 6: context
->Dr6
= *data
; break;
770 case 7: context
->Dr7
= *data
; break;
771 default: return ExceptionContinueSearch
;
773 context
->Rip
+= prefixlen
+ 3;
774 return ExceptionContinueExecution
;
776 case 0x32: /* rdmsr */
778 ULONG reg
= context
->Rcx
;
779 TRACE("rdmsr CR 0x%08x\n", reg
);
784 ULONG_PTR syscall_address
= (ULONG_PTR
)fake_syscall_function
;
785 context
->Rdx
= (ULONG
)(syscall_address
>> 32);
786 context
->Rax
= (ULONG
)syscall_address
;
789 default: return ExceptionContinueSearch
;
791 context
->Rip
+= prefixlen
+ 2;
792 return ExceptionContinueExecution
;
794 case 0xb6: /* movzx Eb, Gv */
795 case 0xb7: /* movzx Ew, Gv */
797 BYTE
*data
= INSTR_GetOperandAddr( context
, instr
+ 2, prefixlen
+ 2, long_addr
,
798 rex
, segprefix
, &len
);
799 unsigned int data_size
= (instr
[1] == 0xb7) ? 2 : 1;
800 SIZE_T offset
= data
- user_shared_data
;
802 if (offset
<= sizeof(KSHARED_USER_DATA
) - data_size
)
805 update_shared_data();
806 memcpy( &temp
, wine_user_shared_data
+ offset
, data_size
);
807 store_reg_word( context
, instr
[2], (BYTE
*)&temp
, long_op
, rex
);
808 context
->Rip
+= prefixlen
+ len
+ 2;
809 return ExceptionContinueExecution
;
811 break; /* Unable to emulate it */
814 break; /* Unable to emulate it */
816 case 0x8a: /* mov Eb, Gb */
817 case 0x8b: /* mov Ev, Gv */
819 BYTE
*data
= INSTR_GetOperandAddr( context
, instr
+ 1, prefixlen
+ 1, long_addr
,
820 rex
, segprefix
, &len
);
821 unsigned int data_size
= (*instr
== 0x8b) ? get_op_size( long_op
, rex
) : 1;
822 SIZE_T offset
= data
- user_shared_data
;
824 if (offset
<= sizeof(KSHARED_USER_DATA
) - data_size
)
826 update_shared_data();
829 case 0x8a: store_reg_byte( context
, instr
[1], wine_user_shared_data
+ offset
, rex
); break;
830 case 0x8b: store_reg_word( context
, instr
[1], wine_user_shared_data
+ offset
, long_op
, rex
); break;
832 context
->Rip
+= prefixlen
+ len
+ 1;
833 return ExceptionContinueExecution
;
835 break; /* Unable to emulate it */
838 case 0xa0: /* mov Ob, AL */
839 case 0xa1: /* mov Ovqp, rAX */
841 BYTE
*data
= (BYTE
*)(long_addr
? *(DWORD64
*)(instr
+ 1) : *(DWORD
*)(instr
+ 1));
842 unsigned int data_size
= (*instr
== 0xa1) ? get_op_size( long_op
, rex
) : 1;
843 SIZE_T offset
= data
- user_shared_data
;
844 len
= long_addr
? sizeof(DWORD64
) : sizeof(DWORD
);
846 if (offset
<= sizeof(KSHARED_USER_DATA
) - data_size
)
848 update_shared_data();
849 memcpy( &context
->Rax
, wine_user_shared_data
+ offset
, data_size
);
850 context
->Rip
+= prefixlen
+ len
+ 1;
851 return ExceptionContinueExecution
;
853 break; /* Unable to emulate it */
858 context
->Rip
+= prefixlen
+ 1;
859 return ExceptionContinueExecution
;
861 return ExceptionContinueSearch
; /* Unable to emulate it */
865 /***********************************************************************
868 * Vectored exception handler used to emulate protected instructions
871 LONG CALLBACK
vectored_handler( EXCEPTION_POINTERS
*ptrs
)
873 EXCEPTION_RECORD
*record
= ptrs
->ExceptionRecord
;
874 CONTEXT
*context
= ptrs
->ContextRecord
;
876 if (record
->ExceptionCode
== EXCEPTION_PRIV_INSTRUCTION
||
877 (record
->ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
&&
878 record
->ExceptionInformation
[0] == EXCEPTION_READ_FAULT
))
880 if (emulate_instruction( record
, context
) == ExceptionContinueExecution
)
882 TRACE( "next instruction rip=%lx\n", context
->Rip
);
883 TRACE( " rax=%016lx rbx=%016lx rcx=%016lx rdx=%016lx\n",
884 context
->Rax
, context
->Rbx
, context
->Rcx
, context
->Rdx
);
885 TRACE( " rsi=%016lx rdi=%016lx rbp=%016lx rsp=%016lx\n",
886 context
->Rsi
, context
->Rdi
, context
->Rbp
, context
->Rsp
);
887 TRACE( " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n",
888 context
->R8
, context
->R9
, context
->R10
, context
->R11
);
889 TRACE( " r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n",
890 context
->R12
, context
->R13
, context
->R14
, context
->R15
);
892 return EXCEPTION_CONTINUE_EXECUTION
;
895 return EXCEPTION_CONTINUE_SEARCH
;
898 #endif /* __x86_64__ */