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