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