Sync up to trunk head before merging.
[reactos.git] / lib / fast486 / common.inl
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * common.inl
4 *
5 * Copyright (C) 2013 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 #include "common.h"
23
24 /* PUBLIC FUNCTIONS ***********************************************************/
25
26 FORCEINLINE
27 INT
28 Fast486GetCurrentPrivLevel(PFAST486_STATE State)
29 {
30 /* Return the CPL, or 3 if we're in virtual 8086 mode */
31 return (!State->Flags.Vm) ? State->Cpl : 3;
32 }
33
34 FORCEINLINE
35 ULONG
36 Fast486GetPageTableEntry(PFAST486_STATE State,
37 ULONG VirtualAddress,
38 BOOLEAN MarkAsDirty)
39 {
40 ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress);
41 ULONG PteIndex = GET_ADDR_PTE(VirtualAddress);
42 FAST486_PAGE_DIR DirectoryEntry;
43 FAST486_PAGE_TABLE TableEntry;
44 ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3];
45
46 if ((State->Tlb != NULL)
47 && (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD))
48 {
49 /* Return the cached entry */
50 return State->Tlb[VirtualAddress >> 12];
51 }
52
53 /* Read the directory entry */
54 State->MemReadCallback(State,
55 PageDirectory + PdeIndex * sizeof(ULONG),
56 &DirectoryEntry.Value,
57 sizeof(DirectoryEntry));
58
59 /* Make sure it is present */
60 if (!DirectoryEntry.Present) return 0;
61
62 /* Was the directory entry accessed before? */
63 if (!DirectoryEntry.Accessed)
64 {
65 /* Well, it is now */
66 DirectoryEntry.Accessed = TRUE;
67
68 /* Write back the directory entry */
69 State->MemWriteCallback(State,
70 PageDirectory + PdeIndex * sizeof(ULONG),
71 &DirectoryEntry.Value,
72 sizeof(DirectoryEntry));
73 }
74
75 /* Read the table entry */
76 State->MemReadCallback(State,
77 (DirectoryEntry.TableAddress << 12)
78 + PteIndex * sizeof(ULONG),
79 &TableEntry.Value,
80 sizeof(TableEntry));
81
82 /* Make sure it is present */
83 if (!TableEntry.Present) return 0;
84
85 if (MarkAsDirty) TableEntry.Dirty = TRUE;
86
87 /* Was the table entry accessed before? */
88 if (!TableEntry.Accessed)
89 {
90 /* Well, it is now */
91 TableEntry.Accessed = TRUE;
92
93 /* Write back the table entry */
94 State->MemWriteCallback(State,
95 (DirectoryEntry.TableAddress << 12)
96 + PteIndex * sizeof(ULONG),
97 &TableEntry.Value,
98 sizeof(TableEntry));
99 }
100
101 /*
102 * The resulting permissions depend on the permissions
103 * in the page directory table too
104 */
105 TableEntry.Writeable &= DirectoryEntry.Writeable;
106 TableEntry.Usermode &= DirectoryEntry.Usermode;
107
108 if (State->Tlb != NULL)
109 {
110 /* Set the TLB entry */
111 State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
112 }
113
114 /* Return the table entry */
115 return TableEntry.Value;
116 }
117
118 FORCEINLINE
119 BOOLEAN
120 Fast486ReadLinearMemory(PFAST486_STATE State,
121 ULONG LinearAddress,
122 PVOID Buffer,
123 ULONG Size)
124 {
125 /* Check if paging is enabled */
126 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
127 {
128 ULONG Page;
129 FAST486_PAGE_TABLE TableEntry;
130 INT Cpl = Fast486GetCurrentPrivLevel(State);
131 ULONG BufferOffset = 0;
132
133 for (Page = PAGE_ALIGN(LinearAddress);
134 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
135 Page += PAGE_SIZE)
136 {
137 ULONG PageOffset = 0, PageLength = PAGE_SIZE;
138
139 /* Get the table entry */
140 TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
141
142 if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
143 {
144 /* Exception */
145 Fast486ExceptionWithErrorCode(State,
146 FAST486_EXCEPTION_PF,
147 TableEntry.Value & 0x07);
148 return FALSE;
149 }
150
151 /* Check if this is the first page */
152 if (Page == PAGE_ALIGN(LinearAddress))
153 {
154 /* Start reading from the offset from the beginning of the page */
155 PageOffset = PAGE_OFFSET(LinearAddress);
156 PageLength -= PageOffset;
157 }
158
159 /* Check if this is the last page */
160 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
161 {
162 /* Read only a part of the page */
163 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
164 }
165
166 /* Read the memory */
167 State->MemReadCallback(State,
168 (TableEntry.Address << 12) | PageOffset,
169 (PVOID)((ULONG_PTR)Buffer + BufferOffset),
170 PageLength);
171
172 BufferOffset += PageLength;
173 }
174 }
175 else
176 {
177 /* Read the memory */
178 State->MemReadCallback(State, LinearAddress, Buffer, Size);
179 }
180
181 return TRUE;
182 }
183
184 FORCEINLINE
185 BOOLEAN
186 Fast486WriteLinearMemory(PFAST486_STATE State,
187 ULONG LinearAddress,
188 PVOID Buffer,
189 ULONG Size)
190 {
191 /* Check if paging is enabled */
192 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
193 {
194 ULONG Page;
195 FAST486_PAGE_TABLE TableEntry;
196 INT Cpl = Fast486GetCurrentPrivLevel(State);
197 ULONG BufferOffset = 0;
198
199 for (Page = PAGE_ALIGN(LinearAddress);
200 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
201 Page += PAGE_SIZE)
202 {
203 ULONG PageOffset = 0, PageLength = PAGE_SIZE;
204
205 /* Get the table entry */
206 TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
207
208 if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
209 || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
210 && !TableEntry.Writeable))
211 {
212 /* Exception */
213 Fast486ExceptionWithErrorCode(State,
214 FAST486_EXCEPTION_PF,
215 TableEntry.Value & 0x07);
216 return FALSE;
217 }
218
219 /* Check if this is the first page */
220 if (Page == PAGE_ALIGN(LinearAddress))
221 {
222 /* Start writing from the offset from the beginning of the page */
223 PageOffset = PAGE_OFFSET(LinearAddress);
224 PageLength -= PageOffset;
225 }
226
227 /* Check if this is the last page */
228 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
229 {
230 /* Write only a part of the page */
231 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
232 }
233
234 /* Write the memory */
235 State->MemWriteCallback(State,
236 (TableEntry.Address << 12) | PageOffset,
237 (PVOID)((ULONG_PTR)Buffer + BufferOffset),
238 PageLength);
239
240 BufferOffset += PageLength;
241 }
242 }
243 else
244 {
245 /* Write the memory */
246 State->MemWriteCallback(State, LinearAddress, Buffer, Size);
247 }
248
249 return TRUE;
250 }
251
252 FORCEINLINE
253 VOID
254 Fast486Exception(PFAST486_STATE State,
255 FAST486_EXCEPTIONS ExceptionCode)
256 {
257 /* Call the internal function */
258 Fast486ExceptionWithErrorCode(State, ExceptionCode, 0);
259 }
260
261 FORCEINLINE
262 BOOLEAN
263 Fast486StackPush(PFAST486_STATE State,
264 ULONG Value)
265 {
266 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
267
268 /* The OPSIZE prefix toggles the size */
269 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
270
271 if (Size)
272 {
273 /* 32-bit size */
274
275 /* Check if ESP is between 1 and 3 */
276 if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
277 && State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
278 {
279 Fast486Exception(State, FAST486_EXCEPTION_SS);
280 return FALSE;
281 }
282
283 /* Subtract ESP by 4 */
284 State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
285
286 /* Store the value in SS:ESP */
287 return Fast486WriteMemory(State,
288 FAST486_REG_SS,
289 State->GeneralRegs[FAST486_REG_ESP].Long,
290 &Value,
291 sizeof(ULONG));
292 }
293 else
294 {
295 /* 16-bit size */
296 USHORT ShortValue = LOWORD(Value);
297
298 /* Check if SP is 1 */
299 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1)
300 {
301 Fast486Exception(State, FAST486_EXCEPTION_SS);
302 return FALSE;
303 }
304
305 /* Subtract SP by 2 */
306 State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
307
308 /* Store the value in SS:SP */
309 return Fast486WriteMemory(State,
310 FAST486_REG_SS,
311 State->GeneralRegs[FAST486_REG_ESP].LowWord,
312 &ShortValue,
313 sizeof(USHORT));
314 }
315 }
316
317 FORCEINLINE
318 BOOLEAN
319 Fast486StackPop(PFAST486_STATE State,
320 PULONG Value)
321 {
322 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
323
324 /* The OPSIZE prefix toggles the size */
325 TOGGLE_OPSIZE(Size);
326
327 if (Size)
328 {
329 /* 32-bit size */
330 ULONG LongValue;
331
332 /* Check if ESP is 0xFFFFFFFF */
333 if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
334 {
335 Fast486Exception(State, FAST486_EXCEPTION_SS);
336 return FALSE;
337 }
338
339 /* Read the value from SS:ESP */
340 if (!Fast486ReadMemory(State,
341 FAST486_REG_SS,
342 State->GeneralRegs[FAST486_REG_ESP].Long,
343 FALSE,
344 &LongValue,
345 sizeof(LongValue)))
346 {
347 /* An exception occurred */
348 return FALSE;
349 }
350
351 /* Increment ESP by 4 */
352 State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(ULONG);
353
354 /* Store the value in the result */
355 *Value = LongValue;
356 }
357 else
358 {
359 /* 16-bit size */
360 USHORT ShortValue;
361
362 /* Check if SP is 0xFFFF */
363 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
364 {
365 Fast486Exception(State, FAST486_EXCEPTION_SS);
366 return FALSE;
367 }
368
369 /* Read the value from SS:SP */
370 if (!Fast486ReadMemory(State,
371 FAST486_REG_SS,
372 State->GeneralRegs[FAST486_REG_ESP].LowWord,
373 FALSE,
374 &ShortValue,
375 sizeof(ShortValue)))
376 {
377 /* An exception occurred */
378 return FALSE;
379 }
380
381 /* Increment SP by 2 */
382 State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(USHORT);
383
384 /* Store the value in the result */
385 *Value = ShortValue;
386 }
387
388 return TRUE;
389 }
390
391 FORCEINLINE
392 BOOLEAN
393 Fast486LoadSegment(PFAST486_STATE State,
394 FAST486_SEG_REGS Segment,
395 USHORT Selector)
396 {
397 PFAST486_SEG_REG CachedDescriptor;
398 FAST486_GDT_ENTRY GdtEntry;
399
400 ASSERT(Segment < FAST486_NUM_SEG_REGS);
401
402 /* Get the cached descriptor */
403 CachedDescriptor = &State->SegmentRegs[Segment];
404
405 /* Check for protected mode */
406 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
407 {
408 if (!(Selector & SEGMENT_TABLE_INDICATOR))
409 {
410 /* Make sure the GDT contains the entry */
411 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
412 {
413 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
414 return FALSE;
415 }
416
417 /* Read the GDT */
418 if (!Fast486ReadLinearMemory(State,
419 State->Gdtr.Address
420 + GET_SEGMENT_INDEX(Selector),
421 &GdtEntry,
422 sizeof(GdtEntry)))
423 {
424 /* Exception occurred */
425 return FALSE;
426 }
427 }
428 else
429 {
430 /* Make sure the LDT contains the entry */
431 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
432 {
433 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
434 return FALSE;
435 }
436
437 /* Read the LDT */
438 if (!Fast486ReadLinearMemory(State,
439 State->Ldtr.Base
440 + GET_SEGMENT_INDEX(Selector),
441 &GdtEntry,
442 sizeof(GdtEntry)))
443 {
444 /* Exception occurred */
445 return FALSE;
446 }
447 }
448
449 if (Segment == FAST486_REG_SS)
450 {
451 /* Loading the stack segment */
452
453 if (GET_SEGMENT_INDEX(Selector) == 0)
454 {
455 Fast486Exception(State, FAST486_EXCEPTION_GP);
456 return FALSE;
457 }
458
459 if (!GdtEntry.SystemType)
460 {
461 /* This is a special descriptor */
462 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
463 return FALSE;
464 }
465
466 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
467 {
468 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
469 return FALSE;
470 }
471
472 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
473 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
474 {
475 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
476 return FALSE;
477 }
478
479 if (!GdtEntry.Present)
480 {
481 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector);
482 return FALSE;
483 }
484 }
485 else if (Segment == FAST486_REG_CS)
486 {
487 /* Loading the code segment */
488
489 if (GET_SEGMENT_INDEX(Selector) == 0)
490 {
491 Fast486Exception(State, FAST486_EXCEPTION_GP);
492 return FALSE;
493 }
494
495 if (!GdtEntry.SystemType)
496 {
497 // TODO: Call/interrupt/task gates NOT IMPLEMENTED!
498 UNIMPLEMENTED;
499 }
500 else
501 {
502 if (!GdtEntry.Present)
503 {
504 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
505 return FALSE;
506 }
507
508 if (!GdtEntry.Executable)
509 {
510 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
511 return FALSE;
512 }
513
514 if (GdtEntry.DirConf)
515 {
516 /* Conforming Code Segment */
517
518 if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
519 {
520 /* Must be accessed from lower-privileged code */
521 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
522 return FALSE;
523 }
524 }
525 else
526 {
527 /* Regular code segment */
528
529 if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
530 || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
531 {
532 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
533 return FALSE;
534 }
535 }
536
537 /* Update CPL */
538 State->Cpl = GET_SEGMENT_RPL(Selector);
539 }
540 }
541 else
542 {
543 /* Loading a data segment */
544
545 if (!GdtEntry.SystemType)
546 {
547 /* This is a special descriptor */
548 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
549 return FALSE;
550 }
551
552 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
553 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
554 {
555 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
556 return FALSE;
557 }
558
559 if (!GdtEntry.Present)
560 {
561 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
562 return FALSE;
563 }
564 }
565
566 /* Update the cache entry */
567 CachedDescriptor->Selector = Selector;
568 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
569 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
570 CachedDescriptor->Accessed = GdtEntry.Accessed;
571 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
572 CachedDescriptor->DirConf = GdtEntry.DirConf;
573 CachedDescriptor->Executable = GdtEntry.Executable;
574 CachedDescriptor->SystemType = GdtEntry.SystemType;
575 CachedDescriptor->Dpl = GdtEntry.Dpl;
576 CachedDescriptor->Present = GdtEntry.Present;
577 CachedDescriptor->Size = GdtEntry.Size;
578
579 /* Check for page granularity */
580 if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
581 }
582 else
583 {
584 /* Update the selector and base */
585 CachedDescriptor->Selector = Selector;
586 CachedDescriptor->Base = Selector << 4;
587 }
588
589 return TRUE;
590 }
591
592 FORCEINLINE
593 BOOLEAN
594 Fast486FetchByte(PFAST486_STATE State,
595 PUCHAR Data)
596 {
597 PFAST486_SEG_REG CachedDescriptor;
598
599 /* Get the cached descriptor of CS */
600 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
601
602 /* Read from memory */
603 if (!Fast486ReadMemory(State,
604 FAST486_REG_CS,
605 (CachedDescriptor->Size) ? State->InstPtr.Long
606 : State->InstPtr.LowWord,
607 TRUE,
608 Data,
609 sizeof(UCHAR)))
610 {
611 /* Exception occurred during instruction fetch */
612 return FALSE;
613 }
614
615 /* Advance the instruction pointer */
616 if (CachedDescriptor->Size) State->InstPtr.Long++;
617 else State->InstPtr.LowWord++;
618
619 return TRUE;
620 }
621
622 FORCEINLINE
623 BOOLEAN
624 Fast486FetchWord(PFAST486_STATE State,
625 PUSHORT Data)
626 {
627 PFAST486_SEG_REG CachedDescriptor;
628
629 /* Get the cached descriptor of CS */
630 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
631
632 /* Read from memory */
633 // FIXME: Fix byte order on big-endian machines
634 if (!Fast486ReadMemory(State,
635 FAST486_REG_CS,
636 (CachedDescriptor->Size) ? State->InstPtr.Long
637 : State->InstPtr.LowWord,
638 TRUE,
639 Data,
640 sizeof(USHORT)))
641 {
642 /* Exception occurred during instruction fetch */
643 return FALSE;
644 }
645
646 /* Advance the instruction pointer */
647 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
648 else State->InstPtr.LowWord += sizeof(USHORT);
649
650 return TRUE;
651 }
652
653 FORCEINLINE
654 BOOLEAN
655 Fast486FetchDword(PFAST486_STATE State,
656 PULONG Data)
657 {
658 PFAST486_SEG_REG CachedDescriptor;
659
660 /* Get the cached descriptor of CS */
661 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
662
663 /* Read from memory */
664 // FIXME: Fix byte order on big-endian machines
665 if (!Fast486ReadMemory(State,
666 FAST486_REG_CS,
667 (CachedDescriptor->Size) ? State->InstPtr.Long
668 : State->InstPtr.LowWord,
669 TRUE,
670 Data,
671 sizeof(ULONG)))
672 {
673 /* Exception occurred during instruction fetch */
674 return FALSE;
675 }
676
677 /* Advance the instruction pointer */
678 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
679 else State->InstPtr.LowWord += sizeof(ULONG);
680
681 return TRUE;
682 }
683
684 FORCEINLINE
685 BOOLEAN
686 Fast486GetIntVector(PFAST486_STATE State,
687 UCHAR Number,
688 PFAST486_IDT_ENTRY IdtEntry)
689 {
690 ULONG FarPointer;
691
692 /* Check for protected mode */
693 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
694 {
695 /* Read from the IDT */
696 if (!Fast486ReadLinearMemory(State,
697 State->Idtr.Address
698 + Number * sizeof(*IdtEntry),
699 IdtEntry,
700 sizeof(*IdtEntry)))
701 {
702 /* Exception occurred */
703 return FALSE;
704 }
705 }
706 else
707 {
708 /* Read from the real-mode IVT */
709
710 /* Paging is always disabled in real mode */
711 State->MemReadCallback(State,
712 State->Idtr.Address
713 + Number * sizeof(FarPointer),
714 &FarPointer,
715 sizeof(FarPointer));
716
717 /* Fill a fake IDT entry */
718 IdtEntry->Offset = LOWORD(FarPointer);
719 IdtEntry->Selector = HIWORD(FarPointer);
720 IdtEntry->Zero = 0;
721 IdtEntry->Type = FAST486_IDT_INT_GATE;
722 IdtEntry->Storage = FALSE;
723 IdtEntry->Dpl = 0;
724 IdtEntry->Present = TRUE;
725 IdtEntry->OffsetHigh = 0;
726 }
727
728 return TRUE;
729 }
730
731 FORCEINLINE
732 BOOLEAN
733 Fast486CalculateParity(UCHAR Number)
734 {
735 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
736 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
737 }
738
739 FORCEINLINE
740 BOOLEAN
741 Fast486ParseModRegRm(PFAST486_STATE State,
742 BOOLEAN AddressSize,
743 PFAST486_MOD_REG_RM ModRegRm)
744 {
745 UCHAR ModRmByte, Mode, RegMem;
746
747 /* Fetch the MOD REG R/M byte */
748 if (!Fast486FetchByte(State, &ModRmByte))
749 {
750 /* Exception occurred */
751 return FALSE;
752 }
753
754 /* Unpack the mode and R/M */
755 Mode = ModRmByte >> 6;
756 RegMem = ModRmByte & 0x07;
757
758 /* Set the register operand */
759 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
760
761 /* Check the mode */
762 if ((ModRmByte >> 6) == 3)
763 {
764 /* The second operand is also a register */
765 ModRegRm->Memory = FALSE;
766 ModRegRm->SecondRegister = RegMem;
767
768 /* Done parsing */
769 return TRUE;
770 }
771
772 /* The second operand is memory */
773 ModRegRm->Memory = TRUE;
774
775 if (AddressSize)
776 {
777 if (RegMem == FAST486_REG_ESP)
778 {
779 UCHAR SibByte;
780 ULONG Scale, Index, Base;
781
782 /* Fetch the SIB byte */
783 if (!Fast486FetchByte(State, &SibByte))
784 {
785 /* Exception occurred */
786 return FALSE;
787 }
788
789 /* Unpack the scale, index and base */
790 Scale = 1 << (SibByte >> 6);
791 Index = (SibByte >> 3) & 0x07;
792 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
793 else Index = 0;
794
795 if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0))
796 {
797 /* Use the register a base */
798 Base = State->GeneralRegs[SibByte & 0x07].Long;
799 }
800 else
801 {
802 /* Fetch the base */
803 if (!Fast486FetchDword(State, &Base))
804 {
805 /* Exception occurred */
806 return FALSE;
807 }
808 }
809
810 if ((SibByte & 0x07) == FAST486_REG_ESP)
811 {
812 /* Check if there is no segment override */
813 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
814 {
815 /* Add a SS: prefix */
816 State->PrefixFlags |= FAST486_PREFIX_SEG;
817 State->SegmentOverride = FAST486_REG_SS;
818 }
819 }
820
821 /* Calculate the address */
822 ModRegRm->MemoryAddress = Base + Index * Scale;
823 }
824 else if (RegMem == FAST486_REG_EBP)
825 {
826 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
827 else ModRegRm->MemoryAddress = 0;
828 }
829 else
830 {
831 /* Get the base from the register */
832 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
833 }
834
835 /* Check if there is no segment override */
836 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
837 {
838 /* Check if the default segment should be SS */
839 if ((RegMem == FAST486_REG_EBP) && Mode)
840 {
841 /* Add a SS: prefix */
842 State->PrefixFlags |= FAST486_PREFIX_SEG;
843 State->SegmentOverride = FAST486_REG_SS;
844 }
845 }
846
847 if (Mode == 1)
848 {
849 CHAR Offset;
850
851 /* Fetch the byte */
852 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
853 {
854 /* Exception occurred */
855 return FALSE;
856 }
857
858 /* Add the signed offset to the address */
859 ModRegRm->MemoryAddress += (LONG)Offset;
860 }
861 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
862 {
863 LONG Offset;
864
865 /* Fetch the dword */
866 if (!Fast486FetchDword(State, (PULONG)&Offset))
867 {
868 /* Exception occurred */
869 return FALSE;
870 }
871
872 /* Add the signed offset to the address */
873 ModRegRm->MemoryAddress += Offset;
874 }
875 }
876 else
877 {
878 /* Check the operand */
879 switch (RegMem)
880 {
881 case 0:
882 {
883 /* [BX + SI] */
884 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
885 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
886
887 break;
888 }
889
890 case 1:
891 {
892 /* [BX + DI] */
893 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
894 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
895
896 break;
897 }
898
899 case 2:
900 {
901 /* SS:[BP + SI] */
902 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
903 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
904
905 break;
906 }
907
908 case 3:
909 {
910 /* SS:[BP + DI] */
911 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
912 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
913
914 break;
915 }
916
917 case 4:
918 {
919 /* [SI] */
920 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
921
922 break;
923 }
924
925 case 5:
926 {
927 /* [DI] */
928 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
929
930 break;
931 }
932
933 case 6:
934 {
935 if (Mode)
936 {
937 /* [BP] */
938 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
939 }
940 else
941 {
942 /* [constant] (added later) */
943 ModRegRm->MemoryAddress = 0;
944 }
945
946 break;
947 }
948
949 case 7:
950 {
951 /* [BX] */
952 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
953
954 break;
955 }
956 }
957
958 /* Check if there is no segment override */
959 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
960 {
961 /* Check if the default segment should be SS */
962 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
963 {
964 /* Add a SS: prefix */
965 State->PrefixFlags |= FAST486_PREFIX_SEG;
966 State->SegmentOverride = FAST486_REG_SS;
967 }
968 }
969
970 if (Mode == 1)
971 {
972 CHAR Offset;
973
974 /* Fetch the byte */
975 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
976 {
977 /* Exception occurred */
978 return FALSE;
979 }
980
981 /* Add the signed offset to the address */
982 ModRegRm->MemoryAddress += (LONG)Offset;
983 }
984 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
985 {
986 SHORT Offset;
987
988 /* Fetch the word */
989 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
990 {
991 /* Exception occurred */
992 return FALSE;
993 }
994
995 /* Add the signed offset to the address */
996 ModRegRm->MemoryAddress += (LONG)Offset;
997 }
998
999 /* Clear the top 16 bits */
1000 ModRegRm->MemoryAddress &= 0x0000FFFF;
1001 }
1002
1003 return TRUE;
1004 }
1005
1006 FORCEINLINE
1007 BOOLEAN
1008 Fast486ReadModrmByteOperands(PFAST486_STATE State,
1009 PFAST486_MOD_REG_RM ModRegRm,
1010 PUCHAR RegValue,
1011 PUCHAR RmValue)
1012 {
1013 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1014
1015 if (RegValue)
1016 {
1017 /* Get the register value */
1018 if (ModRegRm->Register & 0x04)
1019 {
1020 /* AH, CH, DH, BH */
1021 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
1022 }
1023 else
1024 {
1025 /* AL, CL, DL, BL */
1026 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
1027 }
1028 }
1029
1030 if (RmValue)
1031 {
1032 if (!ModRegRm->Memory)
1033 {
1034 /* Get the second register value */
1035 if (ModRegRm->SecondRegister & 0x04)
1036 {
1037 /* AH, CH, DH, BH */
1038 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
1039 }
1040 else
1041 {
1042 /* AL, CL, DL, BL */
1043 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
1044 }
1045 }
1046 else
1047 {
1048 /* Check for the segment override */
1049 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1050 {
1051 /* Use the override segment instead */
1052 Segment = State->SegmentOverride;
1053 }
1054
1055 /* Read memory */
1056 if (!Fast486ReadMemory(State,
1057 Segment,
1058 ModRegRm->MemoryAddress,
1059 FALSE,
1060 RmValue,
1061 sizeof(UCHAR)))
1062 {
1063 /* Exception occurred */
1064 return FALSE;
1065 }
1066 }
1067 }
1068
1069 return TRUE;
1070 }
1071
1072 FORCEINLINE
1073 BOOLEAN
1074 Fast486ReadModrmWordOperands(PFAST486_STATE State,
1075 PFAST486_MOD_REG_RM ModRegRm,
1076 PUSHORT RegValue,
1077 PUSHORT RmValue)
1078 {
1079 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1080
1081 if (RegValue)
1082 {
1083 /* Get the register value */
1084 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
1085 }
1086
1087 if (RmValue)
1088 {
1089 if (!ModRegRm->Memory)
1090 {
1091 /* Get the second register value */
1092 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
1093 }
1094 else
1095 {
1096 /* Check for the segment override */
1097 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1098 {
1099 /* Use the override segment instead */
1100 Segment = State->SegmentOverride;
1101 }
1102
1103 /* Read memory */
1104 if (!Fast486ReadMemory(State,
1105 Segment,
1106 ModRegRm->MemoryAddress,
1107 FALSE,
1108 RmValue,
1109 sizeof(USHORT)))
1110 {
1111 /* Exception occurred */
1112 return FALSE;
1113 }
1114 }
1115 }
1116
1117 return TRUE;
1118 }
1119
1120 FORCEINLINE
1121 BOOLEAN
1122 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
1123 PFAST486_MOD_REG_RM ModRegRm,
1124 PULONG RegValue,
1125 PULONG RmValue)
1126 {
1127 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1128
1129 if (RegValue)
1130 {
1131 /* Get the register value */
1132 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
1133 }
1134
1135 if (RmValue)
1136 {
1137 if (!ModRegRm->Memory)
1138 {
1139 /* Get the second register value */
1140 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
1141 }
1142 else
1143 {
1144 /* Check for the segment override */
1145 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1146 {
1147 /* Use the override segment instead */
1148 Segment = State->SegmentOverride;
1149 }
1150
1151 /* Read memory */
1152 if (!Fast486ReadMemory(State,
1153 Segment,
1154 ModRegRm->MemoryAddress,
1155 FALSE,
1156 RmValue,
1157 sizeof(ULONG)))
1158 {
1159 /* Exception occurred */
1160 return FALSE;
1161 }
1162 }
1163 }
1164
1165 return TRUE;
1166 }
1167
1168 FORCEINLINE
1169 BOOLEAN
1170 Fast486WriteModrmByteOperands(PFAST486_STATE State,
1171 PFAST486_MOD_REG_RM ModRegRm,
1172 BOOLEAN WriteRegister,
1173 UCHAR Value)
1174 {
1175 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1176
1177 if (WriteRegister)
1178 {
1179 /* Store the value in the register */
1180 if (ModRegRm->Register & 0x04)
1181 {
1182 /* AH, CH, DH, BH */
1183 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
1184 }
1185 else
1186 {
1187 /* AL, CL, DL, BL */
1188 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
1189 }
1190 }
1191 else
1192 {
1193 if (!ModRegRm->Memory)
1194 {
1195 /* Store the value in the second register */
1196 if (ModRegRm->SecondRegister & 0x04)
1197 {
1198 /* AH, CH, DH, BH */
1199 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
1200 }
1201 else
1202 {
1203 /* AL, CL, DL, BL */
1204 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
1205 }
1206 }
1207 else
1208 {
1209 /* Check for the segment override */
1210 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1211 {
1212 /* Use the override segment instead */
1213 Segment = State->SegmentOverride;
1214 }
1215
1216 /* Write memory */
1217 if (!Fast486WriteMemory(State,
1218 Segment,
1219 ModRegRm->MemoryAddress,
1220 &Value,
1221 sizeof(UCHAR)))
1222 {
1223 /* Exception occurred */
1224 return FALSE;
1225 }
1226 }
1227 }
1228
1229 return TRUE;
1230 }
1231
1232 FORCEINLINE
1233 BOOLEAN
1234 Fast486WriteModrmWordOperands(PFAST486_STATE State,
1235 PFAST486_MOD_REG_RM ModRegRm,
1236 BOOLEAN WriteRegister,
1237 USHORT Value)
1238 {
1239 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1240
1241 if (WriteRegister)
1242 {
1243 /* Store the value in the register */
1244 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
1245 }
1246 else
1247 {
1248 if (!ModRegRm->Memory)
1249 {
1250 /* Store the value in the second register */
1251 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
1252 }
1253 else
1254 {
1255 /* Check for the segment override */
1256 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1257 {
1258 /* Use the override segment instead */
1259 Segment = State->SegmentOverride;
1260 }
1261
1262 /* Write memory */
1263 if (!Fast486WriteMemory(State,
1264 Segment,
1265 ModRegRm->MemoryAddress,
1266 &Value,
1267 sizeof(USHORT)))
1268 {
1269 /* Exception occurred */
1270 return FALSE;
1271 }
1272 }
1273 }
1274
1275 return TRUE;
1276 }
1277
1278 FORCEINLINE
1279 BOOLEAN
1280 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
1281 PFAST486_MOD_REG_RM ModRegRm,
1282 BOOLEAN WriteRegister,
1283 ULONG Value)
1284 {
1285 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1286
1287 if (WriteRegister)
1288 {
1289 /* Store the value in the register */
1290 State->GeneralRegs[ModRegRm->Register].Long = Value;
1291 }
1292 else
1293 {
1294 if (!ModRegRm->Memory)
1295 {
1296 /* Store the value in the second register */
1297 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
1298 }
1299 else
1300 {
1301 /* Check for the segment override */
1302 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1303 {
1304 /* Use the override segment instead */
1305 Segment = State->SegmentOverride;
1306 }
1307
1308 /* Write memory */
1309 if (!Fast486WriteMemory(State,
1310 Segment,
1311 ModRegRm->MemoryAddress,
1312 &Value,
1313 sizeof(ULONG)))
1314 {
1315 /* Exception occurred */
1316 return FALSE;
1317 }
1318 }
1319 }
1320
1321 return TRUE;
1322 }
1323
1324 /* EOF */