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