reg: Avoid allocating zero bytes of memory when handling REG_BINARY data.
[wine.git] / dlls / ntoskrnl.exe / instr.c
blobf197570db0c1ef3fde291e9fcb9c60999d8707b1
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"
34 #include "wine/exception.h"
36 #define KSHARED_USER_DATA_PAGE_SIZE 0x1000
38 #define CR0_PE 0x00000001 /* Protected Mode */
39 #define CR0_ET 0x00000010 /* Extension Type */
40 #define CR0_NE 0x00000020 /* Numeric Error */
41 #define CR0_WP 0x00010000 /* Write Protect */
42 #define CR0_AM 0x00040000 /* Alignment Mask */
43 #define CR0_PG 0x80000000 /* Paging */
45 enum instr_op
47 INSTR_OP_MOV,
48 INSTR_OP_OR,
49 INSTR_OP_XOR,
52 #ifdef __i386__
54 WINE_DEFAULT_DEBUG_CHANNEL(int);
56 #include "pshpack1.h"
57 struct idtr
59 WORD limit;
60 BYTE *base;
62 #include "poppack.h"
64 static LDT_ENTRY idt[256];
66 static inline struct idtr get_idtr(void)
68 struct idtr ret;
69 #ifdef __GNUC__
70 __asm__( "sidtl %0" : "=m" (ret) );
71 #else
72 ret.base = (BYTE *)idt;
73 ret.limit = sizeof(idt) - 1;
74 #endif
75 return ret;
78 /* store an operand into a register */
79 static void store_reg_word( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int long_op )
81 switch((regmodrm >> 3) & 7)
83 case 0:
84 if (long_op) context->Eax = *(const DWORD *)addr;
85 else context->Eax = (context->Eax & 0xffff0000) | *(const WORD *)addr;
86 break;
87 case 1:
88 if (long_op) context->Ecx = *(const DWORD *)addr;
89 else context->Ecx = (context->Ecx & 0xffff0000) | *(const WORD *)addr;
90 break;
91 case 2:
92 if (long_op) context->Edx = *(const DWORD *)addr;
93 else context->Edx = (context->Edx & 0xffff0000) | *(const WORD *)addr;
94 break;
95 case 3:
96 if (long_op) context->Ebx = *(const DWORD *)addr;
97 else context->Ebx = (context->Ebx & 0xffff0000) | *(const WORD *)addr;
98 break;
99 case 4:
100 if (long_op) context->Esp = *(const DWORD *)addr;
101 else context->Esp = (context->Esp & 0xffff0000) | *(const WORD *)addr;
102 break;
103 case 5:
104 if (long_op) context->Ebp = *(const DWORD *)addr;
105 else context->Ebp = (context->Ebp & 0xffff0000) | *(const WORD *)addr;
106 break;
107 case 6:
108 if (long_op) context->Esi = *(const DWORD *)addr;
109 else context->Esi = (context->Esi & 0xffff0000) | *(const WORD *)addr;
110 break;
111 case 7:
112 if (long_op) context->Edi = *(const DWORD *)addr;
113 else context->Edi = (context->Edi & 0xffff0000) | *(const WORD *)addr;
114 break;
118 /* store an operand into a byte register */
119 static void store_reg_byte( CONTEXT *context, BYTE regmodrm, const BYTE *addr )
121 switch((regmodrm >> 3) & 7)
123 case 0: context->Eax = (context->Eax & 0xffffff00) | *addr; break;
124 case 1: context->Ecx = (context->Ecx & 0xffffff00) | *addr; break;
125 case 2: context->Edx = (context->Edx & 0xffffff00) | *addr; break;
126 case 3: context->Ebx = (context->Ebx & 0xffffff00) | *addr; break;
127 case 4: context->Eax = (context->Eax & 0xffff00ff) | (*addr << 8); break;
128 case 5: context->Ecx = (context->Ecx & 0xffff00ff) | (*addr << 8); break;
129 case 6: context->Edx = (context->Edx & 0xffff00ff) | (*addr << 8); break;
130 case 7: context->Ebx = (context->Ebx & 0xffff00ff) | (*addr << 8); break;
134 static DWORD *get_reg_address( CONTEXT *context, BYTE rm )
136 switch (rm & 7)
138 case 0: return &context->Eax;
139 case 1: return &context->Ecx;
140 case 2: return &context->Edx;
141 case 3: return &context->Ebx;
142 case 4: return &context->Esp;
143 case 5: return &context->Ebp;
144 case 6: return &context->Esi;
145 case 7: return &context->Edi;
147 return NULL;
151 /***********************************************************************
152 * INSTR_GetOperandAddr
154 * Return the address of an instruction operand (from the mod/rm byte).
156 static void *INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr,
157 int long_addr, int segprefix, int *len )
159 int mod, rm, base = 0, index = 0, ss = 0, off;
161 #define GET_VAL(val,type) \
162 { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
164 *len = 0;
165 GET_VAL( &mod, BYTE );
166 rm = mod & 7;
167 mod >>= 6;
169 if (mod == 3) return get_reg_address( context, rm );
171 if (long_addr)
173 if (rm == 4)
175 BYTE sib;
176 GET_VAL( &sib, BYTE );
177 rm = sib & 7;
178 ss = sib >> 6;
179 switch((sib >> 3) & 7)
181 case 0: index = context->Eax; break;
182 case 1: index = context->Ecx; break;
183 case 2: index = context->Edx; break;
184 case 3: index = context->Ebx; break;
185 case 4: index = 0; break;
186 case 5: index = context->Ebp; break;
187 case 6: index = context->Esi; break;
188 case 7: index = context->Edi; break;
192 switch(rm)
194 case 0: base = context->Eax; break;
195 case 1: base = context->Ecx; break;
196 case 2: base = context->Edx; break;
197 case 3: base = context->Ebx; break;
198 case 4: base = context->Esp; break;
199 case 5: base = context->Ebp; break;
200 case 6: base = context->Esi; break;
201 case 7: base = context->Edi; break;
203 switch (mod)
205 case 0:
206 if (rm == 5) /* special case: ds:(disp32) */
208 GET_VAL( &base, DWORD );
210 break;
212 case 1: /* 8-bit disp */
213 GET_VAL( &off, BYTE );
214 base += (signed char)off;
215 break;
217 case 2: /* 32-bit disp */
218 GET_VAL( &off, DWORD );
219 base += (signed long)off;
220 break;
223 else /* short address */
225 switch(rm)
227 case 0: /* ds:(bx,si) */
228 base = LOWORD(context->Ebx) + LOWORD(context->Esi);
229 break;
230 case 1: /* ds:(bx,di) */
231 base = LOWORD(context->Ebx) + LOWORD(context->Edi);
232 break;
233 case 2: /* ss:(bp,si) */
234 base = LOWORD(context->Ebp) + LOWORD(context->Esi);
235 break;
236 case 3: /* ss:(bp,di) */
237 base = LOWORD(context->Ebp) + LOWORD(context->Edi);
238 break;
239 case 4: /* ds:(si) */
240 base = LOWORD(context->Esi);
241 break;
242 case 5: /* ds:(di) */
243 base = LOWORD(context->Edi);
244 break;
245 case 6: /* ss:(bp) */
246 base = LOWORD(context->Ebp);
247 break;
248 case 7: /* ds:(bx) */
249 base = LOWORD(context->Ebx);
250 break;
253 switch(mod)
255 case 0:
256 if (rm == 6) /* special case: ds:(disp16) */
258 GET_VAL( &base, WORD );
260 break;
262 case 1: /* 8-bit disp */
263 GET_VAL( &off, BYTE );
264 base += (signed char)off;
265 break;
267 case 2: /* 16-bit disp */
268 GET_VAL( &off, WORD );
269 base += (signed short)off;
270 break;
272 base &= 0xffff;
274 /* FIXME: we assume that all segments have a base of 0 */
275 return (void *)(base + (index << ss));
276 #undef GET_VAL
280 /***********************************************************************
281 * emulate_instruction
283 * Emulate a privileged instruction.
284 * Returns exception continuation status.
286 static DWORD emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context )
288 static const char *reg_names[8] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
289 int prefix, segprefix, prefixlen, len, long_op, long_addr;
290 BYTE *instr;
292 long_op = long_addr = 1;
293 instr = (BYTE *)context->Eip;
294 if (!instr) return ExceptionContinueSearch;
296 /* First handle any possible prefix */
298 segprefix = -1; /* no prefix */
299 prefix = 1;
300 prefixlen = 0;
301 while(prefix)
303 switch(*instr)
305 case 0x2e:
306 segprefix = context->SegCs;
307 break;
308 case 0x36:
309 segprefix = context->SegSs;
310 break;
311 case 0x3e:
312 segprefix = context->SegDs;
313 break;
314 case 0x26:
315 segprefix = context->SegEs;
316 break;
317 case 0x64:
318 segprefix = context->SegFs;
319 break;
320 case 0x65:
321 segprefix = context->SegGs;
322 break;
323 case 0x66:
324 long_op = !long_op; /* opcode size prefix */
325 break;
326 case 0x67:
327 long_addr = !long_addr; /* addr size prefix */
328 break;
329 case 0xf0: /* lock */
330 break;
331 case 0xf2: /* repne */
332 break;
333 case 0xf3: /* repe */
334 break;
335 default:
336 prefix = 0; /* no more prefixes */
337 break;
339 if (prefix)
341 instr++;
342 prefixlen++;
346 /* Now look at the actual instruction */
348 switch(*instr)
350 case 0x0f: /* extended instruction */
351 switch(instr[1])
353 case 0x20: /* mov crX, Rd */
355 int reg = (instr[2] >> 3) & 7;
356 DWORD *data = get_reg_address( context, instr[2] );
357 TRACE( "mov cr%u,%s at 0x%08x\n", reg, reg_names[instr[2] & 7], context->Eip );
358 switch (reg)
360 case 0: *data = CR0_PE|CR0_ET|CR0_NE|CR0_WP|CR0_AM|CR0_PG; break;
361 case 2: *data = 0; break;
362 case 3: *data = 0; break;
363 case 4: *data = 0; break;
364 default: return ExceptionContinueSearch;
366 context->Eip += prefixlen + 3;
367 return ExceptionContinueExecution;
369 case 0x21: /* mov drX, Rd */
371 int reg = (instr[2] >> 3) & 7;
372 DWORD *data = get_reg_address( context, instr[2] );
373 TRACE( "mov dr%u,%s at 0x%08x\n", reg, reg_names[instr[2] & 7], context->Eip );
374 switch (reg)
376 case 0: *data = context->Dr0; break;
377 case 1: *data = context->Dr1; break;
378 case 2: *data = context->Dr2; break;
379 case 3: *data = context->Dr3; break;
380 case 6: *data = context->Dr6; break;
381 case 7: *data = 0x400; break;
382 default: return ExceptionContinueSearch;
384 context->Eip += prefixlen + 3;
385 return ExceptionContinueExecution;
387 case 0x22: /* mov Rd, crX */
389 int reg = (instr[2] >> 3) & 7;
390 DWORD *data = get_reg_address( context, instr[2] );
391 TRACE( "mov %s,cr%u at 0x%08x, %s=%08x\n", reg_names[instr[2] & 7],
392 reg, context->Eip, reg_names[instr[2] & 7], *data );
393 switch (reg)
395 case 0: break;
396 case 2: break;
397 case 3: break;
398 case 4: break;
399 default: return ExceptionContinueSearch;
401 context->Eip += prefixlen + 3;
402 return ExceptionContinueExecution;
404 case 0x23: /* mov Rd, drX */
406 int reg = (instr[2] >> 3) & 7;
407 DWORD *data = get_reg_address( context, instr[2] );
408 TRACE( "mov %s,dr%u at 0x%08x %s=%08x\n", reg_names[instr[2] & 7],
409 reg, context->Eip, reg_names[instr[2] & 7], *data );
410 switch (reg)
412 case 0: context->Dr0 = *data; break;
413 case 1: context->Dr1 = *data; break;
414 case 2: context->Dr2 = *data; break;
415 case 3: context->Dr3 = *data; break;
416 case 6: context->Dr6 = *data; break;
417 case 7: context->Dr7 = *data; break;
418 default: return ExceptionContinueSearch;
420 context->Eip += prefixlen + 3;
421 return ExceptionContinueExecution;
424 break;
426 case 0x8a: /* mov Eb, Gb */
427 case 0x8b: /* mov Ev, Gv */
429 BYTE *data = INSTR_GetOperandAddr(context, instr + 1, long_addr,
430 segprefix, &len);
431 unsigned int data_size = (*instr == 0x8b) ? (long_op ? 4 : 2) : 1;
432 struct idtr idtr = get_idtr();
433 unsigned int offset = data - idtr.base;
435 if (offset <= idtr.limit + 1 - data_size)
437 idt[1].LimitLow = 0x100; /* FIXME */
438 idt[2].LimitLow = 0x11E; /* FIXME */
439 idt[3].LimitLow = 0x500; /* FIXME */
441 switch (*instr)
443 case 0x8a: store_reg_byte( context, instr[1], (BYTE *)idt + offset ); break;
444 case 0x8b: store_reg_word( context, instr[1], (BYTE *)idt + offset, long_op ); break;
446 context->Eip += prefixlen + len + 1;
447 return ExceptionContinueExecution;
449 break; /* Unable to emulate it */
452 case 0xfa: /* cli */
453 case 0xfb: /* sti */
454 context->Eip += prefixlen + 1;
455 return ExceptionContinueExecution;
457 return ExceptionContinueSearch; /* Unable to emulate it */
461 /***********************************************************************
462 * vectored_handler
464 * Vectored exception handler used to emulate protected instructions
465 * from 32-bit code.
467 LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs )
469 EXCEPTION_RECORD *record = ptrs->ExceptionRecord;
470 CONTEXT *context = ptrs->ContextRecord;
472 if ((record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
473 record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION))
475 if (emulate_instruction( record, context ) == ExceptionContinueExecution)
476 return EXCEPTION_CONTINUE_EXECUTION;
478 return EXCEPTION_CONTINUE_SEARCH;
481 #elif defined(__x86_64__) /* __i386__ */
483 WINE_DEFAULT_DEBUG_CHANNEL(int);
485 #define REX_B 1
486 #define REX_X 2
487 #define REX_R 4
488 #define REX_W 8
490 #define MSR_LSTAR 0xc0000082
492 #define REGMODRM_MOD( regmodrm, rex ) ((regmodrm) >> 6)
493 #define REGMODRM_REG( regmodrm, rex ) (((regmodrm) >> 3) & 7) | (((rex) & REX_R) ? 8 : 0)
494 #define REGMODRM_RM( regmodrm, rex ) (((regmodrm) & 7) | (((rex) & REX_B) ? 8 : 0))
496 #define SIB_SS( sib, rex ) ((sib) >> 6)
497 #define SIB_INDEX( sib, rex ) (((sib) >> 3) & 7) | (((rex) & REX_X) ? 8 : 0)
498 #define SIB_BASE( sib, rex ) (((sib) & 7) | (((rex) & REX_B) ? 8 : 0))
500 /* keep in sync with dlls/ntdll/thread.c:thread_init */
501 static const BYTE *wine_user_shared_data = (BYTE *)0x7ffe0000;
502 static const BYTE *user_shared_data = (BYTE *)0xfffff78000000000;
504 static inline DWORD64 *get_int_reg( CONTEXT *context, int index )
506 return &context->Rax + index; /* index should be in range 0 .. 15 */
509 static inline int get_op_size( int long_op, int rex )
511 if (rex & REX_W)
512 return sizeof(DWORD64);
513 else if (long_op)
514 return sizeof(DWORD);
515 else
516 return sizeof(WORD);
519 /* store an operand into a register */
520 static void store_reg_word( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int long_op, int rex,
521 enum instr_op op )
523 int index = REGMODRM_REG( regmodrm, rex );
524 BYTE *reg = (BYTE *)get_int_reg( context, index );
525 int op_size = get_op_size( long_op, rex );
526 int i;
528 switch (op)
530 case INSTR_OP_MOV:
531 memcpy( reg, addr, op_size );
532 break;
533 case INSTR_OP_OR:
534 for (i = 0; i < op_size; ++i)
535 reg[i] |= addr[i];
536 break;
537 case INSTR_OP_XOR:
538 for (i = 0; i < op_size; ++i)
539 reg[i] ^= addr[i];
540 break;
544 /* store an operand into a byte register */
545 static void store_reg_byte( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int rex, enum instr_op op )
547 int index = REGMODRM_REG( regmodrm, rex );
548 BYTE *reg = (BYTE *)get_int_reg( context, index );
549 if (!rex && index >= 4 && index < 8) reg -= (4 * sizeof(DWORD64) - 1); /* special case: ah, ch, dh, bh */
551 switch (op)
553 case INSTR_OP_MOV:
554 *reg = *addr;
555 break;
556 case INSTR_OP_OR:
557 *reg |= *addr;
558 break;
559 case INSTR_OP_XOR:
560 *reg ^= *addr;
561 break;
565 /***********************************************************************
566 * INSTR_GetOperandAddr
568 * Return the address of an instruction operand (from the mod/rm byte).
570 static BYTE *INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr, int addl_instr_len,
571 int long_addr, int rex, int segprefix, int *len )
573 int mod, rm, ss = 0, off, have_sib = 0;
574 DWORD64 base = 0, index = 0;
576 #define GET_VAL( val, type ) \
577 { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
579 *len = 0;
580 GET_VAL( &mod, BYTE );
581 rm = REGMODRM_RM( mod, rex );
582 mod = REGMODRM_MOD( mod, rex );
584 if (mod == 3)
585 return (BYTE *)get_int_reg( context, rm );
587 if ((rm & 7) == 4)
589 BYTE sib;
590 int id;
592 GET_VAL( &sib, BYTE );
593 rm = SIB_BASE( sib, rex );
594 id = SIB_INDEX( sib, rex );
595 ss = SIB_SS( sib, rex );
597 index = (id != 4) ? *get_int_reg( context, id ) : 0;
598 if (!long_addr) index &= 0xffffffff;
599 have_sib = 1;
602 base = *get_int_reg( context, rm );
603 if (!long_addr) base &= 0xffffffff;
605 switch (mod)
607 case 0:
608 if (rm == 5) /* special case */
610 base = have_sib ? 0 : context->Rip;
611 if (!long_addr) base &= 0xffffffff;
612 GET_VAL( &off, DWORD );
613 base += (signed long)off;
614 base += (signed long)*len + (signed long)addl_instr_len;
616 break;
618 case 1: /* 8-bit disp */
619 GET_VAL( &off, BYTE );
620 base += (signed char)off;
621 break;
623 case 2: /* 32-bit disp */
624 GET_VAL( &off, DWORD );
625 base += (signed long)off;
626 break;
629 /* FIXME: we assume that all segments have a base of 0 */
630 return (BYTE *)(base + (index << ss));
631 #undef GET_VAL
635 static void fake_syscall_function(void)
637 TRACE("() stub\n");
641 /***********************************************************************
642 * emulate_instruction
644 * Emulate a privileged instruction.
645 * Returns exception continuation status.
647 static DWORD emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context )
649 static const char *reg_names[16] = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
650 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
651 int prefix, segprefix, prefixlen, len, long_op, long_addr, rex;
652 BYTE *instr;
654 long_op = long_addr = 1;
655 instr = (BYTE *)context->Rip;
656 if (!instr) return ExceptionContinueSearch;
658 /* First handle any possible prefix */
660 segprefix = -1; /* no seg prefix */
661 rex = 0; /* no rex prefix */
662 prefix = 1;
663 prefixlen = 0;
664 while(prefix)
666 switch(*instr)
668 case 0x2e:
669 segprefix = context->SegCs;
670 break;
671 case 0x36:
672 segprefix = context->SegSs;
673 break;
674 case 0x3e:
675 segprefix = context->SegDs;
676 break;
677 case 0x26:
678 segprefix = context->SegEs;
679 break;
680 case 0x64:
681 segprefix = context->SegFs;
682 break;
683 case 0x65:
684 segprefix = context->SegGs;
685 break;
686 case 0x66:
687 long_op = !long_op; /* opcode size prefix */
688 break;
689 case 0x67:
690 long_addr = !long_addr; /* addr size prefix */
691 break;
692 case 0x40: /* rex */
693 case 0x41:
694 case 0x42:
695 case 0x43:
696 case 0x44:
697 case 0x45:
698 case 0x46:
699 case 0x47:
700 case 0x48:
701 case 0x49:
702 case 0x4a:
703 case 0x4b:
704 case 0x4c:
705 case 0x4d:
706 case 0x4e:
707 case 0x4f:
708 rex = *instr;
709 break;
710 case 0xf0: /* lock */
711 break;
712 case 0xf2: /* repne */
713 break;
714 case 0xf3: /* repe */
715 break;
716 default:
717 prefix = 0; /* no more prefixes */
718 break;
720 if (prefix)
722 instr++;
723 prefixlen++;
727 /* Now look at the actual instruction */
729 switch(*instr)
731 case 0x0f: /* extended instruction */
732 switch(instr[1])
734 case 0x20: /* mov crX, Rd */
736 int reg = REGMODRM_REG( instr[2], rex );
737 int rm = REGMODRM_RM( instr[2], rex );
738 DWORD64 *data = get_int_reg( context, rm );
739 TRACE( "mov cr%u,%s at %lx\n", reg, reg_names[rm], context->Rip );
740 switch (reg)
742 case 0: *data = 0x10; break; /* FIXME: set more bits ? */
743 case 2: *data = 0; break;
744 case 3: *data = 0; break;
745 case 4: *data = 0; break;
746 case 8: *data = 0; break;
747 default: return ExceptionContinueSearch;
749 context->Rip += prefixlen + 3;
750 return ExceptionContinueExecution;
752 case 0x21: /* mov drX, Rd */
754 int reg = REGMODRM_REG( instr[2], rex );
755 int rm = REGMODRM_RM( instr[2], rex );
756 DWORD64 *data = get_int_reg( context, rm );
757 TRACE( "mov dr%u,%s at %lx\n", reg, reg_names[rm], context->Rip );
758 switch (reg)
760 case 0: *data = context->Dr0; break;
761 case 1: *data = context->Dr1; break;
762 case 2: *data = context->Dr2; break;
763 case 3: *data = context->Dr3; break;
764 case 4: /* dr4 and dr5 are obsolete aliases for dr6 and dr7 */
765 case 6: *data = context->Dr6; break;
766 case 5:
767 case 7: *data = 0x400; break;
768 default: return ExceptionContinueSearch;
770 context->Rip += prefixlen + 3;
771 return ExceptionContinueExecution;
773 case 0x22: /* mov Rd, crX */
775 int reg = REGMODRM_REG( instr[2], rex );
776 int rm = REGMODRM_RM( instr[2], rex );
777 DWORD64 *data = get_int_reg( context, rm );
778 TRACE( "mov %s,cr%u at %lx, %s=%lx\n", reg_names[rm], reg, context->Rip, reg_names[rm], *data );
779 switch (reg)
781 case 0: break;
782 case 2: break;
783 case 3: break;
784 case 4: break;
785 case 8: break;
786 default: return ExceptionContinueSearch;
788 context->Rip += prefixlen + 3;
789 return ExceptionContinueExecution;
791 case 0x23: /* mov Rd, drX */
793 int reg = REGMODRM_REG( instr[2], rex );
794 int rm = REGMODRM_RM( instr[2], rex );
795 DWORD64 *data = get_int_reg( context, rm );
796 TRACE( "mov %s,dr%u at %lx, %s=%lx\n", reg_names[rm], reg, context->Rip, reg_names[rm], *data );
797 switch (reg)
799 case 0: context->Dr0 = *data; break;
800 case 1: context->Dr1 = *data; break;
801 case 2: context->Dr2 = *data; break;
802 case 3: context->Dr3 = *data; break;
803 case 4: /* dr4 and dr5 are obsolete aliases for dr6 and dr7 */
804 case 6: context->Dr6 = *data; break;
805 case 5:
806 case 7: context->Dr7 = *data; break;
807 default: return ExceptionContinueSearch;
809 context->Rip += prefixlen + 3;
810 return ExceptionContinueExecution;
812 case 0x32: /* rdmsr */
814 ULONG reg = context->Rcx;
815 TRACE("rdmsr CR 0x%08x\n", reg);
816 switch (reg)
818 case MSR_LSTAR:
820 ULONG_PTR syscall_address = (ULONG_PTR)fake_syscall_function;
821 context->Rdx = (ULONG)(syscall_address >> 32);
822 context->Rax = (ULONG)syscall_address;
823 break;
825 default:
826 FIXME("reg %#x, returning 0.\n", reg);
827 context->Rdx = 0;
828 context->Rax = 0;
829 break;
831 context->Rip += prefixlen + 2;
832 return ExceptionContinueExecution;
834 case 0xb6: /* movzx Eb, Gv */
835 case 0xb7: /* movzx Ew, Gv */
837 BYTE *data = INSTR_GetOperandAddr( context, instr + 2, prefixlen + 2, long_addr,
838 rex, segprefix, &len );
839 unsigned int data_size = (instr[1] == 0xb7) ? 2 : 1;
840 SIZE_T offset = data - user_shared_data;
842 if (offset <= KSHARED_USER_DATA_PAGE_SIZE - data_size)
844 ULONGLONG temp = 0;
846 TRACE("USD offset %#x at %p.\n", (unsigned int)offset, (void *)context->Rip);
847 memcpy( &temp, wine_user_shared_data + offset, data_size );
848 store_reg_word( context, instr[2], (BYTE *)&temp, long_op, rex, INSTR_OP_MOV );
849 context->Rip += prefixlen + len + 2;
850 return ExceptionContinueExecution;
852 break; /* Unable to emulate it */
855 break; /* Unable to emulate it */
857 case 0x8a: /* mov Eb, Gb */
858 case 0x8b: /* mov Ev, Gv */
859 case 0x0b: /* or Ev, Gv */
860 case 0x33: /* xor Ev, Gv */
862 BYTE *data = INSTR_GetOperandAddr( context, instr + 1, prefixlen + 1, long_addr,
863 rex, segprefix, &len );
864 unsigned int data_size = (*instr == 0x8b) ? get_op_size( long_op, rex ) : 1;
865 SIZE_T offset = data - user_shared_data;
867 if (offset <= KSHARED_USER_DATA_PAGE_SIZE - data_size)
869 TRACE("USD offset %#x at %p.\n", (unsigned int)offset, (void *)context->Rip);
870 switch (*instr)
872 case 0x8a:
873 store_reg_byte( context, instr[1], wine_user_shared_data + offset,
874 rex, INSTR_OP_MOV );
875 break;
876 case 0x8b:
877 store_reg_word( context, instr[1], wine_user_shared_data + offset,
878 long_op, rex, INSTR_OP_MOV );
879 break;
880 case 0x0b:
881 store_reg_word( context, instr[1], wine_user_shared_data + offset,
882 long_op, rex, INSTR_OP_OR );
883 break;
884 case 0x33:
885 store_reg_word( context, instr[1], wine_user_shared_data + offset,
886 long_op, rex, INSTR_OP_XOR );
887 break;
889 context->Rip += prefixlen + len + 1;
890 return ExceptionContinueExecution;
892 break; /* Unable to emulate it */
895 case 0xa0: /* mov Ob, AL */
896 case 0xa1: /* mov Ovqp, rAX */
898 BYTE *data = (BYTE *)(long_addr ? *(DWORD64 *)(instr + 1) : *(DWORD *)(instr + 1));
899 unsigned int data_size = (*instr == 0xa1) ? get_op_size( long_op, rex ) : 1;
900 SIZE_T offset = data - user_shared_data;
901 len = long_addr ? sizeof(DWORD64) : sizeof(DWORD);
903 if (offset <= KSHARED_USER_DATA_PAGE_SIZE - data_size)
905 TRACE("USD offset %#x at %p.\n", (unsigned int)offset, (void *)context->Rip);
906 memcpy( &context->Rax, wine_user_shared_data + offset, data_size );
907 context->Rip += prefixlen + len + 1;
908 return ExceptionContinueExecution;
910 break; /* Unable to emulate it */
913 case 0xfa: /* cli */
914 case 0xfb: /* sti */
915 context->Rip += prefixlen + 1;
916 return ExceptionContinueExecution;
918 return ExceptionContinueSearch; /* Unable to emulate it */
922 /***********************************************************************
923 * vectored_handler
925 * Vectored exception handler used to emulate protected instructions
926 * from 64-bit code.
928 LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs )
930 EXCEPTION_RECORD *record = ptrs->ExceptionRecord;
931 CONTEXT *context = ptrs->ContextRecord;
933 if (record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION ||
934 (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
935 record->ExceptionInformation[0] == EXCEPTION_READ_FAULT))
937 if (emulate_instruction( record, context ) == ExceptionContinueExecution)
939 TRACE( "next instruction rip=%lx\n", context->Rip );
940 TRACE( " rax=%016lx rbx=%016lx rcx=%016lx rdx=%016lx\n",
941 context->Rax, context->Rbx, context->Rcx, context->Rdx );
942 TRACE( " rsi=%016lx rdi=%016lx rbp=%016lx rsp=%016lx\n",
943 context->Rsi, context->Rdi, context->Rbp, context->Rsp );
944 TRACE( " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n",
945 context->R8, context->R9, context->R10, context->R11 );
946 TRACE( " r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n",
947 context->R12, context->R13, context->R14, context->R15 );
949 return EXCEPTION_CONTINUE_EXECUTION;
952 return EXCEPTION_CONTINUE_SEARCH;
955 #endif /* __x86_64__ */