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