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

698 lines
15 KiB
C

/*++
Copyright (c) 1996-1998 Microsoft Corporation
Module Name:
miscfns.c
Abstract:
Miscellaneous instuctions
Author:
29-Jun-1995 BarryBo
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include "wx86.h"
#include "cpuassrt.h"
#include "threadst.h"
#include "instr.h"
#include "decoderp.h"
ASSERTNAME;
// table used by ProcessPrefixes
pfnDispatchInstruction *DispatchTables[4] = { Dispatch32, Dispatch16, LockDispatch32, LockDispatch16 };
// ---------------- single-byte functions -------------------------------
DISPATCH(ProcessPrefixes)
{
int DataPrefix = 0;
int LockPrefix = 0;
int cbInstr = 0;
for (;;) {
switch (*(PBYTE)(eipTemp)) {
case 0x64: // fs:
Instr->FsOverride = TRUE;
break;
case 0xf3: // repz
State->RepPrefix = PREFIX_REPZ;
break;
case 0xf2: // repnz
State->RepPrefix = PREFIX_REPNZ;
break;
case 0xf0: // lock
LockPrefix = 2; // The lock tables are in locations 2 and 3 DispatchTables
break;
case 0x2e: // cs:
case 0x36: // ss:
case 0x3e: // ds:
case 0x26: // es:
case 0x65: // gs:
Instr->FsOverride = FALSE;
break;
case 0x66: // data
DataPrefix = 1;
break;
case 0x67: // adr
State->AdrPrefix=TRUE;
break;
default:
// No more prefixes found. Set up dispatch tables based on
// the prefixes seen.
// Decode and execute the actual instruction
((DispatchTables[DataPrefix+LockPrefix])[GET_BYTE(eipTemp)])(State, Instr);
// Adjust the Intel instruction size by the number of prefixes
Instr->Size += cbInstr;
#if DBG
// Ensure that if we saw an ADR: prefix, the decoder had code
// to handle the prefix. In the checked build, all functions which
// handle the ADR: prefix clear State->AdrPrefix.
if (State->AdrPrefix) {
LOGPRINT((TRACELOG, "CPU Decoder: An unsupported instruction had an ADR: prefix.\r\n"
"Instruction Address = 0x%x. Ignoring ADR: - this address may be data\r\n",
Instr->IntelAddress
));
}
#endif
State->AdrPrefix = FALSE;
// return to the decoder
return;
}
eipTemp++;
cbInstr++;
}
}
DISPATCH(bad)
{
BAD_INSTR;
}
DISPATCH(privileged)
{
PRIVILEGED_INSTR;
}
DISPATCH(push_es)
{
Instr->Operation = OP_PushEs;
}
DISPATCH(pop_es)
{
Instr->Operation = OP_PopEs;
}
DISPATCH(push_cs)
{
Instr->Operation = OP_PushCs;
}
DISPATCH(aas)
{
Instr->Operation = OP_Aas;
}
DISPATCH(push_ss)
{
Instr->Operation = OP_PushSs;
}
DISPATCH(pop_ss)
{
Instr->Operation = OP_PopSs;
}
DISPATCH(push_ds)
{
Instr->Operation = OP_PushDs;
}
DISPATCH(pop_ds)
{
Instr->Operation = OP_PopDs;
}
DISPATCH(daa)
{
Instr->Operation = OP_Daa;
}
DISPATCH(das)
{
Instr->Operation = OP_Das;
}
DISPATCH(aaa)
{
Instr->Operation = OP_Aaa;
}
DISPATCH(aad_ib)
{
Instr->Operation = OP_Aad;
Instr->Operand1.Type = OPND_IMM;
Instr->Operand1.Immed = GET_BYTE(eipTemp+1);
Instr->Size = 2;
}
DISPATCH(imul_rw_m_iw16) // reg16 = rm16 * immediate word
{
int cbInstr = mod_rm_reg16(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul3Arg16;
DEREF16(Instr->Operand2);
Instr->Operand3.Type = OPND_IMM;
Instr->Operand3.Immed = GET_SHORT(eipTemp+1+cbInstr);
Instr->Size = 3+cbInstr;
}
DISPATCH(imul_rw_m_iw32)
{
int cbInstr = mod_rm_reg32(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul3Arg32;
DEREF32(Instr->Operand2);
Instr->Operand3.Type = OPND_IMM;
Instr->Operand3.Immed = GET_LONG(eipTemp+1+cbInstr);
Instr->Size = 5+cbInstr;
}
DISPATCH(imul_rw_m_ib16) // reg16 = rm16 * sign-extended immediate byte
{
int cbInstr = mod_rm_reg16(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul3Arg16;
DEREF16(Instr->Operand2);
Instr->Operand3.Type = OPND_IMM;
Instr->Operand3.Immed = (DWORD)(short)(char)GET_BYTE(eipTemp+1+cbInstr);
Instr->Size = 2+cbInstr;
}
DISPATCH(imul_rw_m_ib32) // reg32 = rm32 * sign-extended immediate byte
{
int cbInstr = mod_rm_reg32(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul3Arg32;
DEREF32(Instr->Operand2);
Instr->Operand3.Type = OPND_IMM;
Instr->Operand3.Immed = (DWORD)(long)(char)GET_BYTE(eipTemp+1+cbInstr);
Instr->Size = 2+cbInstr;
}
DISPATCH(mov_mw_seg)
{
int cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL);
get_segreg(State, &Instr->Operand2);
Instr->Operation = OP_Mov16;
Instr->Size = cbInstr+1;
}
DISPATCH(mov_seg_mw)
{
int cbInstr = mod_rm_reg16(State, &Instr->Operand2, NULL);
get_segreg(State, &Instr->Operand1);
Instr->Operation = OP_Mov16;
DEREF16(Instr->Operand2);
CPUASSERT(Instr->Operand1.Type == OPND_REGVALUE);
Instr->Operand1.Type = OPND_REGREF;
Instr->Size = cbInstr+1;
}
DISPATCH(nop)
{
Instr->Operation = OP_Nop;
}
DISPATCH(call_md)
{
Instr->Operation = OP_CTRL_UNCOND_Callf;
Instr->Operand1.Type = OPND_IMM;
Instr->Operand1.Immed = eipTemp+1;
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = eipTemp+sizeof(ULONG)+sizeof(USHORT)+1;
Instr->Size = sizeof(ULONG)+sizeof(USHORT)+1;
}
DISPATCH(sahf)
{
Instr->Operation = OP_Sahf;
}
DISPATCH(lahf)
{
Instr->Operation = OP_Lahf;
}
DISPATCH(mov_ah_ib)
{
Instr->Operation = OP_Mov8;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_AH;
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_BYTE(eipTemp+1);
Instr->Size = 2;
}
DISPATCH(mov_ch_ib)
{
Instr->Operation = OP_Mov8;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_CH;
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_BYTE(eipTemp+1);
Instr->Size = 2;
}
DISPATCH(mov_dh_ib)
{
Instr->Operation = OP_Mov8;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_DH;
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_BYTE(eipTemp+1);
Instr->Size = 2;
}
DISPATCH(mov_bh_ib)
{
Instr->Operation = OP_Mov8;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_BH;
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_BYTE(eipTemp+1);
Instr->Size = 2;
}
DISPATCH(int3)
{
Instr->Operation = OP_Int;
}
DISPATCH(int_ib)
{
Instr->Operation = OP_Int;
Instr->Size = 2;
}
DISPATCH(into)
{
Instr->Operation = OP_IntO;
}
DISPATCH(iret)
{
Instr->Operation = OP_CTRL_INDIR_IRet;
}
DISPATCH(aam_ib)
{
Instr->Operation = OP_Aam;
Instr->Operand1.Type = OPND_IMM;
Instr->Operand1.Immed = GET_BYTE(eipTemp+1);
Instr->Size = 2;
}
DISPATCH(xlat)
{
Instr->Operation = OP_Xlat;
}
DISPATCH(jmpf_md)
{
Instr->Operation = OP_CTRL_UNCOND_Jmpf;
Instr->Operand1.Type = OPND_IMM;
Instr->Operand1.Immed = eipTemp+1;
Instr->Size = 7;
}
DISPATCH(jmp_jb)
{
Instr->Operand1.Type = OPND_NOCODEGEN;
if (State->AdrPrefix) {
Instr->Operand1.Immed = MAKELONG((short)(char)GET_BYTE(eipTemp+1)+2+(short)LOWORD(eipTemp), HIWORD(eipTemp));
#if DBG
State->AdrPrefix = FALSE;
#endif
} else {
Instr->Operand1.Immed = (DWORD)(long)(char)GET_BYTE(eipTemp+1)+2+eipTemp;
}
if (Instr->Operand1.Immed > eipTemp) {
Instr->Operation = OP_CTRL_UNCOND_JmpFwd;
} else {
Instr->Operation = OP_CTRL_UNCOND_Jmp;
}
Instr->Size = 2;
}
DISPATCH(cmc)
{
Instr->Operation = OP_Cmc;
}
DISPATCH(clc)
{
Instr->Operation = OP_Clc;
}
DISPATCH(stc)
{
Instr->Operation = OP_Stc;
}
DISPATCH(cld)
{
Instr->Operation = OP_Cld;
}
DISPATCH(std)
{
Instr->Operation = OP_Std;
}
DISPATCH(GROUP_4)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
BYTE g = GET_BYTE(eipTemp+1);
switch ((g >> 3) & 0x07) {
case 0: // inc modrmB
Instr->Operation = OP_Inc8;
Instr->Size = 1+cbInstr;
break;
case 1: // dec modrmB
Instr->Operation = OP_Dec8;
Instr->Size = 1+cbInstr;
break;
default:
BAD_INSTR;
}
}
//-------- double-byte functions -----------------------------------------------
DISPATCH(GROUP_6)
{
BYTE g = GET_BYTE(eipTemp+1);
int cbInstr;
switch ((g >> 3) & 0x07) {
case 0: // sldt modrmw
case 1: // str modrmw
case 2: // lldt modrmw
case 3: // ltr modrmw
PRIVILEGED_INSTR;
break;
case 4: // verr modrmw
cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Verr;
Instr->Size = 2+cbInstr;
break;
case 5: // verw modrmw
cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Verw;
Instr->Size = 2+cbInstr;
break;
default:
BAD_INSTR; // bad
}
}
DISPATCH(GROUP_7)
{
BYTE g = GET_BYTE(eipTemp+1);
int cbInstr;
switch ((g >> 3) & 0x07) {
case 0: // sgdt modrmw
case 1: // sidt modrmw
case 2: // lgdt modrmw
case 3: // lidt modrmw
case 6: // lmsw modrmw
PRIVILEGED_INSTR;
break;
case 4: // smsw modrmw
cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Smsw;
Instr->Size = 2+cbInstr;
break;
case 5: // bad
case 7: // bad
BAD_INSTR;
}
}
DISPATCH(seto_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Seto;
Instr->Size = 2+cbInstr;
}
DISPATCH(setno_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setno;
Instr->Size = 2+cbInstr;
}
DISPATCH(setb_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setb;
Instr->Size = 2+cbInstr;
}
DISPATCH(setae_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setae;
Instr->Size = 2+cbInstr;
}
DISPATCH(sete_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Sete;
Instr->Size = 2+cbInstr;
}
DISPATCH(setne_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setne;
Instr->Size = 2+cbInstr;
}
DISPATCH(setbe_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setbe;
Instr->Size = 2+cbInstr;
}
DISPATCH(seta_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Seta;
Instr->Size = 2+cbInstr;
}
DISPATCH(sets_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Sets;
Instr->Size = 2+cbInstr;
}
DISPATCH(setns_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setns;
Instr->Size = 2+cbInstr;
}
DISPATCH(setp_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setp;
Instr->Size = 2+cbInstr;
}
DISPATCH(setnp_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setnp;
Instr->Size = 2+cbInstr;
}
DISPATCH(setl_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setl;
Instr->Size = 2+cbInstr;
}
DISPATCH(setge_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setge;
Instr->Size = 2+cbInstr;
}
DISPATCH(setle_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setle;
Instr->Size = 2+cbInstr;
}
DISPATCH(setg_modrmb)
{
int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setg;
Instr->Size = 2+cbInstr;
}
DISPATCH(push_fs)
{
Instr->Operation = OP_PushFs;
Instr->Size = 2;
}
DISPATCH(pop_fs)
{
Instr->Operation = OP_PopFs;
Instr->Size = 2;
}
DISPATCH(push_gs)
{
Instr->Operation = OP_PushGs;
Instr->Size = 2;
}
DISPATCH(pop_gs)
{
Instr->Operation = OP_PopGs;
Instr->Size = 2;
}
DISPATCH(imul_regw_modrmw16) // reg16 = reg16 * mod/rm
{
int cbInstr = mod_rm_reg16(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul16;
DEREF32(Instr->Operand2);
Instr->Size = 2+cbInstr;
}
DISPATCH(imul_regw_modrmw32) // reg32 = reg32 * mod/rm
{
int cbInstr = mod_rm_reg32(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul32;
DEREF32(Instr->Operand2);
Instr->Size = 2+cbInstr;
}
DISPATCH(movzx_regw_modrmw)
{
int cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL);
DEREF16(Instr->Operand1);
Instr->Operation = OP_Movzx16To32;
Instr->Operand2.Type = OPND_NOCODEGEN;
Instr->Operand2.Reg = get_reg32(State);
Instr->Size = 2+cbInstr;
}
DISPATCH(movsx_regw_modrmw)
{
int cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL);
DEREF16(Instr->Operand1);
Instr->Operation = OP_Movsx16To32;
Instr->Operand2.Type = OPND_NOCODEGEN;
Instr->Operand2.Reg = get_reg32(State);
Instr->Size = 2+cbInstr;
}
DISPATCH(wait)
{
Instr->Operation = OP_Wait;
}
DISPATCH(bswap_eax)
{
Instr->Operation = OP_Bswap32;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_EAX;
Instr->Size = 2;
}
DISPATCH(bswap_ebx)
{
Instr->Operation = OP_Bswap32;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_EBX;
Instr->Size = 2;
}
DISPATCH(bswap_ecx)
{
Instr->Operation = OP_Bswap32;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_ECX;
Instr->Size = 2;
}
DISPATCH(bswap_edx)
{
Instr->Operation = OP_Bswap32;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_EDX;
Instr->Size = 2;
}
DISPATCH(bswap_esp)
{
Instr->Operation = OP_Bswap32;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_ESP;
Instr->Size = 2;
}
DISPATCH(bswap_ebp)
{
Instr->Operation = OP_Bswap32;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_EBP;
Instr->Size = 2;
}
DISPATCH(bswap_esi)
{
Instr->Operation = OP_Bswap32;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_ESI;
Instr->Size = 2;
}
DISPATCH(bswap_edi)
{
Instr->Operation = OP_Bswap32;
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = GP_EDI;
Instr->Size = 2;
}
DISPATCH(arpl)
{
int cbInstr = mod_rm_reg16(State, &Instr->Operand1, &Instr->Operand2);
Instr->Operation = OP_Arpl;
CPUASSERT(Instr->Operand2.Type == OPND_REGREF);
Instr->Operand2.Type = OPND_REGVALUE;
Instr->Size = 1+cbInstr;
}
DISPATCH(cpuid)
{
Instr->Operation = OP_CPUID;
Instr->Size = 2;
}
DISPATCH(rdtsc)
{
Instr->Operation = OP_Rdtsc;
Instr->Size = 2;
}
DISPATCH(cmpxchg8b)
{
int cbInstr = mod_rm_reg32(State, &Instr->Operand1, &Instr->Operand2);
Instr->Operation = OP_CMPXCHG8B;
Instr->Size = 2+cbInstr;
}
DISPATCH(LOCKcmpxchg8b)
{
int cbInstr = mod_rm_reg32(State, &Instr->Operand1, &Instr->Operand2);
Instr->Operation = OP_SynchLockCMPXCHG8B;
Instr->Size = 2+cbInstr;
}