[FAST486]
[reactos.git] / reactos / lib / fast486 / extraops.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * extraops.c
4 *
5 * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "opcodes.h"
31 #include "common.h"
32 #include "opgroups.h"
33 #include "extraops.h"
34
35 /* PUBLIC VARIABLES ***********************************************************/
36
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
39 {
40 Fast486OpcodeGroup0F00, /* 0x00 - 0x01 */
41 Fast486OpcodeGroup0F01,
42 Fast486ExtOpcodeLar, /* 0x02 */
43 Fast486ExtOpcodeLsl, /* 0x03 */
44 Fast486ExtOpcodeInvalid, /* 0x04 - 0x05 */ // Invalid
45 Fast486ExtOpcodeInvalid, // Invalid
46 Fast486ExtOpcodeClts, /* 0x06 */
47 Fast486ExtOpcodeInvalid, /* 0x07 */ // Invalid
48 Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x08 NOT IMPLEMENTED
49 Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x09 NOT IMPLEMENTED
50 Fast486ExtOpcodeInvalid, /* 0x0A */ // Invalid
51 Fast486ExtOpcode0F0B, /* 0x0B */ // Reserved (UD2)
52 Fast486ExtOpcodeInvalid, /* 0x0C - 0x1F */ // Invalid
53 Fast486ExtOpcodeInvalid, // Invalid
54 Fast486ExtOpcodeInvalid, // Invalid
55 Fast486ExtOpcodeInvalid, // Invalid
56 Fast486ExtOpcodeInvalid, // Invalid
57 Fast486ExtOpcodeInvalid, // Invalid
58 Fast486ExtOpcodeInvalid, // Invalid
59 Fast486ExtOpcodeInvalid, // Invalid
60 Fast486ExtOpcodeInvalid, // Invalid
61 Fast486ExtOpcodeInvalid, // Invalid
62 Fast486ExtOpcodeInvalid, // Invalid
63 Fast486ExtOpcodeInvalid, // Invalid
64 Fast486ExtOpcodeInvalid, // Invalid
65 Fast486ExtOpcodeInvalid, // Invalid
66 Fast486ExtOpcodeInvalid, // Invalid
67 Fast486ExtOpcodeInvalid, // Invalid
68 Fast486ExtOpcodeInvalid, // Invalid
69 Fast486ExtOpcodeInvalid, // Invalid
70 Fast486ExtOpcodeInvalid, // Invalid
71 Fast486ExtOpcodeInvalid, // Invalid
72 Fast486ExtOpcodeStoreControlReg, /* 0x20 */
73 Fast486ExtOpcodeStoreDebugReg, /* 0x21 */
74 Fast486ExtOpcodeLoadControlReg, /* 0x22 */
75 Fast486ExtOpcodeLoadDebugReg, /* 0x23 */
76 Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x24 NOT IMPLEMENTED
77 Fast486ExtOpcodeInvalid, /* 0x25 */ // Invalid
78 Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x26 NOT IMPLEMENTED
79 Fast486ExtOpcodeInvalid, /* 0x27 - 0x7F */ // Invalid
80 Fast486ExtOpcodeInvalid, // Invalid
81 Fast486ExtOpcodeInvalid, // Invalid
82 Fast486ExtOpcodeInvalid, // Invalid
83 Fast486ExtOpcodeInvalid, // Invalid
84 Fast486ExtOpcodeInvalid, // Invalid
85 Fast486ExtOpcodeInvalid, // Invalid
86 Fast486ExtOpcodeInvalid, // Invalid
87 Fast486ExtOpcodeInvalid, // Invalid
88 Fast486ExtOpcodeInvalid, // Invalid
89 Fast486ExtOpcodeInvalid, // Invalid
90 Fast486ExtOpcodeInvalid, // Invalid
91 Fast486ExtOpcodeInvalid, // Invalid
92 Fast486ExtOpcodeInvalid, // Invalid
93 Fast486ExtOpcodeInvalid, // Invalid
94 Fast486ExtOpcodeInvalid, // Invalid
95 Fast486ExtOpcodeInvalid, // Invalid
96 Fast486ExtOpcodeInvalid, // Invalid
97 Fast486ExtOpcodeInvalid, // Invalid
98 Fast486ExtOpcodeInvalid, // Invalid
99 Fast486ExtOpcodeInvalid, // Invalid
100 Fast486ExtOpcodeInvalid, // Invalid
101 Fast486ExtOpcodeInvalid, // Invalid
102 Fast486ExtOpcodeInvalid, // Invalid
103 Fast486ExtOpcodeInvalid, // Invalid
104 Fast486ExtOpcodeInvalid, // Invalid
105 Fast486ExtOpcodeInvalid, // Invalid
106 Fast486ExtOpcodeInvalid, // Invalid
107 Fast486ExtOpcodeInvalid, // Invalid
108 Fast486ExtOpcodeInvalid, // Invalid
109 Fast486ExtOpcodeInvalid, // Invalid
110 Fast486ExtOpcodeInvalid, // Invalid
111 Fast486ExtOpcodeInvalid, // Invalid
112 Fast486ExtOpcodeInvalid, // Invalid
113 Fast486ExtOpcodeInvalid, // Invalid
114 Fast486ExtOpcodeInvalid, // Invalid
115 Fast486ExtOpcodeInvalid, // Invalid
116 Fast486ExtOpcodeInvalid, // Invalid
117 Fast486ExtOpcodeInvalid, // Invalid
118 Fast486ExtOpcodeInvalid, // Invalid
119 Fast486ExtOpcodeInvalid, // Invalid
120 Fast486ExtOpcodeInvalid, // Invalid
121 Fast486ExtOpcodeInvalid, // Invalid
122 Fast486ExtOpcodeInvalid, // Invalid
123 Fast486ExtOpcodeInvalid, // Invalid
124 Fast486ExtOpcodeInvalid, // Invalid
125 Fast486ExtOpcodeInvalid, // Invalid
126 Fast486ExtOpcodeInvalid, // Invalid
127 Fast486ExtOpcodeInvalid, // Invalid
128 Fast486ExtOpcodeInvalid, // Invalid
129 Fast486ExtOpcodeInvalid, // Invalid
130 Fast486ExtOpcodeInvalid, // Invalid
131 Fast486ExtOpcodeInvalid, // Invalid
132 Fast486ExtOpcodeInvalid, // Invalid
133 Fast486ExtOpcodeInvalid, // Invalid
134 Fast486ExtOpcodeInvalid, // Invalid
135 Fast486ExtOpcodeInvalid, // Invalid
136 Fast486ExtOpcodeInvalid, // Invalid
137 Fast486ExtOpcodeInvalid, // Invalid
138 Fast486ExtOpcodeInvalid, // Invalid
139 Fast486ExtOpcodeInvalid, // Invalid
140 Fast486ExtOpcodeInvalid, // Invalid
141 Fast486ExtOpcodeInvalid, // Invalid
142 Fast486ExtOpcodeInvalid, // Invalid
143 Fast486ExtOpcodeInvalid, // Invalid
144 Fast486ExtOpcodeInvalid, // Invalid
145 Fast486ExtOpcodeInvalid, // Invalid
146 Fast486ExtOpcodeInvalid, // Invalid
147 Fast486ExtOpcodeInvalid, // Invalid
148 Fast486ExtOpcodeInvalid, // Invalid
149 Fast486ExtOpcodeInvalid, // Invalid
150 Fast486ExtOpcodeInvalid, // Invalid
151 Fast486ExtOpcodeInvalid, // Invalid
152 Fast486ExtOpcodeInvalid, // Invalid
153 Fast486ExtOpcodeInvalid, // Invalid
154 Fast486ExtOpcodeInvalid, // Invalid
155 Fast486ExtOpcodeInvalid, // Invalid
156 Fast486ExtOpcodeInvalid, // Invalid
157 Fast486ExtOpcodeInvalid, // Invalid
158 Fast486ExtOpcodeInvalid, // Invalid
159 Fast486ExtOpcodeInvalid, // Invalid
160 Fast486ExtOpcodeInvalid, // Invalid
161 Fast486ExtOpcodeInvalid, // Invalid
162 Fast486ExtOpcodeInvalid, // Invalid
163 Fast486ExtOpcodeInvalid, // Invalid
164 Fast486ExtOpcodeInvalid, // Invalid
165 Fast486ExtOpcodeInvalid, // Invalid
166 Fast486ExtOpcodeInvalid, // Invalid
167 Fast486ExtOpcodeInvalid, // Invalid
168 Fast486ExtOpcodeConditionalJmp, /* 0x80 - 0x8F */
169 Fast486ExtOpcodeConditionalJmp,
170 Fast486ExtOpcodeConditionalJmp,
171 Fast486ExtOpcodeConditionalJmp,
172 Fast486ExtOpcodeConditionalJmp,
173 Fast486ExtOpcodeConditionalJmp,
174 Fast486ExtOpcodeConditionalJmp,
175 Fast486ExtOpcodeConditionalJmp,
176 Fast486ExtOpcodeConditionalJmp,
177 Fast486ExtOpcodeConditionalJmp,
178 Fast486ExtOpcodeConditionalJmp,
179 Fast486ExtOpcodeConditionalJmp,
180 Fast486ExtOpcodeConditionalJmp,
181 Fast486ExtOpcodeConditionalJmp,
182 Fast486ExtOpcodeConditionalJmp,
183 Fast486ExtOpcodeConditionalJmp,
184 Fast486ExtOpcodeConditionalSet, /* 0x90 - 0x9F */
185 Fast486ExtOpcodeConditionalSet,
186 Fast486ExtOpcodeConditionalSet,
187 Fast486ExtOpcodeConditionalSet,
188 Fast486ExtOpcodeConditionalSet,
189 Fast486ExtOpcodeConditionalSet,
190 Fast486ExtOpcodeConditionalSet,
191 Fast486ExtOpcodeConditionalSet,
192 Fast486ExtOpcodeConditionalSet,
193 Fast486ExtOpcodeConditionalSet,
194 Fast486ExtOpcodeConditionalSet,
195 Fast486ExtOpcodeConditionalSet,
196 Fast486ExtOpcodeConditionalSet,
197 Fast486ExtOpcodeConditionalSet,
198 Fast486ExtOpcodeConditionalSet,
199 Fast486ExtOpcodeConditionalSet,
200 Fast486ExtOpcodePushFs, /* 0xA0 */
201 Fast486ExtOpcodePopFs, /* 0xA1 */
202 Fast486ExtOpcodeInvalid, /* 0xA2 */ // Invalid
203 Fast486ExtOpcodeBitTest, /* 0xA3 */
204 Fast486ExtOpcodeShld, /* 0xA4 - 0xA5 */
205 Fast486ExtOpcodeShld,
206 Fast486ExtOpcodeInvalid, /* 0xA6 - 0xA7 */ // Invalid
207 Fast486ExtOpcodeInvalid, // Invalid
208 Fast486ExtOpcodePushGs, /* 0xA8 - 0xA9 */
209 Fast486ExtOpcodePopGs,
210 Fast486ExtOpcodeInvalid, /* 0xAA */ // Invalid
211 Fast486ExtOpcodeBts, /* 0xAB */
212 Fast486ExtOpcodeShrd, /* 0xAC - 0xAD */
213 Fast486ExtOpcodeShrd,
214 Fast486ExtOpcodeInvalid, /* 0xAE */ // Invalid
215 Fast486ExtOpcodeImul, /* 0xAF */
216 Fast486ExtOpcodeCmpXchgByte, /* 0xB0 */
217 Fast486ExtOpcodeCmpXchg, /* 0xB1 */
218 Fast486ExtOpcodeLss, /* 0xB2 */
219 Fast486ExtOpcodeBtr, /* 0xB3 */
220 Fast486ExtOpcodeLfsLgs, /* 0xB4 - 0xB5 */
221 Fast486ExtOpcodeLfsLgs,
222 Fast486ExtOpcodeMovzxByte, /* 0xB6 - 0xB7 */
223 Fast486ExtOpcodeMovzxWord,
224 Fast486ExtOpcodeInvalid, /* 0xB8 */ // Invalid
225 Fast486OpcodeGroup0FB9, /* 0xB9 */
226 Fast486OpcodeGroup0FBA, /* 0xBA */
227 Fast486ExtOpcodeBtc, /* 0xBB */
228 Fast486ExtOpcodeBsf, /* 0xBC */
229 Fast486ExtOpcodeBsr, /* 0xBD */
230 Fast486ExtOpcodeMovsxByte, /* 0xBE - 0xBF */
231 Fast486ExtOpcodeMovsxWord,
232 Fast486ExtOpcodeXaddByte, /* 0xC0 - 0xC1 */
233 Fast486ExtOpcodeXadd,
234 Fast486ExtOpcodeInvalid, /* 0xC2 - 0xC7 */ // Invalid
235 Fast486ExtOpcodeInvalid, // Invalid
236 Fast486ExtOpcodeInvalid, // Invalid
237 Fast486ExtOpcodeInvalid, // Invalid
238 Fast486ExtOpcodeInvalid, // Invalid
239 Fast486ExtOpcodeInvalid, // Invalid
240 Fast486ExtOpcodeBswap, /* 0xC8 - 0xCF */
241 Fast486ExtOpcodeBswap,
242 Fast486ExtOpcodeBswap,
243 Fast486ExtOpcodeBswap,
244 Fast486ExtOpcodeBswap,
245 Fast486ExtOpcodeBswap,
246 Fast486ExtOpcodeBswap,
247 Fast486ExtOpcodeBswap,
248 Fast486ExtOpcodeInvalid, /* 0xD0 - 0xFF */ // Invalid
249 Fast486ExtOpcodeInvalid, // Invalid
250 Fast486ExtOpcodeInvalid, // Invalid
251 Fast486ExtOpcodeInvalid, // Invalid
252 Fast486ExtOpcodeInvalid, // Invalid
253 Fast486ExtOpcodeInvalid, // Invalid
254 Fast486ExtOpcodeInvalid, // Invalid
255 Fast486ExtOpcodeInvalid, // Invalid
256 Fast486ExtOpcodeInvalid, // Invalid
257 Fast486ExtOpcodeInvalid, // Invalid
258 Fast486ExtOpcodeInvalid, // Invalid
259 Fast486ExtOpcodeInvalid, // Invalid
260 Fast486ExtOpcodeInvalid, // Invalid
261 Fast486ExtOpcodeInvalid, // Invalid
262 Fast486ExtOpcodeInvalid, // Invalid
263 Fast486ExtOpcodeInvalid, // Invalid
264 Fast486ExtOpcodeInvalid, // Invalid
265 Fast486ExtOpcodeInvalid, // Invalid
266 Fast486ExtOpcodeInvalid, // Invalid
267 Fast486ExtOpcodeInvalid, // Invalid
268 Fast486ExtOpcodeInvalid, // Invalid
269 Fast486ExtOpcodeInvalid, // Invalid
270 Fast486ExtOpcodeInvalid, // Invalid
271 Fast486ExtOpcodeInvalid, // Invalid
272 Fast486ExtOpcodeInvalid, // Invalid
273 Fast486ExtOpcodeInvalid, // Invalid
274 Fast486ExtOpcodeInvalid, // Invalid
275 Fast486ExtOpcodeInvalid, // Invalid
276 Fast486ExtOpcodeInvalid, // Invalid
277 Fast486ExtOpcodeInvalid, // Invalid
278 Fast486ExtOpcodeInvalid, // Invalid
279 Fast486ExtOpcodeInvalid, // Invalid
280 Fast486ExtOpcodeInvalid, // Invalid
281 Fast486ExtOpcodeInvalid, // Invalid
282 Fast486ExtOpcodeInvalid, // Invalid
283 Fast486ExtOpcodeInvalid, // Invalid
284 Fast486ExtOpcodeInvalid, // Invalid
285 Fast486ExtOpcodeInvalid, // Invalid
286 Fast486ExtOpcodeInvalid, // Invalid
287 Fast486ExtOpcodeInvalid, // Invalid
288 Fast486ExtOpcodeInvalid, // Invalid
289 Fast486ExtOpcodeInvalid, // Invalid
290 Fast486ExtOpcodeInvalid, // Invalid
291 Fast486ExtOpcodeInvalid, // Invalid
292 Fast486ExtOpcodeInvalid, // Invalid
293 Fast486ExtOpcodeInvalid, // Invalid
294 Fast486ExtOpcodeInvalid, // Invalid
295 Fast486ExtOpcodeInvalid, // Invalid
296 };
297
298 /* PUBLIC FUNCTIONS ***********************************************************/
299
300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeInvalid)
301 {
302 DPRINT1("FAST486 -- Extended opcode 0x%02X is INVALID!\n", Opcode);
303 Fast486Exception(State, FAST486_EXCEPTION_UD);
304 return FALSE;
305 }
306
307 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeUnimplemented)
308 {
309 DPRINT1("FAST486 -- Extended opcode 0x%02X is UNIMPLEMENTED\n", Opcode);
310 // Fast486Exception(State, FAST486_EXCEPTION_UD);
311 return FALSE;
312 }
313
314 FAST486_OPCODE_HANDLER(Fast486ExtOpcode0F0B)
315 {
316 /* Reserved opcode (UD2) */
317 Fast486Exception(State, FAST486_EXCEPTION_UD);
318 return FALSE;
319 }
320
321 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar)
322 {
323 BOOLEAN OperandSize, AddressSize;
324 FAST486_MOD_REG_RM ModRegRm;
325 USHORT Selector;
326 FAST486_GDT_ENTRY GdtEntry;
327 DWORD AccessRights;
328
329 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
330
331 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
332 || State->Flags.Vm)
333 {
334 /* Not recognized */
335 Fast486Exception(State, FAST486_EXCEPTION_UD);
336 return FALSE;
337 }
338
339 NO_LOCK_PREFIX();
340 TOGGLE_OPSIZE(OperandSize);
341 TOGGLE_ADSIZE(AddressSize);
342
343 /* Get the operands */
344 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
345 {
346 /* Exception occurred */
347 return FALSE;
348 }
349
350 if (OperandSize)
351 {
352 ULONG Value;
353
354 /* Read the value */
355 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
356 {
357 /* Exception occurred */
358 return FALSE;
359 }
360
361 Selector = LOWORD(Value);
362 }
363 else
364 {
365 /* Read the value */
366 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
367 {
368 /* Exception occurred */
369 return FALSE;
370 }
371 }
372
373 if (!(Selector & SEGMENT_TABLE_INDICATOR))
374 {
375 /* Check if the GDT contains the entry */
376 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
377 {
378 State->Flags.Zf = FALSE;
379 return TRUE;
380 }
381
382 /* Read the GDT */
383 if (!Fast486ReadLinearMemory(State,
384 State->Gdtr.Address
385 + GET_SEGMENT_INDEX(Selector),
386 &GdtEntry,
387 sizeof(GdtEntry)))
388 {
389 /* Exception occurred */
390 return FALSE;
391 }
392 }
393 else
394 {
395 /* Check if the LDT contains the entry */
396 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
397 {
398 State->Flags.Zf = FALSE;
399 return TRUE;
400 }
401
402 /* Read the LDT */
403 if (!Fast486ReadLinearMemory(State,
404 State->Ldtr.Base
405 + GET_SEGMENT_INDEX(Selector),
406 &GdtEntry,
407 sizeof(GdtEntry)))
408 {
409 /* Exception occurred */
410 return FALSE;
411 }
412 }
413
414 /* Privilege check */
415 if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl))
416 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
417 {
418 State->Flags.Zf = FALSE;
419 return TRUE;
420 }
421
422 /* Set ZF */
423 State->Flags.Zf = TRUE;
424
425 /* Get the access rights */
426 AccessRights = ((PDWORD)&GdtEntry)[1] & 0x00F0FF00;
427
428 /* Return the access rights */
429 if (OperandSize)
430 {
431 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, AccessRights))
432 {
433 /* Exception occurred */
434 return FALSE;
435 }
436 }
437 else
438 {
439 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(AccessRights)))
440 {
441 /* Exception occurred */
442 return FALSE;
443 }
444 }
445
446 return TRUE;
447 }
448
449 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
450 {
451 BOOLEAN OperandSize, AddressSize;
452 FAST486_MOD_REG_RM ModRegRm;
453 USHORT Selector;
454 ULONG Limit;
455 FAST486_GDT_ENTRY GdtEntry;
456
457 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
458
459 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
460 || State->Flags.Vm)
461 {
462 /* Not recognized */
463 Fast486Exception(State, FAST486_EXCEPTION_UD);
464 return FALSE;
465 }
466
467 NO_LOCK_PREFIX();
468 TOGGLE_OPSIZE(OperandSize);
469 TOGGLE_ADSIZE(AddressSize);
470
471 /* Get the operands */
472 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
473 {
474 /* Exception occurred */
475 return FALSE;
476 }
477
478 if (OperandSize)
479 {
480 ULONG Value;
481
482 /* Read the value */
483 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
484 {
485 /* Exception occurred */
486 return FALSE;
487 }
488
489 Selector = LOWORD(Value);
490 }
491 else
492 {
493 /* Read the value */
494 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
495 {
496 /* Exception occurred */
497 return FALSE;
498 }
499 }
500
501 if (!(Selector & SEGMENT_TABLE_INDICATOR))
502 {
503 /* Check if the GDT contains the entry */
504 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
505 {
506 State->Flags.Zf = FALSE;
507 return TRUE;
508 }
509
510 /* Read the GDT */
511 if (!Fast486ReadLinearMemory(State,
512 State->Gdtr.Address
513 + GET_SEGMENT_INDEX(Selector),
514 &GdtEntry,
515 sizeof(GdtEntry)))
516 {
517 /* Exception occurred */
518 return FALSE;
519 }
520 }
521 else
522 {
523 /* Check if the LDT contains the entry */
524 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
525 {
526 State->Flags.Zf = FALSE;
527 return TRUE;
528 }
529
530 /* Read the LDT */
531 if (!Fast486ReadLinearMemory(State,
532 State->Ldtr.Base
533 + GET_SEGMENT_INDEX(Selector),
534 &GdtEntry,
535 sizeof(GdtEntry)))
536 {
537 /* Exception occurred */
538 return FALSE;
539 }
540 }
541
542 /* Privilege check */
543 if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl))
544 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
545 {
546 State->Flags.Zf = FALSE;
547 return TRUE;
548 }
549
550 /* Calculate the limit */
551 Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
552 if (GdtEntry.Granularity) Limit <<= 12;
553
554 /* Set ZF */
555 State->Flags.Zf = TRUE;
556
557 if (OperandSize)
558 {
559 /* Return the limit */
560 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Limit))
561 {
562 /* Exception occurred */
563 return FALSE;
564 }
565 }
566 else
567 {
568 /* Return the limit */
569 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(Limit)))
570 {
571 /* Exception occurred */
572 return FALSE;
573 }
574 }
575
576 return TRUE;
577 }
578
579 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts)
580 {
581 NO_LOCK_PREFIX();
582
583 /* The current privilege level must be zero */
584 if (Fast486GetCurrentPrivLevel(State) != 0)
585 {
586 Fast486Exception(State, FAST486_EXCEPTION_GP);
587 return FALSE;
588 }
589
590 /* Clear the task switch bit */
591 State->ControlRegisters[FAST486_REG_CR0] &= ~FAST486_CR0_TS;
592
593 return TRUE;
594 }
595
596 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg)
597 {
598 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
599 FAST486_MOD_REG_RM ModRegRm;
600
601 NO_LOCK_PREFIX();
602 TOGGLE_ADSIZE(AddressSize);
603
604 /* Get the operands */
605 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
606 {
607 /* Exception occurred */
608 return FALSE;
609 }
610
611 /* The current privilege level must be zero */
612 if (Fast486GetCurrentPrivLevel(State) != 0)
613 {
614 Fast486Exception(State, FAST486_EXCEPTION_GP);
615 return FALSE;
616 }
617
618 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
619 {
620 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
621 Fast486Exception(State, FAST486_EXCEPTION_UD);
622 return FALSE;
623 }
624
625 if (ModRegRm.Register != 0)
626 {
627 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
628 ModRegRm.Register--;
629 }
630
631 /* Store the value of the control register */
632 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->ControlRegisters[ModRegRm.Register];
633
634 /* Return success */
635 return TRUE;
636 }
637
638 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg)
639 {
640 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
641 FAST486_MOD_REG_RM ModRegRm;
642
643 NO_LOCK_PREFIX();
644 TOGGLE_ADSIZE(AddressSize);
645
646 /* Get the operands */
647 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
648 {
649 /* Exception occurred */
650 return FALSE;
651 }
652
653 /* The current privilege level must be zero */
654 if (Fast486GetCurrentPrivLevel(State) != 0)
655 {
656 Fast486Exception(State, FAST486_EXCEPTION_GP);
657 return FALSE;
658 }
659
660 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
661 {
662 /* DR6 and DR7 are aliases to DR4 and DR5 */
663 ModRegRm.Register -= 2;
664 }
665
666 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
667 {
668 /* Disallow access to debug registers */
669 Fast486Exception(State, FAST486_EXCEPTION_GP);
670 return FALSE;
671 }
672
673 /* Store the value of the debug register */
674 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->DebugRegisters[ModRegRm.Register];
675
676 /* Return success */
677 return TRUE;
678 }
679
680 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
681 {
682 ULONG Value;
683 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
684 FAST486_MOD_REG_RM ModRegRm;
685
686 NO_LOCK_PREFIX();
687 TOGGLE_ADSIZE(AddressSize);
688
689 /* Get the operands */
690 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
691 {
692 /* Exception occurred */
693 return FALSE;
694 }
695
696 /* The current privilege level must be zero */
697 if (Fast486GetCurrentPrivLevel(State) != 0)
698 {
699 Fast486Exception(State, FAST486_EXCEPTION_GP);
700 return FALSE;
701 }
702
703 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
704 {
705 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
706 Fast486Exception(State, FAST486_EXCEPTION_UD);
707 return FALSE;
708 }
709
710 if (ModRegRm.Register != 0)
711 {
712 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
713 ModRegRm.Register--;
714 }
715
716 /* Get the value */
717 Value = State->GeneralRegs[ModRegRm.SecondRegister].Long;
718
719 if (ModRegRm.Register == (INT)FAST486_REG_CR0)
720 {
721 /* CR0 checks */
722
723 if (((Value & (FAST486_CR0_PG | FAST486_CR0_PE)) == FAST486_CR0_PG)
724 || ((Value & (FAST486_CR0_CD | FAST486_CR0_NW)) == FAST486_CR0_NW))
725 {
726 /* Invalid value */
727 Fast486Exception(State, FAST486_EXCEPTION_GP);
728 return FALSE;
729 }
730 }
731
732 /* Load a value to the control register */
733 State->ControlRegisters[ModRegRm.Register] = Value;
734
735 /* Return success */
736 return TRUE;
737 }
738
739 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg)
740 {
741 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
742 FAST486_MOD_REG_RM ModRegRm;
743
744 NO_LOCK_PREFIX();
745 TOGGLE_ADSIZE(AddressSize);
746
747 /* Get the operands */
748 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
749 {
750 /* Exception occurred */
751 return FALSE;
752 }
753
754 /* The current privilege level must be zero */
755 if (Fast486GetCurrentPrivLevel(State) != 0)
756 {
757 Fast486Exception(State, FAST486_EXCEPTION_GP);
758 return FALSE;
759 }
760
761 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
762 {
763 /* DR6 and DR7 are aliases to DR4 and DR5 */
764 ModRegRm.Register -= 2;
765 }
766
767 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
768 {
769 /* Disallow access to debug registers */
770 Fast486Exception(State, FAST486_EXCEPTION_GP);
771 return FALSE;
772 }
773
774 /* Load a value to the debug register */
775 State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long;
776
777 if (ModRegRm.Register == (INT)FAST486_REG_DR4)
778 {
779 /* The reserved bits are 1 */
780 State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED;
781 }
782 else if (ModRegRm.Register == (INT)FAST486_REG_DR5)
783 {
784 /* The reserved bits are 0 */
785 State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED;
786 }
787
788 /* Return success */
789 return TRUE;
790 }
791
792 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)
793 {
794 /* Call the internal API */
795 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
796 }
797
798 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
799 {
800 ULONG NewSelector;
801
802 if (!Fast486StackPop(State, &NewSelector))
803 {
804 /* Exception occurred */
805 return FALSE;
806 }
807
808 /* Call the internal API */
809 return Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
810 }
811
812 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)
813 {
814 BOOLEAN OperandSize, AddressSize;
815 FAST486_MOD_REG_RM ModRegRm;
816 UINT DataSize;
817 ULONG BitNumber;
818
819 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
820 TOGGLE_OPSIZE(OperandSize);
821 TOGGLE_ADSIZE(AddressSize);
822
823 /* Get the number of bits */
824 if (OperandSize) DataSize = 32;
825 else DataSize = 16;
826
827 /* Get the operands */
828 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
829 {
830 /* Exception occurred */
831 return FALSE;
832 }
833
834 /* Get the bit number */
835 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
836 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
837
838 if (ModRegRm.Memory)
839 {
840 /*
841 * For memory operands, add the bit offset divided by
842 * the data size to the address
843 */
844 ModRegRm.MemoryAddress += BitNumber / DataSize;
845 }
846
847 /* Normalize the bit number */
848 BitNumber %= DataSize;
849
850 if (OperandSize)
851 {
852 ULONG Value;
853
854 /* Read the value */
855 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
856 {
857 /* Exception occurred */
858 return FALSE;
859 }
860
861 /* Set CF to the bit value */
862 State->Flags.Cf = (Value >> BitNumber) & 1;
863 }
864 else
865 {
866 USHORT Value;
867
868 /* Read the value */
869 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
870 {
871 /* Exception occurred */
872 return FALSE;
873 }
874
875 /* Set CF to the bit value */
876 State->Flags.Cf = (Value >> BitNumber) & 1;
877 }
878
879 /* Return success */
880 return TRUE;
881 }
882
883 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld)
884 {
885 BOOLEAN OperandSize, AddressSize;
886 FAST486_MOD_REG_RM ModRegRm;
887 UCHAR Count;
888
889 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
890 TOGGLE_OPSIZE(OperandSize);
891 TOGGLE_ADSIZE(AddressSize);
892
893 /* Make sure this is the right instruction */
894 ASSERT((Opcode & 0xFE) == 0xA4);
895
896 /* Get the operands */
897 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
898 {
899 /* Exception occurred */
900 return FALSE;
901 }
902
903 if (Opcode == 0xA4)
904 {
905 /* Fetch the count */
906 if (!Fast486FetchByte(State, &Count))
907 {
908 /* Exception occurred */
909 return FALSE;
910 }
911 }
912 else
913 {
914 /* The count is in CL */
915 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
916 }
917
918 /* Normalize the count */
919 Count &= 0x1F;
920
921 /* Do nothing if the count is zero */
922 if (Count == 0) return TRUE;
923
924 if (OperandSize)
925 {
926 ULONG Source, Destination, Result;
927
928 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
929 {
930 /* Exception occurred */
931 return FALSE;
932 }
933
934 /* Calculate the result */
935 Result = (Destination << Count) | (Source >> (32 - Count));
936
937 /* Update flags */
938 State->Flags.Cf = (Destination >> (32 - Count)) & 1;
939 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
940 != (Destination & SIGN_FLAG_LONG);
941 State->Flags.Zf = (Result == 0);
942 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
943 State->Flags.Pf = Fast486CalculateParity(Result);
944
945 /* Write back the result */
946 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
947 }
948 else
949 {
950 USHORT Source, Destination, Result;
951 ULONG DoubleSource;
952
953 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
954 {
955 /* Exception occurred */
956 return FALSE;
957 }
958
959 DoubleSource = Source | (Source << 16);
960
961 /* Calculate the result */
962 Result = (Destination << Count) | (DoubleSource >> (32 - Count));
963
964 /* Update flags */
965 if (Count <= 16) State->Flags.Cf = (Destination >> (16 - Count)) & 1;
966 else State->Flags.Cf = (Source >> (32 - Count)) & 1;
967
968 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
969 != (Destination & SIGN_FLAG_WORD);
970 State->Flags.Zf = (Result == 0);
971 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
972 State->Flags.Pf = Fast486CalculateParity(Result);
973
974 /* Write back the result */
975 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
976 }
977 }
978
979 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
980 {
981 /* Call the internal API */
982 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
983 }
984
985 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
986 {
987 ULONG NewSelector;
988
989 if (!Fast486StackPop(State, &NewSelector))
990 {
991 /* Exception occurred */
992 return FALSE;
993 }
994
995 /* Call the internal API */
996 return Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
997 }
998
999 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
1000 {
1001 BOOLEAN OperandSize, AddressSize;
1002 FAST486_MOD_REG_RM ModRegRm;
1003 UINT DataSize;
1004 ULONG BitNumber;
1005
1006 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1007 TOGGLE_OPSIZE(OperandSize);
1008 TOGGLE_ADSIZE(AddressSize);
1009
1010 /* Get the number of bits */
1011 if (OperandSize) DataSize = 32;
1012 else DataSize = 16;
1013
1014 /* Get the operands */
1015 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1016 {
1017 /* Exception occurred */
1018 return FALSE;
1019 }
1020
1021 /* Get the bit number */
1022 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1023 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1024
1025 if (ModRegRm.Memory)
1026 {
1027 /*
1028 * For memory operands, add the bit offset divided by
1029 * the data size to the address
1030 */
1031 ModRegRm.MemoryAddress += BitNumber / DataSize;
1032 }
1033
1034 /* Normalize the bit number */
1035 BitNumber %= DataSize;
1036
1037 if (OperandSize)
1038 {
1039 ULONG Value;
1040
1041 /* Read the value */
1042 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1043 {
1044 /* Exception occurred */
1045 return FALSE;
1046 }
1047
1048 /* Set CF to the bit value */
1049 State->Flags.Cf = (Value >> BitNumber) & 1;
1050
1051 /* Set the bit */
1052 Value |= 1 << BitNumber;
1053
1054 /* Write back the result */
1055 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1056 {
1057 /* Exception occurred */
1058 return FALSE;
1059 }
1060 }
1061 else
1062 {
1063 USHORT Value;
1064
1065 /* Read the value */
1066 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1067 {
1068 /* Exception occurred */
1069 return FALSE;
1070 }
1071
1072 /* Set CF to the bit value */
1073 State->Flags.Cf = (Value >> BitNumber) & 1;
1074
1075 /* Set the bit */
1076 Value |= 1 << BitNumber;
1077
1078 /* Write back the result */
1079 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1080 {
1081 /* Exception occurred */
1082 return FALSE;
1083 }
1084 }
1085
1086 /* Return success */
1087 return TRUE;
1088 }
1089
1090 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd)
1091 {
1092 BOOLEAN OperandSize, AddressSize;
1093 FAST486_MOD_REG_RM ModRegRm;
1094 UCHAR Count;
1095
1096 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1097 TOGGLE_OPSIZE(OperandSize);
1098 TOGGLE_ADSIZE(AddressSize);
1099
1100 /* Make sure this is the right instruction */
1101 ASSERT((Opcode & 0xFE) == 0xAC);
1102
1103 /* Get the operands */
1104 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1105 {
1106 /* Exception occurred */
1107 return FALSE;
1108 }
1109
1110 if (Opcode == 0xAC)
1111 {
1112 /* Fetch the count */
1113 if (!Fast486FetchByte(State, &Count))
1114 {
1115 /* Exception occurred */
1116 return FALSE;
1117 }
1118 }
1119 else
1120 {
1121 /* The count is in CL */
1122 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
1123 }
1124
1125 /* Normalize the count */
1126 Count &= 0x1F;
1127
1128 /* Do nothing if the count is zero */
1129 if (Count == 0) return TRUE;
1130
1131 if (OperandSize)
1132 {
1133 ULONG Source, Destination, Result;
1134
1135 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1136 {
1137 /* Exception occurred */
1138 return FALSE;
1139 }
1140
1141 /* Calculate the result */
1142 Result = (Destination >> Count) | (Source << (32 - Count));
1143
1144 /* Update flags */
1145 State->Flags.Cf = (Destination >> (Count - 1)) & 1;
1146 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
1147 != (Destination & SIGN_FLAG_LONG);
1148 State->Flags.Zf = (Result == 0);
1149 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1150 State->Flags.Pf = Fast486CalculateParity(Result);
1151
1152 /* Write back the result */
1153 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1154 }
1155 else
1156 {
1157 USHORT Source, Destination, Result;
1158
1159 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1160 {
1161 /* Exception occurred */
1162 return FALSE;
1163 }
1164
1165 /* Calculate the result */
1166 Result = (Destination >> Count) | (Source << (16 - Count));
1167
1168 if (Count >= 16) Result |= (ULONG)(Source | (Source << 16)) >> (Count - 16);
1169
1170 /* Update flags */
1171 if (Count <= 16) State->Flags.Cf = (Destination >> (Count - 1)) & 1;
1172 else State->Flags.Cf = (Source >> (Count - 17)) & 1;
1173
1174 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
1175 != (Destination & SIGN_FLAG_WORD);
1176 State->Flags.Zf = (Result == 0);
1177 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1178 State->Flags.Pf = Fast486CalculateParity(Result);
1179
1180 /* Write back the result */
1181 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
1182 }
1183 }
1184
1185 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul)
1186 {
1187 BOOLEAN OperandSize, AddressSize;
1188 FAST486_MOD_REG_RM ModRegRm;
1189
1190 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1191
1192 TOGGLE_OPSIZE(OperandSize);
1193 TOGGLE_ADSIZE(AddressSize);
1194
1195 /* Get the operands */
1196 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1197 {
1198 /* Exception occurred */
1199 return FALSE;
1200 }
1201
1202 if (OperandSize)
1203 {
1204 LONG Source, Destination;
1205 LONGLONG Result;
1206
1207 /* Read the operands */
1208 if (!Fast486ReadModrmDwordOperands(State,
1209 &ModRegRm,
1210 (PULONG)&Destination,
1211 (PULONG)&Source))
1212 {
1213 /* Exception occurred */
1214 return FALSE;
1215 }
1216
1217 /* Calculate the result */
1218 Result = (LONGLONG)Source * (LONGLONG)Destination;
1219
1220 /* Update the flags */
1221 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
1222
1223 /* Write back the result */
1224 return Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Result));
1225 }
1226 else
1227 {
1228 SHORT Source, Destination;
1229 LONG Result;
1230
1231 /* Read the operands */
1232 if (!Fast486ReadModrmWordOperands(State,
1233 &ModRegRm,
1234 (PUSHORT)&Destination,
1235 (PUSHORT)&Source))
1236 {
1237 /* Exception occurred */
1238 return FALSE;
1239 }
1240
1241 /* Calculate the result */
1242 Result = (LONG)Source * (LONG)Destination;
1243
1244 /* Update the flags */
1245 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
1246
1247 /* Write back the result */
1248 return Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, (USHORT)((SHORT)Result));
1249 }
1250 }
1251
1252 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
1253 {
1254 FAST486_MOD_REG_RM ModRegRm;
1255 UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1256 UCHAR Source, Destination, Result;
1257 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1258
1259 TOGGLE_ADSIZE(AddressSize);
1260
1261 /* Get the operands */
1262 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1263 {
1264 /* Exception occurred */
1265 return FALSE;
1266 }
1267
1268 /* Read the operands */
1269 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
1270 {
1271 /* Exception occurred */
1272 return FALSE;
1273 }
1274
1275 /* Compare AL with the destination */
1276 Result = Accumulator - Destination;
1277
1278 /* Update the flags */
1279 State->Flags.Cf = (Accumulator < Destination);
1280 State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE))
1281 && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1282 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1283 State->Flags.Zf = (Result == 0);
1284 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1285 State->Flags.Pf = Fast486CalculateParity(Result);
1286
1287 if (State->Flags.Zf)
1288 {
1289 /* Load the source operand into the destination */
1290 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
1291 }
1292 else
1293 {
1294 /* Load the destination into AL */
1295 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
1296 }
1297
1298 /* Return success */
1299 return TRUE;
1300 }
1301
1302 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
1303 {
1304 FAST486_MOD_REG_RM ModRegRm;
1305 BOOLEAN OperandSize, AddressSize;
1306
1307 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1308
1309 TOGGLE_OPSIZE(OperandSize);
1310 TOGGLE_ADSIZE(AddressSize);
1311
1312 /* Get the operands */
1313 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1314 {
1315 /* Exception occurred */
1316 return FALSE;
1317 }
1318
1319 if (OperandSize)
1320 {
1321 ULONG Source, Destination, Result;
1322 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
1323
1324 /* Read the operands */
1325 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1326 {
1327 /* Exception occurred */
1328 return FALSE;
1329 }
1330
1331 /* Compare EAX with the destination */
1332 Result = Accumulator - Destination;
1333
1334 /* Update the flags */
1335 State->Flags.Cf = (Accumulator < Destination);
1336 State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG))
1337 && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1338 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1339 State->Flags.Zf = (Result == 0);
1340 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1341 State->Flags.Pf = Fast486CalculateParity(Result);
1342
1343 if (State->Flags.Zf)
1344 {
1345 /* Load the source operand into the destination */
1346 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
1347 }
1348 else
1349 {
1350 /* Load the destination into EAX */
1351 State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
1352 }
1353 }
1354 else
1355 {
1356 USHORT Source, Destination, Result;
1357 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1358
1359 /* Read the operands */
1360 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1361 {
1362 /* Exception occurred */
1363 return FALSE;
1364 }
1365
1366 /* Compare AX with the destination */
1367 Result = Accumulator - Destination;
1368
1369 /* Update the flags */
1370 State->Flags.Cf = (Accumulator < Destination);
1371 State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD))
1372 && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1373 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1374 State->Flags.Zf = (Result == 0);
1375 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1376 State->Flags.Pf = Fast486CalculateParity(Result);
1377
1378 if (State->Flags.Zf)
1379 {
1380 /* Load the source operand into the destination */
1381 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
1382 }
1383 else
1384 {
1385 /* Load the destination into AX */
1386 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
1387 }
1388 }
1389
1390 /* Return success */
1391 return TRUE;
1392 }
1393
1394 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss)
1395 {
1396 UCHAR FarPointer[6];
1397 BOOLEAN OperandSize, AddressSize;
1398 FAST486_MOD_REG_RM ModRegRm;
1399
1400 /* Make sure this is the right instruction */
1401 ASSERT(Opcode == 0xB2);
1402
1403 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1404
1405 TOGGLE_OPSIZE(OperandSize);
1406 TOGGLE_ADSIZE(AddressSize);
1407
1408 /* Get the operands */
1409 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1410 {
1411 /* Exception occurred */
1412 return FALSE;
1413 }
1414
1415 if (!ModRegRm.Memory)
1416 {
1417 /* Invalid */
1418 Fast486Exception(State, FAST486_EXCEPTION_UD);
1419 return FALSE;
1420 }
1421
1422 if (!Fast486ReadMemory(State,
1423 (State->PrefixFlags & FAST486_PREFIX_SEG)
1424 ? State->SegmentOverride : FAST486_REG_DS,
1425 ModRegRm.MemoryAddress,
1426 FALSE,
1427 FarPointer,
1428 OperandSize ? 6 : 4))
1429 {
1430 /* Exception occurred */
1431 return FALSE;
1432 }
1433
1434 if (OperandSize)
1435 {
1436 ULONG Offset = *((PULONG)FarPointer);
1437 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1438
1439 /* Set the register to the offset */
1440 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1441
1442 /* Load the segment */
1443 return Fast486LoadSegment(State,
1444 FAST486_REG_SS,
1445 Segment);
1446 }
1447 else
1448 {
1449 USHORT Offset = *((PUSHORT)FarPointer);
1450 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1451
1452 /* Set the register to the offset */
1453 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1454
1455 /* Load the segment */
1456 return Fast486LoadSegment(State,
1457 FAST486_REG_SS,
1458 Segment);
1459 }
1460 }
1461
1462 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
1463 {
1464 BOOLEAN OperandSize, AddressSize;
1465 FAST486_MOD_REG_RM ModRegRm;
1466 UINT DataSize;
1467 ULONG BitNumber;
1468
1469 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1470 TOGGLE_OPSIZE(OperandSize);
1471 TOGGLE_ADSIZE(AddressSize);
1472
1473 /* Get the number of bits */
1474 if (OperandSize) DataSize = 32;
1475 else DataSize = 16;
1476
1477 /* Get the operands */
1478 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1479 {
1480 /* Exception occurred */
1481 return FALSE;
1482 }
1483
1484 /* Get the bit number */
1485 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1486 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1487
1488 if (ModRegRm.Memory)
1489 {
1490 /*
1491 * For memory operands, add the bit offset divided by
1492 * the data size to the address
1493 */
1494 ModRegRm.MemoryAddress += BitNumber / DataSize;
1495 }
1496
1497 /* Normalize the bit number */
1498 BitNumber %= DataSize;
1499
1500 if (OperandSize)
1501 {
1502 ULONG Value;
1503
1504 /* Read the value */
1505 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1506 {
1507 /* Exception occurred */
1508 return FALSE;
1509 }
1510
1511 /* Set CF to the bit value */
1512 State->Flags.Cf = (Value >> BitNumber) & 1;
1513
1514 /* Clear the bit */
1515 Value &= ~(1 << BitNumber);
1516
1517 /* Write back the result */
1518 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1519 {
1520 /* Exception occurred */
1521 return FALSE;
1522 }
1523 }
1524 else
1525 {
1526 USHORT Value;
1527
1528 /* Read the value */
1529 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1530 {
1531 /* Exception occurred */
1532 return FALSE;
1533 }
1534
1535 /* Set CF to the bit value */
1536 State->Flags.Cf = (Value >> BitNumber) & 1;
1537
1538 /* Clear the bit */
1539 Value &= ~(1 << BitNumber);
1540
1541 /* Write back the result */
1542 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1543 {
1544 /* Exception occurred */
1545 return FALSE;
1546 }
1547 }
1548
1549 /* Return success */
1550 return TRUE;
1551 }
1552
1553 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs)
1554 {
1555 UCHAR FarPointer[6];
1556 BOOLEAN OperandSize, AddressSize;
1557 FAST486_MOD_REG_RM ModRegRm;
1558
1559 /* Make sure this is the right instruction */
1560 ASSERT((Opcode & 0xFE) == 0xB4);
1561
1562 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1563
1564 TOGGLE_OPSIZE(OperandSize);
1565 TOGGLE_ADSIZE(AddressSize);
1566
1567 /* Get the operands */
1568 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1569 {
1570 /* Exception occurred */
1571 return FALSE;
1572 }
1573
1574 if (!ModRegRm.Memory)
1575 {
1576 /* Invalid */
1577 Fast486Exception(State, FAST486_EXCEPTION_UD);
1578 return FALSE;
1579 }
1580
1581 if (!Fast486ReadMemory(State,
1582 (State->PrefixFlags & FAST486_PREFIX_SEG)
1583 ? State->SegmentOverride : FAST486_REG_DS,
1584 ModRegRm.MemoryAddress,
1585 FALSE,
1586 FarPointer,
1587 OperandSize ? 6 : 4))
1588 {
1589 /* Exception occurred */
1590 return FALSE;
1591 }
1592
1593 if (OperandSize)
1594 {
1595 ULONG Offset = *((PULONG)FarPointer);
1596 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1597
1598 /* Set the register to the offset */
1599 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1600
1601 /* Load the segment */
1602 return Fast486LoadSegment(State,
1603 (Opcode == 0xB4)
1604 ? FAST486_REG_FS : FAST486_REG_GS,
1605 Segment);
1606 }
1607 else
1608 {
1609 USHORT Offset = *((PUSHORT)FarPointer);
1610 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1611
1612 /* Set the register to the offset */
1613 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1614
1615 /* Load the segment */
1616 return Fast486LoadSegment(State,
1617 (Opcode == 0xB4)
1618 ? FAST486_REG_FS : FAST486_REG_GS,
1619 Segment);
1620 }
1621 }
1622
1623 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte)
1624 {
1625 UCHAR Value;
1626 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1627 FAST486_MOD_REG_RM ModRegRm;
1628
1629 TOGGLE_ADSIZE(AddressSize);
1630
1631 /* Make sure this is the right instruction */
1632 ASSERT(Opcode == 0xB6);
1633
1634 /* Get the operands */
1635 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1636 {
1637 /* Exception occurred */
1638 return FALSE;
1639 }
1640
1641 /* Read the operands */
1642 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1643 {
1644 /* Exception occurred */
1645 return FALSE;
1646 }
1647
1648 /* Write back the zero-extended value */
1649 return Fast486WriteModrmDwordOperands(State,
1650 &ModRegRm,
1651 TRUE,
1652 (ULONG)Value);
1653 }
1654
1655 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord)
1656 {
1657 USHORT Value;
1658 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1659 FAST486_MOD_REG_RM ModRegRm;
1660
1661 TOGGLE_ADSIZE(AddressSize);
1662
1663 /* Make sure this is the right instruction */
1664 ASSERT(Opcode == 0xB7);
1665
1666 /* Get the operands */
1667 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1668 {
1669 /* Exception occurred */
1670 return FALSE;
1671 }
1672
1673 /* Read the operands */
1674 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1675 {
1676 /* Exception occurred */
1677 return FALSE;
1678 }
1679
1680 /* Write back the zero-extended value */
1681 return Fast486WriteModrmDwordOperands(State,
1682 &ModRegRm,
1683 TRUE,
1684 (ULONG)Value);
1685 }
1686
1687 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
1688 {
1689 BOOLEAN OperandSize, AddressSize;
1690 FAST486_MOD_REG_RM ModRegRm;
1691 UINT DataSize;
1692 ULONG BitNumber;
1693
1694 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1695 TOGGLE_OPSIZE(OperandSize);
1696 TOGGLE_ADSIZE(AddressSize);
1697
1698 /* Get the number of bits */
1699 if (OperandSize) DataSize = 32;
1700 else DataSize = 16;
1701
1702 /* Get the operands */
1703 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1704 {
1705 /* Exception occurred */
1706 return FALSE;
1707 }
1708
1709 /* Get the bit number */
1710 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1711 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1712
1713 if (ModRegRm.Memory)
1714 {
1715 /*
1716 * For memory operands, add the bit offset divided by
1717 * the data size to the address
1718 */
1719 ModRegRm.MemoryAddress += BitNumber / DataSize;
1720 }
1721
1722 /* Normalize the bit number */
1723 BitNumber %= DataSize;
1724
1725 if (OperandSize)
1726 {
1727 ULONG Value;
1728
1729 /* Read the value */
1730 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1731 {
1732 /* Exception occurred */
1733 return FALSE;
1734 }
1735
1736 /* Set CF to the bit value */
1737 State->Flags.Cf = (Value >> BitNumber) & 1;
1738
1739 /* Toggle the bit */
1740 Value ^= 1 << BitNumber;
1741
1742 /* Write back the result */
1743 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1744 {
1745 /* Exception occurred */
1746 return FALSE;
1747 }
1748 }
1749 else
1750 {
1751 USHORT Value;
1752
1753 /* Read the value */
1754 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1755 {
1756 /* Exception occurred */
1757 return FALSE;
1758 }
1759
1760 /* Set CF to the bit value */
1761 State->Flags.Cf = (Value >> BitNumber) & 1;
1762
1763 /* Toggle the bit */
1764 Value ^= 1 << BitNumber;
1765
1766 /* Write back the result */
1767 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1768 {
1769 /* Exception occurred */
1770 return FALSE;
1771 }
1772 }
1773
1774 /* Return success */
1775 return TRUE;
1776 }
1777
1778 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf)
1779 {
1780 INT i;
1781 ULONG Value = 0;
1782 BOOLEAN OperandSize, AddressSize;
1783 FAST486_MOD_REG_RM ModRegRm;
1784 ULONG BitNumber;
1785 UINT DataSize;
1786
1787 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1788 TOGGLE_OPSIZE(OperandSize);
1789 TOGGLE_ADSIZE(AddressSize);
1790
1791 /* Make sure this is the right instruction */
1792 ASSERT(Opcode == 0xBC);
1793
1794 /* Get the number of bits */
1795 if (OperandSize) DataSize = 32;
1796 else DataSize = 16;
1797
1798 /* Get the operands */
1799 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1800 {
1801 /* Exception occurred */
1802 return FALSE;
1803 }
1804
1805 /* Read the value */
1806 if (OperandSize)
1807 {
1808 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1809 {
1810 /* Exception occurred */
1811 return FALSE;
1812 }
1813 }
1814 else
1815 {
1816 if (!Fast486ReadModrmWordOperands(State,
1817 &ModRegRm,
1818 (PUSHORT)NULL,
1819 (PUSHORT)&Value))
1820 {
1821 /* Exception occurred */
1822 return FALSE;
1823 }
1824 }
1825
1826 /* Set ZF */
1827 State->Flags.Zf = (Value == 0);
1828 if (State->Flags.Zf) return TRUE;
1829
1830 for (i = 0; i < DataSize; i++)
1831 {
1832 if(Value & (1 << i))
1833 {
1834 /* Save the bit number */
1835 BitNumber = i;
1836
1837 /* Exit the loop */
1838 break;
1839 }
1840 }
1841
1842 /* Write back the result */
1843 if (OperandSize)
1844 {
1845 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1846 {
1847 /* Exception occurred */
1848 return FALSE;
1849 }
1850 }
1851 else
1852 {
1853 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1854 {
1855 /* Exception occurred */
1856 return FALSE;
1857 }
1858 }
1859
1860 return TRUE;
1861 }
1862
1863 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr)
1864 {
1865 INT i;
1866 ULONG Value = 0;
1867 BOOLEAN OperandSize, AddressSize;
1868 FAST486_MOD_REG_RM ModRegRm;
1869 ULONG BitNumber;
1870 UINT DataSize;
1871
1872 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1873 TOGGLE_OPSIZE(OperandSize);
1874 TOGGLE_ADSIZE(AddressSize);
1875
1876 /* Make sure this is the right instruction */
1877 ASSERT(Opcode == 0xBD);
1878
1879 /* Get the number of bits */
1880 if (OperandSize) DataSize = 32;
1881 else DataSize = 16;
1882
1883 /* Get the operands */
1884 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1885 {
1886 /* Exception occurred */
1887 return FALSE;
1888 }
1889
1890 /* Read the value */
1891 if (OperandSize)
1892 {
1893 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1894 {
1895 /* Exception occurred */
1896 return FALSE;
1897 }
1898 }
1899 else
1900 {
1901 if (!Fast486ReadModrmWordOperands(State,
1902 &ModRegRm,
1903 (PUSHORT)NULL,
1904 (PUSHORT)&Value))
1905 {
1906 /* Exception occurred */
1907 return FALSE;
1908 }
1909 }
1910
1911 /* Set ZF according to the value */
1912 State->Flags.Zf = (Value == 0);
1913 if (State->Flags.Zf) return TRUE;
1914
1915 for (i = DataSize - 1; i >= 0; i--)
1916 {
1917 if(Value & (1 << i))
1918 {
1919 /* Save the bit number */
1920 BitNumber = i;
1921
1922 /* Exit the loop */
1923 break;
1924 }
1925 }
1926
1927 /* Write back the result */
1928 if (OperandSize)
1929 {
1930 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1931 {
1932 /* Exception occurred */
1933 return FALSE;
1934 }
1935 }
1936 else
1937 {
1938 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1939 {
1940 /* Exception occurred */
1941 return FALSE;
1942 }
1943 }
1944
1945 return TRUE;
1946 }
1947
1948 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte)
1949 {
1950 CHAR Value;
1951 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1952 FAST486_MOD_REG_RM ModRegRm;
1953
1954 TOGGLE_ADSIZE(AddressSize);
1955
1956 /* Make sure this is the right instruction */
1957 ASSERT(Opcode == 0xBE);
1958
1959 /* Get the operands */
1960 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1961 {
1962 /* Exception occurred */
1963 return FALSE;
1964 }
1965
1966 /* Read the operands */
1967 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, (PUCHAR)&Value))
1968 {
1969 /* Exception occurred */
1970 return FALSE;
1971 }
1972
1973 /* Write back the sign-extended value */
1974 return Fast486WriteModrmDwordOperands(State,
1975 &ModRegRm,
1976 TRUE,
1977 (ULONG)((LONG)Value));
1978 }
1979
1980 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)
1981 {
1982 SHORT Value;
1983 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1984 FAST486_MOD_REG_RM ModRegRm;
1985
1986 TOGGLE_ADSIZE(AddressSize);
1987
1988 /* Make sure this is the right instruction */
1989 ASSERT(Opcode == 0xBF);
1990
1991 /* Get the operands */
1992 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1993 {
1994 /* Exception occurred */
1995 return FALSE;
1996 }
1997
1998 /* Read the operands */
1999 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
2000 {
2001 /* Exception occurred */
2002 return FALSE;
2003 }
2004
2005 /* Write back the sign-extended value */
2006 return Fast486WriteModrmDwordOperands(State,
2007 &ModRegRm,
2008 TRUE,
2009 (ULONG)((LONG)Value));
2010 }
2011
2012 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
2013 {
2014 BOOLEAN Jump = FALSE;
2015 LONG Offset = 0;
2016 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2017
2018 TOGGLE_OPSIZE(Size);
2019 NO_LOCK_PREFIX();
2020
2021 /* Make sure this is the right instruction */
2022 ASSERT((Opcode & 0xF0) == 0x80);
2023
2024 /* Fetch the offset */
2025 if (Size)
2026 {
2027 if (!Fast486FetchDword(State, (PULONG)&Offset))
2028 {
2029 /* Exception occurred */
2030 return FALSE;
2031 }
2032 }
2033 else
2034 {
2035 SHORT Value;
2036
2037 if (!Fast486FetchWord(State, (PUSHORT)&Value))
2038 {
2039 /* Exception occurred */
2040 return FALSE;
2041 }
2042
2043 /* Sign-extend */
2044 Offset = (LONG)Value;
2045 }
2046
2047 switch ((Opcode & 0x0F) >> 1)
2048 {
2049 /* JO / JNO */
2050 case 0:
2051 {
2052 Jump = State->Flags.Of;
2053 break;
2054 }
2055
2056 /* JC / JNC */
2057 case 1:
2058 {
2059 Jump = State->Flags.Cf;
2060 break;
2061 }
2062
2063 /* JZ / JNZ */
2064 case 2:
2065 {
2066 Jump = State->Flags.Zf;
2067 break;
2068 }
2069
2070 /* JBE / JNBE */
2071 case 3:
2072 {
2073 Jump = State->Flags.Cf || State->Flags.Zf;
2074 break;
2075 }
2076
2077 /* JS / JNS */
2078 case 4:
2079 {
2080 Jump = State->Flags.Sf;
2081 break;
2082 }
2083
2084 /* JP / JNP */
2085 case 5:
2086 {
2087 Jump = State->Flags.Pf;
2088 break;
2089 }
2090
2091 /* JL / JNL */
2092 case 6:
2093 {
2094 Jump = State->Flags.Sf != State->Flags.Of;
2095 break;
2096 }
2097
2098 /* JLE / JNLE */
2099 case 7:
2100 {
2101 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
2102 break;
2103 }
2104 }
2105
2106 if (Opcode & 1)
2107 {
2108 /* Invert the result */
2109 Jump = !Jump;
2110 }
2111
2112 if (Jump)
2113 {
2114 /* Move the instruction pointer */
2115 State->InstPtr.Long += Offset;
2116 }
2117
2118 /* Return success */
2119 return TRUE;
2120 }
2121
2122 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
2123 {
2124 BOOLEAN Value = FALSE;
2125 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2126 FAST486_MOD_REG_RM ModRegRm;
2127
2128 TOGGLE_ADSIZE(AddressSize);
2129
2130 /* Get the operands */
2131 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2132 {
2133 /* Exception occurred */
2134 return FALSE;
2135 }
2136
2137 /* Make sure this is the right instruction */
2138 ASSERT((Opcode & 0xF0) == 0x90);
2139
2140 switch ((Opcode & 0x0F) >> 1)
2141 {
2142 /* SETO / SETNO */
2143 case 0:
2144 {
2145 Value = State->Flags.Of;
2146 break;
2147 }
2148
2149 /* SETC / SETNC */
2150 case 1:
2151 {
2152 Value = State->Flags.Cf;
2153 break;
2154 }
2155
2156 /* SETZ / SETNZ */
2157 case 2:
2158 {
2159 Value = State->Flags.Zf;
2160 break;
2161 }
2162
2163 /* SETBE / SETNBE */
2164 case 3:
2165 {
2166 Value = State->Flags.Cf || State->Flags.Zf;
2167 break;
2168 }
2169
2170 /* SETS / SETNS */
2171 case 4:
2172 {
2173 Value = State->Flags.Sf;
2174 break;
2175 }
2176
2177 /* SETP / SETNP */
2178 case 5:
2179 {
2180 Value = State->Flags.Pf;
2181 break;
2182 }
2183
2184 /* SETL / SETNL */
2185 case 6:
2186 {
2187 Value = State->Flags.Sf != State->Flags.Of;
2188 break;
2189 }
2190
2191 /* SETLE / SETNLE */
2192 case 7:
2193 {
2194 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
2195 break;
2196 }
2197 }
2198
2199 if (Opcode & 1)
2200 {
2201 /* Invert the result */
2202 Value = !Value;
2203 }
2204
2205 /* Write back the result */
2206 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
2207 }
2208
2209 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
2210 {
2211 UCHAR Source, Destination, Result;
2212 FAST486_MOD_REG_RM ModRegRm;
2213 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2214
2215 /* Make sure this is the right instruction */
2216 ASSERT(Opcode == 0xC0);
2217
2218 TOGGLE_ADSIZE(AddressSize);
2219
2220 /* Get the operands */
2221 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2222 {
2223 /* Exception occurred */
2224 return FALSE;
2225 }
2226
2227 if (!Fast486ReadModrmByteOperands(State,
2228 &ModRegRm,
2229 &Source,
2230 &Destination))
2231 {
2232 /* Exception occurred */
2233 return FALSE;
2234 }
2235
2236 /* Calculate the result */
2237 Result = Source + Destination;
2238
2239 /* Update the flags */
2240 State->Flags.Cf = (Result < Source) && (Result < Destination);
2241 State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE))
2242 && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2243 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2244 State->Flags.Zf = (Result == 0);
2245 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2246 State->Flags.Pf = Fast486CalculateParity(Result);
2247
2248 /* Write the sum to the destination */
2249 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
2250 {
2251 /* Exception occurred */
2252 return FALSE;
2253 }
2254
2255 /* Write the old value of the destination to the source */
2256 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination))
2257 {
2258 /* Exception occurred */
2259 return FALSE;
2260 }
2261
2262 return TRUE;
2263 }
2264
2265 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
2266 {
2267 FAST486_MOD_REG_RM ModRegRm;
2268 BOOLEAN OperandSize, AddressSize;
2269
2270 /* Make sure this is the right instruction */
2271 ASSERT(Opcode == 0xC1);
2272
2273 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2274
2275 TOGGLE_ADSIZE(AddressSize);
2276 TOGGLE_OPSIZE(OperandSize);
2277
2278 /* Get the operands */
2279 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2280 {
2281 /* Exception occurred */
2282 return FALSE;
2283 }
2284
2285 /* Check the operand size */
2286 if (OperandSize)
2287 {
2288 ULONG Source, Destination, Result;
2289
2290 if (!Fast486ReadModrmDwordOperands(State,
2291 &ModRegRm,
2292 &Source,
2293 &Destination))
2294 {
2295 /* Exception occurred */
2296 return FALSE;
2297 }
2298
2299 /* Calculate the result */
2300 Result = Source + Destination;
2301
2302 /* Update the flags */
2303 State->Flags.Cf = (Result < Source) && (Result < Destination);
2304 State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG))
2305 && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2306 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2307 State->Flags.Zf = (Result == 0);
2308 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2309 State->Flags.Pf = Fast486CalculateParity(Result);
2310
2311 /* Write the old value of the destination to the source */
2312 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
2313 {
2314 /* Exception occurred */
2315 return FALSE;
2316 }
2317
2318 /* Write the sum to the destination */
2319 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result))
2320 {
2321 /* Exception occurred */
2322 return FALSE;
2323 }
2324 }
2325 else
2326 {
2327 USHORT Source, Destination, Result;
2328
2329 if (!Fast486ReadModrmWordOperands(State,
2330 &ModRegRm,
2331 &Source,
2332 &Destination))
2333 {
2334 /* Exception occurred */
2335 return FALSE;
2336 }
2337
2338 /* Calculate the result */
2339 Result = Source + Destination;
2340
2341 /* Update the flags */
2342 State->Flags.Cf = (Result < Source) && (Result < Destination);
2343 State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD))
2344 && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2345 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2346 State->Flags.Zf = (Result == 0);
2347 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2348 State->Flags.Pf = Fast486CalculateParity(Result);
2349
2350 /* Write the old value of the destination to the source */
2351 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
2352 {
2353 /* Exception occurred */
2354 return FALSE;
2355 }
2356
2357 /* Write the sum to the destination */
2358 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result))
2359 {
2360 /* Exception occurred */
2361 return FALSE;
2362 }
2363 }
2364
2365 return TRUE;
2366 }
2367
2368 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
2369 {
2370 PUCHAR Pointer;
2371
2372 NO_LOCK_PREFIX();
2373
2374 /* Get a pointer to the value */
2375 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
2376
2377 /* Swap the byte order */
2378 SWAP(Pointer[0], Pointer[3]);
2379 SWAP(Pointer[1], Pointer[2]);
2380
2381 /* Return success */
2382 return TRUE;
2383 }
2384
2385 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
2386 {
2387 UCHAR SecondOpcode;
2388
2389 /* Fetch the second operation code */
2390 if (!Fast486FetchByte(State, &SecondOpcode))
2391 {
2392 /* Exception occurred */
2393 return FALSE;
2394 }
2395
2396 /* Call the extended opcode handler */
2397 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
2398 }
2399
2400 /* EOF */