[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 /* Make sure the GDT contains the entry */
403 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
404 {
405 Fast486Exception(State, FAST486_EXCEPTION_GP);
406 return FALSE;
407 }
408
409 /* Read the GDT */
410 if (!Fast486ReadLinearMemory(State,
411 State->Gdtr.Address
412 + GET_SEGMENT_INDEX(Selector),
413 &GdtEntry,
414 sizeof(GdtEntry)))
415 {
416 /* Exception occurred */
417 return FALSE;
418 }
419
420 if (Segment == FAST486_REG_SS)
421 {
422 /* Loading the stack segment */
423
424 if (GET_SEGMENT_INDEX(Selector) == 0)
425 {
426 Fast486Exception(State, FAST486_EXCEPTION_GP);
427 return FALSE;
428 }
429
430 if (!GdtEntry.SystemType)
431 {
432 /* This is a special descriptor */
433 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
434 return FALSE;
435 }
436
437 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
438 {
439 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
440 return FALSE;
441 }
442
443 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
444 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
445 {
446 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
447 return FALSE;
448 }
449
450 if (!GdtEntry.Present)
451 {
452 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector);
453 return FALSE;
454 }
455 }
456 else if (Segment == FAST486_REG_CS)
457 {
458 /* Loading the code segment */
459
460 if (GET_SEGMENT_INDEX(Selector) == 0)
461 {
462 Fast486Exception(State, FAST486_EXCEPTION_GP);
463 return FALSE;
464 }
465
466 if (GdtEntry.SystemType)
467 {
468 // TODO: Call/interrupt/task gates NOT IMPLEMENTED!
469 UNIMPLEMENTED;
470 }
471 else
472 {
473 if (!GdtEntry.Present)
474 {
475 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
476 return FALSE;
477 }
478
479 if (!GdtEntry.Executable)
480 {
481 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
482 return FALSE;
483 }
484
485 if (GdtEntry.DirConf)
486 {
487 /* Conforming Code Segment */
488
489 if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
490 {
491 /* Must be accessed from lower-privileged code */
492 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
493 return FALSE;
494 }
495 }
496 else
497 {
498 /* Regular code segment */
499
500 if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
501 || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
502 {
503 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
504 return FALSE;
505 }
506
507 }
508
509 /* Update CPL */
510 State->Cpl = GET_SEGMENT_RPL(Selector);
511 }
512 }
513 else
514 {
515 /* Loading a data segment */
516
517 if (!GdtEntry.SystemType)
518 {
519 /* This is a special descriptor */
520 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
521 return FALSE;
522 }
523
524 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
525 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
526 {
527 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
528 return FALSE;
529 }
530
531 if (!GdtEntry.Present)
532 {
533 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
534 return FALSE;
535 }
536 }
537
538 /* Update the cache entry */
539 CachedDescriptor->Selector = Selector;
540 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
541 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
542 CachedDescriptor->Accessed = GdtEntry.Accessed;
543 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
544 CachedDescriptor->DirConf = GdtEntry.DirConf;
545 CachedDescriptor->Executable = GdtEntry.Executable;
546 CachedDescriptor->SystemType = GdtEntry.SystemType;
547 CachedDescriptor->Dpl = GdtEntry.Dpl;
548 CachedDescriptor->Present = GdtEntry.Present;
549 CachedDescriptor->Size = GdtEntry.Size;
550
551 /* Check for page granularity */
552 if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
553 }
554 else
555 {
556 /* Update the selector and base */
557 CachedDescriptor->Selector = Selector;
558 CachedDescriptor->Base = Selector << 4;
559 }
560
561 return TRUE;
562 }
563
564 FORCEINLINE
565 BOOLEAN
566 Fast486FetchByte(PFAST486_STATE State,
567 PUCHAR Data)
568 {
569 PFAST486_SEG_REG CachedDescriptor;
570
571 /* Get the cached descriptor of CS */
572 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
573
574 /* Read from memory */
575 if (!Fast486ReadMemory(State,
576 FAST486_REG_CS,
577 (CachedDescriptor->Size) ? State->InstPtr.Long
578 : State->InstPtr.LowWord,
579 TRUE,
580 Data,
581 sizeof(UCHAR)))
582 {
583 /* Exception occurred during instruction fetch */
584 return FALSE;
585 }
586
587 /* Advance the instruction pointer */
588 if (CachedDescriptor->Size) State->InstPtr.Long++;
589 else State->InstPtr.LowWord++;
590
591 return TRUE;
592 }
593
594 FORCEINLINE
595 BOOLEAN
596 Fast486FetchWord(PFAST486_STATE State,
597 PUSHORT Data)
598 {
599 PFAST486_SEG_REG CachedDescriptor;
600
601 /* Get the cached descriptor of CS */
602 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
603
604 /* Read from memory */
605 // FIXME: Fix byte order on big-endian machines
606 if (!Fast486ReadMemory(State,
607 FAST486_REG_CS,
608 (CachedDescriptor->Size) ? State->InstPtr.Long
609 : State->InstPtr.LowWord,
610 TRUE,
611 Data,
612 sizeof(USHORT)))
613 {
614 /* Exception occurred during instruction fetch */
615 return FALSE;
616 }
617
618 /* Advance the instruction pointer */
619 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
620 else State->InstPtr.LowWord += sizeof(USHORT);
621
622 return TRUE;
623 }
624
625 FORCEINLINE
626 BOOLEAN
627 Fast486FetchDword(PFAST486_STATE State,
628 PULONG Data)
629 {
630 PFAST486_SEG_REG CachedDescriptor;
631
632 /* Get the cached descriptor of CS */
633 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
634
635 /* Read from memory */
636 // FIXME: Fix byte order on big-endian machines
637 if (!Fast486ReadMemory(State,
638 FAST486_REG_CS,
639 (CachedDescriptor->Size) ? State->InstPtr.Long
640 : State->InstPtr.LowWord,
641 TRUE,
642 Data,
643 sizeof(ULONG)))
644 {
645 /* Exception occurred during instruction fetch */
646 return FALSE;
647 }
648
649 /* Advance the instruction pointer */
650 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
651 else State->InstPtr.LowWord += sizeof(ULONG);
652
653 return TRUE;
654 }
655
656 FORCEINLINE
657 BOOLEAN
658 Fast486GetIntVector(PFAST486_STATE State,
659 UCHAR Number,
660 PFAST486_IDT_ENTRY IdtEntry)
661 {
662 ULONG FarPointer;
663
664 /* Check for protected mode */
665 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
666 {
667 /* Read from the IDT */
668 if (!Fast486ReadLinearMemory(State,
669 State->Idtr.Address
670 + Number * sizeof(*IdtEntry),
671 IdtEntry,
672 sizeof(*IdtEntry)))
673 {
674 /* Exception occurred */
675 return FALSE;
676 }
677 }
678 else
679 {
680 /* Read from the real-mode IVT */
681
682 /* Paging is always disabled in real mode */
683 State->MemReadCallback(State,
684 State->Idtr.Address
685 + Number * sizeof(FarPointer),
686 &FarPointer,
687 sizeof(FarPointer));
688
689 /* Fill a fake IDT entry */
690 IdtEntry->Offset = LOWORD(FarPointer);
691 IdtEntry->Selector = HIWORD(FarPointer);
692 IdtEntry->Zero = 0;
693 IdtEntry->Type = FAST486_IDT_INT_GATE;
694 IdtEntry->Storage = FALSE;
695 IdtEntry->Dpl = 0;
696 IdtEntry->Present = TRUE;
697 IdtEntry->OffsetHigh = 0;
698 }
699
700 return TRUE;
701 }
702
703 FORCEINLINE
704 BOOLEAN
705 Fast486CalculateParity(UCHAR Number)
706 {
707 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
708 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
709 }
710
711 FORCEINLINE
712 BOOLEAN
713 Fast486ParseModRegRm(PFAST486_STATE State,
714 BOOLEAN AddressSize,
715 PFAST486_MOD_REG_RM ModRegRm)
716 {
717 UCHAR ModRmByte, Mode, RegMem;
718
719 /* Fetch the MOD REG R/M byte */
720 if (!Fast486FetchByte(State, &ModRmByte))
721 {
722 /* Exception occurred */
723 return FALSE;
724 }
725
726 /* Unpack the mode and R/M */
727 Mode = ModRmByte >> 6;
728 RegMem = ModRmByte & 0x07;
729
730 /* Set the register operand */
731 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
732
733 /* Check the mode */
734 if ((ModRmByte >> 6) == 3)
735 {
736 /* The second operand is also a register */
737 ModRegRm->Memory = FALSE;
738 ModRegRm->SecondRegister = RegMem;
739
740 /* Done parsing */
741 return TRUE;
742 }
743
744 /* The second operand is memory */
745 ModRegRm->Memory = TRUE;
746
747 if (AddressSize)
748 {
749 if (RegMem == FAST486_REG_ESP)
750 {
751 UCHAR SibByte;
752 ULONG Scale, Index, Base;
753
754 /* Fetch the SIB byte */
755 if (!Fast486FetchByte(State, &SibByte))
756 {
757 /* Exception occurred */
758 return FALSE;
759 }
760
761 /* Unpack the scale, index and base */
762 Scale = 1 << (SibByte >> 6);
763 Index = (SibByte >> 3) & 0x07;
764 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
765 else Index = 0;
766
767 if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0))
768 {
769 /* Use the register a base */
770 Base = State->GeneralRegs[SibByte & 0x07].Long;
771 }
772 else
773 {
774 /* Fetch the base */
775 if (!Fast486FetchDword(State, &Base))
776 {
777 /* Exception occurred */
778 return FALSE;
779 }
780 }
781
782 if ((SibByte & 0x07) == FAST486_REG_ESP)
783 {
784 /* Check if there is no segment override */
785 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
786 {
787 /* Add a SS: prefix */
788 State->PrefixFlags |= FAST486_PREFIX_SEG;
789 State->SegmentOverride = FAST486_REG_SS;
790 }
791 }
792
793 /* Calculate the address */
794 ModRegRm->MemoryAddress = Base + Index * Scale;
795 }
796 else if (RegMem == FAST486_REG_EBP)
797 {
798 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
799 else ModRegRm->MemoryAddress = 0;
800 }
801 else
802 {
803 /* Get the base from the register */
804 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
805 }
806
807 /* Check if there is no segment override */
808 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
809 {
810 /* Check if the default segment should be SS */
811 if ((RegMem == FAST486_REG_EBP) && Mode)
812 {
813 /* Add a SS: prefix */
814 State->PrefixFlags |= FAST486_PREFIX_SEG;
815 State->SegmentOverride = FAST486_REG_SS;
816 }
817 }
818
819 if (Mode == 1)
820 {
821 CHAR Offset;
822
823 /* Fetch the byte */
824 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
825 {
826 /* Exception occurred */
827 return FALSE;
828 }
829
830 /* Add the signed offset to the address */
831 ModRegRm->MemoryAddress += (LONG)Offset;
832 }
833 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
834 {
835 LONG Offset;
836
837 /* Fetch the dword */
838 if (!Fast486FetchDword(State, (PULONG)&Offset))
839 {
840 /* Exception occurred */
841 return FALSE;
842 }
843
844 /* Add the signed offset to the address */
845 ModRegRm->MemoryAddress += Offset;
846 }
847 }
848 else
849 {
850 /* Check the operand */
851 switch (RegMem)
852 {
853 case 0:
854 {
855 /* [BX + SI] */
856 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
857 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
858
859 break;
860 }
861
862 case 1:
863 {
864 /* [BX + DI] */
865 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
866 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
867
868 break;
869 }
870
871 case 2:
872 {
873 /* SS:[BP + SI] */
874 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
875 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
876
877 break;
878 }
879
880 case 3:
881 {
882 /* SS:[BP + DI] */
883 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
884 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
885
886 break;
887 }
888
889 case 4:
890 {
891 /* [SI] */
892 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
893
894 break;
895 }
896
897 case 5:
898 {
899 /* [DI] */
900 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
901
902 break;
903 }
904
905 case 6:
906 {
907 if (Mode)
908 {
909 /* [BP] */
910 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
911 }
912 else
913 {
914 /* [constant] (added later) */
915 ModRegRm->MemoryAddress = 0;
916 }
917
918 break;
919 }
920
921 case 7:
922 {
923 /* [BX] */
924 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
925
926 break;
927 }
928 }
929
930 /* Check if there is no segment override */
931 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
932 {
933 /* Check if the default segment should be SS */
934 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
935 {
936 /* Add a SS: prefix */
937 State->PrefixFlags |= FAST486_PREFIX_SEG;
938 State->SegmentOverride = FAST486_REG_SS;
939 }
940 }
941
942 if (Mode == 1)
943 {
944 CHAR Offset;
945
946 /* Fetch the byte */
947 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
948 {
949 /* Exception occurred */
950 return FALSE;
951 }
952
953 /* Add the signed offset to the address */
954 ModRegRm->MemoryAddress += (LONG)Offset;
955 }
956 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
957 {
958 SHORT Offset;
959
960 /* Fetch the word */
961 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
962 {
963 /* Exception occurred */
964 return FALSE;
965 }
966
967 /* Add the signed offset to the address */
968 ModRegRm->MemoryAddress += (LONG)Offset;
969 }
970
971 /* Clear the top 16 bits */
972 ModRegRm->MemoryAddress &= 0x0000FFFF;
973 }
974
975 return TRUE;
976 }
977
978 FORCEINLINE
979 BOOLEAN
980 Fast486ReadModrmByteOperands(PFAST486_STATE State,
981 PFAST486_MOD_REG_RM ModRegRm,
982 PUCHAR RegValue,
983 PUCHAR RmValue)
984 {
985 FAST486_SEG_REGS Segment = FAST486_REG_DS;
986
987 if (RegValue)
988 {
989 /* Get the register value */
990 if (ModRegRm->Register & 0x04)
991 {
992 /* AH, CH, DH, BH */
993 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
994 }
995 else
996 {
997 /* AL, CL, DL, BL */
998 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
999 }
1000 }
1001
1002 if (RmValue)
1003 {
1004 if (!ModRegRm->Memory)
1005 {
1006 /* Get the second register value */
1007 if (ModRegRm->SecondRegister & 0x04)
1008 {
1009 /* AH, CH, DH, BH */
1010 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
1011 }
1012 else
1013 {
1014 /* AL, CL, DL, BL */
1015 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
1016 }
1017 }
1018 else
1019 {
1020 /* Check for the segment override */
1021 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1022 {
1023 /* Use the override segment instead */
1024 Segment = State->SegmentOverride;
1025 }
1026
1027 /* Read memory */
1028 if (!Fast486ReadMemory(State,
1029 Segment,
1030 ModRegRm->MemoryAddress,
1031 FALSE,
1032 RmValue,
1033 sizeof(UCHAR)))
1034 {
1035 /* Exception occurred */
1036 return FALSE;
1037 }
1038 }
1039 }
1040
1041 return TRUE;
1042 }
1043
1044 FORCEINLINE
1045 BOOLEAN
1046 Fast486ReadModrmWordOperands(PFAST486_STATE State,
1047 PFAST486_MOD_REG_RM ModRegRm,
1048 PUSHORT RegValue,
1049 PUSHORT RmValue)
1050 {
1051 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1052
1053 if (RegValue)
1054 {
1055 /* Get the register value */
1056 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
1057 }
1058
1059 if (RmValue)
1060 {
1061 if (!ModRegRm->Memory)
1062 {
1063 /* Get the second register value */
1064 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
1065 }
1066 else
1067 {
1068 /* Check for the segment override */
1069 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1070 {
1071 /* Use the override segment instead */
1072 Segment = State->SegmentOverride;
1073 }
1074
1075 /* Read memory */
1076 if (!Fast486ReadMemory(State,
1077 Segment,
1078 ModRegRm->MemoryAddress,
1079 FALSE,
1080 RmValue,
1081 sizeof(USHORT)))
1082 {
1083 /* Exception occurred */
1084 return FALSE;
1085 }
1086 }
1087 }
1088
1089 return TRUE;
1090 }
1091
1092 FORCEINLINE
1093 BOOLEAN
1094 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
1095 PFAST486_MOD_REG_RM ModRegRm,
1096 PULONG RegValue,
1097 PULONG RmValue)
1098 {
1099 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1100
1101 if (RegValue)
1102 {
1103 /* Get the register value */
1104 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
1105 }
1106
1107 if (RmValue)
1108 {
1109 if (!ModRegRm->Memory)
1110 {
1111 /* Get the second register value */
1112 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
1113 }
1114 else
1115 {
1116 /* Check for the segment override */
1117 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1118 {
1119 /* Use the override segment instead */
1120 Segment = State->SegmentOverride;
1121 }
1122
1123 /* Read memory */
1124 if (!Fast486ReadMemory(State,
1125 Segment,
1126 ModRegRm->MemoryAddress,
1127 FALSE,
1128 RmValue,
1129 sizeof(ULONG)))
1130 {
1131 /* Exception occurred */
1132 return FALSE;
1133 }
1134 }
1135 }
1136
1137 return TRUE;
1138 }
1139
1140 FORCEINLINE
1141 BOOLEAN
1142 Fast486WriteModrmByteOperands(PFAST486_STATE State,
1143 PFAST486_MOD_REG_RM ModRegRm,
1144 BOOLEAN WriteRegister,
1145 UCHAR Value)
1146 {
1147 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1148
1149 if (WriteRegister)
1150 {
1151 /* Store the value in the register */
1152 if (ModRegRm->Register & 0x04)
1153 {
1154 /* AH, CH, DH, BH */
1155 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
1156 }
1157 else
1158 {
1159 /* AL, CL, DL, BL */
1160 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
1161 }
1162 }
1163 else
1164 {
1165 if (!ModRegRm->Memory)
1166 {
1167 /* Store the value in the second register */
1168 if (ModRegRm->SecondRegister & 0x04)
1169 {
1170 /* AH, CH, DH, BH */
1171 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
1172 }
1173 else
1174 {
1175 /* AL, CL, DL, BL */
1176 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
1177 }
1178 }
1179 else
1180 {
1181 /* Check for the segment override */
1182 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1183 {
1184 /* Use the override segment instead */
1185 Segment = State->SegmentOverride;
1186 }
1187
1188 /* Write memory */
1189 if (!Fast486WriteMemory(State,
1190 Segment,
1191 ModRegRm->MemoryAddress,
1192 &Value,
1193 sizeof(UCHAR)))
1194 {
1195 /* Exception occurred */
1196 return FALSE;
1197 }
1198 }
1199 }
1200
1201 return TRUE;
1202 }
1203
1204 FORCEINLINE
1205 BOOLEAN
1206 Fast486WriteModrmWordOperands(PFAST486_STATE State,
1207 PFAST486_MOD_REG_RM ModRegRm,
1208 BOOLEAN WriteRegister,
1209 USHORT Value)
1210 {
1211 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1212
1213 if (WriteRegister)
1214 {
1215 /* Store the value in the register */
1216 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
1217 }
1218 else
1219 {
1220 if (!ModRegRm->Memory)
1221 {
1222 /* Store the value in the second register */
1223 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
1224 }
1225 else
1226 {
1227 /* Check for the segment override */
1228 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1229 {
1230 /* Use the override segment instead */
1231 Segment = State->SegmentOverride;
1232 }
1233
1234 /* Write memory */
1235 if (!Fast486WriteMemory(State,
1236 Segment,
1237 ModRegRm->MemoryAddress,
1238 &Value,
1239 sizeof(USHORT)))
1240 {
1241 /* Exception occurred */
1242 return FALSE;
1243 }
1244 }
1245 }
1246
1247 return TRUE;
1248 }
1249
1250 FORCEINLINE
1251 BOOLEAN
1252 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
1253 PFAST486_MOD_REG_RM ModRegRm,
1254 BOOLEAN WriteRegister,
1255 ULONG Value)
1256 {
1257 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1258
1259 if (WriteRegister)
1260 {
1261 /* Store the value in the register */
1262 State->GeneralRegs[ModRegRm->Register].Long = Value;
1263 }
1264 else
1265 {
1266 if (!ModRegRm->Memory)
1267 {
1268 /* Store the value in the second register */
1269 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
1270 }
1271 else
1272 {
1273 /* Check for the segment override */
1274 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1275 {
1276 /* Use the override segment instead */
1277 Segment = State->SegmentOverride;
1278 }
1279
1280 /* Write memory */
1281 if (!Fast486WriteMemory(State,
1282 Segment,
1283 ModRegRm->MemoryAddress,
1284 &Value,
1285 sizeof(ULONG)))
1286 {
1287 /* Exception occurred */
1288 return FALSE;
1289 }
1290 }
1291 }
1292
1293 return TRUE;
1294 }
1295
1296 /* EOF */