[NTOS:CM] CmpCmdHiveOpen(): Resolve FileAttributes->RootDirectory when a hive file...
[reactos.git] / sdk / lib / fast486 / common.inl
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * common.inl
4 *
5 * Copyright (C) 2015 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 #include "fpu.h"
24
25 /* PUBLIC FUNCTIONS ***********************************************************/
26
27 #if defined (__GNUC__)
28 #define CountLeadingZeros64(x) __builtin_clzll(x)
29
30 /*
31 #elif (_MSC_VER >= 1500) && defined(_WIN64)
32 #define CountLeadingZeros64(x) __lzcnt64(x)
33 #elif (_MSC_VER >= 1500)
34 #define CountLeadingZeros64(x) ((x) > 0xFFFFFFFFULL) ? __lzcnt((x) >> 32) \
35 : (__lzcnt(x) + 32)
36 */
37
38 #else
39 FORCEINLINE
40 ULONG
41 CountLeadingZeros64(ULONGLONG Value)
42 {
43 ULONG Count = 0;
44 Value = ~Value;
45 while ((LONGLONG)Value < 0)
46 {
47 Count++;
48 Value <<= 1;
49 }
50 return Count;
51 }
52 #endif
53
54 FORCEINLINE
55 UINT
56 FASTCALL
57 Fast486GetCurrentPrivLevel(PFAST486_STATE State)
58 {
59 /* Return the CPL, or 3 if we're in virtual 8086 mode */
60 return (!State->Flags.Vm) ? State->Cpl : 3;
61 }
62
63 FORCEINLINE
64 ULONG
65 FASTCALL
66 Fast486GetPageTableEntry(PFAST486_STATE State,
67 ULONG VirtualAddress,
68 BOOLEAN MarkAsDirty)
69 {
70 ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress);
71 ULONG PteIndex = GET_ADDR_PTE(VirtualAddress);
72 FAST486_PAGE_DIR DirectoryEntry;
73 FAST486_PAGE_TABLE TableEntry;
74 ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3];
75
76 if ((State->Tlb != NULL)
77 && (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD))
78 {
79 /* Return the cached entry */
80 return State->Tlb[VirtualAddress >> 12];
81 }
82
83 /* Read the directory entry */
84 State->MemReadCallback(State,
85 PageDirectory + PdeIndex * sizeof(ULONG),
86 &DirectoryEntry.Value,
87 sizeof(DirectoryEntry));
88
89 /* Make sure it is present */
90 if (!DirectoryEntry.Present) return 0;
91
92 /* Was the directory entry accessed before? */
93 if (!DirectoryEntry.Accessed)
94 {
95 /* Well, it is now */
96 DirectoryEntry.Accessed = TRUE;
97
98 /* Write back the directory entry */
99 State->MemWriteCallback(State,
100 PageDirectory + PdeIndex * sizeof(ULONG),
101 &DirectoryEntry.Value,
102 sizeof(DirectoryEntry));
103 }
104
105 /* Read the table entry */
106 State->MemReadCallback(State,
107 (DirectoryEntry.TableAddress << 12)
108 + PteIndex * sizeof(ULONG),
109 &TableEntry.Value,
110 sizeof(TableEntry));
111
112 /* Make sure it is present */
113 if (!TableEntry.Present) return 0;
114
115 /* Do we need to change any flags? */
116 if (!TableEntry.Accessed || (MarkAsDirty && !TableEntry.Dirty))
117 {
118 /* Mark it as accessed and optionally dirty too */
119 TableEntry.Accessed = TRUE;
120 if (MarkAsDirty) TableEntry.Dirty = TRUE;
121
122 /* Write back the table entry */
123 State->MemWriteCallback(State,
124 (DirectoryEntry.TableAddress << 12)
125 + PteIndex * sizeof(ULONG),
126 &TableEntry.Value,
127 sizeof(TableEntry));
128 }
129
130 /*
131 * The resulting permissions depend on the permissions
132 * in the page directory table too
133 */
134 TableEntry.Writeable &= DirectoryEntry.Writeable;
135 TableEntry.Usermode &= DirectoryEntry.Usermode;
136
137 if (State->Tlb != NULL)
138 {
139 /* Set the TLB entry */
140 State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
141 State->TlbEmpty = FALSE;
142 }
143
144 /* Return the table entry */
145 return TableEntry.Value;
146 }
147
148 FORCEINLINE
149 VOID
150 FASTCALL
151 Fast486FlushTlb(PFAST486_STATE State)
152 {
153 if (!State->Tlb || State->TlbEmpty) return;
154 RtlFillMemory(State->Tlb, NUM_TLB_ENTRIES * sizeof(ULONG), 0xFF);
155 State->TlbEmpty = TRUE;
156 }
157
158 FORCEINLINE
159 BOOLEAN
160 FASTCALL
161 Fast486ReadLinearMemory(PFAST486_STATE State,
162 ULONG LinearAddress,
163 PVOID Buffer,
164 ULONG Size,
165 BOOLEAN CheckPrivilege)
166 {
167 /* Check if paging is enabled */
168 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
169 {
170 ULONG Page;
171 FAST486_PAGE_TABLE TableEntry;
172 INT Cpl = Fast486GetCurrentPrivLevel(State);
173 ULONG BufferOffset = 0;
174
175 for (Page = PAGE_ALIGN(LinearAddress);
176 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
177 Page += FAST486_PAGE_SIZE)
178 {
179 ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
180
181 /* Get the table entry */
182 TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
183
184 /* Check if this is the first page */
185 if (Page == PAGE_ALIGN(LinearAddress))
186 {
187 /* Start reading from the offset from the beginning of the page */
188 PageOffset = PAGE_OFFSET(LinearAddress);
189 PageLength -= PageOffset;
190 }
191
192 if (CheckPrivilege && (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0))))
193 {
194 State->ControlRegisters[FAST486_REG_CR2] = Page + PageOffset;
195
196 /* Exception */
197 Fast486ExceptionWithErrorCode(State,
198 FAST486_EXCEPTION_PF,
199 TableEntry.Present | (State->Cpl ? 0x04 : 0));
200 return FALSE;
201 }
202
203 /* Check if this is the last page */
204 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
205 {
206 /* Read only a part of the page */
207 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
208 }
209
210 /* Read the memory */
211 State->MemReadCallback(State,
212 (TableEntry.Address << 12) | PageOffset,
213 (PVOID)((ULONG_PTR)Buffer + BufferOffset),
214 PageLength);
215
216 BufferOffset += PageLength;
217 }
218 }
219 else
220 {
221 /* Read the memory */
222 State->MemReadCallback(State, LinearAddress, Buffer, Size);
223 }
224
225 return TRUE;
226 }
227
228 FORCEINLINE
229 BOOLEAN
230 FASTCALL
231 Fast486WriteLinearMemory(PFAST486_STATE State,
232 ULONG LinearAddress,
233 PVOID Buffer,
234 ULONG Size,
235 BOOLEAN CheckPrivilege)
236 {
237 /* Check if paging is enabled */
238 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
239 {
240 ULONG Page;
241 FAST486_PAGE_TABLE TableEntry;
242 INT Cpl = Fast486GetCurrentPrivLevel(State);
243 ULONG BufferOffset = 0;
244
245 for (Page = PAGE_ALIGN(LinearAddress);
246 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
247 Page += FAST486_PAGE_SIZE)
248 {
249 ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
250
251 /* Get the table entry */
252 TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
253
254 /* Check if this is the first page */
255 if (Page == PAGE_ALIGN(LinearAddress))
256 {
257 /* Start writing from the offset from the beginning of the page */
258 PageOffset = PAGE_OFFSET(LinearAddress);
259 PageLength -= PageOffset;
260 }
261
262 if (CheckPrivilege
263 && ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
264 || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
265 && !TableEntry.Writeable)))
266 {
267 State->ControlRegisters[FAST486_REG_CR2] = Page + PageOffset;
268
269 /* Exception */
270 Fast486ExceptionWithErrorCode(State,
271 FAST486_EXCEPTION_PF,
272 TableEntry.Present | 0x02 | (State->Cpl ? 0x04 : 0));
273 return FALSE;
274 }
275
276 /* Check if this is the last page */
277 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
278 {
279 /* Write only a part of the page */
280 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
281 }
282
283 /* Write the memory */
284 State->MemWriteCallback(State,
285 (TableEntry.Address << 12) | PageOffset,
286 (PVOID)((ULONG_PTR)Buffer + BufferOffset),
287 PageLength);
288
289 BufferOffset += PageLength;
290 }
291 }
292 else
293 {
294 /* Write the memory */
295 State->MemWriteCallback(State, LinearAddress, Buffer, Size);
296 }
297
298 return TRUE;
299 }
300
301 FORCEINLINE
302 VOID
303 FASTCALL
304 Fast486Exception(PFAST486_STATE State,
305 FAST486_EXCEPTIONS ExceptionCode)
306 {
307 /* Call the internal function */
308 Fast486ExceptionWithErrorCode(State, ExceptionCode, 0);
309 }
310
311 FORCEINLINE
312 BOOLEAN
313 FASTCALL
314 Fast486StackPushInternal(PFAST486_STATE State, BOOLEAN Size, ULONG Value)
315 {
316 ULONG StackPointer = State->GeneralRegs[FAST486_REG_ESP].Long;
317
318 if (Size)
319 {
320 /* Check if ESP is between 1 and 3 */
321 if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
322 && State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
323 {
324 Fast486Exception(State, FAST486_EXCEPTION_SS);
325 return FALSE;
326 }
327
328 /* Store the value in SS:[ESP - 4] */
329 if (!Fast486WriteMemory(State,
330 FAST486_REG_SS,
331 State->SegmentRegs[FAST486_REG_SS].Size
332 ? StackPointer - sizeof(ULONG)
333 : LOWORD(StackPointer - sizeof(ULONG)),
334 &Value,
335 sizeof(ULONG)))
336 {
337 /* Exception occurred */
338 return FALSE;
339 }
340
341 if (State->SegmentRegs[FAST486_REG_SS].Size)
342 {
343 /* Subtract ESP by 4 */
344 State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
345 }
346 else
347 {
348 /* Subtract SP by 4 */
349 State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(ULONG);
350 }
351 }
352 else
353 {
354 /* Check if SP is 1 */
355 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1)
356 {
357 Fast486Exception(State, FAST486_EXCEPTION_SS);
358 return FALSE;
359 }
360
361 /* Store the value in SS:[SP - 2] */
362 if (!Fast486WriteMemory(State,
363 FAST486_REG_SS,
364 State->SegmentRegs[FAST486_REG_SS].Size
365 ? StackPointer - sizeof(USHORT)
366 : LOWORD(StackPointer - sizeof(USHORT)),
367 &Value,
368 sizeof(USHORT)))
369 {
370 /* Exception occurred */
371 return FALSE;
372 }
373
374 if (State->SegmentRegs[FAST486_REG_SS].Size)
375 {
376 /* Subtract ESP by 2 */
377 State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(USHORT);
378 }
379 else
380 {
381 /* Subtract SP by 2 */
382 State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
383 }
384 }
385
386 return TRUE;
387 }
388
389 FORCEINLINE
390 BOOLEAN
391 FASTCALL
392 Fast486StackPush(PFAST486_STATE State, ULONG Value)
393 {
394 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
395
396 /* The OPSIZE prefix toggles the size */
397 TOGGLE_OPSIZE(Size);
398
399 /* Call the internal function */
400 return Fast486StackPushInternal(State, Size, Value);
401 }
402
403 FORCEINLINE
404 BOOLEAN
405 FASTCALL
406 Fast486StackPop(PFAST486_STATE State,
407 PULONG Value)
408 {
409 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
410
411 /* The OPSIZE prefix toggles the size */
412 TOGGLE_OPSIZE(Size);
413
414 if (Size)
415 {
416 /* 32-bit size */
417 ULONG LongValue;
418
419 /* Check if ESP is 0xFFFFFFFF */
420 if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
421 {
422 Fast486Exception(State, FAST486_EXCEPTION_SS);
423 return FALSE;
424 }
425
426 /* Read the value from SS:ESP */
427 if (!Fast486ReadMemory(State,
428 FAST486_REG_SS,
429 State->SegmentRegs[FAST486_REG_SS].Size
430 ? State->GeneralRegs[FAST486_REG_ESP].Long
431 : State->GeneralRegs[FAST486_REG_ESP].LowWord,
432 FALSE,
433 &LongValue,
434 sizeof(LongValue)))
435 {
436 /* An exception occurred */
437 return FALSE;
438 }
439
440 if (State->SegmentRegs[FAST486_REG_SS].Size)
441 {
442 /* Increment ESP by 4 */
443 State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(ULONG);
444 }
445 else
446 {
447 /* Increment SP by 4 */
448 State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(ULONG);
449 }
450
451 /* Store the value in the result */
452 *Value = LongValue;
453 }
454 else
455 {
456 /* 16-bit size */
457 USHORT ShortValue;
458
459 /* Check if SP is 0xFFFF */
460 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
461 {
462 Fast486Exception(State, FAST486_EXCEPTION_SS);
463 return FALSE;
464 }
465
466 /* Read the value from SS:SP */
467 if (!Fast486ReadMemory(State,
468 FAST486_REG_SS,
469 State->SegmentRegs[FAST486_REG_SS].Size
470 ? State->GeneralRegs[FAST486_REG_ESP].Long
471 : State->GeneralRegs[FAST486_REG_ESP].LowWord,
472 FALSE,
473 &ShortValue,
474 sizeof(ShortValue)))
475 {
476 /* An exception occurred */
477 return FALSE;
478 }
479
480 if (State->SegmentRegs[FAST486_REG_SS].Size)
481 {
482 /* Increment ESP by 2 */
483 State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(USHORT);
484 }
485 else
486 {
487 /* Increment SP by 2 */
488 State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(USHORT);
489 }
490
491 /* Store the value in the result */
492 *Value = ShortValue;
493 }
494
495 return TRUE;
496 }
497
498 FORCEINLINE
499 BOOLEAN
500 FASTCALL
501 Fast486ReadDescriptorEntry(PFAST486_STATE State,
502 USHORT Selector,
503 PBOOLEAN EntryValid,
504 PFAST486_GDT_ENTRY Entry)
505 {
506 if (!(Selector & SEGMENT_TABLE_INDICATOR))
507 {
508 /* Make sure the GDT contains the entry */
509 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1u))
510 {
511 *EntryValid = FALSE;
512 return TRUE;
513 }
514
515 /* Read the GDT */
516 if (!Fast486ReadLinearMemory(State,
517 State->Gdtr.Address
518 + GET_SEGMENT_INDEX(Selector),
519 Entry,
520 sizeof(*Entry),
521 FALSE))
522 {
523 /* Exception occurred */
524 *EntryValid = FALSE;
525 return FALSE;
526 }
527 }
528 else
529 {
530 /* Make sure the LDT contains the entry */
531 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1u))
532 {
533 *EntryValid = FALSE;
534 return TRUE;
535 }
536
537 /* Read the LDT */
538 if (!Fast486ReadLinearMemory(State,
539 State->Ldtr.Base
540 + GET_SEGMENT_INDEX(Selector),
541 Entry,
542 sizeof(*Entry),
543 FALSE))
544 {
545 /* Exception occurred */
546 *EntryValid = FALSE;
547 return FALSE;
548 }
549 }
550
551 *EntryValid = TRUE;
552 return TRUE;
553 }
554
555 FORCEINLINE
556 BOOLEAN
557 FASTCALL
558 Fast486LoadSegmentInternal(PFAST486_STATE State,
559 FAST486_SEG_REGS Segment,
560 USHORT Selector,
561 FAST486_EXCEPTIONS Exception)
562 {
563 PFAST486_SEG_REG CachedDescriptor;
564 BOOLEAN Valid;
565 FAST486_GDT_ENTRY GdtEntry;
566
567 ASSERT(Segment < FAST486_NUM_SEG_REGS);
568
569 /* Get the cached descriptor */
570 CachedDescriptor = &State->SegmentRegs[Segment];
571
572 /* Check for protected mode */
573 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
574 {
575 /* Check for VM86 mode */
576 if (State->Flags.Vm)
577 {
578 /* Update the cached descriptor with VM86 values */
579 CachedDescriptor->Selector = Selector;
580 CachedDescriptor->Base = Selector << 4;
581 CachedDescriptor->Limit = 0xFFFF;
582 CachedDescriptor->ReadWrite = TRUE;
583 CachedDescriptor->DirConf = FALSE;
584 CachedDescriptor->SystemType = TRUE;
585 CachedDescriptor->Dpl = CachedDescriptor->Rpl = 3;
586 CachedDescriptor->Present = TRUE;
587 CachedDescriptor->Size = FALSE;
588 return TRUE;
589 }
590
591 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
592 {
593 /* Exception occurred */
594 return FALSE;
595 }
596
597 if (!Valid)
598 {
599 /* Invalid selector */
600 Fast486ExceptionWithErrorCode(State, Exception, Selector);
601 return FALSE;
602 }
603
604 if (Segment == FAST486_REG_SS)
605 {
606 /* Loading the stack segment */
607
608 if (!(Selector & SEGMENT_TABLE_INDICATOR) && GET_SEGMENT_INDEX(Selector) == 0)
609 {
610 Fast486Exception(State, Exception);
611 return FALSE;
612 }
613
614 if (!GdtEntry.SystemType)
615 {
616 /* This is a special descriptor */
617 Fast486ExceptionWithErrorCode(State, Exception, Selector);
618 return FALSE;
619 }
620
621 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
622 {
623 Fast486ExceptionWithErrorCode(State, Exception, Selector);
624 return FALSE;
625 }
626
627 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
628 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
629 {
630 Fast486ExceptionWithErrorCode(State, Exception, Selector);
631 return FALSE;
632 }
633
634 if (!GdtEntry.Present)
635 {
636 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector);
637 return FALSE;
638 }
639 }
640 else if (Segment == FAST486_REG_CS)
641 {
642 /* Loading the code segment */
643
644 #ifndef FAST486_NO_PREFETCH
645 /* Invalidate the prefetch */
646 State->PrefetchValid = FALSE;
647 #endif
648
649 if (!(Selector & SEGMENT_TABLE_INDICATOR) && GET_SEGMENT_INDEX(Selector) == 0)
650 {
651 Fast486Exception(State, Exception);
652 return FALSE;
653 }
654
655 if (!GdtEntry.SystemType)
656 {
657 /* Must be a segment descriptor */
658 Fast486ExceptionWithErrorCode(State, Exception, Selector);
659 return FALSE;
660 }
661
662 if (!GdtEntry.Present)
663 {
664 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
665 return FALSE;
666 }
667
668 if (!GdtEntry.Executable)
669 {
670 Fast486ExceptionWithErrorCode(State, Exception, Selector);
671 return FALSE;
672 }
673
674 if (GdtEntry.DirConf)
675 {
676 /* Conforming Code Segment */
677
678 if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
679 {
680 /* Must be accessed from lower-privileged code */
681 Fast486ExceptionWithErrorCode(State, Exception, Selector);
682 return FALSE;
683 }
684 }
685 else
686 {
687 /* Regular code segment */
688
689 if ((GET_SEGMENT_RPL(Selector) < Fast486GetCurrentPrivLevel(State)))
690 {
691 Fast486ExceptionWithErrorCode(State, Exception, Selector);
692 return FALSE;
693 }
694 }
695 }
696 else
697 {
698 /* Loading a data segment */
699
700 if (GET_SEGMENT_INDEX(Selector) != 0 || (Selector & SEGMENT_TABLE_INDICATOR))
701 {
702 if (!GdtEntry.SystemType)
703 {
704 /* This is a special descriptor */
705 Fast486ExceptionWithErrorCode(State, Exception, Selector);
706 return FALSE;
707 }
708
709 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
710 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
711 {
712 Fast486ExceptionWithErrorCode(State, Exception, Selector);
713 return FALSE;
714 }
715
716 if (!GdtEntry.Present)
717 {
718 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
719 return FALSE;
720 }
721 }
722 else
723 {
724 /* This is a NULL selector */
725 RtlZeroMemory(&GdtEntry, sizeof(GdtEntry));
726 }
727 }
728
729 /* Update the cache entry */
730 CachedDescriptor->Selector = Selector;
731 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
732 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
733 CachedDescriptor->Accessed = GdtEntry.Accessed;
734 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
735 CachedDescriptor->DirConf = GdtEntry.DirConf;
736 CachedDescriptor->Executable = GdtEntry.Executable;
737 CachedDescriptor->SystemType = GdtEntry.SystemType;
738 CachedDescriptor->Rpl = GET_SEGMENT_RPL(Selector);
739 CachedDescriptor->Dpl = GdtEntry.Dpl;
740 CachedDescriptor->Present = GdtEntry.Present;
741 CachedDescriptor->Size = GdtEntry.Size;
742
743 /* Check for page granularity */
744 if (GdtEntry.Granularity)
745 {
746 CachedDescriptor->Limit <<= 12;
747 CachedDescriptor->Limit |= 0x00000FFF;
748 }
749 }
750 else
751 {
752 /* Update the selector and base */
753 CachedDescriptor->Selector = Selector;
754 CachedDescriptor->Base = Selector << 4;
755 }
756
757 return TRUE;
758 }
759
760 FORCEINLINE
761 BOOLEAN
762 FASTCALL
763 Fast486LoadSegment(PFAST486_STATE State,
764 FAST486_SEG_REGS Segment,
765 USHORT Selector)
766 {
767 return Fast486LoadSegmentInternal(State,
768 Segment,
769 Selector,
770 FAST486_EXCEPTION_GP);
771 }
772
773 FORCEINLINE
774 BOOLEAN
775 FASTCALL
776 Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN Call)
777 {
778 BOOLEAN Valid;
779 FAST486_SYSTEM_DESCRIPTOR Descriptor;
780
781 if (!Fast486ReadDescriptorEntry(State,
782 Selector,
783 &Valid,
784 (PFAST486_GDT_ENTRY)&Descriptor))
785 {
786 /* Exception occurred */
787 return FALSE;
788 }
789
790 if (!Valid)
791 {
792 /* Invalid selector */
793 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
794 return FALSE;
795 }
796
797 switch (Descriptor.Signature)
798 {
799 case FAST486_TASK_GATE_SIGNATURE:
800 {
801 Fast486TaskSwitch(State,
802 Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP,
803 ((PFAST486_IDT_ENTRY)&Descriptor)->Selector);
804
805 return FALSE;
806 }
807
808 case FAST486_TSS_16_SIGNATURE:
809 case FAST486_BUSY_TSS_16_SIGNATURE:
810 case FAST486_TSS_SIGNATURE:
811 case FAST486_BUSY_TSS_SIGNATURE:
812 {
813 Fast486TaskSwitch(State,
814 Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP,
815 Selector);
816
817 return FALSE;
818 }
819
820 case FAST486_CALL_GATE_16_SIGNATURE:
821 case FAST486_CALL_GATE_SIGNATURE:
822 {
823 if ((Descriptor.Dpl < Fast486GetCurrentPrivLevel(State))
824 && (Descriptor.Dpl < GET_SEGMENT_RPL(Selector)))
825 {
826 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
827 return FALSE;
828 }
829
830 if (!Descriptor.Present)
831 {
832 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
833 return FALSE;
834 }
835
836 Fast486CallGate(State, (PFAST486_CALL_GATE)&Descriptor, Call);
837
838 /* The gate has been processed here, so return FALSE */
839 return FALSE;
840 }
841
842 default:
843 {
844 /* Security check for jumps and calls only */
845 if (State->Cpl != Descriptor.Dpl)
846 {
847 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
848 return FALSE;
849 }
850
851 return TRUE;
852 }
853 }
854 }
855
856 FORCEINLINE
857 BOOLEAN
858 FASTCALL
859 Fast486FetchByte(PFAST486_STATE State,
860 PUCHAR Data)
861 {
862 PFAST486_SEG_REG CachedDescriptor;
863 ULONG Offset;
864 #ifndef FAST486_NO_PREFETCH
865 ULONG LinearAddress;
866 #endif
867
868 /* Get the cached descriptor of CS */
869 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
870
871 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
872 : State->InstPtr.LowWord;
873 #ifndef FAST486_NO_PREFETCH
874 LinearAddress = CachedDescriptor->Base + Offset;
875
876 if (State->PrefetchValid
877 && (LinearAddress >= State->PrefetchAddress)
878 && ((LinearAddress + sizeof(UCHAR)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
879 {
880 *Data = *(PUCHAR)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
881 }
882 else
883 #endif
884 {
885 /* Read from memory */
886 if (!Fast486ReadMemory(State,
887 FAST486_REG_CS,
888 Offset,
889 TRUE,
890 Data,
891 sizeof(UCHAR)))
892 {
893 /* Exception occurred during instruction fetch */
894 return FALSE;
895 }
896 }
897
898 /* Advance the instruction pointer */
899 if (CachedDescriptor->Size) State->InstPtr.Long++;
900 else State->InstPtr.LowWord++;
901
902 return TRUE;
903 }
904
905 FORCEINLINE
906 BOOLEAN
907 FASTCALL
908 Fast486FetchWord(PFAST486_STATE State,
909 PUSHORT Data)
910 {
911 PFAST486_SEG_REG CachedDescriptor;
912 ULONG Offset;
913 #ifndef FAST486_NO_PREFETCH
914 ULONG LinearAddress;
915 #endif
916
917 /* Get the cached descriptor of CS */
918 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
919
920 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
921 : State->InstPtr.LowWord;
922
923 #ifndef FAST486_NO_PREFETCH
924 LinearAddress = CachedDescriptor->Base + Offset;
925
926 if (State->PrefetchValid
927 && (LinearAddress >= State->PrefetchAddress)
928 && ((LinearAddress + sizeof(USHORT)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
929 {
930 *Data = *(PUSHORT)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
931 }
932 else
933 #endif
934 {
935 /* Read from memory */
936 // FIXME: Fix byte order on big-endian machines
937 if (!Fast486ReadMemory(State,
938 FAST486_REG_CS,
939 Offset,
940 TRUE,
941 Data,
942 sizeof(USHORT)))
943 {
944 /* Exception occurred during instruction fetch */
945 return FALSE;
946 }
947 }
948
949 /* Advance the instruction pointer */
950 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
951 else State->InstPtr.LowWord += sizeof(USHORT);
952
953 return TRUE;
954 }
955
956 FORCEINLINE
957 BOOLEAN
958 FASTCALL
959 Fast486FetchDword(PFAST486_STATE State,
960 PULONG Data)
961 {
962 PFAST486_SEG_REG CachedDescriptor;
963 ULONG Offset;
964 #ifndef FAST486_NO_PREFETCH
965 ULONG LinearAddress;
966 #endif
967
968 /* Get the cached descriptor of CS */
969 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
970
971 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
972 : State->InstPtr.LowWord;
973
974 #ifndef FAST486_NO_PREFETCH
975 LinearAddress = CachedDescriptor->Base + Offset;
976
977 if (State->PrefetchValid
978 && (LinearAddress >= State->PrefetchAddress)
979 && ((LinearAddress + sizeof(ULONG)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
980 {
981 *Data = *(PULONG)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
982 }
983 else
984 #endif
985 {
986 /* Read from memory */
987 // FIXME: Fix byte order on big-endian machines
988 if (!Fast486ReadMemory(State,
989 FAST486_REG_CS,
990 Offset,
991 TRUE,
992 Data,
993 sizeof(ULONG)))
994 {
995 /* Exception occurred during instruction fetch */
996 return FALSE;
997 }
998 }
999
1000 /* Advance the instruction pointer */
1001 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
1002 else State->InstPtr.LowWord += sizeof(ULONG);
1003
1004 return TRUE;
1005 }
1006
1007 FORCEINLINE
1008 BOOLEAN
1009 FASTCALL
1010 Fast486CalculateParity(UCHAR Number)
1011 {
1012 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
1013 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
1014 }
1015
1016 FORCEINLINE
1017 BOOLEAN
1018 FASTCALL
1019 Fast486ParseModRegRm(PFAST486_STATE State,
1020 BOOLEAN AddressSize,
1021 PFAST486_MOD_REG_RM ModRegRm)
1022 {
1023 UCHAR ModRmByte, Mode, RegMem;
1024
1025 /* Fetch the MOD REG R/M byte */
1026 if (!Fast486FetchByte(State, &ModRmByte))
1027 {
1028 /* Exception occurred */
1029 return FALSE;
1030 }
1031
1032 /* Unpack the mode and R/M */
1033 Mode = ModRmByte >> 6;
1034 RegMem = ModRmByte & 0x07;
1035
1036 /* Set the register operand */
1037 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
1038
1039 /* Check the mode */
1040 if (Mode == 3)
1041 {
1042 /* The second operand is also a register */
1043 ModRegRm->Memory = FALSE;
1044 ModRegRm->SecondRegister = RegMem;
1045
1046 /* Done parsing */
1047 return TRUE;
1048 }
1049
1050 /* The second operand is memory */
1051 ModRegRm->Memory = TRUE;
1052
1053 if (AddressSize)
1054 {
1055 if (RegMem == FAST486_REG_ESP)
1056 {
1057 UCHAR SibByte;
1058 ULONG Scale, Index, Base;
1059
1060 /* Fetch the SIB byte */
1061 if (!Fast486FetchByte(State, &SibByte))
1062 {
1063 /* Exception occurred */
1064 return FALSE;
1065 }
1066
1067 /* Unpack the scale, index and base */
1068 Scale = 1 << (SibByte >> 6);
1069 Index = (SibByte >> 3) & 0x07;
1070 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
1071 else Index = 0;
1072
1073 if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0))
1074 {
1075 /* Use the register a base */
1076 Base = State->GeneralRegs[SibByte & 0x07].Long;
1077 }
1078 else
1079 {
1080 /* Fetch the base */
1081 if (!Fast486FetchDword(State, &Base))
1082 {
1083 /* Exception occurred */
1084 return FALSE;
1085 }
1086 }
1087
1088 if (((SibByte & 0x07) == FAST486_REG_ESP)
1089 || ((SibByte & 0x07) == FAST486_REG_EBP && Mode != 0))
1090 {
1091 /* Check if there is no segment override */
1092 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
1093 {
1094 /* Add a SS: prefix */
1095 State->PrefixFlags |= FAST486_PREFIX_SEG;
1096 State->SegmentOverride = FAST486_REG_SS;
1097 }
1098 }
1099
1100 /* Calculate the address */
1101 ModRegRm->MemoryAddress = Base + Index * Scale;
1102 }
1103 else if (RegMem == FAST486_REG_EBP)
1104 {
1105 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
1106 else ModRegRm->MemoryAddress = 0;
1107 }
1108 else
1109 {
1110 /* Get the base from the register */
1111 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
1112 }
1113
1114 /* Check if there is no segment override */
1115 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
1116 {
1117 /* Check if the default segment should be SS */
1118 if ((RegMem == FAST486_REG_EBP) && Mode)
1119 {
1120 /* Add a SS: prefix */
1121 State->PrefixFlags |= FAST486_PREFIX_SEG;
1122 State->SegmentOverride = FAST486_REG_SS;
1123 }
1124 }
1125
1126 if (Mode == 1)
1127 {
1128 CHAR Offset;
1129
1130 /* Fetch the byte */
1131 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1132 {
1133 /* Exception occurred */
1134 return FALSE;
1135 }
1136
1137 /* Add the signed offset to the address */
1138 ModRegRm->MemoryAddress += (LONG)Offset;
1139 }
1140 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
1141 {
1142 LONG Offset;
1143
1144 /* Fetch the dword */
1145 if (!Fast486FetchDword(State, (PULONG)&Offset))
1146 {
1147 /* Exception occurred */
1148 return FALSE;
1149 }
1150
1151 /* Add the signed offset to the address */
1152 ModRegRm->MemoryAddress += Offset;
1153 }
1154 }
1155 else
1156 {
1157 /* Check the operand */
1158 switch (RegMem)
1159 {
1160 case 0:
1161 {
1162 /* [BX + SI] */
1163 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
1164 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
1165 break;
1166 }
1167
1168 case 1:
1169 {
1170 /* [BX + DI] */
1171 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
1172 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
1173 break;
1174 }
1175
1176 case 2:
1177 {
1178 /* SS:[BP + SI] */
1179 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
1180 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
1181 break;
1182 }
1183
1184 case 3:
1185 {
1186 /* SS:[BP + DI] */
1187 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
1188 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
1189 break;
1190 }
1191
1192 case 4:
1193 {
1194 /* [SI] */
1195 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
1196 break;
1197 }
1198
1199 case 5:
1200 {
1201 /* [DI] */
1202 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
1203 break;
1204 }
1205
1206 case 6:
1207 {
1208 if (Mode)
1209 {
1210 /* [BP] */
1211 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
1212 }
1213 else
1214 {
1215 /* [constant] (added later) */
1216 ModRegRm->MemoryAddress = 0;
1217 }
1218
1219 break;
1220 }
1221
1222 case 7:
1223 {
1224 /* [BX] */
1225 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
1226 break;
1227 }
1228 }
1229
1230 /* Check if there is no segment override */
1231 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
1232 {
1233 /* Check if the default segment should be SS */
1234 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
1235 {
1236 /* Add a SS: prefix */
1237 State->PrefixFlags |= FAST486_PREFIX_SEG;
1238 State->SegmentOverride = FAST486_REG_SS;
1239 }
1240 }
1241
1242 if (Mode == 1)
1243 {
1244 CHAR Offset;
1245
1246 /* Fetch the byte */
1247 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1248 {
1249 /* Exception occurred */
1250 return FALSE;
1251 }
1252
1253 /* Add the signed offset to the address */
1254 ModRegRm->MemoryAddress += (LONG)Offset;
1255 }
1256 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
1257 {
1258 SHORT Offset;
1259
1260 /* Fetch the word */
1261 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
1262 {
1263 /* Exception occurred */
1264 return FALSE;
1265 }
1266
1267 /* Add the signed offset to the address */
1268 ModRegRm->MemoryAddress += (LONG)Offset;
1269 }
1270
1271 /* Clear the top 16 bits */
1272 ModRegRm->MemoryAddress &= 0x0000FFFF;
1273 }
1274
1275 return TRUE;
1276 }
1277
1278 FORCEINLINE
1279 BOOLEAN
1280 FASTCALL
1281 Fast486ReadModrmByteOperands(PFAST486_STATE State,
1282 PFAST486_MOD_REG_RM ModRegRm,
1283 PUCHAR RegValue,
1284 PUCHAR RmValue)
1285 {
1286 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1287
1288 if (RegValue)
1289 {
1290 /* Get the register value */
1291 if (ModRegRm->Register & 0x04)
1292 {
1293 /* AH, CH, DH, BH */
1294 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
1295 }
1296 else
1297 {
1298 /* AL, CL, DL, BL */
1299 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
1300 }
1301 }
1302
1303 if (RmValue)
1304 {
1305 if (!ModRegRm->Memory)
1306 {
1307 /* Get the second register value */
1308 if (ModRegRm->SecondRegister & 0x04)
1309 {
1310 /* AH, CH, DH, BH */
1311 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
1312 }
1313 else
1314 {
1315 /* AL, CL, DL, BL */
1316 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
1317 }
1318 }
1319 else
1320 {
1321 /* Check for the segment override */
1322 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1323 {
1324 /* Use the override segment instead */
1325 Segment = State->SegmentOverride;
1326 }
1327
1328 /* Read memory */
1329 if (!Fast486ReadMemory(State,
1330 Segment,
1331 ModRegRm->MemoryAddress,
1332 FALSE,
1333 RmValue,
1334 sizeof(UCHAR)))
1335 {
1336 /* Exception occurred */
1337 return FALSE;
1338 }
1339 }
1340 }
1341
1342 return TRUE;
1343 }
1344
1345 FORCEINLINE
1346 BOOLEAN
1347 FASTCALL
1348 Fast486ReadModrmWordOperands(PFAST486_STATE State,
1349 PFAST486_MOD_REG_RM ModRegRm,
1350 PUSHORT RegValue,
1351 PUSHORT RmValue)
1352 {
1353 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1354
1355 if (RegValue)
1356 {
1357 /* Get the register value */
1358 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
1359 }
1360
1361 if (RmValue)
1362 {
1363 if (!ModRegRm->Memory)
1364 {
1365 /* Get the second register value */
1366 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
1367 }
1368 else
1369 {
1370 /* Check for the segment override */
1371 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1372 {
1373 /* Use the override segment instead */
1374 Segment = State->SegmentOverride;
1375 }
1376
1377 /* Read memory */
1378 if (!Fast486ReadMemory(State,
1379 Segment,
1380 ModRegRm->MemoryAddress,
1381 FALSE,
1382 RmValue,
1383 sizeof(USHORT)))
1384 {
1385 /* Exception occurred */
1386 return FALSE;
1387 }
1388 }
1389 }
1390
1391 return TRUE;
1392 }
1393
1394 FORCEINLINE
1395 BOOLEAN
1396 FASTCALL
1397 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
1398 PFAST486_MOD_REG_RM ModRegRm,
1399 PULONG RegValue,
1400 PULONG RmValue)
1401 {
1402 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1403
1404 if (RegValue)
1405 {
1406 /* Get the register value */
1407 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
1408 }
1409
1410 if (RmValue)
1411 {
1412 if (!ModRegRm->Memory)
1413 {
1414 /* Get the second register value */
1415 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
1416 }
1417 else
1418 {
1419 /* Check for the segment override */
1420 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1421 {
1422 /* Use the override segment instead */
1423 Segment = State->SegmentOverride;
1424 }
1425
1426 /* Read memory */
1427 if (!Fast486ReadMemory(State,
1428 Segment,
1429 ModRegRm->MemoryAddress,
1430 FALSE,
1431 RmValue,
1432 sizeof(ULONG)))
1433 {
1434 /* Exception occurred */
1435 return FALSE;
1436 }
1437 }
1438 }
1439
1440 return TRUE;
1441 }
1442
1443 FORCEINLINE
1444 BOOLEAN
1445 FASTCALL
1446 Fast486WriteModrmByteOperands(PFAST486_STATE State,
1447 PFAST486_MOD_REG_RM ModRegRm,
1448 BOOLEAN WriteRegister,
1449 UCHAR Value)
1450 {
1451 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1452
1453 if (WriteRegister)
1454 {
1455 /* Store the value in the register */
1456 if (ModRegRm->Register & 0x04)
1457 {
1458 /* AH, CH, DH, BH */
1459 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
1460 }
1461 else
1462 {
1463 /* AL, CL, DL, BL */
1464 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
1465 }
1466 }
1467 else
1468 {
1469 if (!ModRegRm->Memory)
1470 {
1471 /* Store the value in the second register */
1472 if (ModRegRm->SecondRegister & 0x04)
1473 {
1474 /* AH, CH, DH, BH */
1475 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
1476 }
1477 else
1478 {
1479 /* AL, CL, DL, BL */
1480 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
1481 }
1482 }
1483 else
1484 {
1485 /* Check for the segment override */
1486 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1487 {
1488 /* Use the override segment instead */
1489 Segment = State->SegmentOverride;
1490 }
1491
1492 /* Write memory */
1493 if (!Fast486WriteMemory(State,
1494 Segment,
1495 ModRegRm->MemoryAddress,
1496 &Value,
1497 sizeof(UCHAR)))
1498 {
1499 /* Exception occurred */
1500 return FALSE;
1501 }
1502 }
1503 }
1504
1505 return TRUE;
1506 }
1507
1508 FORCEINLINE
1509 BOOLEAN
1510 FASTCALL
1511 Fast486WriteModrmWordOperands(PFAST486_STATE State,
1512 PFAST486_MOD_REG_RM ModRegRm,
1513 BOOLEAN WriteRegister,
1514 USHORT Value)
1515 {
1516 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1517
1518 if (WriteRegister)
1519 {
1520 /* Store the value in the register */
1521 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
1522 }
1523 else
1524 {
1525 if (!ModRegRm->Memory)
1526 {
1527 /* Store the value in the second register */
1528 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
1529 }
1530 else
1531 {
1532 /* Check for the segment override */
1533 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1534 {
1535 /* Use the override segment instead */
1536 Segment = State->SegmentOverride;
1537 }
1538
1539 /* Write memory */
1540 if (!Fast486WriteMemory(State,
1541 Segment,
1542 ModRegRm->MemoryAddress,
1543 &Value,
1544 sizeof(USHORT)))
1545 {
1546 /* Exception occurred */
1547 return FALSE;
1548 }
1549 }
1550 }
1551
1552 return TRUE;
1553 }
1554
1555 FORCEINLINE
1556 BOOLEAN
1557 FASTCALL
1558 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
1559 PFAST486_MOD_REG_RM ModRegRm,
1560 BOOLEAN WriteRegister,
1561 ULONG Value)
1562 {
1563 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1564
1565 if (WriteRegister)
1566 {
1567 /* Store the value in the register */
1568 State->GeneralRegs[ModRegRm->Register].Long = Value;
1569 }
1570 else
1571 {
1572 if (!ModRegRm->Memory)
1573 {
1574 /* Store the value in the second register */
1575 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
1576 }
1577 else
1578 {
1579 /* Check for the segment override */
1580 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1581 {
1582 /* Use the override segment instead */
1583 Segment = State->SegmentOverride;
1584 }
1585
1586 /* Write memory */
1587 if (!Fast486WriteMemory(State,
1588 Segment,
1589 ModRegRm->MemoryAddress,
1590 &Value,
1591 sizeof(ULONG)))
1592 {
1593 /* Exception occurred */
1594 return FALSE;
1595 }
1596 }
1597 }
1598
1599 return TRUE;
1600 }
1601
1602 FORCEINLINE
1603 BOOLEAN
1604 FASTCALL
1605 Fast486IoPrivilegeCheck(PFAST486_STATE State, USHORT Port)
1606 {
1607 UCHAR Bits;
1608 ULONG Location;
1609 FAST486_TSS Tss;
1610
1611 /* Access is always allowed if the CPL is less than or equal to the IOPL */
1612 if (State->Cpl <= State->Flags.Iopl) return TRUE;
1613
1614 /* Legacy Task State Segments have no IOPB */
1615 if (!State->TaskReg.Modern) return FALSE;
1616
1617 /* Read the TSS */
1618 if (!Fast486ReadLinearMemory(State, State->TaskReg.Base, &Tss, sizeof(FAST486_TSS), FALSE))
1619 {
1620 /* Exception occurred */
1621 return FALSE;
1622 }
1623
1624 Location = State->TaskReg.Base + HIWORD(Tss.IopbOffset) + (Port >> 3);
1625
1626 if (Location > State->TaskReg.Limit)
1627 {
1628 /* Access denied */
1629 Fast486Exception(State, FAST486_EXCEPTION_GP);
1630 return FALSE;
1631 }
1632
1633 /* Read the appropriate bit from the TSS IOPB */
1634 if (!Fast486ReadLinearMemory(State, Location, &Bits, sizeof(UCHAR), FALSE))
1635 {
1636 /* Exception occurred */
1637 return FALSE;
1638 }
1639
1640 if (Bits & (1 << (Port & 0x07)))
1641 {
1642 /* Access denied */
1643 Fast486Exception(State, FAST486_EXCEPTION_GP);
1644 return FALSE;
1645 }
1646
1647 return TRUE;
1648 }
1649
1650 #ifndef FAST486_NO_FPU
1651
1652 FORCEINLINE
1653 VOID
1654 FASTCALL
1655 Fast486FpuExceptionCheck(PFAST486_STATE State)
1656 {
1657 /* Check if an unmasked exception occurred */
1658 if ((State->FpuStatus.Ie && !State->FpuControl.Im)
1659 || (State->FpuStatus.De && !State->FpuControl.Dm)
1660 || (State->FpuStatus.Ze && !State->FpuControl.Zm)
1661 || (State->FpuStatus.Oe && !State->FpuControl.Om)
1662 || (State->FpuStatus.Ue && !State->FpuControl.Um)
1663 || (State->FpuStatus.Pe && !State->FpuControl.Pm))
1664 {
1665 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_NE)
1666 {
1667 /* Call the #MF handler */
1668 Fast486Exception(State, FAST486_EXCEPTION_MF);
1669 }
1670 else
1671 {
1672 /* Use the external interrupt */
1673 State->FpuCallback(State);
1674 }
1675 }
1676 }
1677
1678 FORCEINLINE
1679 BOOLEAN
1680 FASTCALL
1681 Fast486FpuNormalize(PFAST486_STATE State,
1682 PFAST486_FPU_DATA_REG Data)
1683 {
1684 UINT LeadingZeros;
1685
1686 if (FPU_IS_ZERO(Data))
1687 {
1688 Data->Exponent = 0;
1689 return TRUE;
1690 }
1691
1692 if (FPU_IS_NORMALIZED(Data)) return TRUE;
1693
1694 LeadingZeros = CountLeadingZeros64(Data->Mantissa);
1695
1696 if (LeadingZeros < Data->Exponent)
1697 {
1698 Data->Mantissa <<= LeadingZeros;
1699 Data->Exponent -= LeadingZeros;
1700 }
1701 else
1702 {
1703 /* Raise the underflow exception */
1704 State->FpuStatus.Ue = TRUE;
1705
1706 if (State->FpuControl.Um)
1707 {
1708 /* Make it denormalized */
1709 Data->Mantissa <<= Data->Exponent - 1;
1710 Data->Exponent = 1;
1711 }
1712 else
1713 {
1714 return FALSE;
1715 }
1716 }
1717
1718 return TRUE;
1719 }
1720
1721 FORCEINLINE
1722 USHORT
1723 FASTCALL
1724 Fast486FpuGetValueTag(PFAST486_FPU_DATA_REG Data)
1725 {
1726 if (FPU_IS_ZERO(Data)) return FPU_TAG_ZERO;
1727 else if (FPU_IS_NAN(Data)) return FPU_TAG_SPECIAL;
1728 else return FPU_TAG_VALID;
1729 }
1730
1731 FORCEINLINE
1732 BOOLEAN
1733 FASTCALL
1734 Fast486FpuPush(PFAST486_STATE State,
1735 PCFAST486_FPU_DATA_REG Data)
1736 {
1737 State->FpuStatus.Top--;
1738
1739 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1740 {
1741 FPU_ST(0) = *Data;
1742 FPU_UPDATE_TAG(0);
1743
1744 return TRUE;
1745 }
1746 else
1747 {
1748 /* Raise the stack fault and invalid operation exception */
1749 State->FpuStatus.Sf = State->FpuStatus.Ie = TRUE;
1750
1751 /* Set the C1 condition code bit (stack overflow) */
1752 State->FpuStatus.Code1 = TRUE;
1753
1754 return FALSE;
1755 }
1756 }
1757
1758 FORCEINLINE
1759 BOOLEAN
1760 FASTCALL
1761 Fast486FpuPop(PFAST486_STATE State)
1762 {
1763 if (FPU_GET_TAG(0) != FPU_TAG_EMPTY)
1764 {
1765 FPU_SET_TAG(0, FPU_TAG_EMPTY);
1766 State->FpuStatus.Top++;
1767
1768 return TRUE;
1769 }
1770 else
1771 {
1772 /* Raise the stack fault and invalid operation exception */
1773 State->FpuStatus.Sf = State->FpuStatus.Ie = TRUE;
1774
1775 /* Clear the C1 condition code bit (stack underflow) */
1776 State->FpuStatus.Code1 = FALSE;
1777
1778 return FALSE;
1779 }
1780 }
1781
1782 #endif
1783
1784 /* EOF */