winewayland.drv: Update desktop window size on display changes.
[wine.git] / dlls / ntoskrnl.exe / instr.c
blob8f1aa4d45a30590837490ba858d25fe5c578f19f
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 #define NONAMELESSUNION
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winternl.h"
30 #define WIN32_NO_STATUS
31 #include "ddk/wdm.h"
32 #include "excpt.h"
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 */
44 enum instr_op
46 INSTR_OP_MOV,
47 INSTR_OP_OR,
48 INSTR_OP_XOR,
51 #ifdef __i386__
53 WINE_DEFAULT_DEBUG_CHANNEL(int);
55 #include "pshpack1.h"
56 struct idtr
58 WORD limit;
59 BYTE *base;
61 #include "poppack.h"
63 static LDT_ENTRY idt[256];
65 static inline struct idtr get_idtr(void)
67 struct idtr ret;
68 #ifdef __GNUC__
69 __asm__( "sidtl %0" : "=m" (ret) );
70 #else
71 ret.base = (BYTE *)idt;
72 ret.limit = sizeof(idt) - 1;
73 #endif
74 return ret;
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)
82 case 0:
83 if (long_op) context->Eax = *(const DWORD *)addr;
84 else context->Eax = (context->Eax & 0xffff0000) | *(const WORD *)addr;
85 break;
86 case 1:
87 if (long_op) context->Ecx = *(const DWORD *)addr;
88 else context->Ecx = (context->Ecx & 0xffff0000) | *(const WORD *)addr;
89 break;
90 case 2:
91 if (long_op) context->Edx = *(const DWORD *)addr;
92 else context->Edx = (context->Edx & 0xffff0000) | *(const WORD *)addr;
93 break;
94 case 3:
95 if (long_op) context->Ebx = *(const DWORD *)addr;
96 else context->Ebx = (context->Ebx & 0xffff0000) | *(const WORD *)addr;
97 break;
98 case 4:
99 if (long_op) context->Esp = *(const DWORD *)addr;
100 else context->Esp = (context->Esp & 0xffff0000) | *(const WORD *)addr;
101 break;
102 case 5:
103 if (long_op) context->Ebp = *(const DWORD *)addr;
104 else context->Ebp = (context->Ebp & 0xffff0000) | *(const WORD *)addr;
105 break;
106 case 6:
107 if (long_op) context->Esi = *(const DWORD *)addr;
108 else context->Esi = (context->Esi & 0xffff0000) | *(const WORD *)addr;
109 break;
110 case 7:
111 if (long_op) context->Edi = *(const DWORD *)addr;
112 else context->Edi = (context->Edi & 0xffff0000) | *(const WORD *)addr;
113 break;
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 )
135 switch (rm & 7)
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;
146 return NULL;
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); }
163 *len = 0;
164 GET_VAL( &mod, BYTE );
165 rm = mod & 7;
166 mod >>= 6;
168 if (mod == 3) return get_reg_address( context, rm );
170 if (long_addr)
172 if (rm == 4)
174 BYTE sib;
175 GET_VAL( &sib, BYTE );
176 rm = sib & 7;
177 ss = sib >> 6;
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;
191 switch(rm)
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;
202 switch (mod)
204 case 0:
205 if (rm == 5) /* special case: ds:(disp32) */
207 GET_VAL( &base, DWORD );
209 break;
211 case 1: /* 8-bit disp */
212 GET_VAL( &off, BYTE );
213 base += (signed char)off;
214 break;
216 case 2: /* 32-bit disp */
217 GET_VAL( &off, DWORD );
218 base += (signed long)off;
219 break;
222 else /* short address */
224 switch(rm)
226 case 0: /* ds:(bx,si) */
227 base = LOWORD(context->Ebx) + LOWORD(context->Esi);
228 break;
229 case 1: /* ds:(bx,di) */
230 base = LOWORD(context->Ebx) + LOWORD(context->Edi);
231 break;
232 case 2: /* ss:(bp,si) */
233 base = LOWORD(context->Ebp) + LOWORD(context->Esi);
234 break;
235 case 3: /* ss:(bp,di) */
236 base = LOWORD(context->Ebp) + LOWORD(context->Edi);
237 break;
238 case 4: /* ds:(si) */
239 base = LOWORD(context->Esi);
240 break;
241 case 5: /* ds:(di) */
242 base = LOWORD(context->Edi);
243 break;
244 case 6: /* ss:(bp) */
245 base = LOWORD(context->Ebp);
246 break;
247 case 7: /* ds:(bx) */
248 base = LOWORD(context->Ebx);
249 break;
252 switch(mod)
254 case 0:
255 if (rm == 6) /* special case: ds:(disp16) */
257 GET_VAL( &base, WORD );
259 break;
261 case 1: /* 8-bit disp */
262 GET_VAL( &off, BYTE );
263 base += (signed char)off;
264 break;
266 case 2: /* 16-bit disp */
267 GET_VAL( &off, WORD );
268 base += (signed short)off;
269 break;
271 base &= 0xffff;
273 /* FIXME: we assume that all segments have a base of 0 */
274 return (void *)(base + (index << ss));
275 #undef GET_VAL
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;
289 BYTE *instr;
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 */
298 prefix = 1;
299 prefixlen = 0;
300 while(prefix)
302 switch(*instr)
304 case 0x2e:
305 segprefix = context->SegCs;
306 break;
307 case 0x36:
308 segprefix = context->SegSs;
309 break;
310 case 0x3e:
311 segprefix = context->SegDs;
312 break;
313 case 0x26:
314 segprefix = context->SegEs;
315 break;
316 case 0x64:
317 segprefix = context->SegFs;
318 break;
319 case 0x65:
320 segprefix = context->SegGs;
321 break;
322 case 0x66:
323 long_op = !long_op; /* opcode size prefix */
324 break;
325 case 0x67:
326 long_addr = !long_addr; /* addr size prefix */
327 break;
328 case 0xf0: /* lock */
329 break;
330 case 0xf2: /* repne */
331 break;
332 case 0xf3: /* repe */
333 break;
334 default:
335 prefix = 0; /* no more prefixes */
336 break;
338 if (prefix)
340 instr++;
341 prefixlen++;
345 /* Now look at the actual instruction */
347 switch(*instr)
349 case 0x0f: /* extended instruction */
350 switch(instr[1])
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 );
357 switch (reg)
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 );
373 switch (reg)
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 );
392 switch (reg)
394 case 0: break;
395 case 2: break;
396 case 3: break;
397 case 4: break;
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 );
409 switch (reg)
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;
423 break;
425 case 0x8a: /* mov Eb, Gb */
426 case 0x8b: /* mov Ev, Gv */
428 BYTE *data = INSTR_GetOperandAddr(context, instr + 1, long_addr,
429 segprefix, &len);
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 */
440 switch (*instr)
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 */
451 case 0xfa: /* cli */
452 case 0xfb: /* sti */
453 context->Eip += prefixlen + 1;
454 return ExceptionContinueExecution;
456 return ExceptionContinueSearch; /* Unable to emulate it */
460 /***********************************************************************
461 * vectored_handler
463 * Vectored exception handler used to emulate protected instructions
464 * from 32-bit code.
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);
484 #define REX_B 1
485 #define REX_X 2
486 #define REX_R 4
487 #define REX_W 8
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 )
510 if (rex & REX_W)
511 return sizeof(DWORD64);
512 else if (long_op)
513 return sizeof(DWORD);
514 else
515 return sizeof(WORD);
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,
520 enum instr_op op )
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 );
525 int i;
527 switch (op)
529 case INSTR_OP_MOV:
530 memcpy( reg, addr, op_size );
531 break;
532 case INSTR_OP_OR:
533 for (i = 0; i < op_size; ++i)
534 reg[i] |= addr[i];
535 break;
536 case INSTR_OP_XOR:
537 for (i = 0; i < op_size; ++i)
538 reg[i] ^= addr[i];
539 break;
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 */
550 switch (op)
552 case INSTR_OP_MOV:
553 *reg = *addr;
554 break;
555 case INSTR_OP_OR:
556 *reg |= *addr;
557 break;
558 case INSTR_OP_XOR:
559 *reg ^= *addr;
560 break;
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); }
578 *len = 0;
579 GET_VAL( &mod, BYTE );
580 rm = REGMODRM_RM( mod, rex );
581 mod = REGMODRM_MOD( mod, rex );
583 if (mod == 3)
584 return (BYTE *)get_int_reg( context, rm );
586 if ((rm & 7) == 4)
588 BYTE sib;
589 int id;
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;
598 have_sib = 1;
601 base = *get_int_reg( context, rm );
602 if (!long_addr) base &= 0xffffffff;
604 switch (mod)
606 case 0:
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;
615 break;
617 case 1: /* 8-bit disp */
618 GET_VAL( &off, BYTE );
619 base += (signed char)off;
620 break;
622 case 2: /* 32-bit disp */
623 GET_VAL( &off, DWORD );
624 base += (signed long)off;
625 break;
628 /* FIXME: we assume that all segments have a base of 0 */
629 return (BYTE *)(base + (index << ss));
630 #undef GET_VAL
634 static void fake_syscall_function(void)
636 TRACE("() stub\n");
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;
651 BYTE *instr;
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 */
661 prefix = 1;
662 prefixlen = 0;
663 while(prefix)
665 switch(*instr)
667 case 0x2e:
668 segprefix = context->SegCs;
669 break;
670 case 0x36:
671 segprefix = context->SegSs;
672 break;
673 case 0x3e:
674 segprefix = context->SegDs;
675 break;
676 case 0x26:
677 segprefix = context->SegEs;
678 break;
679 case 0x64:
680 segprefix = context->SegFs;
681 break;
682 case 0x65:
683 segprefix = context->SegGs;
684 break;
685 case 0x66:
686 long_op = !long_op; /* opcode size prefix */
687 break;
688 case 0x67:
689 long_addr = !long_addr; /* addr size prefix */
690 break;
691 case 0x40: /* rex */
692 case 0x41:
693 case 0x42:
694 case 0x43:
695 case 0x44:
696 case 0x45:
697 case 0x46:
698 case 0x47:
699 case 0x48:
700 case 0x49:
701 case 0x4a:
702 case 0x4b:
703 case 0x4c:
704 case 0x4d:
705 case 0x4e:
706 case 0x4f:
707 rex = *instr;
708 break;
709 case 0xf0: /* lock */
710 break;
711 case 0xf2: /* repne */
712 break;
713 case 0xf3: /* repe */
714 break;
715 default:
716 prefix = 0; /* no more prefixes */
717 break;
719 if (prefix)
721 instr++;
722 prefixlen++;
726 /* Now look at the actual instruction */
728 switch(*instr)
730 case 0x0f: /* extended instruction */
731 switch(instr[1])
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 );
739 switch (reg)
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 );
757 switch (reg)
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;
765 case 5:
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 );
778 switch (reg)
780 case 0: break;
781 case 2: break;
782 case 3: break;
783 case 4: break;
784 case 8: break;
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 );
796 switch (reg)
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;
804 case 5:
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);
815 switch (reg)
817 case MSR_LSTAR:
819 ULONG_PTR syscall_address = (ULONG_PTR)fake_syscall_function;
820 context->Rdx = (ULONG)(syscall_address >> 32);
821 context->Rax = (ULONG)syscall_address;
822 break;
824 default:
825 FIXME("reg %#lx, returning 0.\n", reg);
826 context->Rdx = 0;
827 context->Rax = 0;
828 break;
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)
843 ULONGLONG temp = 0;
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);
869 switch (*instr)
871 case 0x8a:
872 store_reg_byte( context, instr[1], wine_user_shared_data + offset,
873 rex, INSTR_OP_MOV );
874 break;
875 case 0x8b:
876 store_reg_word( context, instr[1], wine_user_shared_data + offset,
877 long_op, rex, INSTR_OP_MOV );
878 break;
879 case 0x0b:
880 store_reg_word( context, instr[1], wine_user_shared_data + offset,
881 long_op, rex, INSTR_OP_OR );
882 break;
883 case 0x33:
884 store_reg_word( context, instr[1], wine_user_shared_data + offset,
885 long_op, rex, INSTR_OP_XOR );
886 break;
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 */
912 case 0xfa: /* cli */
913 case 0xfb: /* sti */
914 context->Rip += prefixlen + 1;
915 return ExceptionContinueExecution;
917 return ExceptionContinueSearch; /* Unable to emulate it */
921 /***********************************************************************
922 * vectored_handler
924 * Vectored exception handler used to emulate protected instructions
925 * from 64-bit code.
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__ */