mscoree: Update Wine Mono to 9.2.0.
[wine.git] / dlls / ntoskrnl.exe / instr.c
blobabdd9349dcd72b26f687c1386afc5eea7b5b6ad8
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 <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winternl.h"
29 #define WIN32_NO_STATUS
30 #include "ddk/wdm.h"
31 #include "excpt.h"
32 #include "wine/debug.h"
34 #define KSHARED_USER_DATA_PAGE_SIZE 0x1000
36 #define CR0_PE 0x00000001 /* Protected Mode */
37 #define CR0_ET 0x00000010 /* Extension Type */
38 #define CR0_NE 0x00000020 /* Numeric Error */
39 #define CR0_WP 0x00010000 /* Write Protect */
40 #define CR0_AM 0x00040000 /* Alignment Mask */
41 #define CR0_PG 0x80000000 /* Paging */
43 enum instr_op
45 INSTR_OP_MOV,
46 INSTR_OP_OR,
47 INSTR_OP_XOR,
50 #ifdef __i386__
52 WINE_DEFAULT_DEBUG_CHANNEL(int);
54 #include "pshpack1.h"
55 struct idtr
57 WORD limit;
58 BYTE *base;
60 #include "poppack.h"
62 static LDT_ENTRY idt[256];
64 static inline struct idtr get_idtr(void)
66 struct idtr ret;
67 #ifdef __GNUC__
68 __asm__( "sidtl %0" : "=m" (ret) );
69 #else
70 ret.base = (BYTE *)idt;
71 ret.limit = sizeof(idt) - 1;
72 #endif
73 return ret;
76 /* store an operand into a register */
77 static void store_reg_word( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int long_op )
79 switch((regmodrm >> 3) & 7)
81 case 0:
82 if (long_op) context->Eax = *(const DWORD *)addr;
83 else context->Eax = (context->Eax & 0xffff0000) | *(const WORD *)addr;
84 break;
85 case 1:
86 if (long_op) context->Ecx = *(const DWORD *)addr;
87 else context->Ecx = (context->Ecx & 0xffff0000) | *(const WORD *)addr;
88 break;
89 case 2:
90 if (long_op) context->Edx = *(const DWORD *)addr;
91 else context->Edx = (context->Edx & 0xffff0000) | *(const WORD *)addr;
92 break;
93 case 3:
94 if (long_op) context->Ebx = *(const DWORD *)addr;
95 else context->Ebx = (context->Ebx & 0xffff0000) | *(const WORD *)addr;
96 break;
97 case 4:
98 if (long_op) context->Esp = *(const DWORD *)addr;
99 else context->Esp = (context->Esp & 0xffff0000) | *(const WORD *)addr;
100 break;
101 case 5:
102 if (long_op) context->Ebp = *(const DWORD *)addr;
103 else context->Ebp = (context->Ebp & 0xffff0000) | *(const WORD *)addr;
104 break;
105 case 6:
106 if (long_op) context->Esi = *(const DWORD *)addr;
107 else context->Esi = (context->Esi & 0xffff0000) | *(const WORD *)addr;
108 break;
109 case 7:
110 if (long_op) context->Edi = *(const DWORD *)addr;
111 else context->Edi = (context->Edi & 0xffff0000) | *(const WORD *)addr;
112 break;
116 /* store an operand into a byte register */
117 static void store_reg_byte( CONTEXT *context, BYTE regmodrm, const BYTE *addr )
119 switch((regmodrm >> 3) & 7)
121 case 0: context->Eax = (context->Eax & 0xffffff00) | *addr; break;
122 case 1: context->Ecx = (context->Ecx & 0xffffff00) | *addr; break;
123 case 2: context->Edx = (context->Edx & 0xffffff00) | *addr; break;
124 case 3: context->Ebx = (context->Ebx & 0xffffff00) | *addr; break;
125 case 4: context->Eax = (context->Eax & 0xffff00ff) | (*addr << 8); break;
126 case 5: context->Ecx = (context->Ecx & 0xffff00ff) | (*addr << 8); break;
127 case 6: context->Edx = (context->Edx & 0xffff00ff) | (*addr << 8); break;
128 case 7: context->Ebx = (context->Ebx & 0xffff00ff) | (*addr << 8); break;
132 static DWORD *get_reg_address( CONTEXT *context, BYTE rm )
134 switch (rm & 7)
136 case 0: return &context->Eax;
137 case 1: return &context->Ecx;
138 case 2: return &context->Edx;
139 case 3: return &context->Ebx;
140 case 4: return &context->Esp;
141 case 5: return &context->Ebp;
142 case 6: return &context->Esi;
143 case 7: return &context->Edi;
145 return NULL;
149 /***********************************************************************
150 * INSTR_GetOperandAddr
152 * Return the address of an instruction operand (from the mod/rm byte).
154 static void *INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr,
155 int long_addr, int segprefix, int *len )
157 int mod, rm, base = 0, index = 0, ss = 0, off;
159 #define GET_VAL(val,type) \
160 { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
162 *len = 0;
163 GET_VAL( &mod, BYTE );
164 rm = mod & 7;
165 mod >>= 6;
167 if (mod == 3) return get_reg_address( context, rm );
169 if (long_addr)
171 if (rm == 4)
173 BYTE sib;
174 GET_VAL( &sib, BYTE );
175 rm = sib & 7;
176 ss = sib >> 6;
177 switch((sib >> 3) & 7)
179 case 0: index = context->Eax; break;
180 case 1: index = context->Ecx; break;
181 case 2: index = context->Edx; break;
182 case 3: index = context->Ebx; break;
183 case 4: index = 0; break;
184 case 5: index = context->Ebp; break;
185 case 6: index = context->Esi; break;
186 case 7: index = context->Edi; break;
190 switch(rm)
192 case 0: base = context->Eax; break;
193 case 1: base = context->Ecx; break;
194 case 2: base = context->Edx; break;
195 case 3: base = context->Ebx; break;
196 case 4: base = context->Esp; break;
197 case 5: base = context->Ebp; break;
198 case 6: base = context->Esi; break;
199 case 7: base = context->Edi; break;
201 switch (mod)
203 case 0:
204 if (rm == 5) /* special case: ds:(disp32) */
206 GET_VAL( &base, DWORD );
208 break;
210 case 1: /* 8-bit disp */
211 GET_VAL( &off, BYTE );
212 base += (signed char)off;
213 break;
215 case 2: /* 32-bit disp */
216 GET_VAL( &off, DWORD );
217 base += (signed long)off;
218 break;
221 else /* short address */
223 switch(rm)
225 case 0: /* ds:(bx,si) */
226 base = LOWORD(context->Ebx) + LOWORD(context->Esi);
227 break;
228 case 1: /* ds:(bx,di) */
229 base = LOWORD(context->Ebx) + LOWORD(context->Edi);
230 break;
231 case 2: /* ss:(bp,si) */
232 base = LOWORD(context->Ebp) + LOWORD(context->Esi);
233 break;
234 case 3: /* ss:(bp,di) */
235 base = LOWORD(context->Ebp) + LOWORD(context->Edi);
236 break;
237 case 4: /* ds:(si) */
238 base = LOWORD(context->Esi);
239 break;
240 case 5: /* ds:(di) */
241 base = LOWORD(context->Edi);
242 break;
243 case 6: /* ss:(bp) */
244 base = LOWORD(context->Ebp);
245 break;
246 case 7: /* ds:(bx) */
247 base = LOWORD(context->Ebx);
248 break;
251 switch(mod)
253 case 0:
254 if (rm == 6) /* special case: ds:(disp16) */
256 GET_VAL( &base, WORD );
258 break;
260 case 1: /* 8-bit disp */
261 GET_VAL( &off, BYTE );
262 base += (signed char)off;
263 break;
265 case 2: /* 16-bit disp */
266 GET_VAL( &off, WORD );
267 base += (signed short)off;
268 break;
270 base &= 0xffff;
272 /* FIXME: we assume that all segments have a base of 0 */
273 return (void *)(base + (index << ss));
274 #undef GET_VAL
278 /***********************************************************************
279 * emulate_instruction
281 * Emulate a privileged instruction.
282 * Returns exception continuation status.
284 static DWORD emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context )
286 static const char *reg_names[8] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
287 int prefix, segprefix, prefixlen, len, long_op, long_addr;
288 BYTE *instr;
290 long_op = long_addr = 1;
291 instr = (BYTE *)context->Eip;
292 if (!instr) return ExceptionContinueSearch;
294 /* First handle any possible prefix */
296 segprefix = -1; /* no prefix */
297 prefix = 1;
298 prefixlen = 0;
299 while(prefix)
301 switch(*instr)
303 case 0x2e:
304 segprefix = context->SegCs;
305 break;
306 case 0x36:
307 segprefix = context->SegSs;
308 break;
309 case 0x3e:
310 segprefix = context->SegDs;
311 break;
312 case 0x26:
313 segprefix = context->SegEs;
314 break;
315 case 0x64:
316 segprefix = context->SegFs;
317 break;
318 case 0x65:
319 segprefix = context->SegGs;
320 break;
321 case 0x66:
322 long_op = !long_op; /* opcode size prefix */
323 break;
324 case 0x67:
325 long_addr = !long_addr; /* addr size prefix */
326 break;
327 case 0xf0: /* lock */
328 break;
329 case 0xf2: /* repne */
330 break;
331 case 0xf3: /* repe */
332 break;
333 default:
334 prefix = 0; /* no more prefixes */
335 break;
337 if (prefix)
339 instr++;
340 prefixlen++;
344 /* Now look at the actual instruction */
346 switch(*instr)
348 case 0x0f: /* extended instruction */
349 switch(instr[1])
351 case 0x20: /* mov crX, Rd */
353 int reg = (instr[2] >> 3) & 7;
354 DWORD *data = get_reg_address( context, instr[2] );
355 TRACE( "mov cr%u,%s at 0x%08lx\n", reg, reg_names[instr[2] & 7], context->Eip );
356 switch (reg)
358 case 0: *data = CR0_PE|CR0_ET|CR0_NE|CR0_WP|CR0_AM|CR0_PG; break;
359 case 2: *data = 0; break;
360 case 3: *data = 0; break;
361 case 4: *data = 0; break;
362 default: return ExceptionContinueSearch;
364 context->Eip += prefixlen + 3;
365 return ExceptionContinueExecution;
367 case 0x21: /* mov drX, Rd */
369 int reg = (instr[2] >> 3) & 7;
370 DWORD *data = get_reg_address( context, instr[2] );
371 TRACE( "mov dr%u,%s at 0x%08lx\n", reg, reg_names[instr[2] & 7], context->Eip );
372 switch (reg)
374 case 0: *data = context->Dr0; break;
375 case 1: *data = context->Dr1; break;
376 case 2: *data = context->Dr2; break;
377 case 3: *data = context->Dr3; break;
378 case 6: *data = context->Dr6; break;
379 case 7: *data = 0x400; break;
380 default: return ExceptionContinueSearch;
382 context->Eip += prefixlen + 3;
383 return ExceptionContinueExecution;
385 case 0x22: /* mov Rd, crX */
387 int reg = (instr[2] >> 3) & 7;
388 DWORD *data = get_reg_address( context, instr[2] );
389 TRACE( "mov %s,cr%u at 0x%08lx, %s=%08lx\n", reg_names[instr[2] & 7],
390 reg, context->Eip, reg_names[instr[2] & 7], *data );
391 switch (reg)
393 case 0: break;
394 case 2: break;
395 case 3: break;
396 case 4: break;
397 default: return ExceptionContinueSearch;
399 context->Eip += prefixlen + 3;
400 return ExceptionContinueExecution;
402 case 0x23: /* mov Rd, drX */
404 int reg = (instr[2] >> 3) & 7;
405 DWORD *data = get_reg_address( context, instr[2] );
406 TRACE( "mov %s,dr%u at 0x%08lx %s=%08lx\n", reg_names[instr[2] & 7],
407 reg, context->Eip, reg_names[instr[2] & 7], *data );
408 switch (reg)
410 case 0: context->Dr0 = *data; break;
411 case 1: context->Dr1 = *data; break;
412 case 2: context->Dr2 = *data; break;
413 case 3: context->Dr3 = *data; break;
414 case 6: context->Dr6 = *data; break;
415 case 7: context->Dr7 = *data; break;
416 default: return ExceptionContinueSearch;
418 context->Eip += prefixlen + 3;
419 return ExceptionContinueExecution;
422 break;
424 case 0x8a: /* mov Eb, Gb */
425 case 0x8b: /* mov Ev, Gv */
427 BYTE *data = INSTR_GetOperandAddr(context, instr + 1, long_addr,
428 segprefix, &len);
429 unsigned int data_size = (*instr == 0x8b) ? (long_op ? 4 : 2) : 1;
430 struct idtr idtr = get_idtr();
431 unsigned int offset = data - idtr.base;
433 if (offset <= idtr.limit + 1 - data_size)
435 idt[1].LimitLow = 0x100; /* FIXME */
436 idt[2].LimitLow = 0x11E; /* FIXME */
437 idt[3].LimitLow = 0x500; /* FIXME */
439 switch (*instr)
441 case 0x8a: store_reg_byte( context, instr[1], (BYTE *)idt + offset ); break;
442 case 0x8b: store_reg_word( context, instr[1], (BYTE *)idt + offset, long_op ); break;
444 context->Eip += prefixlen + len + 1;
445 return ExceptionContinueExecution;
447 break; /* Unable to emulate it */
450 case 0xfa: /* cli */
451 case 0xfb: /* sti */
452 context->Eip += prefixlen + 1;
453 return ExceptionContinueExecution;
455 return ExceptionContinueSearch; /* Unable to emulate it */
459 /***********************************************************************
460 * vectored_handler
462 * Vectored exception handler used to emulate protected instructions
463 * from 32-bit code.
465 LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs )
467 EXCEPTION_RECORD *record = ptrs->ExceptionRecord;
468 CONTEXT *context = ptrs->ContextRecord;
470 if ((record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
471 record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION))
473 if (emulate_instruction( record, context ) == ExceptionContinueExecution)
474 return EXCEPTION_CONTINUE_EXECUTION;
476 return EXCEPTION_CONTINUE_SEARCH;
479 #elif defined(__x86_64__) /* __i386__ */
481 WINE_DEFAULT_DEBUG_CHANNEL(int);
483 #define REX_B 1
484 #define REX_X 2
485 #define REX_R 4
486 #define REX_W 8
488 #define MSR_LSTAR 0xc0000082
490 #define REGMODRM_MOD( regmodrm, rex ) ((regmodrm) >> 6)
491 #define REGMODRM_REG( regmodrm, rex ) (((regmodrm) >> 3) & 7) | (((rex) & REX_R) ? 8 : 0)
492 #define REGMODRM_RM( regmodrm, rex ) (((regmodrm) & 7) | (((rex) & REX_B) ? 8 : 0))
494 #define SIB_SS( sib, rex ) ((sib) >> 6)
495 #define SIB_INDEX( sib, rex ) (((sib) >> 3) & 7) | (((rex) & REX_X) ? 8 : 0)
496 #define SIB_BASE( sib, rex ) (((sib) & 7) | (((rex) & REX_B) ? 8 : 0))
498 /* keep in sync with dlls/ntdll/thread.c:thread_init */
499 static const BYTE *wine_user_shared_data = (BYTE *)0x7ffe0000;
500 static const BYTE *user_shared_data = (BYTE *)0xfffff78000000000;
502 static inline DWORD64 *get_int_reg( CONTEXT *context, int index )
504 return &context->Rax + index; /* index should be in range 0 .. 15 */
507 static inline int get_op_size( int long_op, int rex )
509 if (rex & REX_W)
510 return sizeof(DWORD64);
511 else if (long_op)
512 return sizeof(DWORD);
513 else
514 return sizeof(WORD);
517 /* store an operand into a register */
518 static void store_reg_word( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int long_op, int rex,
519 enum instr_op op )
521 int index = REGMODRM_REG( regmodrm, rex );
522 BYTE *reg = (BYTE *)get_int_reg( context, index );
523 int op_size = get_op_size( long_op, rex );
524 int i;
526 switch (op)
528 case INSTR_OP_MOV:
529 memcpy( reg, addr, op_size );
530 break;
531 case INSTR_OP_OR:
532 for (i = 0; i < op_size; ++i)
533 reg[i] |= addr[i];
534 break;
535 case INSTR_OP_XOR:
536 for (i = 0; i < op_size; ++i)
537 reg[i] ^= addr[i];
538 break;
542 /* store an operand into a byte register */
543 static void store_reg_byte( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int rex, enum instr_op op )
545 int index = REGMODRM_REG( regmodrm, rex );
546 BYTE *reg = (BYTE *)get_int_reg( context, index );
547 if (!rex && index >= 4 && index < 8) reg -= (4 * sizeof(DWORD64) - 1); /* special case: ah, ch, dh, bh */
549 switch (op)
551 case INSTR_OP_MOV:
552 *reg = *addr;
553 break;
554 case INSTR_OP_OR:
555 *reg |= *addr;
556 break;
557 case INSTR_OP_XOR:
558 *reg ^= *addr;
559 break;
563 /***********************************************************************
564 * INSTR_GetOperandAddr
566 * Return the address of an instruction operand (from the mod/rm byte).
568 static BYTE *INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr, int addl_instr_len,
569 int long_addr, int rex, int segprefix, int *len )
571 int mod, rm, ss = 0, off, have_sib = 0;
572 DWORD64 base = 0, index = 0;
574 #define GET_VAL( val, type ) \
575 { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
577 *len = 0;
578 GET_VAL( &mod, BYTE );
579 rm = REGMODRM_RM( mod, rex );
580 mod = REGMODRM_MOD( mod, rex );
582 if (mod == 3)
583 return (BYTE *)get_int_reg( context, rm );
585 if ((rm & 7) == 4)
587 BYTE sib;
588 int id;
590 GET_VAL( &sib, BYTE );
591 rm = SIB_BASE( sib, rex );
592 id = SIB_INDEX( sib, rex );
593 ss = SIB_SS( sib, rex );
595 index = (id != 4) ? *get_int_reg( context, id ) : 0;
596 if (!long_addr) index &= 0xffffffff;
597 have_sib = 1;
600 base = *get_int_reg( context, rm );
601 if (!long_addr) base &= 0xffffffff;
603 switch (mod)
605 case 0:
606 if (rm == 5) /* special case */
608 base = have_sib ? 0 : context->Rip;
609 if (!long_addr) base &= 0xffffffff;
610 GET_VAL( &off, DWORD );
611 base += (signed long)off;
612 base += (signed long)*len + (signed long)addl_instr_len;
614 break;
616 case 1: /* 8-bit disp */
617 GET_VAL( &off, BYTE );
618 base += (signed char)off;
619 break;
621 case 2: /* 32-bit disp */
622 GET_VAL( &off, DWORD );
623 base += (signed long)off;
624 break;
627 /* FIXME: we assume that all segments have a base of 0 */
628 return (BYTE *)(base + (index << ss));
629 #undef GET_VAL
633 static void fake_syscall_function(void)
635 TRACE("() stub\n");
639 /***********************************************************************
640 * emulate_instruction
642 * Emulate a privileged instruction.
643 * Returns exception continuation status.
645 static DWORD emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context )
647 static const char *reg_names[16] = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
648 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
649 int prefix, segprefix, prefixlen, len, long_op, long_addr, rex;
650 BYTE *instr;
652 long_op = long_addr = 1;
653 instr = (BYTE *)context->Rip;
654 if (!instr) return ExceptionContinueSearch;
656 /* First handle any possible prefix */
658 segprefix = -1; /* no seg prefix */
659 rex = 0; /* no rex prefix */
660 prefix = 1;
661 prefixlen = 0;
662 while(prefix)
664 switch(*instr)
666 case 0x2e:
667 segprefix = context->SegCs;
668 break;
669 case 0x36:
670 segprefix = context->SegSs;
671 break;
672 case 0x3e:
673 segprefix = context->SegDs;
674 break;
675 case 0x26:
676 segprefix = context->SegEs;
677 break;
678 case 0x64:
679 segprefix = context->SegFs;
680 break;
681 case 0x65:
682 segprefix = context->SegGs;
683 break;
684 case 0x66:
685 long_op = !long_op; /* opcode size prefix */
686 break;
687 case 0x67:
688 long_addr = !long_addr; /* addr size prefix */
689 break;
690 case 0x40: /* rex */
691 case 0x41:
692 case 0x42:
693 case 0x43:
694 case 0x44:
695 case 0x45:
696 case 0x46:
697 case 0x47:
698 case 0x48:
699 case 0x49:
700 case 0x4a:
701 case 0x4b:
702 case 0x4c:
703 case 0x4d:
704 case 0x4e:
705 case 0x4f:
706 rex = *instr;
707 break;
708 case 0xf0: /* lock */
709 break;
710 case 0xf2: /* repne */
711 break;
712 case 0xf3: /* repe */
713 break;
714 default:
715 prefix = 0; /* no more prefixes */
716 break;
718 if (prefix)
720 instr++;
721 prefixlen++;
725 /* Now look at the actual instruction */
727 switch(*instr)
729 case 0x0f: /* extended instruction */
730 switch(instr[1])
732 case 0x20: /* mov crX, Rd */
734 int reg = REGMODRM_REG( instr[2], rex );
735 int rm = REGMODRM_RM( instr[2], rex );
736 DWORD64 *data = get_int_reg( context, rm );
737 TRACE( "mov cr%u,%s at %Ix\n", reg, reg_names[rm], context->Rip );
738 switch (reg)
740 case 0: *data = 0x10; break; /* FIXME: set more bits ? */
741 case 2: *data = 0; break;
742 case 3: *data = 0; break;
743 case 4: *data = 0; break;
744 case 8: *data = 0; break;
745 default: return ExceptionContinueSearch;
747 context->Rip += prefixlen + 3;
748 return ExceptionContinueExecution;
750 case 0x21: /* mov drX, Rd */
752 int reg = REGMODRM_REG( instr[2], rex );
753 int rm = REGMODRM_RM( instr[2], rex );
754 DWORD64 *data = get_int_reg( context, rm );
755 TRACE( "mov dr%u,%s at %Ix\n", reg, reg_names[rm], context->Rip );
756 switch (reg)
758 case 0: *data = context->Dr0; break;
759 case 1: *data = context->Dr1; break;
760 case 2: *data = context->Dr2; break;
761 case 3: *data = context->Dr3; break;
762 case 4: /* dr4 and dr5 are obsolete aliases for dr6 and dr7 */
763 case 6: *data = context->Dr6; break;
764 case 5:
765 case 7: *data = 0x400; break;
766 default: return ExceptionContinueSearch;
768 context->Rip += prefixlen + 3;
769 return ExceptionContinueExecution;
771 case 0x22: /* mov Rd, crX */
773 int reg = REGMODRM_REG( instr[2], rex );
774 int rm = REGMODRM_RM( instr[2], rex );
775 DWORD64 *data = get_int_reg( context, rm );
776 TRACE( "mov %s,cr%u at %Ix, %s=%Ix\n", reg_names[rm], reg, context->Rip, reg_names[rm], *data );
777 switch (reg)
779 case 0: break;
780 case 2: break;
781 case 3: break;
782 case 4: break;
783 case 8: break;
784 default: return ExceptionContinueSearch;
786 context->Rip += prefixlen + 3;
787 return ExceptionContinueExecution;
789 case 0x23: /* mov Rd, drX */
791 int reg = REGMODRM_REG( instr[2], rex );
792 int rm = REGMODRM_RM( instr[2], rex );
793 DWORD64 *data = get_int_reg( context, rm );
794 TRACE( "mov %s,dr%u at %Ix, %s=%Ix\n", reg_names[rm], reg, context->Rip, reg_names[rm], *data );
795 switch (reg)
797 case 0: context->Dr0 = *data; break;
798 case 1: context->Dr1 = *data; break;
799 case 2: context->Dr2 = *data; break;
800 case 3: context->Dr3 = *data; break;
801 case 4: /* dr4 and dr5 are obsolete aliases for dr6 and dr7 */
802 case 6: context->Dr6 = *data; break;
803 case 5:
804 case 7: context->Dr7 = *data; break;
805 default: return ExceptionContinueSearch;
807 context->Rip += prefixlen + 3;
808 return ExceptionContinueExecution;
810 case 0x32: /* rdmsr */
812 ULONG reg = context->Rcx;
813 TRACE("rdmsr CR 0x%08lx\n", reg);
814 switch (reg)
816 case MSR_LSTAR:
818 ULONG_PTR syscall_address = (ULONG_PTR)fake_syscall_function;
819 context->Rdx = (ULONG)(syscall_address >> 32);
820 context->Rax = (ULONG)syscall_address;
821 break;
823 default:
824 FIXME("reg %#lx, returning 0.\n", reg);
825 context->Rdx = 0;
826 context->Rax = 0;
827 break;
829 context->Rip += prefixlen + 2;
830 return ExceptionContinueExecution;
832 case 0xb6: /* movzx Eb, Gv */
833 case 0xb7: /* movzx Ew, Gv */
835 BYTE *data = INSTR_GetOperandAddr( context, instr + 2, prefixlen + 2, long_addr,
836 rex, segprefix, &len );
837 unsigned int data_size = (instr[1] == 0xb7) ? 2 : 1;
838 SIZE_T offset = data - user_shared_data;
840 if (offset <= KSHARED_USER_DATA_PAGE_SIZE - data_size)
842 ULONGLONG temp = 0;
844 TRACE("USD offset %#x at %p.\n", (unsigned int)offset, (void *)context->Rip);
845 memcpy( &temp, wine_user_shared_data + offset, data_size );
846 store_reg_word( context, instr[2], (BYTE *)&temp, long_op, rex, INSTR_OP_MOV );
847 context->Rip += prefixlen + len + 2;
848 return ExceptionContinueExecution;
850 break; /* Unable to emulate it */
853 break; /* Unable to emulate it */
855 case 0x8a: /* mov Eb, Gb */
856 case 0x8b: /* mov Ev, Gv */
857 case 0x0b: /* or Ev, Gv */
858 case 0x33: /* xor Ev, Gv */
860 BYTE *data = INSTR_GetOperandAddr( context, instr + 1, prefixlen + 1, long_addr,
861 rex, segprefix, &len );
862 unsigned int data_size = (*instr == 0x8b) ? get_op_size( long_op, rex ) : 1;
863 SIZE_T offset = data - user_shared_data;
865 if (offset <= KSHARED_USER_DATA_PAGE_SIZE - data_size)
867 TRACE("USD offset %#x at %p.\n", (unsigned int)offset, (void *)context->Rip);
868 switch (*instr)
870 case 0x8a:
871 store_reg_byte( context, instr[1], wine_user_shared_data + offset,
872 rex, INSTR_OP_MOV );
873 break;
874 case 0x8b:
875 store_reg_word( context, instr[1], wine_user_shared_data + offset,
876 long_op, rex, INSTR_OP_MOV );
877 break;
878 case 0x0b:
879 store_reg_word( context, instr[1], wine_user_shared_data + offset,
880 long_op, rex, INSTR_OP_OR );
881 break;
882 case 0x33:
883 store_reg_word( context, instr[1], wine_user_shared_data + offset,
884 long_op, rex, INSTR_OP_XOR );
885 break;
887 context->Rip += prefixlen + len + 1;
888 return ExceptionContinueExecution;
890 break; /* Unable to emulate it */
893 case 0xa0: /* mov Ob, AL */
894 case 0xa1: /* mov Ovqp, rAX */
896 BYTE *data = (BYTE *)(long_addr ? *(DWORD64 *)(instr + 1) : *(DWORD *)(instr + 1));
897 unsigned int data_size = (*instr == 0xa1) ? get_op_size( long_op, rex ) : 1;
898 SIZE_T offset = data - user_shared_data;
899 len = long_addr ? sizeof(DWORD64) : sizeof(DWORD);
901 if (offset <= KSHARED_USER_DATA_PAGE_SIZE - data_size)
903 TRACE("USD offset %#x at %p.\n", (unsigned int)offset, (void *)context->Rip);
904 memcpy( &context->Rax, wine_user_shared_data + offset, data_size );
905 context->Rip += prefixlen + len + 1;
906 return ExceptionContinueExecution;
908 break; /* Unable to emulate it */
911 case 0xfa: /* cli */
912 case 0xfb: /* sti */
913 context->Rip += prefixlen + 1;
914 return ExceptionContinueExecution;
916 return ExceptionContinueSearch; /* Unable to emulate it */
920 /***********************************************************************
921 * vectored_handler
923 * Vectored exception handler used to emulate protected instructions
924 * from 64-bit code.
926 LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs )
928 EXCEPTION_RECORD *record = ptrs->ExceptionRecord;
929 CONTEXT *context = ptrs->ContextRecord;
931 if (record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION ||
932 (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
933 record->ExceptionInformation[0] == EXCEPTION_READ_FAULT))
935 if (emulate_instruction( record, context ) == ExceptionContinueExecution)
937 TRACE( "next instruction rip=%Ix\n", context->Rip );
938 TRACE( " rax=%016Ix rbx=%016Ix rcx=%016Ix rdx=%016Ix\n",
939 context->Rax, context->Rbx, context->Rcx, context->Rdx );
940 TRACE( " rsi=%016Ix rdi=%016Ix rbp=%016Ix rsp=%016Ix\n",
941 context->Rsi, context->Rdi, context->Rbp, context->Rsp );
942 TRACE( " r8=%016Ix r9=%016Ix r10=%016Ix r11=%016Ix\n",
943 context->R8, context->R9, context->R10, context->R11 );
944 TRACE( " r12=%016Ix r13=%016Ix r14=%016Ix r15=%016Ix\n",
945 context->R12, context->R13, context->R14, context->R15 );
947 return EXCEPTION_CONTINUE_EXECUTION;
950 return EXCEPTION_CONTINUE_SEARCH;
953 #endif /* __x86_64__ */