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