2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: 386/486 CPU Emulation Library
5 * PURPOSE: Common functions used internally by Soft386 (inlined funtions).
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* PUBLIC FUNCTIONS ***********************************************************/
13 Soft386Exception(PSOFT386_STATE State,
14 SOFT386_EXCEPTIONS ExceptionCode)
16 /* Call the internal function */
17 Soft386ExceptionWithErrorCode(State, ExceptionCode, 0);
22 Soft386StackPush(PSOFT386_STATE State,
25 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size;
27 /* The OPSIZE prefix toggles the size */
28 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE) Size = !Size;
34 /* Check if ESP is between 1 and 3 */
35 if (State->GeneralRegs[SOFT386_REG_ESP].Long >= 1
36 && State->GeneralRegs[SOFT386_REG_ESP].Long <= 3)
38 Soft386Exception(State, SOFT386_EXCEPTION_SS);
42 /* Subtract ESP by 4 */
43 State->GeneralRegs[SOFT386_REG_ESP].Long -= 4;
45 /* Store the value in SS:ESP */
46 return Soft386WriteMemory(State,
48 State->GeneralRegs[SOFT386_REG_ESP].Long,
55 USHORT ShortValue = LOWORD(Value);
57 /* Check if SP is 1 */
58 if (State->GeneralRegs[SOFT386_REG_ESP].Long == 1)
60 Soft386Exception(State, SOFT386_EXCEPTION_SS);
64 /* Subtract SP by 2 */
65 State->GeneralRegs[SOFT386_REG_ESP].LowWord -= 2;
67 /* Store the value in SS:SP */
68 return Soft386WriteMemory(State,
70 State->GeneralRegs[SOFT386_REG_ESP].LowWord,
78 Soft386StackPop(PSOFT386_STATE State,
83 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size;
85 /* The OPSIZE prefix toggles the size */
86 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE) Size = !Size;
92 /* Check if ESP is 0xFFFFFFFF */
93 if (State->GeneralRegs[SOFT386_REG_ESP].Long == 0xFFFFFFFF)
95 Soft386Exception(State, SOFT386_EXCEPTION_SS);
99 /* Read the value from SS:ESP */
100 if (!Soft386ReadMemory(State,
102 State->GeneralRegs[SOFT386_REG_ESP].Long,
107 /* An exception occurred */
111 /* Increment ESP by 4 */
112 State->GeneralRegs[SOFT386_REG_ESP].Long += 4;
114 /* Store the value in the result */
121 /* Check if SP is 0xFFFF */
122 if (State->GeneralRegs[SOFT386_REG_ESP].LowWord == 0xFFFF)
124 Soft386Exception(State, SOFT386_EXCEPTION_SS);
128 /* Read the value from SS:SP */
129 if (!Soft386ReadMemory(State,
131 State->GeneralRegs[SOFT386_REG_ESP].LowWord,
136 /* An exception occurred */
140 /* Increment SP by 2 */
141 State->GeneralRegs[SOFT386_REG_ESP].Long += 2;
143 /* Store the value in the result */
152 Soft386LoadSegment(PSOFT386_STATE State,
156 PSOFT386_SEG_REG CachedDescriptor;
157 SOFT386_GDT_ENTRY GdtEntry;
159 ASSERT(Segment < SOFT386_NUM_SEG_REGS);
161 /* Get the cached descriptor */
162 CachedDescriptor = &State->SegmentRegs[Segment];
164 /* Check for protected mode */
165 if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
167 /* Make sure the GDT contains the entry */
168 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
170 Soft386Exception(State, SOFT386_EXCEPTION_GP);
175 // FIXME: This code is only correct when paging is disabled!!!
176 if (State->MemReadCallback)
178 State->MemReadCallback(State,
180 + GET_SEGMENT_INDEX(Selector),
186 RtlMoveMemory(&GdtEntry,
187 (PVOID)(State->Gdtr.Address
188 + GET_SEGMENT_INDEX(Selector)),
192 /* Check if we are loading SS */
193 if (Segment == SOFT386_REG_SS)
195 if (GET_SEGMENT_INDEX(Selector) == 0)
197 Soft386Exception(State, SOFT386_EXCEPTION_GP);
201 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
203 Soft386Exception(State, SOFT386_EXCEPTION_GP);
207 if ((GET_SEGMENT_RPL(Selector) != Soft386GetCurrentPrivLevel(State))
208 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
210 Soft386Exception(State, SOFT386_EXCEPTION_GP);
214 if (!GdtEntry.Present)
216 Soft386Exception(State, SOFT386_EXCEPTION_SS);
222 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
223 && (Soft386GetCurrentPrivLevel(State) > GdtEntry.Dpl))
225 Soft386Exception(State, SOFT386_EXCEPTION_GP);
229 if (!GdtEntry.Present)
231 Soft386Exception(State, SOFT386_EXCEPTION_NP);
236 /* Update the cache entry */
237 CachedDescriptor->Selector = Selector;
238 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseHigh << 24);
239 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
240 CachedDescriptor->Accessed = GdtEntry.Accessed;
241 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
242 CachedDescriptor->DirConf = GdtEntry.DirConf;
243 CachedDescriptor->Executable = GdtEntry.Executable;
244 CachedDescriptor->SystemType = GdtEntry.SystemType;
245 CachedDescriptor->Dpl = GdtEntry.Dpl;
246 CachedDescriptor->Present = GdtEntry.Present;
247 CachedDescriptor->Size = GdtEntry.Size;
249 /* Check for page granularity */
250 if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
254 /* Update the selector and base */
255 CachedDescriptor->Selector = Selector;
256 CachedDescriptor->Base = Selector << 4;
264 Soft386FetchByte(PSOFT386_STATE State,
267 PSOFT386_SEG_REG CachedDescriptor;
269 /* Get the cached descriptor of CS */
270 CachedDescriptor = &State->SegmentRegs[SOFT386_REG_CS];
272 /* Read from memory */
273 if (!Soft386ReadMemory(State,
275 (CachedDescriptor->Size) ? State->InstPtr.Long
276 : State->InstPtr.LowWord,
281 /* Exception occurred during instruction fetch */
285 /* Advance the instruction pointer */
286 if (CachedDescriptor->Size) State->InstPtr.Long++;
287 else State->InstPtr.LowWord++;
294 Soft386FetchWord(PSOFT386_STATE State,
297 PSOFT386_SEG_REG CachedDescriptor;
299 /* Get the cached descriptor of CS */
300 CachedDescriptor = &State->SegmentRegs[SOFT386_REG_CS];
302 /* Read from memory */
303 // FIXME: Fix byte order on big-endian machines
304 if (!Soft386ReadMemory(State,
306 (CachedDescriptor->Size) ? State->InstPtr.Long
307 : State->InstPtr.LowWord,
312 /* Exception occurred during instruction fetch */
316 /* Advance the instruction pointer */
317 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
318 else State->InstPtr.LowWord += sizeof(USHORT);
325 Soft386FetchDword(PSOFT386_STATE State,
328 PSOFT386_SEG_REG CachedDescriptor;
330 /* Get the cached descriptor of CS */
331 CachedDescriptor = &State->SegmentRegs[SOFT386_REG_CS];
333 /* Read from memory */
334 // FIXME: Fix byte order on big-endian machines
335 if (!Soft386ReadMemory(State,
337 (CachedDescriptor->Size) ? State->InstPtr.Long
338 : State->InstPtr.LowWord,
343 /* Exception occurred during instruction fetch */
347 /* Advance the instruction pointer */
348 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
349 else State->InstPtr.LowWord += sizeof(ULONG);
356 Soft386GetIntVector(PSOFT386_STATE State,
358 PSOFT386_IDT_ENTRY IdtEntry)
362 /* Check for protected mode */
363 if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
365 /* Read from the IDT */
366 // FIXME: This code is only correct when paging is disabled!!!
367 if (State->MemReadCallback)
369 State->MemReadCallback(State,
371 + Number * sizeof(*IdtEntry),
377 RtlMoveMemory(IdtEntry,
378 (PVOID)(State->Idtr.Address
379 + Number * sizeof(*IdtEntry)),
385 /* Read from the real-mode IVT */
387 /* Paging is always disabled in real mode */
388 if (State->MemReadCallback)
390 State->MemReadCallback(State,
392 + Number * sizeof(FarPointer),
398 RtlMoveMemory(IdtEntry,
399 (PVOID)(State->Idtr.Address
400 + Number * sizeof(FarPointer)),
404 /* Fill a fake IDT entry */
405 IdtEntry->Offset = LOWORD(FarPointer);
406 IdtEntry->Selector = HIWORD(FarPointer);
408 IdtEntry->Type = SOFT386_IDT_INT_GATE;
409 IdtEntry->Storage = FALSE;
411 IdtEntry->Present = TRUE;
412 IdtEntry->OffsetHigh = 0;
416 * Once paging support is implemented this function
417 * will not always return true
424 Soft386CalculateParity(UCHAR Number)
426 Number ^= Number >> 1;
427 Number ^= Number >> 2;
428 Number ^= Number >> 4;
429 return !(Number & 1);
434 Soft386ParseModRegRm(PSOFT386_STATE State,
436 PSOFT386_MOD_REG_RM ModRegRm)
438 UCHAR ModRmByte, Mode, RegMem;
440 /* Fetch the MOD REG R/M byte */
441 if (!Soft386FetchByte(State, &ModRmByte))
443 /* Exception occurred */
447 /* Unpack the mode and R/M */
448 Mode = ModRmByte >> 6;
449 RegMem = ModRmByte & 0x07;
451 /* Set the register operand */
452 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
455 if ((ModRmByte >> 6) == 3)
457 /* The second operand is also a register */
458 ModRegRm->Memory = FALSE;
459 ModRegRm->SecondRegister = RegMem;
465 /* The second operand is memory */
466 ModRegRm->Memory = TRUE;
470 if (RegMem == SOFT386_REG_ESP)
473 ULONG Scale, Index, Base;
475 /* Fetch the SIB byte */
476 if (!Soft386FetchByte(State, &SibByte))
478 /* Exception occurred */
482 /* Unpack the scale, index and base */
483 Scale = 1 << (SibByte >> 6);
484 Index = (SibByte >> 3) & 0x07;
485 if (Index != SOFT386_REG_ESP) Index = State->GeneralRegs[Index].Long;
487 Base = State->GeneralRegs[SibByte & 0x07].Long;
489 /* Calculate the address */
490 ModRegRm->MemoryAddress = Base + Index * Scale;
492 else if (RegMem == SOFT386_REG_EBP)
494 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EBP].Long;
495 else ModRegRm->MemoryAddress = 0;
499 /* Get the base from the register */
500 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
503 /* Check if there is no segment override */
504 if (!(State->PrefixFlags & SOFT386_PREFIX_SEG))
506 /* Check if the default segment should be SS */
507 if ((RegMem == SOFT386_REG_EBP) && Mode)
509 /* Add a SS: prefix */
510 State->PrefixFlags |= SOFT386_PREFIX_SEG;
511 State->SegmentOverride = SOFT386_REG_SS;
520 if (!Soft386FetchByte(State, (PUCHAR)&Offset))
522 /* Exception occurred */
526 /* Add the signed offset to the address */
527 ModRegRm->MemoryAddress += (LONG)Offset;
529 else if ((Mode == 2) || ((Mode == 0) && (RegMem == SOFT386_REG_EBP)))
533 /* Fetch the dword */
534 if (!Soft386FetchDword(State, (PULONG)&Offset))
536 /* Exception occurred */
540 /* Add the signed offset to the address */
541 ModRegRm->MemoryAddress += Offset;
546 /* Check the operand */
553 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EBX].LowWord
554 + State->GeneralRegs[SOFT386_REG_ESI].LowWord;
563 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EBX].LowWord
564 + State->GeneralRegs[SOFT386_REG_EDI].LowWord;
572 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_ESI].LowWord;
580 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EDI].LowWord;
590 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EBP].LowWord;
594 /* [constant] (added later) */
595 ModRegRm->MemoryAddress = 0;
604 ModRegRm->MemoryAddress = State->GeneralRegs[SOFT386_REG_EBX].LowWord;
610 /* Check if there is no segment override */
611 if (!(State->PrefixFlags & SOFT386_PREFIX_SEG))
613 /* Check if the default segment should be SS */
614 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
616 /* Add a SS: prefix */
617 State->PrefixFlags |= SOFT386_PREFIX_SEG;
618 State->SegmentOverride = SOFT386_REG_SS;
627 if (!Soft386FetchByte(State, (PUCHAR)&Offset))
629 /* Exception occurred */
633 /* Add the signed offset to the address */
634 ModRegRm->MemoryAddress += (LONG)Offset;
636 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
641 if (!Soft386FetchWord(State, (PUSHORT)&Offset))
643 /* Exception occurred */
647 /* Add the signed offset to the address */
648 ModRegRm->MemoryAddress += (LONG)Offset;
657 Soft386ReadModrmByteOperands(PSOFT386_STATE State,
658 PSOFT386_MOD_REG_RM ModRegRm,
662 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
664 /* Get the register value */
665 if (ModRegRm->Register & 0x04)
668 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
673 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
676 if (!ModRegRm->Memory)
678 /* Get the second register value */
679 if (ModRegRm->SecondRegister & 0x04)
682 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
687 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
692 /* Check for the segment override */
693 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
695 /* Use the override segment instead */
696 Segment = State->SegmentOverride;
700 if (!Soft386ReadMemory(State,
702 ModRegRm->MemoryAddress,
707 /* Exception occurred */
717 Soft386ReadModrmWordOperands(PSOFT386_STATE State,
718 PSOFT386_MOD_REG_RM ModRegRm,
722 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
724 /* Get the register value */
725 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
727 if (!ModRegRm->Memory)
729 /* Get the second register value */
730 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
734 /* Check for the segment override */
735 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
737 /* Use the override segment instead */
738 Segment = State->SegmentOverride;
742 if (!Soft386ReadMemory(State,
744 ModRegRm->MemoryAddress,
749 /* Exception occurred */
759 Soft386ReadModrmDwordOperands(PSOFT386_STATE State,
760 PSOFT386_MOD_REG_RM ModRegRm,
764 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
766 /* Get the register value */
767 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
769 if (!ModRegRm->Memory)
771 /* Get the second register value */
772 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
776 /* Check for the segment override */
777 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
779 /* Use the override segment instead */
780 Segment = State->SegmentOverride;
784 if (!Soft386ReadMemory(State,
786 ModRegRm->MemoryAddress,
791 /* Exception occurred */
801 Soft386WriteModrmByteOperands(PSOFT386_STATE State,
802 PSOFT386_MOD_REG_RM ModRegRm,
803 BOOLEAN WriteRegister,
806 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
810 /* Store the value in the register */
811 if (ModRegRm->Register & 0x04)
814 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
819 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
824 if (!ModRegRm->Memory)
826 /* Store the value in the second register */
827 if (ModRegRm->SecondRegister & 0x04)
830 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
835 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
840 /* Check for the segment override */
841 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
843 /* Use the override segment instead */
844 Segment = State->SegmentOverride;
848 if (!Soft386WriteMemory(State,
850 ModRegRm->MemoryAddress,
854 /* Exception occurred */
865 Soft386WriteModrmWordOperands(PSOFT386_STATE State,
866 PSOFT386_MOD_REG_RM ModRegRm,
867 BOOLEAN WriteRegister,
870 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
874 /* Store the value in the register */
875 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
879 if (!ModRegRm->Memory)
881 /* Store the value in the second register */
882 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
886 /* Check for the segment override */
887 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
889 /* Use the override segment instead */
890 Segment = State->SegmentOverride;
894 if (!Soft386WriteMemory(State,
896 ModRegRm->MemoryAddress,
900 /* Exception occurred */
911 Soft386WriteModrmDwordOperands(PSOFT386_STATE State,
912 PSOFT386_MOD_REG_RM ModRegRm,
913 BOOLEAN WriteRegister,
916 SOFT386_SEG_REGS Segment = SOFT386_REG_DS;
920 /* Store the value in the register */
921 State->GeneralRegs[ModRegRm->Register].Long = Value;
925 if (!ModRegRm->Memory)
927 /* Store the value in the second register */
928 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
932 /* Check for the segment override */
933 if (State->PrefixFlags & SOFT386_PREFIX_SEG)
935 /* Use the override segment instead */
936 Segment = State->SegmentOverride;
940 if (!Soft386WriteMemory(State,
942 ModRegRm->MemoryAddress,
946 /* Exception occurred */