windows-nt/Source/XPSP1/NT/base/wow64/mscpu/fraglib/fragmisc.c
2020-09-26 16:20:57 +08:00

622 lines
12 KiB
C

/*++
Copyright (c) 1995-2000 Microsoft Corporation
Module Name:
fragmisc.c
Abstract:
Miscellaneous instuction fragments.
Author:
12-Jun-1995 BarryBo
Revision History:
24-Aug-1999 [askhalid] copied from 32-bit wx86 directory and make work for 64bit.
20-Sept-1999[barrybo] added FRAG2REF(CmpXchg8bFrag32, ULONGLONG)
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include <float.h>
#include "wx86.h"
#include "wx86nt.h"
#include "fragp.h"
#include "fragmisc.h"
#include "cpunotif.h"
#include "config.h"
#include "mrsw.h"
#include "cpuassrt.h"
#if MSCPU
#include "atomic.h"
#endif
ASSERTNAME;
void
CpupUnlockTCAndDoInterrupt(
PTHREADSTATE cpu,
int Interrupt
)
{
MrswReaderExit(&MrswTC);
cpu->fTCUnlocked = TRUE;
CpupDoInterrupt(Interrupt);
// If we get here, CpupDoInterrupt returned due to CONTINUE_EXECUTION.
// We need to redesign so we can jump to EndTranslatedCode now, as
// the cache may have been flushed.
CPUASSERT(FALSE);
MrswReaderEnter(&MrswTC);
cpu->fTCUnlocked = FALSE;
}
FRAG0(CbwFrag32)
{
eax = (signed long)(signed short)ax;
}
FRAG0(CbwFrag16)
{
ax = (signed short)(signed char)al;
}
FRAG0(PushEsFrag)
{
PUSH_LONG(ES);
}
FRAG0(PopEsFrag)
{
DWORD temp;
POP_LONG(temp);
ES = (USHORT)temp;
}
FRAG0(PushFsFrag)
{
PUSH_LONG(FS);
}
FRAG0(PopFsFrag)
{
DWORD temp;
POP_LONG(temp);
FS = (USHORT)temp;
}
FRAG0(PushGsFrag)
{
PUSH_LONG(GS);
}
FRAG0(PopGsFrag)
{
DWORD temp;
POP_LONG(temp);
GS = (USHORT)temp;
}
FRAG0(PushCsFrag)
{
PUSH_LONG(CS);
}
FRAG0(AasFrag)
{
if ( (al & 0x0f) > 9 || GET_AUXFLAG) {
ah--;
al = (al-6) & 0x0f;
SET_CFLAG_ON;
SET_AUXFLAG_ON;
} else {
SET_CFLAG_OFF;
SET_AUXFLAG_OFF;
al &= 0xf;
}
}
FRAG0(PushSsFrag)
{
PUSH_LONG(SS);
}
FRAG0(PopSsFrag)
{
DWORD temp;
POP_LONG(temp);
SS = (USHORT)temp;
}
FRAG0(PushDsFrag)
{
PUSH_LONG(DS);
}
FRAG0(PopDsFrag)
{
DWORD temp;
POP_LONG(temp);
DS = (USHORT)temp;
}
FRAG0(DaaFrag)
{
if ((al & 0x0f) > 9 || GET_AUXFLAG) {
al += 6;
SET_AUXFLAG_ON;
} else {
SET_AUXFLAG_OFF;
}
if ((al & 0xf0) > 0x90 || GET_CFLAG) {
al += 0x60;
SET_CFLAG_ON;
} else {
SET_CFLAG_OFF;
}
SET_ZFLAG(al);
SET_PFLAG(al);
SET_SFLAG(al << (31-7)); // SET_SFLAG_IND(al & 0x80);
}
FRAG0(DasFrag)
{
if ( (al & 0x0f) > 9 || GET_AUXFLAG) {
al -= 6;
SET_AUXFLAG_ON;
} else {
SET_AUXFLAG_OFF;
}
if ( al > 0x9f || GET_CFLAG) {
al -= 0x60;
SET_CFLAG_ON;
} else {
SET_CFLAG_OFF;
}
SET_ZFLAG(al);
SET_PFLAG(al);
SET_SFLAG(al << (31-7)); // SET_SFLAG_IND(al & 0x80);
}
FRAG0(AaaFrag)
{
if ((al & 0x0f) > 9 || GET_AUXFLAG) {
al=(al+6) & 0x0f;
ah++; // inc ah
SET_AUXFLAG_ON;
SET_CFLAG_ON;
} else {
SET_AUXFLAG_OFF;
SET_CFLAG_OFF;
al &= 0xf;
}
}
FRAG1IMM(AadFrag, BYTE)
{
al += ah * op1;
ah = 0;
SET_ZFLAG(al);
SET_PFLAG(al);
SET_SFLAG(al << (31-7)); // SET_SFLAG_IND(al & 0x80);
}
FRAG2(ImulFrag16, USHORT)
{
Imul3ArgFrag16(cpu, pop1, GET_SHORT(pop1), op2);
}
FRAG2(ImulFrag16A, USHORT)
{
Imul3ArgFrag16A(cpu, pop1, *pop1, op2);
}
FRAG3(Imul3ArgFrag16, USHORT, USHORT, USHORT)
{
long result;
result = (long)(short)op2 * (long)(short)op3;
PUT_SHORT(pop1, (USHORT)(short)result);
if (HIWORD(result) == 0 || HIWORD(result) == 0xffff) {
SET_CFLAG_OFF;
SET_OFLAG_OFF;
} else {
SET_CFLAG_ON;
SET_OFLAG_ON;
}
}
FRAG3(Imul3ArgFrag16A, USHORT, USHORT, USHORT)
{
long result;
result = (short)op2 * (short)op3;
*pop1 = (USHORT)(short)result;
if (HIWORD(result) == 0 || HIWORD(result) == 0xffff) {
SET_CFLAG_OFF;
SET_OFLAG_OFF;
} else {
SET_CFLAG_ON;
SET_OFLAG_ON;
}
}
FRAG2(ImulNoFlagsFrag16, USHORT)
{
short op1 = (short)GET_SHORT(pop1);
PUT_SHORT(pop1, (op2 * (short)op2));
}
FRAG2(ImulNoFlagsFrag16A, USHORT)
{
*(short *)pop1 *= (short)op2;
}
FRAG3(Imul3ArgNoFlagsFrag16, USHORT, USHORT, USHORT)
{
PUT_SHORT(pop1, ((short)op2 * (short)op3));
}
FRAG3(Imul3ArgNoFlagsFrag16A, USHORT, USHORT, USHORT)
{
*pop1 = (USHORT)((short)op2 * (short)op3);
}
FRAG2(ImulFrag32, DWORD)
{
Imul3ArgFrag32(cpu, pop1, GET_LONG(pop1), op2);
}
FRAG2(ImulFrag32A, DWORD)
{
Imul3ArgFrag32A(cpu, pop1, *pop1, (long)op2);
}
FRAG3(Imul3ArgFrag32A, DWORD, DWORD, DWORD)
{
LARGE_INTEGER result;
LONGLONG ll;
ll = Int32x32To64((long)op2, (long)op3);
result = *(LARGE_INTEGER *)&ll;
*pop1 = result.LowPart;
if (result.HighPart == 0 || result.HighPart == 0xffffffff) {
SET_CFLAG_OFF;
SET_OFLAG_OFF;
} else {
SET_CFLAG_ON;
SET_OFLAG_ON;
}
}
FRAG3(Imul3ArgFrag32, DWORD, DWORD, DWORD)
{
LARGE_INTEGER result;
LONGLONG ll;
ll = Int32x32To64((long)op2, (long)op3);
result = *(LARGE_INTEGER *)&ll;
PUT_LONG(pop1, result.LowPart);
if (result.HighPart == 0 || result.HighPart == 0xffffffff) {
SET_CFLAG_OFF;
SET_OFLAG_OFF;
} else {
SET_CFLAG_ON;
SET_OFLAG_ON;
}
}
FRAG2(ImulNoFlagsFrag32, DWORD)
{
long op1 = (LONG)GET_LONG(pop1);
PUT_LONG(pop1, (op1 * (long)op2));
}
FRAG2(ImulNoFlagsFrag32A, DWORD)
{
*(long *)pop1 *= (long)op2;
}
FRAG3(Imul3ArgNoFlagsFrag32A, DWORD, DWORD, DWORD)
{
*pop1 = (DWORD)( (long)op2 * (long)op3);
}
FRAG3(Imul3ArgNoFlagsFrag32, DWORD, DWORD, DWORD)
{
PUT_LONG(pop1, ((long)op2 * (long)op3));
}
FRAG0(SahfFrag)
{
DWORD dw = (DWORD)ah;
SET_CFLAG(dw << 31); // CFLAG is low-bit of ah
SET_PFLAG (!(dw & FLAG_PF)); // flag_pf contains an index into ParityBit[] array
SET_AUXFLAG(dw); // AUX bit is already in the right place
SET_ZFLAG (!(dw & FLAG_ZF)); // zf has inverse logic
SET_SFLAG(dw << (31-7)); // SFLAG is bit 7 in AH
}
FRAG0(LahfFrag)
{
ah= 2 | // this bit is always set on Intel
((GET_CFLAG) ? FLAG_CF : 0) |
((GET_PFLAG) ? FLAG_PF : 0) |
((GET_AUXFLAG)? FLAG_AUX: 0) |
((cpu->flag_zf) ? 0 : FLAG_ZF) | // zf has inverse logic
((GET_SFLAG) ? FLAG_SF : 0);
}
FRAG1IMM(AamFrag, BYTE)
{
ah = al / op1;
al %= op1;
SET_ZFLAG(al);
SET_PFLAG(al);
SET_SFLAG(al << (31-7));
}
FRAG0(XlatFrag)
{
al = GET_BYTE(ebx+al);
}
FRAG0(CmcFrag)
{
SET_CFLAG_IND(!GET_CFLAG);
}
FRAG0(ClcFrag)
{
SET_CFLAG_OFF;
}
FRAG0(StcFrag)
{
SET_CFLAG_ON;
}
FRAG0(CldFrag)
{
cpu->flag_df = 1;
}
FRAG0(StdFrag)
{
cpu->flag_df = 0xffffffff;
}
FRAG1(SetoFrag, BYTE)
{
PUT_BYTE(pop1, (BYTE)GET_OFLAGZO);
}
FRAG1(SetnoFrag, BYTE)
{
PUT_BYTE(pop1, (GET_OFLAG == 0));
}
FRAG1(SetbFrag, BYTE)
{
PUT_BYTE(pop1, (BYTE)GET_CFLAGZO);
}
FRAG1(SetaeFrag, BYTE)
{
PUT_BYTE(pop1, (GET_CFLAG == 0));
}
FRAG1(SeteFrag, BYTE)
{
PUT_BYTE(pop1, (cpu->flag_zf == 0)); // inverse logic
}
FRAG1(SetneFrag, BYTE)
{
PUT_BYTE(pop1, (cpu->flag_zf != 0)); // inverse logic
}
FRAG1(SetbeFrag, BYTE)
{
PUT_BYTE(pop1, (GET_CFLAG || cpu->flag_zf == 0)); // inverse logic
}
FRAG1(SetaFrag, BYTE)
{
PUT_BYTE(pop1, (GET_CFLAG == 0 && cpu->flag_zf != 0)); // inverse logic
}
FRAG1(SetsFrag, BYTE)
{
PUT_BYTE(pop1, (BYTE)GET_SFLAGZO);
}
FRAG1(SetnsFrag, BYTE)
{
PUT_BYTE(pop1, (GET_SFLAG == 0));
}
FRAG1(SetpFrag, BYTE)
{
PUT_BYTE(pop1, (GET_PFLAG != 0));
}
FRAG1(SetnpFrag, BYTE)
{
PUT_BYTE(pop1, (GET_PFLAG == 0));
}
FRAG1(SetlFrag, BYTE)
{
PUT_BYTE(pop1, (GET_SFLAG != GET_OFLAG));
}
FRAG1(SetgeFrag, BYTE)
{
PUT_BYTE(pop1, (GET_SFLAGZO == GET_OFLAGZO));
}
FRAG1(SetleFrag, BYTE)
{
PUT_BYTE(pop1, (!cpu->flag_zf || (GET_SFLAG != GET_OFLAG))); // inverse logic
}
FRAG1(SetgFrag, BYTE)
{
PUT_BYTE(pop1, (cpu->flag_zf && !(GET_SFLAG ^ GET_OFLAG))); // inverse logic
}
FRAG2(Movzx8ToFrag16, USHORT)
{
PUT_SHORT(pop1, (USHORT)(BYTE)op2);
}
FRAG2(Movzx8ToFrag16A, USHORT)
{
*pop1 = (USHORT)(BYTE)op2;
}
FRAG2(Movsx8ToFrag16, USHORT)
{
PUT_SHORT(pop1, (USHORT)(short)(char)(BYTE)op2);
}
FRAG2(Movsx8ToFrag16A, USHORT)
{
*pop1 = (USHORT)(short)(char)(BYTE)op2;
}
FRAG2(Movzx8ToFrag32, DWORD)
{
PUT_LONG(pop1, (DWORD)(BYTE)op2);
}
FRAG2(Movzx8ToFrag32A, DWORD)
{
*pop1 = (DWORD)(BYTE)op2;
}
FRAG2(Movsx8ToFrag32, DWORD)
{
PUT_LONG(pop1, (DWORD)(long)(char)(BYTE)op2);
}
FRAG2(Movsx8ToFrag32A, DWORD)
{
*pop1 = (DWORD)(long)(char)(BYTE)op2;
}
FRAG2(Movzx16ToFrag32, DWORD)
{
PUT_LONG(pop1, (DWORD)(USHORT)op2);
}
FRAG2(Movzx16ToFrag32A, DWORD)
{
*pop1 = (DWORD)(USHORT)op2;
}
FRAG2(Movsx16ToFrag32, DWORD)
{
PUT_LONG(pop1, (DWORD)(long)(short)(USHORT)op2);
}
FRAG2(Movsx16ToFrag32A, DWORD)
{
*pop1 = (DWORD)(long)(short)(USHORT)op2;
}
FRAG1(BswapFrag32, DWORD)
{
DWORD d;
PBYTE pSrc = (PBYTE)pop1;
d = (pSrc[0] << 24) | (pSrc[1] << 16) | (pSrc[2] << 8) | pSrc[3];
// pop1 is always a pointer to a register, so an ALIGNED store is correct
*pop1 = d;
}
FRAG2(ArplFrag, USHORT)
{
USHORT op1 = GET_SHORT(pop1);
op2 &= 3; // just get the RPL bits of the selector
if ((op1&3) < op2) {
// RPL bits of DEST < RPL bits of SRC
op1 = (op1 & ~3) | op2; // copy RPL bits from SRC to DEST
PUT_SHORT(pop1, op1); // store DEST
SET_ZFLAG(0); // ZF=1
} else {
SET_ZFLAG(1);
}
}
FRAG1(VerrFrag, USHORT)
{
USHORT op1 = GET_SHORT(pop1) & ~3; // mask off RPL bits
if (op1 == KGDT_R3_CODE || // CS: selector
op1 == KGDT_R3_DATA || // DS:, SS:, ES: selector
op1 == KGDT_R3_TEB // FS: selector
) {
SET_ZFLAG(0); // ZF=1
} else {
SET_ZFLAG(1); // ZF=0
}
}
FRAG1(VerwFrag, USHORT)
{
USHORT op1 = GET_SHORT(pop1) & ~3; // mask off RPL bits
if (op1 == KGDT_R3_DATA || // DS:, SS:, ES: selector
op1 == KGDT_R3_TEB // FS: selector
) {
SET_ZFLAG(0); // ZF=1
} else {
SET_ZFLAG(1); // ZF=0
}
}
FRAG1(SmswFrag, USHORT)
{
//
// This value is empirically discovered by running it on a Pentium
// machine. CR0_PE, CR0_EX, and CR0_NE bits were set, and all others
// notably CR0_MP, are clear.
//
PUT_SHORT(pop1, 0x31);
}
#if MSCPU
FRAG0(IntOFrag)
{
if (GET_OFLAG) {
Int4(); // raise overflow
}
}
FRAG0(NopFrag)
{
}
FRAG0(PrivilegedInstructionFrag)
{
PRIVILEGED_INSTR;
}
FRAG0(BadInstructionFrag)
{
Int6(); // Throw invalid opcode exception
}
FRAG2(FaultFrag, DWORD)
{
// pop1 = exception code
// op2 = address where fault occurred
#if DBG
LOGPRINT((TRACELOG, "CPU: FaultFrag called\r\n"));
#endif
RtlRaiseStatus((NTSTATUS)(ULONGLONG)pop1);
}
#endif //MSCPU
FRAG0(CPUID)
{
switch (eax) {
case 0:
eax = 1; // We are a 486 with CPUID (PPro returns 2)
//ebx = 0x756e6547; // "GenuineIntel"
//edx = 0x49656e69;
//ecx = 0x6c65746e;
ebx = 0x7263694d; // "Micr" with M in the low nibble of BL
edx = 0x666f736f; // "osof" with o in the low nibble of DL
ecx = 0x55504374; // "tCPU" with t in the low nibble of CL
break;
case 1:
eax = (0 << 12) | // Type = 0 (2 bits) Original OEM Processor
(4 << 8) | // Family = 4 (4 bits) 80486
(1 << 4) | // Model = 1 (4 bits)
0; // Stepping=0 (4 bits)
edx = (fUseNPXEM) ? 1: 0; // bit 0: FPU on-chip. wx86cpu doesn't
// support any other features.
break;
default:
//
// The Intel behavior indicates that if eax is out-of-range, the
// results returned in the regsiters are unpredictable but it
// doesn't fault.
//
break;
}
}
FRAG2REF(CmpXchg8bFrag32, ULONGLONG)
{
ULONGLONG EdxEax;
ULONGLONG Value;
EdxEax = (((ULONGLONG)edx) << 32) | (ULONGLONG)eax;
Value = *(ULONGLONG UNALIGNED *)pop1;
if (Value == EdxEax) {
ULONGLONG EcxEbx;
EcxEbx = (ULONGLONG)ecx << 32 | (ULONGLONG)ebx;
*(ULONGLONG UNALIGNED *)pop1 = EcxEbx;
SET_ZFLAG(0); // zf has inverse logic
} else {
eax = (ULONG)Value;
edx = (ULONG)(Value >> 32);
SET_ZFLAG(1); // zf has inverse logic
}
}
FRAG0(Rdtsc)
{
LARGE_INTEGER Counter;
// This is cheese, but it will at least return a value that increases
// over time.
NtQueryPerformanceCounter(&Counter, NULL);
edx = Counter.HighPart;
eax = Counter.LowPart;
}