38dadbf00c34344197910e9c95b01be88820dab1
[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 Base = State->GeneralRegs[SibByte & 0x07].Long;
723
724 /* Calculate the address */
725 ModRegRm->MemoryAddress = Base + Index * Scale;
726 }
727 else if (RegMem == FAST486_REG_EBP)
728 {
729 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
730 else ModRegRm->MemoryAddress = 0;
731 }
732 else
733 {
734 /* Get the base from the register */
735 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
736 }
737
738 /* Check if there is no segment override */
739 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
740 {
741 /* Check if the default segment should be SS */
742 if ((RegMem == FAST486_REG_EBP) && Mode)
743 {
744 /* Add a SS: prefix */
745 State->PrefixFlags |= FAST486_PREFIX_SEG;
746 State->SegmentOverride = FAST486_REG_SS;
747 }
748 }
749
750 if (Mode == 1)
751 {
752 CHAR Offset;
753
754 /* Fetch the byte */
755 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
756 {
757 /* Exception occurred */
758 return FALSE;
759 }
760
761 /* Add the signed offset to the address */
762 ModRegRm->MemoryAddress += (LONG)Offset;
763 }
764 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
765 {
766 LONG Offset;
767
768 /* Fetch the dword */
769 if (!Fast486FetchDword(State, (PULONG)&Offset))
770 {
771 /* Exception occurred */
772 return FALSE;
773 }
774
775 /* Add the signed offset to the address */
776 ModRegRm->MemoryAddress += Offset;
777 }
778 }
779 else
780 {
781 /* Check the operand */
782 switch (RegMem)
783 {
784 case 0:
785 {
786 /* [BX + SI] */
787 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
788 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
789
790 break;
791 }
792
793 case 1:
794 {
795 /* [BX + DI] */
796 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
797 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
798
799 break;
800 }
801
802 case 2:
803 {
804 /* SS:[BP + SI] */
805 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
806 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
807
808 break;
809 }
810
811 case 3:
812 {
813 /* SS:[BP + DI] */
814 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
815 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
816
817 break;
818 }
819
820 case 4:
821 {
822 /* [SI] */
823 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
824
825 break;
826 }
827
828 case 5:
829 {
830 /* [DI] */
831 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
832
833 break;
834 }
835
836 case 6:
837 {
838 if (Mode)
839 {
840 /* [BP] */
841 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
842 }
843 else
844 {
845 /* [constant] (added later) */
846 ModRegRm->MemoryAddress = 0;
847 }
848
849 break;
850 }
851
852 case 7:
853 {
854 /* [BX] */
855 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
856
857 break;
858 }
859 }
860
861 /* Check if there is no segment override */
862 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
863 {
864 /* Check if the default segment should be SS */
865 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
866 {
867 /* Add a SS: prefix */
868 State->PrefixFlags |= FAST486_PREFIX_SEG;
869 State->SegmentOverride = FAST486_REG_SS;
870 }
871 }
872
873 if (Mode == 1)
874 {
875 CHAR Offset;
876
877 /* Fetch the byte */
878 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
879 {
880 /* Exception occurred */
881 return FALSE;
882 }
883
884 /* Add the signed offset to the address */
885 ModRegRm->MemoryAddress += (LONG)Offset;
886 }
887 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
888 {
889 SHORT Offset;
890
891 /* Fetch the word */
892 if (!Fast486FetchWord(State, (PUSHORT)&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
902 /* Clear the top 16 bits */
903 ModRegRm->MemoryAddress &= 0x0000FFFF;
904 }
905
906 return TRUE;
907 }
908
909 FORCEINLINE
910 BOOLEAN
911 Fast486ReadModrmByteOperands(PFAST486_STATE State,
912 PFAST486_MOD_REG_RM ModRegRm,
913 PUCHAR RegValue,
914 PUCHAR RmValue)
915 {
916 FAST486_SEG_REGS Segment = FAST486_REG_DS;
917
918 /* Get the register value */
919 if (ModRegRm->Register & 0x04)
920 {
921 /* AH, CH, DH, BH */
922 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
923 }
924 else
925 {
926 /* AL, CL, DL, BL */
927 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
928 }
929
930 if (!ModRegRm->Memory)
931 {
932 /* Get the second register value */
933 if (ModRegRm->SecondRegister & 0x04)
934 {
935 /* AH, CH, DH, BH */
936 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
937 }
938 else
939 {
940 /* AL, CL, DL, BL */
941 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
942 }
943 }
944 else
945 {
946 /* Check for the segment override */
947 if (State->PrefixFlags & FAST486_PREFIX_SEG)
948 {
949 /* Use the override segment instead */
950 Segment = State->SegmentOverride;
951 }
952
953 /* Read memory */
954 if (!Fast486ReadMemory(State,
955 Segment,
956 ModRegRm->MemoryAddress,
957 FALSE,
958 RmValue,
959 sizeof(UCHAR)))
960 {
961 /* Exception occurred */
962 return FALSE;
963 }
964 }
965
966 return TRUE;
967 }
968
969 FORCEINLINE
970 BOOLEAN
971 Fast486ReadModrmWordOperands(PFAST486_STATE State,
972 PFAST486_MOD_REG_RM ModRegRm,
973 PUSHORT RegValue,
974 PUSHORT RmValue)
975 {
976 FAST486_SEG_REGS Segment = FAST486_REG_DS;
977
978 /* Get the register value */
979 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
980
981 if (!ModRegRm->Memory)
982 {
983 /* Get the second register value */
984 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
985 }
986 else
987 {
988 /* Check for the segment override */
989 if (State->PrefixFlags & FAST486_PREFIX_SEG)
990 {
991 /* Use the override segment instead */
992 Segment = State->SegmentOverride;
993 }
994
995 /* Read memory */
996 if (!Fast486ReadMemory(State,
997 Segment,
998 ModRegRm->MemoryAddress,
999 FALSE,
1000 RmValue,
1001 sizeof(USHORT)))
1002 {
1003 /* Exception occurred */
1004 return FALSE;
1005 }
1006 }
1007
1008 return TRUE;
1009 }
1010
1011 FORCEINLINE
1012 BOOLEAN
1013 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
1014 PFAST486_MOD_REG_RM ModRegRm,
1015 PULONG RegValue,
1016 PULONG RmValue)
1017 {
1018 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1019
1020 /* Get the register value */
1021 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
1022
1023 if (!ModRegRm->Memory)
1024 {
1025 /* Get the second register value */
1026 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
1027 }
1028 else
1029 {
1030 /* Check for the segment override */
1031 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1032 {
1033 /* Use the override segment instead */
1034 Segment = State->SegmentOverride;
1035 }
1036
1037 /* Read memory */
1038 if (!Fast486ReadMemory(State,
1039 Segment,
1040 ModRegRm->MemoryAddress,
1041 FALSE,
1042 RmValue,
1043 sizeof(ULONG)))
1044 {
1045 /* Exception occurred */
1046 return FALSE;
1047 }
1048 }
1049
1050 return TRUE;
1051 }
1052
1053 FORCEINLINE
1054 BOOLEAN
1055 Fast486WriteModrmByteOperands(PFAST486_STATE State,
1056 PFAST486_MOD_REG_RM ModRegRm,
1057 BOOLEAN WriteRegister,
1058 UCHAR Value)
1059 {
1060 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1061
1062 if (WriteRegister)
1063 {
1064 /* Store the value in the register */
1065 if (ModRegRm->Register & 0x04)
1066 {
1067 /* AH, CH, DH, BH */
1068 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
1069 }
1070 else
1071 {
1072 /* AL, CL, DL, BL */
1073 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
1074 }
1075 }
1076 else
1077 {
1078 if (!ModRegRm->Memory)
1079 {
1080 /* Store the value in the second register */
1081 if (ModRegRm->SecondRegister & 0x04)
1082 {
1083 /* AH, CH, DH, BH */
1084 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
1085 }
1086 else
1087 {
1088 /* AL, CL, DL, BL */
1089 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
1090 }
1091 }
1092 else
1093 {
1094 /* Check for the segment override */
1095 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1096 {
1097 /* Use the override segment instead */
1098 Segment = State->SegmentOverride;
1099 }
1100
1101 /* Write memory */
1102 if (!Fast486WriteMemory(State,
1103 Segment,
1104 ModRegRm->MemoryAddress,
1105 &Value,
1106 sizeof(UCHAR)))
1107 {
1108 /* Exception occurred */
1109 return FALSE;
1110 }
1111 }
1112 }
1113
1114 return TRUE;
1115 }
1116
1117 FORCEINLINE
1118 BOOLEAN
1119 Fast486WriteModrmWordOperands(PFAST486_STATE State,
1120 PFAST486_MOD_REG_RM ModRegRm,
1121 BOOLEAN WriteRegister,
1122 USHORT Value)
1123 {
1124 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1125
1126 if (WriteRegister)
1127 {
1128 /* Store the value in the register */
1129 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
1130 }
1131 else
1132 {
1133 if (!ModRegRm->Memory)
1134 {
1135 /* Store the value in the second register */
1136 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
1137 }
1138 else
1139 {
1140 /* Check for the segment override */
1141 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1142 {
1143 /* Use the override segment instead */
1144 Segment = State->SegmentOverride;
1145 }
1146
1147 /* Write memory */
1148 if (!Fast486WriteMemory(State,
1149 Segment,
1150 ModRegRm->MemoryAddress,
1151 &Value,
1152 sizeof(USHORT)))
1153 {
1154 /* Exception occurred */
1155 return FALSE;
1156 }
1157 }
1158 }
1159
1160 return TRUE;
1161 }
1162
1163 FORCEINLINE
1164 BOOLEAN
1165 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
1166 PFAST486_MOD_REG_RM ModRegRm,
1167 BOOLEAN WriteRegister,
1168 ULONG Value)
1169 {
1170 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1171
1172 if (WriteRegister)
1173 {
1174 /* Store the value in the register */
1175 State->GeneralRegs[ModRegRm->Register].Long = Value;
1176 }
1177 else
1178 {
1179 if (!ModRegRm->Memory)
1180 {
1181 /* Store the value in the second register */
1182 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
1183 }
1184 else
1185 {
1186 /* Check for the segment override */
1187 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1188 {
1189 /* Use the override segment instead */
1190 Segment = State->SegmentOverride;
1191 }
1192
1193 /* Write memory */
1194 if (!Fast486WriteMemory(State,
1195 Segment,
1196 ModRegRm->MemoryAddress,
1197 &Value,
1198 sizeof(ULONG)))
1199 {
1200 /* Exception occurred */
1201 return FALSE;
1202 }
1203 }
1204 }
1205
1206 return TRUE;
1207 }
1208
1209 /* EOF */